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
exist on their remote after fetching.
- Added a `--bookmark-file` flag to support multiple bookmark config files.
- 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
will automatically migrate to the new one.
- 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"
__copyright__ = "Copyright (C) 2011-2016 Ben Kurtovic"
__license__ = "MIT License"
__version__ = "0.3.1.dev0"
__version__ = "0.4.dev0"
__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 .config import (get_default_config_path, get_bookmarks, add_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):
"""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_b = parser.add_argument_group("bookmarking")
group_a = parser.add_argument_group("advanced")
group_m = parser.add_argument_group("miscellaneous")

group_u.add_argument(
@@ -71,6 +72,10 @@ def main():
help="use a specific bookmark config file (default: {0})".format(
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(
'-h', '--help', action="help", help="show this help message and exit")
group_m.add_argument(
@@ -113,11 +118,18 @@ def main():
if args.clean_bookmarks:
clean_bookmarks(args.bookmark_file)
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():
"""Thin wrapper for main() that catches KeyboardInterrupts."""


+ 37
- 13
gitup/update.py View File

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

import os
import shlex

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

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

BOLD = Style.BRIGHT
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):
_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 = []
for item in os.listdir(path):
try:
@@ -189,15 +205,17 @@ def _update_subdirectories(path, update_args):
suffix = "" if len(repos) == 1 else "s"
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]):
_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
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:
repo = Repo(path)
@@ -205,18 +223,18 @@ def _update_directory(path, update_args):
print(ERROR, BOLD + path, "doesn't exist!")
except exc.InvalidGitRepositoryError:
if os.path.isdir(path):
_update_subdirectories(path, update_args)
_dispatch_to_subdirs(path, callback, *args)
else:
print(ERROR, BOLD + path, "isn't a repository!")
else:
print(BOLD + repo.working_dir, "(1 repo):")
_update_repository(repo, *update_args)
callback(repo, *args)

def update_bookmarks(bookmarks, update_args):
"""Loop through and update all bookmarks."""
if bookmarks:
for path in bookmarks:
_update_directory(path, update_args)
_dispatch(path, _update_repository, *update_args)
else:
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."""
for path in paths:
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