Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --add and --rm path to Action Menu #157

Merged
merged 13 commits into from
Oct 30, 2018
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
shallow_backup.egg-info/*
build/bdist.macosx-10.6-intel
build/lib
.vscode
50 changes: 28 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,32 +38,38 @@ To start the interactive program, simply run `$ shallow-backup`.
```shell
Usage: cli.py [OPTIONS]

Easily back up installed packages, dotfiles, and more.
You can edit which dotfiles are backed up in ~/.shallow-backup.
Easily back up installed packages, dotfiles, and more.
You can edit which files are backed up in ~/.shallow-backup.

Written by Aaron Lichtman (@alichtman).

Options:
--add <CHOICE TEXT>... Add path to be backed up.
-all Full back up.
-configs Back up app config files.
-delete_config Remove config file.
-destroy_backup Removes the backup directory and its content.
-dotfiles Back up dotfiles.
-fonts Back up installed fonts.
--new_path TEXT Input a new back up directory path.
-old_path Skip setting new back up directory path prompt.
-packages Back up package libraries.
-reinstall_configs Reinstall configs.
-reinstall_dots Reinstall dotfiles and dotfolders.
-reinstall_fonts Reinstall fonts.
-reinstall_packages Reinstall packages.
-reinstall_all Full reinstallation.
--remote TEXT Set remote URL for the git repo.
--rm TEXT Remove path from config.
-show Show config file.
-v Display version and author information and exit.
-h, -help, --help Show this message and exit.
--add <CHOICE TEXT TEXT>... Add path to back up. Format: (dot, config)
PATH [DEST]. PATH should be relative to HOME
for dots, and relative to / for configs. DEST
should be used for assigning a dest dir to non-
plist config files.
-all Full back up.
-configs Back up app config files.
-delete_config Delete config file.
-destroy_backup Delete backup directory.
-dotfiles Back up dotfiles.
-fonts Back up installed fonts.
--new_path TEXT Input a new back up directory path.
-old_path Skip setting new back up directory path prompt.
-packages Back up package libraries.
-reinstall_configs Reinstall configs.
-reinstall_dots Reinstall dotfiles and dotfolders.
-reinstall_fonts Reinstall fonts.
-reinstall_packages Reinstall packages.
-reinstall_all Full reinstallation.
--remote TEXT Set remote URL for the git repo.
--rm TEXT Remove path from backup. Use the source path,
just as it's displayed in the config file.
-show Display config file.
-v Display version and author information and
exit.
-h, -help, --help Show this message and exit.
```

### A Word of Caution
Expand Down
15 changes: 7 additions & 8 deletions shallow_backup/backup.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import os
from utils import *
from printing import *
from colorama import Fore
import multiprocessing as mp
from colorama import Fore, Style
from shutil import copytree, copyfile
from config import get_config
from printing import print_section_header, print_pkg_mgr_backup, print_blue
from utils import home_prefix, mkdir_warn_overwrite, mkdir_overwrite, \
run_cmd_write_stdout, copy_dir_if_valid, safe_mkdir, get_abs_path_subfiles


def overwrite_dir_prompt_if_needed(path, needed):
Expand Down Expand Up @@ -54,13 +53,13 @@ def backup_dotfiles(backup_path, skip=False):

# Multiprocessing
with mp.Pool(mp.cpu_count()):
print(Fore.BLUE + Style.BRIGHT + "Backing up dotfolders..." + Style.RESET_ALL)
print_blue_bold("Backing up dotfolders...")
for x in dotfolders_mp_in:
x = list(x)
mp.Process(target=copy_dir_if_valid, args=(x[0], x[1],)).start()

with mp.Pool(mp.cpu_count()):
print(Fore.BLUE + Style.BRIGHT + "Backing up dotfiles..." + Style.RESET_ALL)
print_blue_bold("Backing up dotfiles...")
for x in dotfiles_mp_in:
x = list(x)
mp.Process(target=copyfile, args=(x[0], x[1],)).start()
Expand All @@ -77,7 +76,7 @@ def backup_configs(backup_path, skip=False):
configs_dir_mapping = config["config_path_to_dest_map"]
plist_files = config["plist_path_to_dest_map"]

print(Fore.BLUE + Style.BRIGHT + "Backing up configs..." + Style.RESET_ALL)
print_blue_bold("Backing up configs...")

# backup config dirs in backup_path/<target>/
for config, target in configs_dir_mapping.items():
Expand All @@ -88,7 +87,7 @@ def backup_configs(backup_path, skip=False):
copytree(src_dir, configs_backup_path, symlinks=True)

# backup plist files in backup_path/configs/plist/
print(Fore.BLUE + Style.BRIGHT + "Backing up plist files..." + Style.RESET_ALL)
print_blue_bold("Backing up plist files...")
plist_backup_path = os.path.join(backup_path, "plist")
safe_mkdir(plist_backup_path)
for plist, dest in plist_files.items():
Expand Down
40 changes: 18 additions & 22 deletions shallow_backup/cli.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import os
import sys
import click
from config import *
from backup import *
from prompts import *
from printing import *
from reinstall import *
from git_wrapper import *
from utils import mkdir_warn_overwrite, destroy_backup_dir, expand_to_abs_path
from reinstall import reinstall_packages_sb, reinstall_configs_sb, reinstall_all_sb, reinstall_fonts_sb, reinstall_dots_sb
from prompts import actions_menu_prompt, prompt_for_git_url, prompt_for_path_update
from backup import backup_all, backup_configs, backup_dotfiles, backup_fonts, backup_packages
from git_wrapper import safe_git_init, git_set_remote, git_add_all_commit_push, safe_create_gitignore
from config import get_config, show_config, add_to_config, rm_from_config, write_config, safe_create_config, get_config_path


# custom help options
@click.command(context_settings=dict(help_option_names=['-h', '-help', '--help']))
@click.option('--add', nargs=2, default=[None, None], type=(click.Choice(['dot', 'config']), str),
help="\b Add path to back up. Format: [dot, config] PATH")
@click.option('-all', is_flag=True, default=False, help="Full back up.")
@click.option('-configs', is_flag=True, default=False, help="Back up app config files.")
@click.option('-delete_config', is_flag=True, default=False, help="Delete config file.")
Expand All @@ -29,10 +27,9 @@
@click.option('-reinstall_packages', is_flag=True, default=False, help="Reinstall packages.")
@click.option('-reinstall_all', is_flag=True, default=False, help="Full reinstallation.")
@click.option('--remote', default=None, help="Set remote URL for the git repo.")
@click.option('--rm', default=None, type=str, help="Remove path from backup.")
@click.option('-show', is_flag=True, default=False, help="Display config file.")
@click.option('-v', is_flag=True, default=False, help='Display version and author information and exit.')
def cli(add, rm, show, all, dotfiles, configs, packages, fonts, old_path, new_path, remote, reinstall_all,
def cli(show, all, dotfiles, configs, packages, fonts, old_path, new_path, remote, reinstall_all,
reinstall_configs, reinstall_dots, reinstall_fonts, reinstall_packages, delete_config, destroy_backup, v):
"""
\b
Expand All @@ -43,7 +40,7 @@ def cli(add, rm, show, all, dotfiles, configs, packages, fonts, old_path, new_pa
"""

# Process CLI args
admin_action = any([v, delete_config, destroy_backup, show, rm]) or None not in add
admin_action = any([v, delete_config, destroy_backup, show])
has_cli_arg = any([old_path, all, dotfiles, packages, fonts, configs,
reinstall_dots, reinstall_fonts, reinstall_all,
reinstall_configs, reinstall_packages])
Expand All @@ -61,10 +58,6 @@ def cli(add, rm, show, all, dotfiles, configs, packages, fonts, old_path, new_pa
elif destroy_backup:
backup_home_path = expand_to_abs_path(get_config()["backup_path"])
destroy_backup_dir(backup_home_path)
elif None not in add:
add_to_config(add[0], add[1])
elif rm:
rm_from_config(rm)
elif show:
show_config()
sys.exit()
Expand All @@ -77,8 +70,7 @@ def cli(add, rm, show, all, dotfiles, configs, packages, fonts, old_path, new_pa
# User entered a new path, so update the config
if new_path:
abs_path = os.path.abspath(new_path)
print(Fore.BLUE + Style.NORMAL + "\nUpdating shallow-backup path to -> " + Style.BRIGHT + "{}".format(
abs_path) + Style.RESET_ALL)
print(Fore.BLUE + Style.NORMAL + "\nUpdating shallow-backup path to -> " + Style.BRIGHT + "{}".format(abs_path) + Style.RESET_ALL)
backup_config["backup_path"] = abs_path
write_config(backup_config)

Expand Down Expand Up @@ -165,14 +157,18 @@ def cli(add, rm, show, all, dotfiles, configs, packages, fonts, old_path, new_pa
reinstall_dots_sb(dotfiles_path)
elif selection_words[-1] == "all":
reinstall_all_sb(dotfiles_path, packages_path, fonts_path, configs_path)
else:
elif selection.endswith("config"):
if selection == "show config":
show_config()
elif selection == "destroy backup":
if prompt_yes_no("Erase backup directory: {}?".format(backup_home_path), Fore.RED):
destroy_backup_dir(backup_home_path)
else:
print_red_bold("Exiting to prevent accidental deletion of backup directory.")
elif selection == "add path to config":
add_to_config()
elif selection == "remove path from config":
remove_from_config()
elif selection == "destroy backup":
if prompt_yes_no("Erase backup directory: {}?".format(backup_home_path), Fore.RED):
destroy_backup_dir(backup_home_path)
else:
print_red_bold("Exiting to prevent accidental deletion of backup directory.")

sys.exit()

Expand Down
70 changes: 4 additions & 66 deletions shallow_backup/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def write_config(config):
def get_default_config():
"""
Returns a default configuration.
# TODO: Cross-platform compatibility
"""
return {
"backup_path": "~/shallow-backup",
Expand Down Expand Up @@ -78,69 +79,6 @@ def safe_create_config():
write_config(backup_config)


# TODO: Rethink these methods.
def add_to_config(section, path):
"""
Adds the path under the correct section in the config file.
FIRST ARG: [dot, config, other]
SECOND ARG: path, relative to home directory for dotfiles, absolute for configs
"""
full_path = home_prefix(path)
if not os.path.exists(full_path):
print_red_bold("ERR: {} doesn't exist.".format(full_path))
sys.exit(1)

if section == "dot":
# Make sure dotfile starts with a period
if path[0] != ".":
print_red_bold("ERR: Not a dotfile.")
sys.exit(1)

if not os.path.isdir(full_path):
section = "dotfiles"
print(Fore.BLUE + Style.BRIGHT + "Adding {} to dotfile backup.".format(full_path) + Style.RESET_ALL)
else:
section = "dotfolders"
if path[-1] != "/":
full_path += "/"
path += "/"
print(Fore.BLUE + Style.BRIGHT + "Adding {} to dotfolder backup.".format(full_path) + Style.RESET_ALL)

# TODO: Add config section once configs backup prefs are moved to the config file
elif section == "config":
print(Fore.RED + Style.BRIGHT + "ERR: Option not currently supported." + Style.RESET_ALL)
sys.exit(1)
elif section == "other":
print(Fore.RED + Style.BRIGHT + "ERR: Option not currently supported." + Style.RESET_ALL)
sys.exit(1)

config = get_config()
file_set = set(config[section])
file_set.update([path])
config[section] = list(file_set)
write_config(config)


def rm_from_config(path):
"""
Removes the path from a section in the config file. Exits if the path doesn't exist.
Path, relative to home directory for dotfiles, absolute for configs
"""
flag = False
config = get_config()
for section, items in config.items():
if path in items:
print(Fore.BLUE + Style.BRIGHT + "Removing {} from backup...".format(path) + Style.RESET_ALL)
items.remove(path)
config[section] = items
flag = True

if not flag:
print(Fore.RED + Style.BRIGHT + "ERR: Not currently backing that path up..." + Style.RESET_ALL)
else:
write_config(config)


def show_config():
"""
Print the config. Colorize section titles and indent contents.
Expand All @@ -155,16 +93,16 @@ def show_config():
elif section == "backup_path":
print(Fore.RED + Style.BRIGHT + "Backup Path: " + Style.RESET_ALL + contents)
elif section == "config_path_to_dest_map":
print(Fore.RED + Style.BRIGHT + "Configs to Backup Path Mapping: " + Style.RESET_ALL)
print_red_bold("Configs to Backup Path Mapping: ")
for path, dest in contents.items():
print(" {} -> {}".format(path, dest))
elif section == "plist_path_to_dest_map":
print(Fore.RED + Style.BRIGHT + "Plist to Backup Path Mapping: " + Style.RESET_ALL)
print_red_bold("Plist to Backup Path Mapping: ")
for path, dest in contents.items():
print(" {} -> {}".format(path, dest))
# Print section header and then contents indented.
else:
print(Fore.RED + Style.BRIGHT + "\n{}: ".format(section.capitalize()) + Style.RESET_ALL)
print_red_bold("\n{}: ".format(section.capitalize()))
for item in contents:
print(" {}".format(item))

Expand Down
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 = '1.3'
VERSION = '1.4a'
AUTHOR_GITHUB = 'alichtman'
AUTHOR_FULL_NAME = 'Aaron Lichtman'
DESCRIPTION = "Easily create lightweight backups of installed packages, dotfiles, and more."
Expand Down
Loading