Browse Source

Add --exec to run a shell command on all repos.

tags/v0.4
Ben Kurtovic 8 years ago
parent
commit
70e96ad673
4 changed files with 58 additions and 21 deletions
  1. +2
    -1
      CHANGELOG
  2. +1
    -1
      gitup/__init__.py
  3. +18
    -6
      gitup/script.py
  4. +37
    -13
      gitup/update.py

+ 2
- 1
CHANGELOG View File

@@ -1,9 +1,10 @@
v0.3.1 (unreleased):
v0.4 (unreleased):


- Added a `--prune` flag to delete remote-tracking branches that no longer - Added a `--prune` flag to delete remote-tracking branches that no longer
exist on their remote after fetching. exist on their remote after fetching.
- Added a `--bookmark-file` flag to support multiple bookmark config files. - Added a `--bookmark-file` flag to support multiple bookmark config files.
- Added a `--cleanup` flag to remove old bookmarks that don't exist. - Added a `--cleanup` flag to remove old bookmarks that don't exist.
- Added an `--execute` flag to run a shell command on all of your repos.
- Cleaned up the bookmark file format, fixing a related Windows bug. The script - Cleaned up the bookmark file format, fixing a related Windows bug. The script
will automatically migrate to the new one. will automatically migrate to the new one.
- Fixed a bug related to Python 3 compatibility. - Fixed a bug related to Python 3 compatibility.


+ 1
- 1
gitup/__init__.py View File

@@ -10,5 +10,5 @@ gitup: the git repository updater
__author__ = "Ben Kurtovic" __author__ = "Ben Kurtovic"
__copyright__ = "Copyright (C) 2011-2016 Ben Kurtovic" __copyright__ = "Copyright (C) 2011-2016 Ben Kurtovic"
__license__ = "MIT License" __license__ = "MIT License"
__version__ = "0.3.1.dev0"
__version__ = "0.4.dev0"
__email__ = "ben.kurtovic@gmail.com" __email__ = "ben.kurtovic@gmail.com"

+ 18
- 6
gitup/script.py View File

@@ -14,7 +14,7 @@ from colorama import init as color_init, Fore, Style
from . import __version__ from . import __version__
from .config import (get_default_config_path, get_bookmarks, add_bookmarks, from .config import (get_default_config_path, get_bookmarks, add_bookmarks,
delete_bookmarks, list_bookmarks, clean_bookmarks) delete_bookmarks, list_bookmarks, clean_bookmarks)
from .update import update_bookmarks, update_directories
from .update import update_bookmarks, update_directories, run_command


def _decode(path): def _decode(path):
"""Decode the given string using the system's filesystem encoding.""" """Decode the given string using the system's filesystem encoding."""
@@ -34,6 +34,7 @@ def main():


group_u = parser.add_argument_group("updating repositories") group_u = parser.add_argument_group("updating repositories")
group_b = parser.add_argument_group("bookmarking") group_b = parser.add_argument_group("bookmarking")
group_a = parser.add_argument_group("advanced")
group_m = parser.add_argument_group("miscellaneous") group_m = parser.add_argument_group("miscellaneous")


group_u.add_argument( group_u.add_argument(
@@ -71,6 +72,10 @@ def main():
help="use a specific bookmark config file (default: {0})".format( help="use a specific bookmark config file (default: {0})".format(
get_default_config_path())) get_default_config_path()))


group_a.add_argument(
'-e', '--exec', '--batch', dest="command", metavar="command",
help="run a shell command on all repos")

