def add_backup(flags, bak_dir, name="unknown"): """ Adds a backup of the git repository. - bak_dir -- The destination directory. - name -- The name of the backup, replaces '_' with '-'. Returns the name of the created backup file. """ try: check_git_rep() # Make sure there are no '_' in the name. name.replace('_', '-') # Set the path to the new backup file. tar_name = "{0}_{1}{2}".format(name, strftime(_BAK_FILE_DATE_FORMAT), _BAK_FILE_EXT) tar_path = path.join(bak_dir, tar_name) # Make a safety backup of the current git repository. log(flags, "Creating backup file \'" + tar_path + "\'") if not flags[Flag.SAFEMODE]: mkdirs(flags, bak_dir) exec_cmd(["tar", "-czf", tar_path, "."]) return tar_name except Error as err: log(flags, "Could not add backup in \'" + bak_dir + "\'") raise OpError(err)
def clean_repository(flags): """ Cleans untracked files and files matched by a .gitignore file. """ try: if not flags[Flag.SAFEMODE]: exec_cmd(["git", "clean", "-fxd"]) exec_cmd(["git", "clean", "-fX"]) except CommandError: raise GitError("Could not clean ignored files", "clean")
def check_git_rep(): """ Checks if the current directory is a git repository. Errors will be raised as GitError (if not a rep). """ try: exec_cmd(["git", "status"]) except CommandError: raise GitError(getcwd() + " is not a git repository", "status")
def delete_tag(flags, tag): """ Deletes the given tag. Errors will be raised as GitError. """ check_git_rep() try: if not flags[Flag.SAFEMODE]: exec_cmd(["git", "tag", "-d", tag]) except CommandError: raise GitError("The tag '" + tag + "' could not be deleted", "tag")
def tag_head(flags, branch, tag): """ Tags the HEAD of the given branch. Errors will be raised as GitError. """ switch_branch(branch) try: if not flags[Flag.SAFEMODE]: exec_cmd(["git", "tag", tag]) except CommandError: raise GitError("The tag '" + tag + "' could not be created " + "and may already exist", "tag")
def reset_branch(flags, branch, commit): """ Resets the given branch to the given commit, (accepts HEAD as commit). Errors will be raised as GitError. """ switch_branch(branch) try: if not flags[Flag.SAFEMODE]: exec_cmd(["git", "reset", "--hard", commit]) except CommandError: raise GitError("Could not reset branch '" + branch + "' " + "to commit '" + commit + "'")
def commit_changes(flags, msg): """ Commits all changes for the current branch. Errors will be raised as GitError. """ check_git_rep() try: if not flags[Flag.SAFEMODE]: exec_cmd(["git", "add", "-A"]) exec_cmd(["git", "commit", "-m", msg]) except CommandError: raise GitError("Could not commit changes to current branch")
def stash_changes(flags, name=None): """ Stashes the changes in the working directory with a optional stash name. """ check_git_rep() try: if not flags[Flag.SAFEMODE]: if name is not None: exec_cmd(["git", "stash", "save", "--include-untracked", name]) else: exec_cmd(["git", "stash", "save", "--include-untracked"]) except CommandError: raise GitError("Could not stash uncommitted changes", "stash")
def switch_branch(branch): """ Switches to git branch. Errors will be raised as GitError (if checkout isn't possible). """ # Verify that the current dir is a git repository. check_git_rep() try: # Try to switch branch. exec_cmd(["git", "checkout", branch]) except: raise GitError( "Please make sure that the branch '" + branch + "' exists and all changes " + "are commited", "checkout" )
def init_repository(flags, dir_path): """ Initiate a git repository. :param flags: :type flags: dict :param dir_path: path of the repository to initiate :type dir_path: str :raises: GitError """ try: if not flags[Flag.SAFEMODE]: exec_cmd(["git", "init", dir_path]) except CommandError: raise GitError("Could not initiate repository '{}' ".format(dir_path))
def create_branch(flags, branch): """ Create a branch from the current. :param flags: :type flags: dict :param branch: the branch to create :type branch: str :raises: GitError """ try: if not flags[Flag.SAFEMODE]: exec_cmd(["git", "branch", branch]) except CommandError: raise GitError("Could not create branch '{}' ".format(branch))
def is_working_dir_clean(): """ Check if working directory is clean. Returns True if clean, False otherwise. """ check_git_rep() try: return exec_cmd(["git", "status", "--porcelain"]) == "" except CommandError: raise GitError("Could not determine if working directory is clean.", "status")
def get_branch(): """ Retrives the name of the current branch. Errors will be raised as GitError. """ check_git_rep() try: return exec_cmd(["git", "rev-parse", "--abbrev-ref", "HEAD"]) except CommandError: raise GitError("Could not find the name of the current branch", "rev-parse")
def get_head_commit(branch): """ Retrives the name HEAD commit on the given branch. Errors will be raised as GitError. """ switch_branch(branch) try: return exec_cmd(["git", "rev-parse", "HEAD"]) except CommandError: raise GitError("Could not find HEAD commit of branch '" + branch + "'", "rev-parse")
def get_latest_tag(branch, tag_type): """ Retrieves the latest tag (<tag_type>/<version>) for a branch. Errors will be raised as GitError (underlying errors or if no tags exists). """ # Get the latest tag. switch_branch(branch) try: return exec_cmd(["git", "describe", "--abbrev=0", "--tags", "--match", tag_type + "/*"]) except CommandError: raise GitError("The branch '" + branch + "' has no tags of type: " + tag_type + "/<version>")
def get_head_tags(branch, tag_type): """ Retrieves the tags for the HEAD commit on form (<tag_type>/<version>). Errors will be raised as GitError (underlying errors). Returns the list of HEAD tags for the given branch (can be empty). """ switch_branch(branch) try: # Get all tags at HEAD. head_tags = exec_cmd(["git", "tag", "--points-at", "HEAD"]) # Find the matching tags. matching_tags = findall(r"(?m)^" + tag_type + r"/.*$", head_tags) return matching_tags except CommandError: raise GitError("The tags pointing at '" + branch + "' HEAD, could not be retrieved", "tag")
def apply_stash(flags, branch, name=None, drop=True): """ Applies stashed changes on the given branch with a optional stash name. """ switch_branch(branch) try: if not flags[Flag.SAFEMODE]: if name is not None: exec_cmd(["git", "stash", "apply", "stash^{/{}}".format(name)]) if drop: exec_cmd(["git", "stash", "drop", "stash^{/{}}".format(name)]) else: exec_cmd(["git", "stash", "apply"]) if drop: exec_cmd(["git", "stash", "drop"]) except CommandError: raise GitError("Could not apply stashed changes" + (" (" + name + ")" if name is not None else ""), "stash")
def restore_backup(flags, bak_dir, num=None, name=None): """ Tries to restore repository to a saved backup. Will prompt the user for the requested restore point if num is not set. - bak_dir -- The backup storage directory. - num -- The index number of the restore point (latest first). """ try: check_git_rep() # If name is set just restore that file. if name is not None: bak_name = name else: # Find all previously backed up states. bak_files = get_files_with_extension(bak_dir, _BAK_FILE_EXT) if not bak_files: raise OpError("No backups exists in directory \'" + bak_dir + "\'") # Sort the bak_files according to date. bak_files.sort(key=lambda bak_f: [int(v) for v in bak_f.split('_')[1].split('.')[ 0].split('-')], reverse=True) # Set the max tab depth. max_tab_depth = max([1 + (len(s.split('_')[0]) // _TAB_WIDTH) for s in bak_files]) # Prompt user to select a state to restore. options = [] for f_name in bak_files: option = "\t" + f_name.split('_')[0] option += "\t" * (max_tab_depth - len(f_name.split('_')[0]) // _TAB_WIDTH) option += datetime.strptime( f_name.split('_')[1].split('.')[0], _BAK_FILE_DATE_FORMAT).strftime(_BAK_DISPLAY_DATE_FORMAT) options.append(option) # Check if prompt can be skipped. if num is not None: if num >= len(options) or num < 0: raise OpError("Invalid backup index \'" + num + "\' is outside [0-" + str(len(options) - 1) + "]") else: # Prompt. num = prompt_user_options("Select the backup to restore", options) if num is None: raise OpError(msg="Restore aborted by user") # Set the chosen backup name. bak_name = bak_files[num] # Restore backup. try: log(flags, "Restoring backup \'" + bak_name + "\'") clean_dir(flags, getcwd()) if not flags[Flag.SAFEMODE]: exec_cmd(["tar", "-xf", path.join(bak_dir, bak_name)]) except Error as err: log(flags, "Restore failed, the backup can be found in \'" + bak_dir + "\'", TextType.ERR) raise OpError(err) except GitError as err: log(flags, "Restore could not be completed") raise OpError(err)