summaryrefslogtreecommitdiffhomepage
path: root/gbp
diff options
context:
space:
mode:
authorGuido Guenther <agx@sigxcpu.org>2007-02-07 14:00:58 +0100
committerGuido Guenther <agx@bogon.sigxcpu.org>2007-02-07 14:00:58 +0100
commit8517e0965163ce6b9ae22cb3e6e3ba09a9be8a68 (patch)
tree8c08c2a6a8081d202f3604cbdab94c5566261268 /gbp
parent9288730ff4e24639a455db5d963ca6ec09ca39c3 (diff)
rename git_buildpackage to gbp and use GbpError everywhere
Diffstat (limited to 'gbp')
-rw-r--r--gbp/__init__.py187
-rw-r--r--gbp/config.py67
-rw-r--r--gbp/deb_utils.py44
-rw-r--r--gbp/git_utils.py79
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: