A console script that allows you to easily update multiple git repositories at once
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

151 lines
5.4 KiB

  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright (C) 2011-2014 Ben Kurtovic <ben.kurtovic@gmail.com>
  4. # See the LICENSE file for details.
  5. from __future__ import print_function
  6. import os
  7. import shlex
  8. import subprocess
  9. from colorama import Fore, Style
  10. __all__ = ["update_bookmarks", "update_directories"]
  11. BOLD = Style.BRIGHT
  12. RED = Fore.RED + BOLD
  13. GREEN = Fore.GREEN + BOLD
  14. BLUE = Fore.BLUE + BOLD
  15. RESET = Style.RESET_ALL
  16. INDENT1 = " " * 3
  17. INDENT2 = " " * 7
  18. def _directory_is_git_repo(directory_path):
  19. """Check if a directory is a git repository."""
  20. if os.path.isdir(directory_path):
  21. git_subfolder = os.path.join(directory_path, ".git")
  22. if os.path.isdir(git_subfolder): # Check for path/to/repository/.git
  23. return True
  24. return False
  25. def _update_repository(repo_path, repo_name):
  26. """Update a single git repository by pulling from the remote."""
  27. def _exec_shell(command):
  28. """Execute a shell command and get the output."""
  29. command = shlex.split(command)
  30. result = subprocess.check_output(command, stderr=subprocess.STDOUT)
  31. if result:
  32. result = result[:-1] # Strip newline if command returned anything
  33. return result
  34. print(INDENT1, BOLD + repo_name + ":")
  35. # cd into our folder so git commands target the correct repo:
  36. os.chdir(repo_path) # TODO: remove this when using gitpython
  37. try:
  38. # Check if there is anything to pull, but don't do it yet:
  39. dry_fetch = _exec_shell("git fetch --dry-run")
  40. except subprocess.CalledProcessError:
  41. print(INDENT2, RED + "Error:" + RESET, "cannot fetch;",
  42. "do you have a remote repository configured correctly?")
  43. return
  44. try:
  45. last_commit = _exec_shell("git log -n 1 --pretty=\"%ar\"")
  46. except subprocess.CalledProcessError:
  47. last_commit = "never" # Couldn't get a log, so no commits
  48. if not dry_fetch: # No new changes to pull
  49. print(INDENT2, BLUE + "No new changes." + RESET,
  50. "Last commit was {0}.".format(last_commit))
  51. else: # Stuff has happened!
  52. print(INDENT2, "There are new changes upstream...")
  53. status = _exec_shell("git status")
  54. if status.endswith("nothing to commit, working directory clean"):
  55. print(INDENT2, GREEN + "Pulling new changes...")
  56. result = _exec_shell("git pull")
  57. if last_commit == "never":
  58. print(INDENT2, "The following changes have been made:")
  59. else:
  60. print(INDENT2, "The following changes have been made since",
  61. last_commit + ":")
  62. print(result)
  63. else:
  64. print(INDENT2, RED + "Warning:" + RESET,
  65. "you have uncommitted changes in this repository!")
  66. print(INDENT2, "Ignoring.")
  67. def _update_directory(dir_path, dir_name, is_bookmark=False):
  68. """Update a particular directory.
  69. First, make sure the specified object is actually a directory, then
  70. determine whether the directory is a git repo on its own or a directory
  71. of git repositories. If the former, update the single repository; if the
  72. latter, update all repositories contained within.
  73. """
  74. if is_bookmark:
  75. dir_type = "bookmark" # Where did we get this directory from?
  76. else:
  77. dir_type = "directory"
  78. dir_long_name = dir_type + ' "' + BOLD + dir_path + RESET + '"'
  79. try:
  80. os.listdir(dir_path) # Test if we can access this directory
  81. except OSError:
  82. print(RED + "Error:" + RESET,
  83. "cannot enter {0}; does it exist?".format(dir_long_name))
  84. return
  85. if not os.path.isdir(dir_path):
  86. if os.path.exists(dir_path):
  87. print(RED + "Error:" + RESET, dir_long_name, "is not a directory!")
  88. else:
  89. print(RED + "Error:" + RESET, dir_long_name, "does not exist!")
  90. return
  91. if _directory_is_git_repo(dir_path):
  92. print(dir_long_name.capitalize(), "is a git repository:")
  93. _update_repository(dir_path, dir_name)
  94. else:
  95. repositories = []
  96. dir_contents = os.listdir(dir_path) # Get potential repos in directory
  97. for item in dir_contents:
  98. repo_path = os.path.join(dir_path, item)
  99. repo_name = os.path.join(dir_name, item)
  100. if _directory_is_git_repo(repo_path): # Filter out non-repos
  101. repositories.append((repo_path, repo_name))
  102. num_of_repos = len(repositories)
  103. if num_of_repos == 1:
  104. print(dir_long_name.capitalize(), "contains 1 git repository:")
  105. else:
  106. print(dir_long_name.capitalize(),
  107. "contains {0} git repositories:".format(num_of_repos))
  108. repositories.sort() # Go alphabetically instead of randomly
  109. for repo_path, repo_name in repositories:
  110. _update_repository(repo_path, repo_name)
  111. def update_bookmarks(bookmarks):
  112. """Loop through and update all bookmarks."""
  113. if bookmarks:
  114. for bookmark_path, bookmark_name in bookmarks:
  115. _update_directory(bookmark_path, bookmark_name, is_bookmark=True)
  116. else:
  117. print("You don't have any bookmarks configured! Get help with 'gitup -h'.")
  118. def update_directories(paths):
  119. """Update a list of directories supplied by command arguments."""
  120. for path in paths:
  121. path = os.path.abspath(path) # Convert relative to absolute path
  122. path_name = os.path.split(path)[1] # Dir name ("x" in /path/to/x/)
  123. _update_directory(path, path_name, is_bookmark=False)