A console script that allows you to easily update multiple git repositories at once
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

151 rader
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)