group_m.add_argument( group_m.add_argument(
'-h', '--help', action="help", help="show this help message and exit") '-h', '--help', action="help", help="show this help message and exit")
group_m.add_argument( group_m.add_argument(
@@ -113,11 +118,18 @@ def main():
if args.clean_bookmarks: if args.clean_bookmarks:
clean_bookmarks(args.bookmark_file) clean_bookmarks(args.bookmark_file)
acted = True acted = True
if args.directories_to_update:
update_directories(args.directories_to_update, update_args)
acted = True
if args.update or not acted:
update_bookmarks(get_bookmarks(args.bookmark_file), update_args)

if args.command:
if args.directories_to_update:
run_command(args.directories_to_update, args.command)
if args.update or not args.directories_to_update:
run_command(get_bookmarks(args.bookmark_file), args.command)
else:
if args.directories_to_update:
update_directories(args.directories_to_update, update_args)
acted = True
if args.update or not acted:
update_bookmarks(get_bookmarks(args.bookmark_file), update_args)


def run(): def run():
"""Thin wrapper for main() that catches KeyboardInterrupts.""" """Thin wrapper for main() that catches KeyboardInterrupts."""


+ 37
- 13
gitup/update.py View File

@@ -6,12 +6,13 @@
from __future__ import print_function from __future__ import print_function


import os import os
import shlex


from colorama import Fore, Style from colorama import Fore, Style
from git import RemoteReference as RemoteRef, Repo, exc from git import RemoteReference as RemoteRef, Repo, exc
from git.util import RemoteProgress from git.util import RemoteProgress


__all__ = ["update_bookmarks", "update_directories"]
__all__ = ["update_bookmarks", "update_directories", "run_command"]


BOLD = Style.BRIGHT BOLD = Style.BRIGHT
BLUE = Fore.BLUE + BOLD BLUE = Fore.BLUE + BOLD
@@ -176,8 +177,23 @@ def _update_repository(repo, current_only, fetch_only, prune):
for branch in sorted(repo.heads, key=lambda b: b.name): for branch in sorted(repo.heads, key=lambda b: b.name):
_update_branch(repo, branch, branch == active) _update_branch(repo, branch, branch == active)


def _update_subdirectories(path, update_args):
"""Update all subdirectories that are git repos in a given directory."""
def _run_command(repo, command):
"""Run an arbitrary shell command on the given repository."""
print(INDENT1, BOLD + os.path.split(repo.working_dir)[1] + ":")

cmd = shlex.split(command)
try:
out = repo.git.execute(
cmd, with_extended_output=True, with_exceptions=False)
except exc.GitCommandNotFound as err:
print(INDENT2, ERROR, err)
return

for line in out[1].splitlines() + out[2].splitlines():
print(INDENT2, line)

def _dispatch_to_subdirs(path, callback, *args):
"""Apply the callback to all git repo subdirectories in the directory."""
repos = [] repos = []
for item in os.listdir(path): for item in os.listdir(path):
try: try:
@@ -189,15 +205,17 @@ def _update_subdirectories(path, update_args):
suffix = "" if len(repos) == 1 else "s" suffix = "" if len(repos) == 1 else "s"
print(BOLD + path, "({0} repo{1}):".format(len(repos), suffix)) print(BOLD + path, "({0} repo{1}):".format(len(repos), suffix))
for repo in sorted(repos, key=lambda r: os.path.split(r.working_dir)[1]): for repo in sorted(repos, key=lambda r: os.path.split(r.working_dir)[1]):
_update_repository(repo, *update_args)
callback(repo, *args)


def _update_directory(path, update_args):
"""Update a particular directory.
def _dispatch(path, callback, *args):
"""Apply a callback function on each valid repo in the given path.


Determine whether the directory is a git repo on its own, a directory of 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.
git repositories, or something invalid. If the first, apply the callback on
it; if the second, apply the callback on all repositories contained within;
if the third, print an error.

The given args are passed directly to the callback function after the repo.
""" """
try: try:
repo = Repo(path) repo = Repo(path)
@@ -205,18 +223,18 @@ def _update_directory(path, update_args):
print(ERROR, BOLD + path, "doesn't exist!") print(ERROR, BOLD + path, "doesn't exist!")
except exc.InvalidGitRepositoryError: except exc.InvalidGitRepositoryError:
if os.path.isdir(path): if os.path.isdir(path):
_update_subdirectories(path, update_args)
_dispatch_to_subdirs(path, callback, *args)
else: else:
print(ERROR, BOLD + path, "isn't a repository!") print(ERROR, BOLD + path, "isn't a repository!")
else: else:
print(BOLD + repo.working_dir, "(1 repo):") print(BOLD + repo.working_dir, "(1 repo):")
_update_repository(repo, *update_args)
callback(repo, *args)


def update_bookmarks(bookmarks, update_args): def update_bookmarks(bookmarks, update_args):
"""Loop through and update all bookmarks.""" """Loop through and update all bookmarks."""
if bookmarks: if bookmarks:
for path in bookmarks: for path in bookmarks:
_update_directory(path, update_args)
_dispatch(path, _update_repository, *update_args)
else: else:
print("You don't have any bookmarks configured! Get help with 'gitup -h'.") print("You don't have any bookmarks configured! Get help with 'gitup -h'.")


@@ -224,4 +242,10 @@ def update_directories(paths, update_args):
"""Update a list of directories supplied by command arguments.""" """Update a list of directories supplied by command arguments."""
for path in paths: for path in paths:
full_path = os.path.abspath(path) full_path = os.path.abspath(path)
_update_directory(full_path, update_args)
_dispatch(full_path, _update_repository, *update_args)

def run_command(paths, command):
"""Run an arbitrary shell command on all repos."""
for path in paths:
full_path = os.path.abspath(path)
_dispatch(full_path, _run_command, command)

Loading…
Cancel
Save