Skip to content

Commit

Permalink
Merge pull request #251 from alichtman/fix_gitignore_usage
Browse files Browse the repository at this point in the history
Carefully reinstall .git and .gitignore files
  • Loading branch information
alichtman authored Mar 22, 2020
2 parents bd7b952 + ac05997 commit a6879e4
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 35 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ If you'd like to modify which files are backed up, you have to edit the `~/.conf
1. Select the appropriate option in the CLI and follow the prompts.
2. Open the file in a text editor and make your changes.
#### .gitignore
As of `v4.0`, any `.gitignore` changes should be made in the `shallow-backup` config file. `.gitignore` changes that are meant to apply to all directories should be under the `root-gitignore` key. Dotfile specific gitignores should be placed under the `dotfiles-gitignore` key. The original `default-gitignore` key in the config is still supported for backwards compatibility, however, converting to the new config format is strongly encouraged.
#### Output Structure
---
Expand Down
12 changes: 6 additions & 6 deletions shallow_backup/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,19 +95,19 @@ def cli(add_dot, all, configs, delete_config, destroy_backup, dotfiles, fonts, n
backup_home_path = expand_to_abs_path(get_config()["backup_path"])
mkdir_warn_overwrite(backup_home_path)
repo, new_git_repo_created = safe_git_init(backup_home_path)
create_gitignore(backup_home_path, "root-gitignore")

# Create default gitignore if we just ran git init
if new_git_repo_created:
safe_create_gitignore(backup_home_path)
# Prompt user for remote URL
if not remote:
git_url_prompt(repo)
# Prompt user for remote URL if needed
if new_git_repo_created and not remote:
git_url_prompt(repo)

# Set remote URL from CLI arg
if remote:
git_set_remote(repo, remote)

dotfiles_path = os.path.join(backup_home_path, "dotfiles")
create_gitignore(dotfiles_path, "dotfiles-gitignore")

configs_path = os.path.join(backup_home_path, "configs")
packages_path = os.path.join(backup_home_path, "packages")
fonts_path = os.path.join(backup_home_path, "fonts")
Expand Down
16 changes: 9 additions & 7 deletions shallow_backup/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,16 @@ def get_default_config():
".ssh",
".vim"
],
"default-gitignore": [
"root-gitignore": [
"dotfiles/.ssh",
"dotfiles/.pypirc",
".DS_Store"
],
"dotfiles-gitignore": [
".ssh",
".pypirc",
".DS_Store",
],
"config_mapping" : get_config_paths()
}

