Mercurial > hg > gut
view gut/main.py @ 12:67b04f3c5032 default tip
dont pull from origin; there shouldnt be changes there
use --rebase flag when pulling from master, dont know why
author | Jeff Hammel <jhammel@mozilla.com> |
---|---|
date | Fri, 06 Aug 2010 17:50:54 -0700 |
parents | 6884a771ed54 |
children |
line wrap: on
line source
#!/usr/bin/env python """ a workflow for git """ import os import subprocess import sys from command import CommandParser def call(command, **kw): if isinstance(command, basestring): kw['shell'] = True output = kw.pop('output', True) if output or kw.pop('pipe', False): kw['stdout'] = subprocess.PIPE kw['stderr'] = subprocess.PIPE check = kw.pop('check', True) process = subprocess.Popen(command, **kw) stdout, stderr = process.communicate() code = process.poll() if check and code: if isinstance(command, basestring): cmdstr = command else: cmdstr = ' '.join(command) raise SystemExit("Command `%s` exited with code %d" % (cmdstr, code)) if output: print stdout print stderr return dict(stdout=stdout, stderr=stderr, code=code) def fake_call(command, **kw): if isinstance(command, basestring): print command else: print ' '.join(command) class gut(object): """ a workflow for git """ def __init__(self, remote=None, simulate=False, branches=('master',)): """ - remote: name of the remote repository in .git/config - simulate: print what calls will be used but don't run them - branches: branches to apply to """ self.simulate = simulate # sanity check try: self.root() except SystemExit: print "Not in a git repository" sys.exit(1) self.remote = remote self.branches = branches if simulate: globals()['call'] = fake_call def update(self): """update the master""" branch = self.branch() if self.simulate: branch = '<branch>' call(['git', 'checkout', 'master']) if self.remote: call(['git', 'pull', '--rebase', self.remote, 'master']) call(['git', 'checkout', branch]) call(['git', 'merge', 'master']) def feature(self, name): """make a new feature branch""" call(['git', 'checkout', 'master']) call(['git', 'checkout', '-b', name]) call(['git', 'push', 'origin', name]) def patch(self, output=None, logfile=None): """ generate a patch for review - output: name of patch - logfile: name of file to output the log to [DEFAULT: stdout] """ self.update() diff = call(['git', 'diff', 'master'], pipe=True, output=False) log = call(['git', 'log', 'master..'], pipe=True, output=False) if self.simulate: return if not output: output = self.branch() + '.diff' diff = diff['stdout'] log = log['stdout'] # format the log lines = [] oldline = None for line in log.splitlines(): if not line: continue if line[0].strip(): if oldline: lines.append(oldline) oldline = None incomment = False continue line = line.strip() if line.startswith('*'): if oldline: lines.append(oldline) oldline = None lines.append(line[1:].strip()) continue if oldline: oldline = oldline + ' ' + line else: oldline = line else: if oldline: lines.append(oldline) log = '\n\n'.join(['* %s' % line for line in lines]) f = file(output, 'w') # write the output to a patch file print >> f, diff f.close() # output the log if logfile: f = file(logfile, 'w') # write the log to a file print >> f, log else: return log def apply(self): """ apply the existing feature branch to master as a patch """ # sanity check branch = self.branch() if self.simulate: branch = '<branch>' assert branch != 'master', "Can't apply master to itself!" assert self.branches, "No branches defined!" # get the patch self.patch(branch + '.diff', branch + '.log') diff = os.path.abspath(branch + '.diff') log = os.path.abspath(branch + '.log') # apply the patch if not self.simulate: cwd = os.getcwd() os.chdir(self.root()) for b in self.branches: call(['git', 'checkout', b]) call('patch -p1 < %s' % diff) call(['git', 'commit', '-a', '-F', log]) call(['git', 'push', 'origin', b]) if self.remote: call(['git', 'push', self.remote, b]) # cleanup call(['git', 'checkout', branch]) if not self.simulate: os.chdir(cwd) def delete(self): """delete the current feature branch""" # sanity check branch = self.branch() assert branch != 'master', "You can't delete the master!" call(['git', 'checkout', 'master']) call(['git', '-D', branch]) def branch(self): """print what branch you're on""" output = call(['git', 'branch'], output=False, pipe=True) if self.simulate: return for line in output['stdout'].splitlines(): if line.startswith('*'): return line[1:].strip() def root(self): """return (relative) root location of repository""" if self.simulate: return '<root>' output = call(['git', 'rev-parse', '--show-cdup'], output=False, pipe=True) location = output['stdout'].strip() if not location: return '.' return location def main(args=sys.argv[1:]): parser = CommandParser(gut) parser.invoke(args) if __name__ == '__main__': main()