diff options
author | Guido Guenther <agx@sigxcpu.org> | 2007-02-07 14:00:58 +0100 |
---|---|---|
committer | Guido Guenther <agx@bogon.sigxcpu.org> | 2007-02-07 14:00:58 +0100 |
commit | 8517e0965163ce6b9ae22cb3e6e3ba09a9be8a68 (patch) | |
tree | 8c08c2a6a8081d202f3604cbdab94c5566261268 /gbp | |
parent | 9288730ff4e24639a455db5d963ca6ec09ca39c3 (diff) |
rename git_buildpackage to gbp and use GbpError everywhere
Diffstat (limited to 'gbp')
-rw-r--r-- | gbp/__init__.py | 187 | ||||
-rw-r--r-- | gbp/config.py | 67 | ||||
-rw-r--r-- | gbp/deb_utils.py | 44 | ||||
-rw-r--r-- | gbp/git_utils.py | 79 |
4 files changed, 377 insertions, 0 deletions
diff --git a/gbp/__init__.py b/gbp/__init__.py new file mode 100644 index 00000000..99251094 --- /dev/null +++ b/gbp/__init__.py @@ -0,0 +1,187 @@ +# -*- coding: utf-8 -*- +# +# (C) 2006 Guido Guenther <agx@sigxcpu.org> +"""Simple class wrappers for the various commands needed by git-buildpackage""" + +import subprocess +import sys + + +class CommandExecFailed(Exception): + """Exception raised by the Command class""" + pass + + +class Command(object): + """ + Wraps a shell command, so we don't have to store any kind of command line options in + one of the git-buildpackage commands + """ + verbose = False + + def __init__(self, cmd, args=[], shell=False): + self.cmd = cmd + self.args = args + self.run_error = "Couldn't run '%s'" % (" ".join([self.cmd] + self.args)) + self.shell = shell + + def __run(self, args): + """run self.cmd adding args as additional arguments""" + try: + if self.verbose: + print self.cmd, self.args, args + cmd = [ self.cmd ] + self.args + args + if self.shell: # subprocess.call only cares about the first argument if shell=True + cmd = " ".join(cmd) + retcode = subprocess.call(cmd, shell=self.shell) + if retcode < 0: + print >>sys.stderr, "%s was terminated by signal %d" % (self.cmd, -retcode) + elif retcode > 0: + print >>sys.stderr, "%s returned %d" % (self.cmd, retcode) + except OSError, e: + print >>sys.stderr, "Execution failed:", e + retcode = 1 + if retcode: + print >>sys.stderr,self.run_error + return retcode + + def __call__(self, args=[]): + if self.__run(args): + raise CommandExecFailed + + +class UnpackTGZ(Command): + """Wrap tar to Unpack a gzipped tar archive""" + def __init__(self, tgz, dir): + self.tgz = tgz + self.dir = dir + Command.__init__(self, 'tar', [ '-C', dir, '-zxf', tgz ]) + self.run_error = "Couldn't unpack %s" % self.tgz + + +class RemoveTree(Command): + "Wrap rm to remove a whole directory tree" + def __init__(self, tree): + self.tree = tree + Command.__init__(self, 'rm', [ '-rf', tree ]) + self.run_error = "Couldn't remove %s" % self.tree + + +class Dch(Command): + """Wrap dch and set a specific version""" + def __init__(self, version, msg): + args = ['-v', version] + if msg: + args.append(msg) + Command.__init__(self, 'dch', args) + self.run_error = "Dch failed." + + +class DpkgSourceExtract(Command): + """ + Wrap dpkg-source to extract a Debian source package into a certain + directory, this needs + """ + def __init__(self): + Command.__init__(self, 'dpkg-source', ['-x']) + + def __call__(self, dsc, output_dir): + self.run_error = "Couldn't extract %s" % dsc + Command.__call__(self, [dsc, output_dir]) + + +class GitLoadDirs(Command): + """Wrap git_load_dirs""" + def __init__(self): + Command.__init__(self, 'git_load_dirs') + + def __call__(self, dir, log=''): + self.dir = dir + self.run_error = "Couldn't import %s" % self.dir + args = [ [], ['-L', log] ] [len(log) > 0] + Command.__call__(self, args+[dir]) + + +class GitCommand(Command): + "Mother/Father of all git commands" + def __init__(self, cmd, args=[]): + Command.__init__(self, 'git-'+cmd, args) + + +class GitInitDB(GitCommand): + """Wrap git-init-db""" + def __init__(self): + GitCommand.__init__(self, 'init-db') + self.run_error = "Couldn't init git repository" + + +class GitShowBranch(GitCommand): + """Wrap git-show-branch""" + def __init__(self): + GitCommand.__init__(self, 'branch') + self.run_error = "Couldn't list branches" + + +class GitBranch(GitCommand): + """Wrap git-branch""" + def __init__(self): + GitCommand.__init__(self, 'branch') + + def __call__(self, branch): + self.run_error = "Couldn't create branch %s" % (branch,) + GitCommand.__call__(self, [branch]) + + +class GitCheckoutBranch(GitCommand): + """Wrap git-checkout in order tos switch to a certain branch""" + def __init__(self, branch): + GitCommand.__init__(self, 'checkout', [branch]) + self.branch = branch + self.run_error = "Couldn't switch to %s branch" % self.branch + + +class GitPull(GitCommand): + """Wrap git-pull""" + def __init__(self, repo, branch): + GitCommand.__init__(self, 'pull', [repo, branch]) + self.run_error = "Couldn't pull %s to %s" % (branch, repo) + + +class GitTag(GitCommand): + """Wrap git-tag""" + def __init__(self, sign_tag=False, keyid=None): + GitCommand.__init__(self,'tag') + self.sign_tag = sign_tag + self.keyid = keyid + + def __call__(self, version, msg="Tagging %(version)s"): + self.run_error = "Couldn't tag %s" % (version,) + if self.sign_tag: + if self.keyid: + sign_opts = [ '-u', self.keyid ] + else: + sign_opts = [ '-s' ] + else: + sign_opts = [] + GitCommand.__call__(self, sign_opts+[ '-m', msg % locals(), version]) + + +class GitAdd(GitCommand): + """Wrap git-add to add new files""" + def __init__(self): + GitCommand.__init__(self,'add') + self.run_error = "Couldn't add files" + + +class GitCommitAll(GitCommand): + """Wrap git-commit to commit all changes""" + def __init__(self): + GitCommand.__init__(self, 'commit', ['-a']) + + def __call__(self, msg=''): + args = [ [], ['-m', msg] ][len(msg) > 0] + self.run_error = "Couldn't commit -a %s" % " ".join(args) + GitCommand.__call__(self, args) + + +# vim:et:ts=4:sw=4: diff --git a/gbp/config.py b/gbp/config.py new file mode 100644 index 00000000..eeffd440 --- /dev/null +++ b/gbp/config.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +# (C) 2006 Guido Guenther <agx@sigxcpu.org> +"""handles command line and config file option parsing for the gbp commands""" + +from optparse import OptionParser +from ConfigParser import SafeConfigParser +import os.path + +class GbpOptionParser(OptionParser): + """ + Handles commandline options and parsing of config files + @ivar command: the gbp command we store the options for + @type command: string + @ivar prefix: prefix to prepend to all commandline options + @type prefix: string + @ivar config: current configuration parameters + @type config: dict + @cvar defaults: defaults value of an option if not in the config file or + given on the command line + @type defaults: dict + @cvar config_files: list of config files we parse + @type config_files: list + """ + defaults={ 'builder' : 'debuild', + 'cleaner' : 'debuild clean', + 'debian-branch' : 'master', + 'upstream-branch' : 'upstream', + 'sign-tags' : '', # empty means False + 'keyid' : '', + 'posttag' : '', + 'debian-tag' : 'debian/%(version)s', + 'upstream-tag' : 'upstream/%(version)s', + } + config_files=['/etc/git-buildpackage/gbp.conf', + os.path.expanduser('~/.gbp.conf'), + '.git/gbp.conf' ] + + def __parse_config_files(self): + """parse the possible config files and set appropriate values default values""" + parser=SafeConfigParser(self.defaults) + parser.read(self.config_files) + self.config=dict(parser.defaults()) + if parser.has_section(self.command): + self.config=dict(parser.items(self.command, raw=True)) + + def __init__(self, command, prefix='', usage=None): + self.command=command + self.prefix=prefix + self.__parse_config_files() + OptionParser.__init__(self, usage=usage) + + + def add_config_file_option(self, option_name, dest, help, **kwargs): + """ + set a option for the command line parser, the default is read from the config file + @var option_name: name of the option + @type option_name: string + @var dest: where to store this option + @type dest: string + @var help: help text + @type help: string + """ + OptionParser.add_option(self,"--%s%s" % (self.prefix, option_name), dest=dest, + default=self.config[option_name], + help=help % self.config, **kwargs) + +# vim:et:ts=4:sw=4: diff --git a/gbp/deb_utils.py b/gbp/deb_utils.py new file mode 100644 index 00000000..8121ca70 --- /dev/null +++ b/gbp/deb_utils.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# (C) 2006 Guido Guenther <agx@sigxcpu.org> +"""provides some debian source package related helpers""" + +import email +import commands +import os + +# When trying to parse a version-number from a dsc or changes file, these are +# the valid characters. +debian_version_chars = 'a-zA-Z\d.~+-' + +def parse_changelog(changelog): + """parse changelog file changelog""" + status, output = commands.getstatusoutput('dpkg-parsechangelog -l%s' % (changelog, )) + if status: + return None + cp = email.message_from_string(output) + if '-' in cp['Version']: + cp['Upstream-Version'], cp['Debian-Version'] = cp['Version'].rsplit('-', 1) + else: + cp['Debian-Version'] = cp['Version'] + return cp + + +def orig_file(cp): + "The name of the orig.tar.gz belonging to changelog cp" + return "%s_%s.orig.tar.gz" % (cp['Source'], cp['Upstream-Version']) + + +def is_native(cp): + "Is this a debian native package" + return [ True, False ]['-' in cp['Version']] + + +def has_orig(cp, dir): + "Check if orig.tar.gz exists in dir" + try: + os.stat( os.path.join(dir, orig_file(cp)) ) + except OSError: + return False + return True + +# vim:et:ts=4:sw=4: diff --git a/gbp/git_utils.py b/gbp/git_utils.py new file mode 100644 index 00000000..4859a71d --- /dev/null +++ b/gbp/git_utils.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +# +# (C) 2006 Guido Guenther <agx@sigxcpu.org> +"""provides some git repository related helpers""" + +import subprocess +import os.path + +class GitRepositoryError(Exception): + """Exception thrown by GitRepository""" + pass + + +class GitRepository(object): + """Represents a git repository at path""" + + def __init__(self, path): + try: + os.stat(os.path.join(path,'.git')) + except: + raise GitRepositoryError + self.path = os.path.abspath(path) + + + def __check_path(self): + if os.getcwd() != self.path: + raise GitRepositoryError + + + def __git_getoutput(self, command): + """Exec a git command and return the output""" + popen = subprocess.Popen(['git', command], stdout=subprocess.PIPE) + popen.wait() + return popen.stdout.readlines() + + + def has_branch(self, branch): + """check if the repository has branch 'branch'""" + self.__check_path() + for line in self.__git_getoutput('branch'): + if line.split(' ', 1)[1].strip() == branch: + return True + return False + + + def get_branch(self): + """on what branch is the current working copy""" + self.__check_path() + for line in self.__git_getoutput('branch'): + if line.startswith('*'): + return line.split(' ', 1)[1].strip() + + + def is_clean(self): + """does the repository contain any uncommitted modifications""" + self.__check_path() + clean_msg = 'nothing to commit' + out = self.__git_getoutput('status') + if out[0].strip() == clean_msg: + ret = True + elif out[0].startswith('#') and out[1].strip() == clean_msg: + ret = True + else: + ret = False + return (ret, "".join(out)) + + +def build_tag(format, version): + """Generate a tag from a given format and a version""" + return format % dict(version=sanitize_version(version)) + + +def sanitize_version(version): + """sanitize a version so git accepts it as a tag""" + if ':' in version: # strip of any epochs + version = version.split(':', 1)[1] + return version.replace('~', '.') + +# vim:et:ts=4:sw=4: |