Source code for easydev.multigit
# -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of easydev software
#
# Copyright (c) 2014
#
# File author(s): Thomas Cokelaer <cokelaer@gmail.com>
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# website: http://github.com/cokelaer/easydev
#
##############################################################################
import glob
import sys
import os
from easydev.console import red, darkgreen, purple
# could use argparse
[docs]class MultiGIT(object):
"""A multi git command line
You can either use MultiGIT as an executable (installed with easydev) and type the following
command in a shell::
multigit --help
or create a script as follows in the repository that contains the git repositories::
from easydev.multigit import MultiGIT
import sys
if __name__ == "__main__":
dirs = ['easydev', 'bioservices']
mg = MultiGIT(commands=sys.argv[1:], directories=dirs)
You can then call the local script (e.g. for the pull command)::
python multigit.py pull
This would be equivalent to calling the executable as follows::
multigit pull --directories easydev bioservices
"""
def __init__(self, commands, directories=None, curdir='.', verbose=True):
"""Simple utility to apply a git command to all local directories"""
self.verbose = verbose
self.commands = commands
# catch the multigit commands that is
# --quiet (which is also a valid git option),
# --help, which is also a git option; replaces the git --help
# --directories
# --exclude-directories
if '-h' in self.commands or '--help' in self.commands:
MultiGIT.help()
sys.exit()
if "--quiet" in self.commands:
self.verbose = False
if "--directories" in self.commands:
directories = self._get_arguments('--directories')
self.commands.remove("--directories")
for this in directories:
self.commands.remove(this)
if "--exclude-directories" in self.commands:
exclude_directories = self._get_arguments('--exclude-directories')
self.commands.remove("--exclude-directories")
for this in exclude_directories:
self.commands.remove(this)
else:
exclude_directories = []
# look for all directories by default
if directories is None:
directories = glob.glob('*')
directories = [x for x in directories if os.path.isdir(x)]
self.directories = [x for x in directories if x not in exclude_directories]
self.commands = " ".join(self.commands)
cmds = self.commands
if len(cmds) == 0:
print("No commands provided...")
MultiGIT.help()
else:
if ' -h' not in cmds and ' --help' not in cmds:
self.run()
def _get_arguments(self, cmd):
# identify
index = self.commands.index(cmd)
args = []
for this in self.commands[index+1:]:
if this.strip().startswith('-'):
break
else:
args.append(this.strip())
return args
[docs] def run(self):
"""call the git commands """
results = {'failure': [], 'success': []}
for directory in self.directories:
if self.verbose:
print(purple("Entering in {0}".format(directory)))
code = "cd {0}; git {1}".format(directory, self.commands)
try:
if self.verbose:
print(code)
status = os.system(code)
if status == 0:
results['success'].append(directory)
self._print_status('ok')
else:
print(directory + " failed\n")
results['failure'].append(directory)
self._print_error("Failed. Skipped")
except:
print(directory + "failed\n")
results['failure'].append(directory)
self._print_error("Failed. Skipped")
finally:
code = "cd .."
os.system(code)
if self.verbose:
print("")
if self.commands == 'help':
break
if len(results['failure']):
print("Failed repos: " + str(results['failure']))
def _print_status(self, msg):
if self.verbose is False:
return
try:
print(darkgreen(msg))
except:
print(msg)
def _print_error(self, msg):
if self.verbose is False:
return
try:
print(red(msg))
except:
print(msg)
@classmethod
[docs] def help(cls):
"""help: to get more help and usage
"""
print("""
MultiGIT allows to apply git commands on a set of directories.
This could be quite useful if you keep all your GIT repositories within
a single directory for instance to pull new commits systematically
Examples:
---------
>>> python multigit.py pull --directories test,easydev,requests
Global options:
--quiet do not show setup outputs [default=False]
Options not yet implemented:
--keep-going force the commands running[default=False]
--help show detailed help message
--directories list of directories to look at [default: all]
--exclude-directories list of directories to ignore
print "usage: multigit.py pull --directories
""")
[docs]def main_func(args=None):
if args:
pass
else:
args = sys.argv[1:] # 1 ignore the name of the calling program itself
if len(args) == 0:
print(red("USAGE: python multigit.py pull"))
else:
MultiGIT(args)
if __name__ == "__main__":
args = sys.argv[1:] # 1 ignore the name of the calling program itself
main_func(args)