aboutsummaryrefslogtreecommitdiffhomepage
path: root/gbp
diff options
context:
space:
mode:
authorGuido Günther <agx@sigxcpu.org>2011-04-09 22:38:40 +0200
committerGuido Günther <agx@sigxcpu.org>2011-04-09 22:38:40 +0200
commit943686c8c059f6aa90cb03a86862ddd0253f46de (patch)
tree5b5d393b1144a30b625771460265cb291b20b1d6 /gbp
parent61513e6869a0c6d9036da3fe255bf2e2d3f5796a (diff)
parentaa72b4f43d64e9669752441d13d12add743907df (diff)
Merge branch 'master' into experimental
Diffstat (limited to 'gbp')
-rw-r--r--gbp/command_wrappers.py60
-rw-r--r--gbp/config.py14
-rw-r--r--gbp/deb.py40
-rw-r--r--gbp/git.py164
-rw-r--r--gbp/log.py16
-rw-r--r--gbp/notifications.py1
6 files changed, 185 insertions, 110 deletions
diff --git a/gbp/command_wrappers.py b/gbp/command_wrappers.py
index 545380c1..64300cfb 100644
--- a/gbp/command_wrappers.py
+++ b/gbp/command_wrappers.py
@@ -159,6 +159,16 @@ class RepackTarArchive(Command):
self.run_error = 'Couldn\'t repack "%s"' % self.archive
+class CatenateTarArchive(Command):
+ """Wrap tar to catenate a tar file with the next"""
+ def __init__(self, archive, **kwargs):
+ self.archive = archive
+ Command.__init__(self, 'tar', ['-A', '-f', archive], **kwargs)
+
+ def __call__(self, target):
+ Command.__call__(self, [target])
+
+
class RemoveTree(Command):
"Wrap rm to remove a whole directory tree"
def __init__(self, tree):
@@ -197,6 +207,7 @@ class GitCommand(Command):
self.run_error = "Couldn't run git %s" % cmd
+# FIXME: move to gbp.git.__init__
class GitInit(GitCommand):
"""Wrap git init"""
def __init__(self):
@@ -204,20 +215,14 @@ class GitInit(GitCommand):
self.run_error = "Couldn't init git repository"
+# FIXME: move to gbp.git.__init__
class GitClone(GitCommand):
"""Wrap git clone"""
def __init__(self):
GitCommand.__init__(self, 'clone')
self.run_error = "Couldn't clone git repository"
-
-class GitShowBranch(GitCommand):
- """Wrap git show-branch"""
- def __init__(self):
- GitCommand.__init__(self, 'branch')
- self.run_error = "Couldn't list branches"
-
-
+# FIXME: move to gbp.git.create_branch
class GitBranch(GitCommand):
"""Wrap git branch"""
def __init__(self):
@@ -231,21 +236,7 @@ class GitBranch(GitCommand):
GitCommand.__call__(self, options)
-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 branch "%s"' % 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)
-
-
+# FIXME: move to gbp.git.fetch
class GitFetch(GitCommand):
"""Wrap git fetch"""
def __init__(self, remote = None):
@@ -255,6 +246,7 @@ class GitFetch(GitCommand):
GitCommand.__init__(self, 'fetch', opts)
+# FIXME: move to gbp.git.merge
class GitMerge(GitCommand):
"""Wrap git merge"""
def __init__(self, branch, verbose=False):
@@ -263,6 +255,7 @@ class GitMerge(GitCommand):
self.run_error = 'Couldn\'t merge from "%s"' % (branch,)
+# FIXME: move to gbp.git.create_tag
class GitTag(GitCommand):
"""Wrap git tag"""
def __init__(self, sign_tag=False, keyid=None):
@@ -285,6 +278,7 @@ class GitTag(GitCommand):
GitCommand.__call__(self, cmd)
+# FIXME: move to gbp.git.add
class GitAdd(GitCommand):
"""Wrap git add to add new files"""
def __init__(self, extra_env=None):
@@ -292,26 +286,6 @@ class GitAdd(GitCommand):
self.run_error = "Couldn't add files"
-class GitRm(GitCommand):
- """Wrap git rm to remove files"""
- def __init__(self, verbose=False):
- args = [ ['--quiet'], [] ][verbose]
- GitCommand.__init__(self, cmd='rm', args=args)
- self.run_error = "Couldn't remove files"
-
-
-class GitCommitAll(GitCommand):
- """Wrap git commit to commit all changes"""
- def __init__(self, verbose=False, **kwargs):
- args = ['-a'] + [ ['-q'], [] ][verbose]
- GitCommand.__init__(self, cmd='commit', args=args, **kwargs)
-
- def __call__(self, msg=''):
- args = [ [], ['-m', msg] ][len(msg) > 0]
- self.run_error = "Couldn't %s %s" % (self.cmd, " ".join(self.args + args))
- GitCommand.__call__(self, args)
-
-
def copy_from(orig_dir, filters=[]):
"""
copy a source tree over via tar
diff --git a/gbp/config.py b/gbp/config.py
index d1211334..9f3d1692 100644
--- a/gbp/config.py
+++ b/gbp/config.py
@@ -1,6 +1,6 @@
# vim: set fileencoding=utf-8 :
#
-# (C) 2006,2007,2010 Guido Guenther <agx@sigxcpu.org>
+# (C) 2006,2007,2010,2011 Guido Guenther <agx@sigxcpu.org>
"""handles command line and config file option parsing for the gbp commands"""
from optparse import OptionParser, OptionGroup, Option, OptionValueError
@@ -13,6 +13,12 @@ except ImportError:
gbp_version = "[Unknown version]"
import gbp.tristate
+no_upstream_branch_msg = """
+Repository does not have branch '%s' for upstream sources. If there is none see
+file:///usr/share/doc/git-buildpackage/manual-html/gbp.import.html#GBP.IMPORT.CONVERT
+on howto create it otherwise use --upstream-branch to specify it.
+"""
+
def expand_path(option, opt, value):
value = os.path.expandvars(value)
return os.path.expanduser(value)
@@ -99,6 +105,8 @@ class GbpOptionParser(OptionParser):
'track' : 'True',
'author-is-committer': 'False',
'author-date-is-committer-date': 'False',
+ 'create-missing-branches': 'False',
+ 'submodules' : 'True',
}
help = {
'debian-branch':
@@ -163,6 +171,10 @@ class GbpOptionParser(OptionParser):
"Use the authors's name also as the comitter's name, default is '%(author-is-committer)s'",
'author-date-is-committer-date':
"Use the authors's date as the comitter's date, default is '%(author-date-is-committer-date)s'",
+ 'create-missing-branches':
+ "Create missing branches automatically, default is '%(create-missing-branches)s'",
+ 'submodules':
+ "Transparently handle submodules in the upstream tree"
}
config_files = [ '/etc/git-buildpackage/gbp.conf',
os.path.expanduser('~/.gbp.conf'),
diff --git a/gbp/deb.py b/gbp/deb.py
index ff361d66..9f81c6a5 100644
--- a/gbp/deb.py
+++ b/gbp/deb.py
@@ -244,8 +244,14 @@ def orig_file(cp, compression):
def is_native(cp):
- "Is this a debian native package"
- return [ True, False ]['-' in cp['Version']]
+ """
+ Is this a debian native package
+ >>> is_native(dict(Version="1"))
+ True
+ >>> is_native(dict(Version="1-1"))
+ False
+ """
+ return not '-' in cp['Version']
def is_valid_packagename(name):
"Is this a valid Debian package name?"
@@ -256,8 +262,19 @@ def is_valid_upstreamversion(version):
return upstreamversion_re.match(version)
def get_compression(orig_file):
- "Given an orig file return the compression used"
- ext = orig_file.rsplit('.',1)[1]
+ """
+ Given an orig file return the compression used
+ >>> get_compression("abc.tar.gz")
+ 'gzip'
+ >>> get_compression("abc.tar.bz2")
+ 'bzip2'
+ >>> get_compression("abc.tar.foo")
+ >>> get_compression("abc")
+ """
+ try:
+ ext = orig_file.rsplit('.',1)[1]
+ except IndexError:
+ return None
for (c, o) in compressor_opts.iteritems():
if o[1] == ext:
return c
@@ -265,12 +282,15 @@ def get_compression(orig_file):
def has_epoch(cp):
- """does the topmost version number contain an epoch"""
- try:
- if cp['Epoch']:
- return True
- except KeyError:
- return False
+ """
+ Does the topmost version number in the changelog contain an epoch
+ >>> has_epoch(dict(Epoch="1"))
+ True
+ >>> has_epoch(dict())
+ False
+ """
+ return cp.has_key("Epoch")
+
def has_orig(cp, compression, dir):
"Check if orig.tar.gz exists in dir"
diff --git a/gbp/git.py b/gbp/git.py
index 4f2507f9..f72f866e 100644
--- a/gbp/git.py
+++ b/gbp/git.py
@@ -1,12 +1,12 @@
# vim: set fileencoding=utf-8 :
#
-# (C) 2006,2007,2008 Guido Guenther <agx@sigxcpu.org>
+# (C) 2006,2007,2008,2011 Guido Guenther <agx@sigxcpu.org>
"""provides git repository related helpers"""
import re
import subprocess
import os.path
-from command_wrappers import (GitAdd, GitRm, GitCheckoutBranch, GitInit, GitCommand, copy_from)
+from command_wrappers import (GitCommand, GitInit, GitAdd, GitBranch, copy_from)
from errors import GbpError
import log
import dateutil.parser
@@ -39,14 +39,14 @@ class GitRepository(object):
env.update(extra_env)
return env
- def __git_getoutput(self, command, args=[], extra_env=None):
+ def __git_getoutput(self, command, args=[], extra_env=None, cwd=None):
"""exec a git command and return the output"""
output = []
env = self.__build_env(extra_env)
cmd = ['git', command] + args
log.debug(cmd)
- popen = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env)
+ popen = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env, cwd=cwd)
while popen.poll() == None:
output += popen.stdout.readlines()
ret = popen.poll()
@@ -63,9 +63,7 @@ class GitRepository(object):
stdout=subprocess.PIPE,
env=env)
(stdout, stderr) = popen.communicate(input)
- if popen.returncode:
- stdout = None
- return stdout
+ return stdout, stderr, popen.returncode
def base_dir(self):
"""Base of the repository"""
@@ -174,7 +172,8 @@ class GitRepository(object):
has_local = False # local repo has new commits
has_remote = False # remote repo has new commits
out = self.__git_getoutput('rev-list', ["--left-right",
- "%s...%s" % (from_branch, to_branch)])[0]
+ "%s...%s" % (from_branch, to_branch),
+ "--"])[0]
if not out: # both branches have the same commits
return True, True
@@ -196,7 +195,16 @@ class GitRepository(object):
"""switch to branch 'branch'"""
self.__check_path()
if self.get_branch() != branch:
- GitCheckoutBranch(branch)()
+ GitCommand("checkout", [ branch ])()
+
+ def create_branch(self, branch, rev=None):
+ """create a new branch
+ @param rev: where to start the branch from
+
+ if param is None the branch starts form the current HEAD
+ """
+ self.__check_path()
+ GitBranch()(branch, rev)
def delete_branch(self, branch):
self.__check_path()
@@ -344,20 +352,6 @@ class GitRepository(object):
raise GitRepositoryError, "can't write out current index"
return tree[0].strip()
- def replace_tree(self, src_dir, filters, verbose=False):
- """
- make the current wc match what's in src_dir
- @return: True if wc was modified
- @rtype: boolean
- """
- old = set(self.index_files())
- new = set(copy_from(src_dir, filters))
- GitAdd()(['-f', '.'])
- files = [ obj for obj in old - new if not os.path.isdir(obj)]
- if files:
- GitRm(verbose=verbose)(files)
- return not self.is_clean()[0]
-
def update_ref(self, ref, new, old=None, msg=None):
"""Update ref 'ref' to commit 'new'"""
args = [ ref, new ]
@@ -367,45 +361,37 @@ class GitRepository(object):
args = [ '-m', msg ] + args
GitCommand("update-ref")(args)
- def commit_tree(self, tree, msg, parents, author=None, email=None,
- date=None, committer_name=None, committer_email=None,
- committer_date=None):
+ def commit_tree(self, tree, msg, parents, author={}, committer={}):
"""Commit a tree with commit msg 'msg' and parents 'parents'"""
extra_env = {}
- if author:
- extra_env['GIT_AUTHOR_NAME'] = author
- if email:
- extra_env['GIT_AUTHOR_EMAIL'] = email
- if date:
- extra_env['GIT_AUTHOR_DATE'] = date
- if committer_name:
- extra_env['GIT_COMMITTER_NAME'] = committer_name
- if committer_email:
- extra_env['GIT_COMMITTER_EMAIL'] = committer_email
- if committer_date:
- extra_env['GIT_COMMITTER_DATE'] = committer_date
+ for key, val in author.items():
+ if val:
+ extra_env['GIT_AUTHOR_%s' % key.upper()] = val
+ for key, val in committer.items():
+ if val:
+ extra_env['GIT_COMMITTER_%s' % key.upper()] = val
args = [ tree ]
for parent in parents:
args += [ '-p' , parent ]
- sha1 = self.__git_inout('commit-tree', args, msg, extra_env).strip()
- return sha1
+ sha1, stderr, ret = self.__git_inout('commit-tree', args, msg, extra_env)
+ if not ret:
+ return sha1.strip()
+ else:
+ raise GbpError, "Failed to commit tree: %s" % stderr
def commit_dir(self, unpack_dir, msg, branch, other_parents=None,
- author = None, email = None, date = None,
- committer_name = None, committer_email = None,
- committer_date = None):
+ author={}, committer={}):
"""Replace the current tip of branch 'branch' with the contents from 'unpack_dir'
@param unpack_dir: content to add
@param msg: commit message to use
@param branch: branch to add the contents of unpack_dir to
@param parents: additional parents of this commit
- @param author: commit with author name 'author'
- @param email: commit with author email 'email'
- @param date: set author date to 'date'
- @param committer_author: commit with committer name 'commiter_name'
- @param committer_email: commit with committer email 'commiter_email'
- @param committer_date: set commit date to 'date'"""
+ @param author: commit with author information from author
+ @type author: dict with keys 'name', 'email', 'date'
+ @param committer_author: commit with committer information from committer
+ @type comitter: dict with keys 'name', 'email', 'date'"""
+
self.__check_path()
git_index_file = os.path.join(self.path, '.git', 'gbp_index')
try:
@@ -434,10 +420,7 @@ class GitRepository(object):
parents += [ sha ]
commit = self.commit_tree(tree=tree, msg=msg, parents=parents,
- author=author, email=email, date=date,
- committer_name=committer_name,
- committer_email=committer_email,
- committer_date=committer_date)
+ author=author, committer=committer)
if not commit:
raise GbpError, "Failed to commit tree"
self.update_ref("refs/heads/%s" % branch, commit, cur)
@@ -486,6 +469,81 @@ class GitRepository(object):
output, ret = self.__git_getoutput('format-patch', options)
return [ line.strip() for line in output ]
+ def apply_patch(self, patch, index=True, context=None):
+ """Apply a patch using git apply"""
+
+ args = []
+ if context:
+ args += [ '-C', context ]
+ if index:
+ args.append("--index")
+ args.append(patch)
+ GitCommand("apply", args)()
+
+ def archive(self, format, prefix, output, treeish, **kwargs):
+ args = [ '--format=%s' % format, '--prefix=%s' % prefix,
+ '--output=%s' % output, treeish ]
+ out, ret = self.__git_getoutput('archive', args, **kwargs)
+ if ret:
+ raise GitRepositoryError, "unable to archive %s"%(treeish)
+
+
+ def has_submodules(self):
+ """Does the repo have submodules"""
+ if os.path.exists('.gitmodules'):
+ return True
+ else:
+ return False
+
+
+ def add_submodule(self, repo_path):
+ """Add a submodule"""
+ GitCommand("submodule", [ "add", repo_path ])()
+
+
+ def update_submodules(self, init=True, recursive=True, fetch=False):
+ """Update all submodules"""
+ if not self.has_submodules():
+ return
+ args = [ "update" ]
+ if recursive:
+ args.append("--recursive")
+ if init:
+ args.append("--init")
+ if not fetch:
+ args.append("--no-fetch")
+
+ GitCommand("submodule", args)()
+
+
+ def get_submodules(self, treeish, path=None, recursive=True):
+ """ list the submodules of treeish
+
+ returns a list of submodule/commit-id tuples
+ """
+ # Note that we is lstree instead of submodule commands because
+ # there's no way to list the submodules of another branch with
+ # the latter.
+ submodules = []
+ if path is None:
+ path = "."
+
+ args = [ treeish ]
+ if recursive:
+ args += ['-r']
+
+ out, ret = self.__git_getoutput('ls-tree', args, cwd=path)
+ for line in out:
+ mode, objtype, commit, name = line.split()
+ # A submodules is shown as "commit" object in ls-tree:
+ if objtype == "commit":
+ nextpath = os.path.sep.join([path, name])
+ submodules.append( (nextpath, commit) )
+ if recursive:
+ submodules += self.get_submodules(commit, path=nextpath,
+ recursive=recursive)
+ return submodules
+
class FastImport(object):
"""Invoke git-fast-import"""
diff --git a/gbp/log.py b/gbp/log.py
index 86e4943c..67ecad56 100644
--- a/gbp/log.py
+++ b/gbp/log.py
@@ -17,6 +17,7 @@
#
"""Simple colored logging classes"""
+import os
import sys
import gbp.tristate
@@ -50,6 +51,17 @@ class Logger(object):
def set_level(self, level):
self.level = level
+ def _is_tty(self):
+ if (os.getenv("EMACS") and
+ os.getenv("INSIDE_EMACS", "").endswith(",comint")):
+ return False
+
+ if (sys.stderr.isatty() and
+ sys.stdout.isatty()):
+ return True
+
+ return False
+
def set_color(self, color):
if type(color) == type(True):
self.color = color
@@ -57,9 +69,7 @@ class Logger(object):
if color.is_on():
self.color = True
elif color.is_auto():
- if (sys.stderr.isatty() and
- sys.stdout.isatty()):
- self.color = True
+ self.color = self._is_tty()
else:
self.color = False
diff --git a/gbp/notifications.py b/gbp/notifications.py
index b2534e3f..9115ac39 100644
--- a/gbp/notifications.py
+++ b/gbp/notifications.py
@@ -45,6 +45,7 @@ def build_msg(cp, success):
def send_notification(summary, msg):
n = notify_module.Notification(summary, msg)
+ n.set_hint('transient', True)
try:
if not n.show():
return False