# -*- coding: utf-8 -*- # # Copyright (C) 2011-2014 Ben Kurtovic # See the LICENSE file for details. from __future__ import print_function import os from colorama import Fore, Style from git import Repo, exc __all__ = ["update_bookmarks", "update_directories"] BOLD = Style.BRIGHT RED = Fore.RED + BOLD GREEN = Fore.GREEN + BOLD BLUE = Fore.BLUE + BOLD RESET = Style.RESET_ALL INDENT1 = " " * 3 INDENT2 = " " * 7 def _update_repository(repo, rebase=True): """Update a single git repository by fetching remotes and rebasing/merging. The specific actions depends on ... """ print(INDENT1, BOLD + os.path.split(repo.working_dir)[1] + ":") ref = repo.head.ref.tracking_branch() if ref: remote = repo.remotes[ref.remote_name] # else: ### remote.fetch() if not repo.remotes: print(INDENT2, RED + "Error:" + RESET, "no remotes configured.") return try: repo = repo.remotes.origin except AttributeError: if len(repo.remotes) == 1: repo = repo.remotes[0] else: print(INDENT2, RED + "Error:" + RESET, "ambiguous remotes:", ", ".join(remote.name for remote in repo.remotes)) ##################################### try: # Check if there is anything to pull, but don't do it yet: dry_fetch = _exec_shell("git fetch --dry-run") except subprocess.CalledProcessError: print(INDENT2, RED + "Error:" + RESET, "cannot fetch;", "do you have a remote repository configured correctly?") return try: last_commit = _exec_shell("git log -n 1 --pretty=\"%ar\"") except subprocess.CalledProcessError: last_commit = "never" # Couldn't get a log, so no commits if not dry_fetch: # No new changes to pull print(INDENT2, BLUE + "No new changes." + RESET, "Last commit was {0}.".format(last_commit)) else: # Stuff has happened! print(INDENT2, "There are new changes upstream...") status = _exec_shell("git status") if status.endswith("nothing to commit, working directory clean"): print(INDENT2, GREEN + "Pulling new changes...") result = _exec_shell("git pull") if last_commit == "never": print(INDENT2, "The following changes have been made:") else: print(INDENT2, "The following changes have been made since", last_commit + ":") print(result) else: print(INDENT2, RED + "Warning:" + RESET, "you have uncommitted changes in this repository!") print(INDENT2, "Ignoring.") def _update_subdirectories(path, long_name): """Update all subdirectories that are git repos in a given directory.""" repos = [] for item in os.listdir(path): try: repo = Repo(os.path.join(path, item)) except (exc.InvalidGitRepositoryError, exc.NoSuchPathError): continue repos.append(repo) suffix = "ies" if len(repos) != 1 else "y" print(long_name[0].upper() + long_name[1:], "contains {0} git repositor{1}:".format(len(repos), suffix)) for repo in sorted(repos, key=lambda r: os.path.split(r.working_dir)[1]): _update_repository(repo) def _update_directory(path, is_bookmark=False): """Update a particular directory. Determine whether the directory is a git repo on its own, a directory of git repositories, or something invalid. If the first, update the single repository; if the second, update all repositories contained within; if the third, print an error. """ dir_type = "bookmark" if is_bookmark else "directory" long_name = dir_type + ' "' + BOLD + path + RESET + '"' try: repo = Repo(path) except exc.NoSuchPathError: print(RED + "Error:" + RESET, long_name, "doesn't exist!") except exc.InvalidGitRepositoryError: if os.path.isdir(path): _update_subdirectories(path, long_name) else: print(RED + "Error:" + RESET, long_name, "isn't a repository!") else: long_name = (dir_type.capitalize() + ' "' + BOLD + repo.working_dir + RESET + '"') print(long_name, "is a git repository:") _update_repository(repo) def update_bookmarks(bookmarks, current_only=False, rebase=False, merge=False, verbose=False): """Loop through and update all bookmarks.""" if bookmarks: for path, name in bookmarks: _update_directory(path, is_bookmark=True) else: print("You don't have any bookmarks configured! Get help with 'gitup -h'.") def update_directories(paths, current_only=False, rebase=False, merge=False, verbose=False): """Update a list of directories supplied by command arguments.""" for path in paths: _update_directory(os.path.abspath(path), is_bookmark=False)