A console script that allows you to easily update multiple git repositories at once
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

149 lines
5.5 KiB

  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright (C) 2011-2018 Ben Kurtovic <ben.kurtovic@gmail.com>
  4. # Released under the terms of the MIT License. See LICENSE for details.
  5. from __future__ import print_function
  6. import argparse
  7. import os
  8. import platform
  9. import sys
  10. from colorama import init as color_init, Style
  11. from gitup import __version__
  12. from gitup.config import (get_default_config_path, get_bookmarks, add_bookmarks,
  13. delete_bookmarks, list_bookmarks, clean_bookmarks)
  14. from gitup.update import update_bookmarks, update_directories, run_command
  15. def _decode(path):
  16. """Decode the given string using the system's filesystem encoding."""
  17. if sys.version_info.major > 2:
  18. return path
  19. return path.decode(sys.getfilesystemencoding())
  20. def _build_parser():
  21. """Build and return the argument parser."""
  22. parser = argparse.ArgumentParser(
  23. description="Easily update multiple git repositories at once.",
  24. epilog="""
  25. Both relative and absolute paths are accepted by all arguments.
  26. Direct bug reports and feature requests to
  27. https://github.com/earwig/git-repo-updater.""",
  28. add_help=False)
  29. group_u = parser.add_argument_group("updating repositories")
  30. group_b = parser.add_argument_group("bookmarking")
  31. group_a = parser.add_argument_group("advanced")
  32. group_m = parser.add_argument_group("miscellaneous")
  33. group_u.add_argument(
  34. 'directories_to_update', nargs="*", metavar="path", type=_decode,
  35. help="""update this repository, or all repositories it contains
  36. (if not a repo directly)""")
  37. group_u.add_argument(
  38. '-u', '--update', action="store_true", help="""update all bookmarks
  39. (default behavior when called without arguments)""")
  40. group_u.add_argument(
  41. '-t', '--depth', dest="max_depth", metavar="n", type=int, default=3,
  42. help="""max recursion depth when searching for repos in subdirectories
  43. (default: 3; use 0 for no recursion, or -1 for unlimited)""")
  44. group_u.add_argument(
  45. '-c', '--current-only', action="store_true", help="""only fetch the
  46. remote tracked by the current branch instead of all remotes""")
  47. group_u.add_argument(
  48. '-f', '--fetch-only', action="store_true",
  49. help="only fetch remotes, don't try to fast-forward any branches")
  50. group_u.add_argument(
  51. '-p', '--prune', action="store_true", help="""after fetching, delete
  52. remote-tracking branches that no longer exist on their remote""")
  53. group_b.add_argument(
  54. '-a', '--add', dest="bookmarks_to_add", nargs="+", metavar="path",
  55. type=_decode, help="add directory(s) as bookmarks")
  56. group_b.add_argument(
  57. '-d', '--delete', dest="bookmarks_to_del", nargs="+", metavar="path",
  58. type=_decode,
  59. help="delete bookmark(s) (leaves actual directories alone)")
  60. group_b.add_argument(
  61. '-l', '--list', dest="list_bookmarks", action="store_true",
  62. help="list current bookmarks")
  63. group_b.add_argument(
  64. '-n', '--clean', '--cleanup', dest="clean_bookmarks",
  65. action="store_true", help="delete any bookmarks that don't exist")
  66. group_b.add_argument(
  67. '-b', '--bookmark-file', nargs="?", metavar="path", type=_decode,
  68. help="use a specific bookmark config file (default: {0})".format(
  69. get_default_config_path()))
  70. group_a.add_argument(
  71. '-e', '--exec', '--batch', dest="command", metavar="command",
  72. help="run a shell command on all repos")
  73. group_m.add_argument(
  74. '-h', '--help', action="help", help="show this help message and exit")
  75. group_m.add_argument(
  76. '-v', '--version', action="version",
  77. version="gitup {0} (Python {1})".format(
  78. __version__, platform.python_version()))
  79. group_m.add_argument(
  80. '--selftest', action="store_true",
  81. help="run integrated test suite and exit (pytest must be available)")
  82. return parser
  83. def _selftest():
  84. """Run the integrated test suite with pytest."""
  85. from .test import run_tests
  86. run_tests()
  87. def main():
  88. """Parse arguments and then call the appropriate function(s)."""
  89. parser = _build_parser()
  90. color_init(autoreset=True)
  91. args = parser.parse_args()
  92. print(Style.BRIGHT + "gitup" + Style.RESET_ALL + ": the git-repo-updater")
  93. print()
  94. if args.selftest:
  95. _selftest()
  96. return
  97. if args.bookmark_file:
  98. args.bookmark_file = os.path.expanduser(args.bookmark_file)
  99. acted = False
  100. if args.bookmarks_to_add:
  101. add_bookmarks(args.bookmarks_to_add, args.bookmark_file)
  102. acted = True
  103. if args.bookmarks_to_del:
  104. delete_bookmarks(args.bookmarks_to_del, args.bookmark_file)
  105. acted = True
  106. if args.list_bookmarks:
  107. list_bookmarks(args.bookmark_file)
  108. acted = True
  109. if args.clean_bookmarks:
  110. clean_bookmarks(args.bookmark_file)
  111. acted = True
  112. if args.command:
  113. if args.directories_to_update:
  114. run_command(args.directories_to_update, args)
  115. if args.update or not args.directories_to_update:
  116. run_command(get_bookmarks(args.bookmark_file), args)
  117. else:
  118. if args.directories_to_update:
  119. update_directories(args.directories_to_update, args)
  120. acted = True
  121. if args.update or not acted:
  122. update_bookmarks(get_bookmarks(args.bookmark_file), args)
  123. def run():
  124. """Thin wrapper for main() that catches KeyboardInterrupts."""
  125. try:
  126. main()
  127. except KeyboardInterrupt:
  128. print("Stopped by user.")