def uninstall(self): """ Uninstall Mackup. Restore any file where it was before the 1st Mackup backup. Algorithm: for each file in config if mackup/file exists if home/file exists delete home/file copy mackup/file home/file delete the mackup folder print how to delete mackup """ # For each file used by the application for filename in self.files: (home_filepath, mackup_filepath) = self.getFilepaths(filename) # If the mackup file exists if os.path.isfile(mackup_filepath) or os.path.isdir( mackup_filepath): # Check if there is a corresponding file in the home folder if os.path.exists(home_filepath): if self.verbose: print( colorize_text("Reverting ") + colorize_filename(mackup_filepath) + "\n " + colorize_text("at ") + colorize_filename(home_filepath) + colorize_text(" ...")) else: print( colorize_text("Reverting ") + colorize_filename(filename) + colorize_text(" ...")) if self.dry_run: continue # If there is, delete it as we are gonna copy the Dropbox # one there utils.delete(home_filepath) # Copy the Dropbox file to the home folder utils.copy(mackup_filepath, home_filepath) elif self.verbose: print( colorize_text("Doing nothing, ") + colorize_filename(mackup_filepath) + colorize_text(" does not exist"))
def backup(self): """ Backup the application config files. Algorithm: if exists home/file if home/file is a real file if exists mackup/file are you sure ? if sure rm mackup/file mv home/file mackup/file link mackup/file home/file else mv home/file mackup/file link mackup/file home/file """ # For each file used by the application for filename in self.files: (home_filepath, mackup_filepath) = self.getFilepaths(filename) # If the file exists and is not already a link pointing to Mackup if (os.path.isfile(home_filepath) or os.path.isdir(home_filepath) ) and not (os.path.islink(home_filepath) and (os.path.isfile(mackup_filepath) or os.path.isdir(mackup_filepath)) and os.path.samefile(home_filepath, mackup_filepath)): if self.verbose: print((colorize_text("Backing up") + "\n " + colorize_filename(home_filepath) + "\n " + colorize_text("to") + "\n " + colorize_filename(mackup_filepath) + colorize_text(" ..."))) else: print( (colorize_text("Backing up ") + colorize_filename(filename) + colorize_text(" ..."))) if self.dry_run: continue # Check if we already have a backup if os.path.exists(mackup_filepath): # Name it right if os.path.isfile(mackup_filepath): file_type = "file" elif os.path.isdir(mackup_filepath): file_type = "folder" elif os.path.islink(mackup_filepath): file_type = "link" else: raise ValueError( "Unsupported file: {}".format(mackup_filepath)) # Ask the user if he really want to replace it if utils.confirm("A {} named {} already exists in the" " backup.\nAre you sure that you want to" " replace it ?".format( file_type, mackup_filepath)): # Delete the file in Mackup utils.delete(mackup_filepath) # Copy the file utils.copy(home_filepath, mackup_filepath) # Delete the file in the home utils.delete(home_filepath) # Link the backuped file to its original place utils.link(mackup_filepath, home_filepath) else: # Copy the file utils.copy(home_filepath, mackup_filepath) # Delete the file in the home utils.delete(home_filepath) # Link the backuped file to its original place utils.link(mackup_filepath, home_filepath) elif self.verbose: if os.path.exists(home_filepath): print( colorize_text("Doing nothing") + "\n " + colorize_filename(home_filepath) + "\n " + colorize_text("is already backed up to") + "\n " + colorize_filename(mackup_filepath)) elif os.path.islink(home_filepath): print( colorize_text("Doing nothing") + "\n " + colorize_filename(home_filepath) + "\n " + colorize_text( "is a broken link, you might want to fix it.")) else: print( colorize_text("Doing nothing") + "\n " + colorize_filename(home_filepath) + "\n" + colorize_text("does not exist"))
def main(): """Main function.""" # Get the command line arg args = docopt(__doc__, version="Mackup {}".format(VERSION)) mckp = Mackup() app_db = ApplicationsDatabase() def printAppHeader(app_name): if verbose: print("\n" + colorize_header("---") + " " + colorize_header_app_name(app_name) + " " + colorize_header("---")) # If we want to answer mackup with "yes" for each question if args["--force"]: utils.FORCE_YES = True # Allow mackup to be run as root if args["--root"]: utils.CAN_RUN_AS_ROOT = True dry_run = args["--dry-run"] verbose = args["--verbose"] if args["backup"]: # Check the env where the command is being run mckp.check_for_usable_backup_env() # Backup each application for app_name in sorted(mckp.get_apps_to_backup()): app = ApplicationProfile(mckp, app_db.get_files(app_name), dry_run, verbose) printAppHeader(app_name) app.backup() elif args["restore"]: # Check the env where the command is being run mckp.check_for_usable_restore_env() # Restore the Mackup config before any other config, as we might need # it to know about custom settings mackup_app = ApplicationProfile(mckp, app_db.get_files(MACKUP_APP_NAME), dry_run, verbose) printAppHeader(MACKUP_APP_NAME) mackup_app.restore() # Initialize again the apps db, as the Mackup config might have changed # it mckp = Mackup() app_db = ApplicationsDatabase() # Restore the rest of the app configs, using the restored Mackup config app_names = mckp.get_apps_to_backup() # Mackup has already been done app_names.discard(MACKUP_APP_NAME) for app_name in sorted(app_names): app = ApplicationProfile(mckp, app_db.get_files(app_name), dry_run, verbose) printAppHeader(app_name) app.restore() elif args["uninstall"]: # Check the env where the command is being run mckp.check_for_usable_restore_env() if dry_run or (utils.confirm( colorize_text( "You are going to uninstall Mackup.\n" "Every configuration file, setting and dotfile" " managed by Mackup will be unlinked and moved back" " to their original place, in your home folder.\n" "Are you sure ?"))): # Uninstall the apps except Mackup, which we'll uninstall last, to # keep the settings as long as possible app_names = mckp.get_apps_to_backup() app_names.discard(MACKUP_APP_NAME) for app_name in sorted(app_names): app = ApplicationProfile(mckp, app_db.get_files(app_name), dry_run, verbose) printAppHeader(app_name) app.uninstall() # Restore the Mackup config before any other config, as we might # need it to know about custom settings mackup_app = ApplicationProfile(mckp, app_db.get_files(MACKUP_APP_NAME), dry_run, verbose) mackup_app.uninstall() # Delete the Mackup folder in Dropbox # Don't delete this as there might be other Macs that aren't # uninstalled yet # delete(mckp.mackup_folder) print( colorize_text( "\n" "All your files have been put back into place. You can now" " safely uninstall Mackup.\n" "\n" "Thanks for using Mackup !")) elif args["list"]: # Display the list of supported applications mckp.check_for_usable_environment() output = colorize_text("Supported applications:") + "\n" for app_name in sorted(app_db.get_app_names()): output += colorize_item_bullet(" - ") + colorize_filename( app_name) + "\n" output += "\n" output += colorize_text( "{} applications supported in Mackup v{}".format( len(app_db.get_app_names()), VERSION)) print(output) elif args["show"]: mckp.check_for_usable_environment() app_name = args["<application>"] # Make sure the app exists if app_name not in app_db.get_app_names(): sys.exit("Unsupported application: {}".format(app_name)) print( colorize_text("Name: ") + colorize_name(app_db.get_name(app_name))) print(colorize_text("Configuration files:")) for file in app_db.get_files(app_name): print(colorize_item_bullet(" - ") + colorize_filename(file)) # Delete the tmp folder mckp.clean_temp_folder()
def restore(self): """ Restore the application config files. Algorithm: if exists mackup/file if exists home/file are you sure ? if sure rm home/file link mackup/file home/file else link mackup/file home/file """ # For each file used by the application for filename in self.files: (home_filepath, mackup_filepath) = self.getFilepaths(filename) # If the file exists and is not already pointing to the mackup file # and the folder makes sense on the current platform (Don't sync # any subfolder of ~/Library on GNU/Linux) file_or_dir_exists = os.path.isfile( mackup_filepath) or os.path.isdir(mackup_filepath) pointing_to_mackup = (os.path.islink(home_filepath) and os.path.exists(mackup_filepath) and os.path.samefile(mackup_filepath, home_filepath)) supported = utils.can_file_be_synced_on_current_platform(filename) if file_or_dir_exists and not pointing_to_mackup and supported: if self.verbose: print( colorize_text("Restoring\n linking ") + colorize_filename(home_filepath) + "\n " + colorize_text("to ") + colorize_filename(mackup_filepath) + colorize_text(" ...")) else: print( colorize_text("Restoring ") + colorize_filename(filename) + colorize_text(" ...")) if self.dry_run: continue # Check if there is already a file in the home folder if os.path.exists(home_filepath): # Name it right if os.path.isfile(home_filepath): file_type = "file" elif os.path.isdir(home_filepath): file_type = "folder" elif os.path.islink(home_filepath): file_type = "link" else: raise ValueError( "Unsupported file: {}".format(mackup_filepath)) if utils.confirm("You already have a {} named {} in your" " home.\nDo you want to replace it with" " your backup ?".format( file_type, filename)): utils.delete(home_filepath) utils.link(mackup_filepath, home_filepath) else: utils.link(mackup_filepath, home_filepath) elif self.verbose: if os.path.exists(home_filepath): print( colorize_text("Doing nothing") + "\n " + colorize_filename(mackup_filepath) + "\n " + colorize_text("already linked by") + "\n " + colorize_filename(home_filepath)) elif os.path.islink(home_filepath): print( colorize_text("Doing nothing") + "\n " + colorize_filename(home_filepath) + "\n " + colorize_text( "is a broken link, you might want to fix it.")) else: print( colorize_text("Doing nothing") + "\n " + colorize_filename(mackup_filepath) + "\n" + colorize_text("does not exist"))
def test_colorize_filename(self): assert colorize_filename("Blah") == "\x1b[1;34mBlah\x1b[0m"