Expand Down Expand Up @@ -142,18 +147,15 @@ def show_config():
"""
print_section_header("SHALLOW BACKUP CONFIG", Fore.RED)
for section, contents in get_config().items():
# Hide gitignore config
if section == "default-gitignore":
continue
# Print backup path on same line
elif section == "backup_path":
if section == "backup_path":
print_path_red("Backup Path:", contents)
elif section == "config_mapping":
print_red_bold("Configs:")
print_red_bold("\nConfigs:")
for path, dest in contents.items():
print(" {} -> {}".format(path, dest))
# Print section header and intent contents. (Dotfiles/folders)
else:
print_red_bold("\n{}: ".format(section.capitalize()))
print_red_bold("\n{}: ".format(section.replace("-", " ").capitalize()))
for item in contents:
print(" {}".format(item))
2 changes: 1 addition & 1 deletion shallow_backup/constants.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class ProjInfo:
PROJECT_NAME = 'shallow-backup'
VERSION = '3.4'
VERSION = '4.0'
AUTHOR_GITHUB = 'alichtman'
AUTHOR_FULL_NAME = 'Aaron Lichtman'
DESCRIPTION = "Easily create lightweight backups of installed packages, dotfiles, and more."
Expand Down
25 changes: 15 additions & 10 deletions shallow_backup/git_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,24 @@ def git_set_remote(repo, remote_url):
origin.fetch()


def safe_create_gitignore(dir_path):
def create_gitignore(dir_path, key):
"""
Creates a .gitignore file that ignores all files listed in config.
Handles backwards compatibility for the default-gitignore -> root-gitignore
change and the introduction of the dotfiles-gitignore key in v4.0.
"""
gitignore_path = os.path.join(dir_path, ".gitignore")
if os.path.exists(gitignore_path):
print_yellow_bold("Detected .gitignore file.")
else:
print_yellow_bold("Creating default .gitignore...")
files_to_ignore = get_config()["default-gitignore"]
with open(gitignore_path, "w+") as f:
for ignore in files_to_ignore:
f.write("{}\n".format(ignore))
print_yellow_bold(f"Updating .gitignore file at {gitignore_path} with config from {key}")
try:
files_to_ignore = get_config()[key]
except KeyError:
if key == "root-gitignore":
files_to_ignore = get_config()["default-gitignore"]
elif key == "dotfiles-gitignore":
pass
with open(os.path.join(dir_path, ".gitignore"), "w+") as f:
for ignore in files_to_ignore:
f.write("{}\n".format(ignore))


def safe_git_init(dir_path):
Expand Down Expand Up @@ -87,7 +92,7 @@ def git_add_all_commit_push(repo, message, separate_dotfiles_repo=False):
repo.git.add(A=True)
try:
repo.git.commit(m=COMMIT_MSG[message])
# Git submodule issue https://github.com/alichtman/shallow-backup/issues/229
# Git submodule issue https://github.com/alichtman/shallow-backup/issues/229
except git.exc.GitCommandError as e:
error = e.stdout.strip()
error = error[error.find("\'") + 1:-1]
Expand Down
11 changes: 8 additions & 3 deletions shallow_backup/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,19 @@ def destroy_backup_dir(backup_path):

def get_abs_path_subfiles(directory):
"""
Returns list of absolute paths of files and folders contained in a directory, excluding .git directories.
Returns list of absolute paths of files and folders contained in a directory,
excluding the root .git directory and root .gitignore..
"""
file_paths = []
for path, _, files in os.walk(directory):
for name in files:
joined = os.path.join(path, name)
if "/.git/" not in joined:
file_paths.append(os.path.join(path, name))
root_git_dir = os.path.join(directory, ".git")
root_gitignore = os.path.join(directory, ".gitignore")
if root_git_dir not in joined and root_gitignore not in joined:
file_paths.append(joined)
else:
print(f"Excluded: {joined}")
return file_paths


Expand Down
4 changes: 2 additions & 2 deletions tests/test_git_folder_moving.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import shutil
from .test_utils import BACKUP_DEST_DIR, FAKE_HOME_DIR, DIRS, setup_env_vars, create_config_for_test
sys.path.insert(0, "../shallow_backup")
from shallow_backup.git_wrapper import move_git_repo, safe_git_init, safe_create_gitignore
from shallow_backup.git_wrapper import move_git_repo, safe_git_init, create_gitignore


class TestGitFolderCopying:
Expand Down Expand Up @@ -32,7 +32,7 @@ def test_copy_git_folder(self):
Test copying the .git folder and .gitignore from an old directory to a new one
"""
safe_git_init(FAKE_HOME_DIR)
safe_create_gitignore(FAKE_HOME_DIR)
create_gitignore(FAKE_HOME_DIR, "root-gitignore")
move_git_repo(FAKE_HOME_DIR, BACKUP_DEST_DIR)
assert os.path.isdir(os.path.join(BACKUP_DEST_DIR, '.git/'))
assert os.path.isfile(os.path.join(BACKUP_DEST_DIR, '.gitignore'))
Expand Down
24 changes: 18 additions & 6 deletions tests/test_reinstall_dotfiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ def create_file(parent, name):
with open(file, "w+") as f:
f.write(TEST_TEXT_CONTENT)

def create_git_dir(parent):
git_dir = create_dir(parent, ".git/")
git_objects = create_dir(git_dir, "objects/")
create_file(git_dir, "config")
create_file(git_objects, "obj1")
return git_dir


setup_env_vars()
create_config_for_test()
for directory in DIRS:
Expand All @@ -49,14 +57,13 @@ def create_file(parent, name):
testfolder = create_dir(DOTFILES_PATH, "testfolder1/")
testfolder2 = create_dir(testfolder, "testfolder2/")

# Git dir that should not be reinstalled
git = create_dir(DOTFILES_PATH, ".git/")
git_objects = create_dir(git, "objects/")
create_file(git, "config")
create_file(git_objects, "obj1")
git_dir_should_not_reinstall = create_git_dir(DOTFILES_PATH)
git_dir_should_reinstall = create_git_dir(testfolder2)

# SAMPLE DOTFILES TO REINSTALL
create_file(testfolder2, ".testsubfolder_rc1")
create_file(testfolder2, ".gitignore")
create_file(DOTFILES_PATH, ".gitignore")
create_file(testfolder2, ".testsubfolder_rc2")
create_file(DOTFILES_PATH, ".testrc")

Expand All @@ -76,4 +83,9 @@ def test_reinstall_dotfiles(self):
assert os.path.isfile(os.path.join(testfolder2, '.testsubfolder_rc1'))
assert os.path.isfile(os.path.join(testfolder2, '.testsubfolder_rc2'))

assert not os.path.isdir(os.path.join(FAKE_HOME_DIR, '.git'))
# Don't reinstall root-level git files
assert not os.path.isdir(os.path.join(FAKE_HOME_DIR, ".git"))
assert not os.path.isfile(os.path.join(FAKE_HOME_DIR, ".gitignore"))
# Do reinstall all other git files
assert os.path.isdir(os.path.join(testfolder2, ".git"))
assert os.path.isfile(os.path.join(testfolder2, ".gitignore"))

0 comments on commit a6879e4

Please sign in to comment.