diff options
44 files changed, 455 insertions, 341 deletions
diff --git a/debian/control b/debian/control index afd3198c..0ccbc204 100755 --- a/debian/control +++ b/debian/control @@ -24,7 +24,7 @@ Standards-Version: 3.9.4 Vcs-Git: git://honk.sigxcpu.org/git/git-buildpackage.git Vcs-Browser: https://honk.sigxcpu.org/gitweb/?p=git-buildpackage.git Homepage: https://honk.sigxcpu.org/piki/projects/git-buildpackage/ -X-Python-Version: >= 2.6 +X-Python3-Version: >= 3.5 Package: git-buildpackage-common @@ -32,14 +32,16 @@ Architecture: all Depends: ${python3:Depends}, ${shlibs:Depends}, ${misc:Depends}, + devscripts (>= 2.13.5~), git (>= 1:1.7.9.1-1~), man-db, + python3-dateutil, python3-pkg-resources, python3-dateutil, #unittest need zipmerge Recommends: pristine-tar (>= 0.5) -Suggests: python-notify, unzip, zipmerge +Suggests: python3-notify2, unzip, zipmerge Description: Suite to help with packaging in Git repositories This package contains the common API and scripts for Debian and rpm packaging diff --git a/debian/rules b/debian/rules index 91265d43..0ac72e48 100755 --- a/debian/rules +++ b/debian/rules @@ -37,8 +37,7 @@ endif override_dh_auto_build: dh_auto_build make -C docs - #generate apidocs - #sh gen_apidocs.sh + override_dh_auto_install: dh_auto_install dh_bash-completion diff --git a/examples/gbp-add-patch b/examples/gbp-add-patch index 5da1b02f..9594f199 100755 --- a/examples/gbp-add-patch +++ b/examples/gbp-add-patch @@ -34,7 +34,8 @@ commits debian/patches/0010-bla-fasel with this changelog message: import re import sys -import os, os.path +import os +import os.path from gbp.command_wrappers import (Command) from gbp.config import (GbpOptionParserDebian, GbpOptionGroup) from gbp.errors import GbpError @@ -85,7 +86,8 @@ def main(argv): try: repo = GitRepository(os.path.curdir) except GitRepositoryError: - print >>sys.stderr, "%s is not a git repository" % (os.path.abspath('.')) + print("%s is not a git repository" % os.path.abspath('.'), + file=sys.stderr) return 1 try: @@ -105,8 +107,8 @@ def main(argv): except GitRepositoryError: retval = 1 except GbpError as err: - if len(err.__str__()): - print >>sys.stderr, err + if str(err): + print(err, file=sys.stderr) retval = 1 return retval diff --git a/examples/zeitgeist-git.py b/examples/zeitgeist-git.py index 578f5041..89b5d3a4 100755 --- a/examples/zeitgeist-git.py +++ b/examples/zeitgeist-git.py @@ -1,7 +1,7 @@ #! /usr/bin/python3 # vim: set fileencoding=utf-8 : # -# (C) 2010 Guido Guenther <agx@sigxcpu.org> +# (C) 2010 Guido G¨¹nther <agx@sigxcpu.org> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or @@ -13,8 +13,8 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# along with this program; if not, please see +# <http://www.gnu.org/licenses/> # # Simple Zeitgeist Git data source @@ -48,14 +48,14 @@ else: try: CLIENT = ZeitgeistClient() except RuntimeError as e: - print("Unable to connect to Zeitgeist, won't send events. Reason: '%s'" %e) + print("Unable to connect to Zeitgeist, won't send events. Reason: '%s'" % e) def get_repo(): """Get uri of remote repository and its name""" repo = None uri = subprocess.Popen(['git', 'config', '--get', 'remote.origin.url'], - stdout=subprocess.PIPE).communicate()[0] + stdout=subprocess.PIPE).communicate()[0] if uri: uri = uri.strip().decode(sys.getfilesystemencoding()) @@ -64,10 +64,10 @@ def get_repo(): else: sep = ':' try: - repo = str(uri.rsplit(sep, 1)[1]) - except IndexError: # no known separator + repo = unicode(uri.rsplit(sep, 1)[1]) + except IndexError: # no known separator repo = uri - repo = repo.rsplit('.git', 1)[0] + repo = repo.rsplit(u'.git', 1)[0] return repo, uri @@ -78,27 +78,27 @@ def main(argv): # * branch # * log summary (git log -1 --format=%s HEAD) curdir = os.path.abspath(os.curdir).decode(sys.getfilesystemencoding()) - uri = "file://%s" % curdir + uri = u"file://%s" % curdir repo, origin = get_repo() if not repo: - repo = str(curdir.rsplit('/', 1)[1]) + repo = unicode(curdir.rsplit('/', 1)[1]) origin = uri subject = Subject.new_for_values( - uri = uri, - interpretation = Interpretation.DOCUMENT.TEXT_DOCUMENT.PLAIN_TEXT_DOCUMENT.SOURCE_CODE.uri, - manifestation = Manifestation.FILE_DATA_OBJECT.uri, - text = repo, - origin = origin) + uri=uri, + interpretation=Interpretation.DOCUMENT.TEXT_DOCUMENT.PLAIN_TEXT_DOCUMENT.SOURCE_CODE.uri, + manifestation=Manifestation.FILE_DATA_OBJECT.uri, + text=repo, + origin=origin) event = Event.new_for_values( - timestamp = int(time.time() * 1000), - interpretation = interpretation, - manifestation = Manifestation.USER_ACTIVITY.uri, - actor = "application://gitg.desktop", - subjects = [subject]) + timestamp=int(time.time() * 1000), + interpretation=interpretation, + manifestation=Manifestation.USER_ACTIVITY.uri, + actor="application://gitg.desktop", + subjects=[subject]) CLIENT.insert_event(event) + if __name__ == '__main__': main(sys.argv) - diff --git a/gbp/command_wrappers.py b/gbp/command_wrappers.py index 0d29af17..b4f24457 100644 --- a/gbp/command_wrappers.py +++ b/gbp/command_wrappers.py @@ -43,7 +43,7 @@ class Command(object): self.run_error = "'%s' failed" % (" ".join([self.cmd] + self.args)) self.shell = shell self.retcode = 1 - self.stderr = '' + self.stderr = b'' self.capture_stderr = capture_stderr self.cwd = cwd if extra_env is not None: @@ -62,7 +62,7 @@ class Command(object): signal.signal(signal.SIGPIPE, signal.SIG_DFL) log.debug("%s %s %s" % (self.cmd, self.args, args)) - self.stderr = '' + self.stderr = b'' stderr_arg = subprocess.PIPE if self.capture_stderr else None cmd = [ self.cmd ] + self.args + args if self.shell: diff --git a/gbp/deb/changelog.py b/gbp/deb/changelog.py index 9b3c03bb..41aca947 100644 --- a/gbp/deb/changelog.py +++ b/gbp/deb/changelog.py @@ -93,10 +93,10 @@ class ChangeLog(object): stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (output, errors) = cmd.communicate(self._contents) + (output, errors) = cmd.communicate(self._contents.encode('utf-8')) if cmd.returncode: raise ParseChangeLogError("Failed to parse changelog. " - "dpkg-parsechangelog said:\n%s" % (errors, )) + "dpkg-parsechangelog said:\n%s" % errors.decode().strip())) # Parse the result of dpkg-parsechangelog (which looks like # email headers) cp = email.message_from_string(output) @@ -115,8 +115,8 @@ class ChangeLog(object): self._cp = cp def _read(self): - with open(self.filename) as f: - self._contents = f.read() + with open(self.filename, encoding='utf-8') as f: + self._contents = f.read() def __getitem__(self, item): return self._cp[item] @@ -131,7 +131,7 @@ class ChangeLog(object): @property def name(self): - """The packges name""" + """The packages name""" return self._cp['Source'] @property diff --git a/gbp/deb/format.py b/gbp/deb/format.py index 3a4c8ab3..cd56cdfb 100644 --- a/gbp/deb/format.py +++ b/gbp/deb/format.py @@ -84,7 +84,7 @@ class DebianSourceFormat(object): >>> import tempfile, os >>> with tempfile.NamedTemporaryFile(delete=False) as t: - ... t.write("3.0 (quilt)") + ... ret = t.write(b"3.0 (quilt)") >>> d = DebianSourceFormat.parse_file(t.name) >>> d.version '3.0' diff --git a/gbp/format.py b/gbp/format.py index 2a4af15c..59c932d8 100644 --- a/gbp/format.py +++ b/gbp/format.py @@ -42,3 +42,23 @@ def format_msg(msg, args): raise GbpError("Failed to format %s: Missing value %s in %s" % (msg, e, args)) +def format_b(fmtstr, *args): + """String-like interpolation for bytes objects. + + NOTE: This is a compatibility wrapper for older versions (<3.5) of Python 3 + which do not support the percent operator ('%') for bytes objects. This + function should be removed (and replaced by simple '%') when Python 3.5 + has gained wide enough adoption. + + >>> format_b(b'%s %d', b'foo', 123) + b'foo 123' + >>> format_b(b'foo 123') + b'foo 123' + >>> format_b('%s %d', b'foo', 123) + Traceback (most recent call last): + ... + AttributeError: 'str' object has no attribute 'decode' + """ + fmtstr = fmtstr.decode() + strargs = tuple([(a.decode() if isinstance(a, bytes) else a) for a in args]) + return (fmtstr % strargs).encode()
\ No newline at end of file diff --git a/gbp/git/__init__.py b/gbp/git/__init__.py index 57b74eff..53c2bfcd 100644 --- a/gbp/git/__init__.py +++ b/gbp/git/__init__.py @@ -43,3 +43,4 @@ def rfc822_date_to_git(rfc822_date): return '%d %s' % (seconds, tz) # vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: + diff --git a/gbp/git/fastimport.py b/gbp/git/fastimport.py index 435d5e0e..9b27a2b6 100644 --- a/gbp/git/fastimport.py +++ b/gbp/git/fastimport.py @@ -20,6 +20,9 @@ import subprocess import time from gbp.errors import GbpError +from gbp.format import format_b +from gbp.paths import to_bin + class FastImport(object): """Add data to a git repository using I{git fast-import}""" @@ -36,7 +39,7 @@ class FastImport(object): """ self._repo = repo try: - self._fi = subprocess.Popen([ 'git', 'fast-import', '--quiet'], + self._fi = subprocess.Popen(['git', 'fast-import', '--quiet'], stdin=subprocess.PIPE, cwd=repo.path) self._out = self._fi.stdin except OSError as err: @@ -46,17 +49,17 @@ class FastImport(object): "Invalid argument when spawning git fast-import: %s" % err) def _do_data(self, fd, size): - self._out.write("data %s\n" % size) + self._out.write(format_b(b"data %d\n", size)) while True: data = fd.read(self._bufsize) self._out.write(data) if len(data) != self._bufsize: break - self._out.write("\n") + self._out.write(b"\n") def _do_file(self, filename, mode, fd, size): - name = "/".join(filename.split('/')[1:]) - self._out.write("M %d inline %s\n" % (mode, name)) + name = b"/".join(to_bin(filename).split(b'/')[1:]) + self._out.write(format_b(b"M %d inline %s\n", mode, name)) self._do_data(fd, size) def add_file(self, filename, fd, size, mode=m_regular): @@ -83,9 +86,11 @@ class FastImport(object): @param linktarget: the target the symlink points to @type linktarget: C{str} """ - self._out.write("M %d inline %s\n" % (self.m_symlink, linkname)) - self._out.write("data %s\n" % len(linktarget)) - self._out.write("%s\n" % linktarget) + linktarget = to_bin(linktarget) + linkname = to_bin(linkname) + self._out.write(format_b(b"M %d inline %s\n", self.m_symlink, linkname)) + self._out.write(format_b(b"data %d\n", len(linktarget))) + self._out.write(format_b(b"%s\n", linktarget)) def start_commit(self, branch, committer, msg): """ @@ -108,24 +113,23 @@ class FastImport(object): else: from_ = '' - self._out.write("""commit refs/heads/%(branch)s + s = """commit refs/heads/%(branch)s committer %(name)s <%(email)s> %(time)s data %(length)s -%(msg)s%(from)s""" % - { 'branch': branch, - 'name': committer.name, - 'email': committer.email, - 'time': committer.date, - 'length': length, - 'msg': msg, - 'from': from_, - }) +%(msg)s%(from)s""" % {'branch': branch, + 'name': committer.name, + 'email': committer.email, + 'time': committer.date, + 'length': length, + 'msg': msg, + 'from': from_} + self._out.write(s.encode()) def deleteall(self): """ Issue I{deleteall} to fastimport so we start from a empty tree """ - self._out.write("deleteall\n") + self._out.write(b"deleteall\n") def close(self): """ diff --git a/gbp/git/modifier.py b/gbp/git/modifier.py index 5f5b5999..ba5ad763 100644 --- a/gbp/git/modifier.py +++ b/gbp/git/modifier.py @@ -20,7 +20,8 @@ Someone who modifiers something in git like committing changes or authoring a patch """ -import calendar, datetime +import calendar +import datetime from gbp.git.errors import GitError @@ -72,7 +73,7 @@ class GitModifier(object): self._date = date else: self._date = date.replace(tzinfo=tz) - elif date != None: + elif date is not None: raise ValueError("Date '%s' not timestamp, " "datetime object or git raw date" % date) @@ -119,9 +120,11 @@ class GitModifier(object): """ Get env vars for authorship information - >>> g = GitModifier("foo", "bar") - >>> g.get_author_env() - {'GIT_AUTHOR_EMAIL': 'bar', 'GIT_AUTHOR_NAME': 'foo'} + >>> g = GitModifier("Joey Ramone", "joey@example.com") + >>> g.get_author_env()['GIT_AUTHOR_EMAIL'] + 'joey@example.com' + >>> g.get_author_env()['GIT_AUTHOR_NAME'] + 'Joey Ramone' @return: Author information suitable to use as environment variables @rtype: C{dict} @@ -132,15 +135,23 @@ class GitModifier(object): """ Get env vars for committer information - >>> g = GitModifier("foo", "bar") - >>> g.get_committer_env() - {'GIT_COMMITTER_NAME': 'foo', 'GIT_COMMITTER_EMAIL': 'bar'} + >>> g = GitModifier("Joey Ramone", "joey@example.com") + >>> g.get_committer_env()['GIT_COMMITTER_EMAIL'] + 'joey@example.com' + >>> g.get_committer_env()['GIT_COMMITTER_NAME'] + 'Joey Ramone' - @return: Commiter information suitable to use as environment variables + @return: Committer information suitable to use as environment variables @rtype: C{dict} """ return self._get_env('committer') + def get(self, key, default=None): + if key in self.keys(): + return self.__getitem__(key) + else: + return default + def __getitem__(self, key): if key == 'date': return self.date diff --git a/gbp/git/repository.py b/gbp/git/repository.py index 42661678..3dfecdc1 100644 --- a/gbp/git/repository.py +++ b/gbp/git/repository.py @@ -19,14 +19,17 @@ import subprocess import os.path import re +import sys from collections import defaultdict import select import gbp.log as log +from gbp.format import format_b from gbp.git.modifier import GitModifier from gbp.git.commit import GitCommit from gbp.git.errors import GitError from gbp.git.args import GitArgs +from gbp.paths import to_bin class GitRepositoryError(GitError): @@ -85,7 +88,7 @@ class GitRepository(object): "Failed to get repository git dir at '%s'" % self.path) # Set git meta data dir - git_dir = out.strip() + git_dir = out.strip().decode(sys.getfilesystemencoding()) if os.path.isabs(git_dir): self._git_dir = git_dir else: @@ -106,6 +109,7 @@ class GitRepository(object): # Check for bare repository out, dummy, ret = self._git_inout('rev-parse', ['--is-bare-repository'], capture_stderr=True) + cdup = out.strip().decode(sys.getfilesystemencoding()) if ret: raise GitRepositoryError("No Git repository at '%s': '%s'" % (self.path, out)) self._bare = False if out.strip() != 'true' else True @@ -298,9 +302,8 @@ class GitRepository(object): except Exception as excobj: raise GitRepositoryError("Error running git %s: %s" % (command, excobj)) if ret: - raise GitRepositoryError("Error running git %s: %s" % - (command, stderr.strip())) - + detail = stderr or stdout + raise GitRepositoryError("Error running git %s: %s" % (command, detail.decode().strip())) def _cmd_has_feature(self, command, feature): """ @@ -315,12 +318,12 @@ class GitRepository(object): """ args = GitArgs(command, '-m') help, stderr, ret = self._git_inout('help', - args.args, - extra_env={'LC_ALL': 'C'}, - capture_stderr=True) + args.args, + extra_env={'LC_ALL': 'C'}, + capture_stderr=True) if ret: raise GitRepositoryError("Invalid git command '%s': %s" - % (command, stderr[:-1])) + % (command, stderr.decode().strip())) # Parse git command man page section_re = re.compile(r'^(?P<section>[A-Z].*)') @@ -328,7 +331,7 @@ class GitRepository(object): optopt_re = re.compile(r'--\[(?P<prefix>[a-zA-Z\-]+)\]-?') backspace_re = re.compile(".\b") man_section = None - for line in help.splitlines(): + for line in help.decode().splitlines(): if man_section == "OPTIONS" and line.startswith(' -'): opts = line.split(',') for opt in opts: @@ -359,7 +362,7 @@ class GitRepository(object): @property def bare(self): - """Wheter this is a bare repository""" + """Whether this is a bare repository""" return self._bare @property @@ -377,7 +380,7 @@ class GitRepository(object): @property def head(self): - """return the SHA1 of the current HEAD""" + """SHA1 of the current HEAD""" return self.rev_parse('HEAD') #{ Branches and Merging @@ -433,13 +436,13 @@ class GitRepository(object): @raises GitRepositoryError: if HEAD is not a symbolic ref (e.g. when in detached HEAD state) """ - out, dummy, ret = self._git_inout('symbolic-ref', [ 'HEAD' ], - capture_stderr=True) + out, _, ret = self._git_inout('symbolic-ref', ['HEAD'], + capture_stderr=True) if ret: # We don't append stderr since # "fatal: ref HEAD is not a symbolic ref" confuses people raise GitRepositoryError("Currently not on a branch") - ref = out.split('\n')[0] + ref = out.decode().split('\n')[0] # Check if ref really exists try: @@ -517,9 +520,9 @@ class GitRepository(object): args.add(commit2) sha1, stderr, ret = self._git_inout('merge-base', args.args, capture_stderr=True) if not ret: - return self.strip_sha1(sha1) + return self.strip_sha1(sha1.decode()) else: - raise GitRepositoryError("Failed to get common ancestor: %s" % stderr.strip()) + raise GitRepositoryError("Failed to get common ancestor: %s" % stderr.decode().strip()) def merge(self, commit, verbose=False, edit=False): """ @@ -529,7 +532,7 @@ class GitRepository(object): @type commit: C{str} @param verbose: whether to print a summary after the merge @type verbose: C{bool} - @param edit: wheter to invoke an editor to edit the merge message + @param edit: whether to invoke an editor to edit the merge message @type edit: C{bool} """ args = GitArgs() @@ -559,14 +562,15 @@ 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", + out = self._git_getoutput('rev-list', + ["--left-right", "%s...%s" % (from_branch, to_branch), "--"])[0] - if not out: # both branches have the same commits + if not out: # both branches have the same commits return True, True - for line in out: + for line in (l.decode() for l in out): if line.startswith("<"): has_local = True elif line.startswith(">"): @@ -588,10 +592,10 @@ class GitRepository(object): @return: local or remote branches @rtype: C{list} """ - args = [ '--format=%(refname:short)' ] - args += [ 'refs/remotes/' ] if remote else [ 'refs/heads/' ] + args = ['--format=%(refname:short)'] + args += ['refs/remotes/'] if remote else ['refs/heads/'] out = self._git_getoutput('for-each-ref', args)[0] - return [ ref.strip() for ref in out ] + return [ref.decode().strip() for ref in out] def get_local_branches(self): """ @@ -649,8 +653,8 @@ class GitRepository(object): args.add('--contains') args.add(commit) - out, ret = self._git_getoutput('branch', args.args) - for line in out: + out, ret = self._git_getoutput('branch', args.args) + for line in [l.decode() for l in out]: # remove prefix '*' for current branch before comparing line = line.replace('*', '') if line.strip() == branch: @@ -703,7 +707,7 @@ class GitRepository(object): out = self._git_getoutput('for-each-ref', args.args)[0] - return out[0].strip() + return out[0].decode().strip() #{ Tags @@ -802,9 +806,9 @@ class GitRepository(object): tag, err, ret = self._git_inout('describe', args.args, capture_stderr=True) if ret: - raise GitRepositoryError("Can't describe %s. Git error: %s" % \ - (commitish, err.strip())) - return tag.strip() + raise GitRepositoryError("Can't describe %s. Git error: %s" % + (commitish, err.decode().strip())) + return tag.decode().strip() def find_tag(self, commit, pattern=None): """ @@ -828,8 +832,8 @@ class GitRepository(object): @return: tags @rtype: C{list} of C{str} """ - args = [ '-l', pattern ] if pattern else [] - return [ line.strip() for line in self._git_getoutput('tag', args)[0] ] + args = ['-l', pattern] if pattern else [] + return [line.decode().strip() for line in self._git_getoutput('tag', args)[0]] def verify_tag(self, tag): """ @@ -902,7 +906,7 @@ class GitRepository(object): # Get a more helpful error message. out = self._status(porcelain=False, ignore_untracked=ignore_untracked) - return (False, "".join(out)) + return (False, "".join([e.decode() for e in out])) else: return (True, '') @@ -946,16 +950,16 @@ class GitRepository(object): if ret: raise GitRepositoryError("Can't get repository status: %s" % err) - elements = out.split('\x00') + elements = out.split(b'\x00') result = defaultdict(list) - while elements[0] != '': + while elements[0] != b'': element = elements.pop(0) - status = element[:2] + status = element[:2].decode() filepath = element[3:] # Expect to have two filenames for renames and copies if status[0] in ['R', 'C']: - filepath = elements.pop(0) + '\x00' + filepath + filepath = elements.pop(0) + b'\x00' + filepath result[status].append(filepath) return result @@ -989,7 +993,7 @@ class GitRepository(object): capture_stderr=True) if ret: raise GitRepositoryError("revision '%s' not found" % name) - return self.strip_sha1(sha.splitlines()[0], short) + return self.strip_sha1(sha[0].decode(), short) @staticmethod def strip_sha1(sha1, length=0): @@ -1002,7 +1006,7 @@ class GitRepository(object): >>> GitRepository.strip_sha1('58ef37d', 10) Traceback (most recent call last): ... - GitRepositoryError: '58ef37d' is not a valid sha1 of length 10 + gbp.git.repository.GitRepositoryError: '58ef37d' is not a valid sha1 of length 10 >>> GitRepository.strip_sha1('58ef37d', 7) '58ef37d' >>> GitRepository.strip_sha1('123456789', 7) @@ -1010,16 +1014,16 @@ class GitRepository(object): >>> GitRepository.strip_sha1('foobar') Traceback (most recent call last): ... - GitRepositoryError: 'foobar' is not a valid sha1 + gbp.git.repository.GitRepositoryError: 'foobar' is not a valid sha1 """ maxlen = 40 s = sha1.strip() - l = length or maxlen + sl = length or maxlen - if len(s) < l or len(s) > maxlen: + if len(s) < sl or len(s) > maxlen: raise GitRepositoryError("'%s' is not a valid sha1%s" % - (s, " of length %d" % l if length else "")) + (s, " of length %d" % sl if length else "")) return s #{ Trees @@ -1041,9 +1045,9 @@ class GitRepository(object): @return: C{True} if the repository has that tree, C{False} otherwise @rtype: C{bool} """ - _out, _err, ret = self._git_inout('ls-tree', [treeish], - capture_stderr=True) - return [ True, False ][ret != 0] + _out, _err, ret = self._git_inout('ls-tree', [treeish], + capture_stderr=True) + return [True, False][ret != 0] def write_tree(self, index_file=None): """ @@ -1063,28 +1067,30 @@ class GitRepository(object): extra_env=extra_env, capture_stderr=True) if ret: - raise GitRepositoryError("Can't write out current index: %s" % stderr[:-1]) - return tree.strip() + raise GitRepositoryError("Can't write out current index: %s" % stderr.decode().strip()) + return tree.decode().strip() def make_tree(self, contents): """ - Create a tree based on contents. I{contents} has the same format than - the I{GitRepository.list_tree} output. + Create a tree based on contents. + + @param contents: same format as I{GitRepository.list_tree} output. + @type contents: C{list} of C{str} """ - out='' + objs = b'' args = GitArgs('-z') - for obj in contents: - mode, type, sha1, name = obj - out += '%s %s %s\t%s\0' % (mode, type, sha1, name) + for mode, type_, sha1, name in contents: + name = to_bin(name) + objs += format_b(b'%s %s %s\t%s\0', mode.encode(), type_.encode(), sha1.encode(), name) - sha1, err, ret = self._git_inout('mktree', - args.args, - out, - capture_stderr=True) + sha1, err, ret = self._git_inout('mktree', + args.args, + objs, + capture_stderr=True) if ret: raise GitRepositoryError("Failed to mktree: '%s'" % err) - return self.strip_sha1(sha1) + return self.strip_sha1(sha1.decode()) def get_obj_type(self, obj): """ @@ -1098,12 +1104,12 @@ class GitRepository(object): out, ret = self._git_getoutput('cat-file', args=['-t', obj]) if ret: raise GitRepositoryError("Not a Git repository object: '%s'" % obj) - return out[0].strip() + return out[0].decode().strip() def list_tree(self, treeish, recurse=False, paths=None): """ Get a trees content. It returns a list of objects that match the - 'ls-tree' output: [ mode, type, sha1, path ]. + 'ls-tree' output: [mode, type, sha1, path]. @param treeish: the treeish object to list @type treeish: C{str} @@ -1118,14 +1124,18 @@ class GitRepository(object): args.add("--") args.add_cond(paths, paths) - out, err, ret = self._git_inout('ls-tree', args.args, capture_stderr=True) + out, err, ret = self._git_inout('ls-tree', args.args, capture_stderr=True) if ret: - raise GitRepositoryError("Failed to ls-tree '%s': '%s'" % (treeish, err)) + raise GitRepositoryError("Failed to ls-tree '%s': '%s'" % (treeish, err.decode().strip())) tree = [] - for line in out.split('\0'): + for line in out.split(b'\0'): if line: - tree.append(line.split(None, 3)) + parts = line.split(None, 3) + # decode everything but the file name + for i in range(len(parts) - 1): + parts[i] = parts[i].decode() + tree.append(parts) return tree #} @@ -1139,8 +1149,9 @@ class GitRepository(object): @rtype: C{str} """ value, ret = self._git_getoutput('config', [ name ]) - if ret: raise KeyError - return value[0][:-1] # first line with \n ending removed + if ret: + raise KeyError("'%s' not found in git config") + return value[0].decode()[:-1] # first line with \n ending removed def get_author_info(self): """ @@ -1151,11 +1162,11 @@ class GitRepository(object): @rtype: L{GitModifier} """ try: - name = self.get_config("user.name") + name = self.get_config("user.name") except KeyError: - name = os.getenv("USER") + name = os.getenv("USER") try: - email = self.get_config("user.email") + email = self.get_config("user.email") except KeyError: email = os.getenv("EMAIL") email = os.getenv("GIT_AUTHOR_EMAIL", email) @@ -1173,19 +1184,19 @@ class GitRepository(object): """ out, err, ret = self._git_inout('remote', [], capture_stderr=True) if ret: - raise GitRepositoryError('Failed to get list of remotes: %s' % err) + raise GitRepositoryError('Failed to get list of remotes: %s' % err.decode().strip()) # Get information about all remotes remotes = {} - for remote in out.splitlines(): + for remote in out.decode().splitlines(): out, err, _ret = self._git_inout('remote', ['show', '-n', remote], capture_stderr=True) if ret: raise GitRepositoryError('Failed to get information for remote ' - '%s: %s' % (remote, err)) + '%s: %s' % (remote, err.decode().strip())) fetch_url = None push_urls = [] - for line in out.splitlines(): + for line in out.decode().splitlines(): match = re.match('\s*Fetch\s+URL:\s*(\S.*)', line) if match: fetch_url = match.group(1) @@ -1208,11 +1219,11 @@ class GitRepository(object): stdout, stderr, ret = self._git_inout('remote', ['-v'], capture_stderr=True) if ret: - raise GitRepositoryError('Failed to get remotes: %s' % stderr) + raise GitRepositoryError('Failed to get remotes: %s' % stderr.decode().strip()) remotes = {} for rem in stdout.splitlines(): - name, url_urltype = rem.split('\t', 1) + name, url_urltype = rem.remote.decode().strip().split('\t', 1) url, urltype = url_urltype.rsplit(' ', 1) urltype = urltype.strip('()') if not name in remotes: @@ -1404,12 +1415,12 @@ class GitRepository(object): @param types: list of types to show @type types: C{list} - @return: list of files + @return: list of files as byte string @rtype: C{list} of C{str} """ - all_types = [ 'cached', 'deleted', 'others', 'ignored', 'stage' - 'unmerged', 'killed', 'modified' ] - args = [ '-z' ] + all_types = ['cached', 'deleted', 'others', 'ignored', 'stage' + 'unmerged', 'killed', 'modified'] + args = ['-z'] for t in types: if t in all_types: @@ -1420,7 +1431,7 @@ class GitRepository(object): if ret: raise GitRepositoryError("Error listing files: '%d'" % ret) if out: - return [ file for file in out[0].split('\0') if file ] + return [file for file in out[0].split(b'\0') if file] else: return [] @@ -1430,7 +1441,7 @@ class GitRepository(object): Hash a single file and write it into the object database @param filename: the filename to the content of the file to hash - @type filename: C{str} + @type filename: C{bytestr} @param filters: whether to run filters @type filters: C{bool} @return: the hash of the file @@ -1444,10 +1455,9 @@ class GitRepository(object): args.args, capture_stderr=True) if not ret: - return self.strip_sha1(sha1) + return self.strip_sha1(sha1.decode()) else: - raise GitRepositoryError("Failed to hash %s: %s" % (filename, - stderr)) + raise GitRepositoryError("Failed to hash %s: %s" % (filename, stderr.decode().strip())) #} #{ Comitting @@ -1606,13 +1616,13 @@ class GitRepository(object): args += [ '-p' , parent ] sha1, stderr, ret = self._git_inout('commit-tree', args, - msg, + msg.encode(), extra_env, capture_stderr=True) if not ret: - return self.strip_sha1(sha1) + return self.strip_sha1(sha1.decode()) else: - raise GitRepositoryError("Failed to commit tree: %s" % stderr) + raise GitRepositoryError("Failed to commit tree: %s" % stderr.decode().strip()) #{ Commit Information @@ -1645,22 +1655,26 @@ class GitRepository(object): args.add_cond(options, options) args.add("--") if isinstance(paths, str): - paths = [ paths ] + paths = [paths] args.add_cond(paths, paths) commits, ret = self._git_getoutput('log', args.args) if ret: where = " on %s" % paths if paths else "" raise GitRepositoryError("Error getting commits %s..%s%s" % - (since, until, where)) - return [ commit.strip() for commit in commits ] + (since, until, where)) + return [commit.decode().strip() for commit in commits] def show(self, id): - """git-show id""" + """ + Show a git object + + @rtype: C{bytestr} + """ obj, stderr, ret = self._git_inout('show', ["--pretty=medium", id], - capture_stderr=True) + capture_stderr=True) if ret: - raise GitRepositoryError("can't get %s: %s" % (id, stderr.rstrip())) + raise GitRepositoryError("can't get %s: %s" % (id, stderr.decode().rstrip())) return obj def grep_log(self, regex, since=None): @@ -1682,9 +1696,9 @@ class GitRepository(object): capture_stderr=True) if ret: raise GitRepositoryError("Error grepping log for %s: %s" % - (regex, stderr[:-1])) + (regex, stderr.decode().strip())) if stdout: - return [ commit.strip() for commit in stdout.split('\n')[::-1] ] + return [commit.strip() for commit in stdout.decode().split('\n')[::-1]] else: return [] @@ -1713,36 +1727,38 @@ class GitRepository(object): args = GitArgs('--pretty=format:%an%x00%ae%x00%ad%x00%cn%x00%ce%x00%cd%x00%s%x00%f%x00%b%x00', '-z', '--date=raw', '--no-renames', '--name-status', commit_sha1) - out, err, ret = self._git_inout('show', args.args) + out, err, ret = self._git_inout('show', args.args) if ret: raise GitRepositoryError("Unable to retrieve commit info for %s" % commitish) - fields = out.split('\x00') + fields = out.split(b'\x00') - author = GitModifier(fields[0].strip(), - fields[1].strip(), - fields[2].strip()) - committer = GitModifier(fields[3].strip(), - fields[4].strip(), - fields[5].strip()) + author = GitModifier(fields[0].decode().strip(), + fields[1].decode().strip(), + fields[2].decode().strip()) + committer = GitModifier(fields[3].decode().strip(), + fields[4].decode().strip(), + fields[5].decode().strip()) files = defaultdict(list) file_fields = fields[9:] + # For some reason git returns one extra empty field for merge commits - if file_fields[0] == '': file_fields.pop(0) - while len(file_fields) and file_fields[0] != '': - status = file_fields.pop(0).strip() + if file_fields[0] == b'': + file_fields.pop(0) + while len(file_fields) and file_fields[0] != b'': + status = file_fields.pop(0).decode().strip() path = file_fields.pop(0) files[status].append(path) - return {'id' : commitish, - 'author' : author, - 'committer' : committer, - 'subject' : fields[6], - 'patchname' : fields[7], - 'body' : fields[8], - 'files' : files} + return {'id': commitish, + 'author': author, + 'committer': committer, + 'subject': fields[6].decode(), + 'patchname': fields[7].decode(), + 'body': fields[8].decode(), + 'files': files} #{ Patches def format_patches(self, start, end, output_dir, @@ -1803,7 +1819,7 @@ class GitRepository(object): @param ignore_submodules: ignore changes to submodules @type ignore_submodules: C{bool} @return: diff - @rtype: C{str} + @rtype: C{binary} """ options = GitArgs('-p', '--no-ext-diff') if stat is True: @@ -1836,11 +1852,11 @@ class GitRepository(object): options = GitArgs('--name-status', '-z', obj1, obj2) output, stderr, ret = self._git_inout('diff', options.args) - elements = output.split('\x00') + elements = output.split(b'\x00') result = defaultdict(list) - while elements[0] != '': - status = elements.pop(0)[0] + while elements[0] != b'': + status = elements.pop(0).decode()[0] filepath = elements.pop(0) # Expect to have two filenames for renames and copies if status in ['R', 'C']: @@ -1879,8 +1895,7 @@ class GitRepository(object): if output: out, err, ret = self._git_inout('archive', args.args) if ret: - raise GitRepositoryError("Unable to archive %s: %s" % (treeish, - err)) + raise GitRepositoryError("Unable to archive %s: %s" % (treeish, err.decode().strip())) else: return self._git_inout2('archive', args.args) @@ -1969,13 +1984,16 @@ class GitRepository(object): args += ['-r'] out, ret = self._git_getoutput('ls-tree', args, cwd=path) - for line in out: - mode, objtype, commit, name = line[:-1].split(None, 3) + for line in out.split(b'\n'): + if not line: + continue + mode, objtype, commit, name = line.decode().split(None, 3) + # A submodules is shown as "commit" object in ls-tree: if objtype == "commit": nextpath = os.path.join(path, name) - submodules.append( (nextpath.replace(self.path,'').lstrip('/'), - commit) ) + submodules.append((nextpath.replace(self.path, '').lstrip('/'), + commit)) if recursive: submodules += self.get_submodules(commit, path=nextpath, recursive=recursive) @@ -2004,7 +2022,7 @@ class GitRepository(object): try: if not os.path.exists(abspath): os.makedirs(abspath) - stderr = '' + stderr = b'' try: for out in klass.__git_inout(command='init', args=args.args, @@ -2015,7 +2033,7 @@ class GitRepository(object): capture_stdout=True): stderr += out[1] except GitRepositoryError: - raise GitRepositoryError("Error running git init: %s" % stderr) + raise GitRepositoryError("Error running git init: %s" % stderr.decode().strip()) except Exception as excobj: raise GitRepositoryError("Error running git init: %s" % excobj) if description: @@ -2025,7 +2043,7 @@ class GitRepository(object): return klass(abspath) except OSError as err: raise GitRepositoryError("Cannot create Git repository at '%s': %s" - % (abspath, err[1])) + % (abspath, err)) return None @classmethod @@ -2068,7 +2086,7 @@ class GitRepository(object): try: if not os.path.exists(abspath): os.makedirs(abspath) - stderr = '' + stderr = b'' try: for out in klass.__git_inout(command='clone', args=args.args, @@ -2079,7 +2097,7 @@ class GitRepository(object): capture_stdout=True): stderr += out[1] except GitRepositoryError: - raise GitRepositoryError("Error running git clone: %s" % stderr) + raise GitRepositoryError("Error running git clone: %s" % stderr.decode()) except Exception as excobj: raise GitRepositoryError("Error running git clone: %s" % excobj) diff --git a/gbp/patch_series.py b/gbp/patch_series.py index f608f200..caebfbfe 100644 --- a/gbp/patch_series.py +++ b/gbp/patch_series.py @@ -49,7 +49,7 @@ class Patch(object): repr = "<gbp.patch_series.Patch path='%s' " % self.path if self.topic: repr += "topic='%s' " % self.topic - if self.strip != None: + if self.strip is not None: repr += "strip=%d " % self.strip repr += ">" return repr @@ -62,22 +62,23 @@ class Patch(object): """ self.info = {} body = tempfile.NamedTemporaryFile(prefix='gbp_') - pipe = subprocess.Popen("git mailinfo '%s' /dev/null 2>/dev/null < '%s'" % + pipe = subprocess.Popen("git mailinfo -k '%s' /dev/null 2>/dev/null < '%s'" % (body.name, self.path), shell=True, stdout=subprocess.PIPE).stdout for line in pipe: + line = line.decode() if ':' in line: rfc_header, value = line.split(" ", 1) header = rfc_header[:-1].lower() self.info[header] = value.strip() try: - self.long_desc = body.read() - body.close() - except IOError as msg: + self.long_desc = "".join([l.decode("utf-8", "backslashreplace") for l in body]) + except (IOError, UnicodeDecodeError) as msg: raise GbpError("Failed to read patch header of '%s': %s" % - (self.patch, msg)) + (self.path, msg)) finally: + body.close() if os.path.exists(body.name): os.unlink(body.name) @@ -112,7 +113,7 @@ class Patch(object): if ext in self.patch_exts: subject = base except ValueError: - pass # No ext so keep subject as is + pass # No ext so keep subject as is return subject.lstrip('0123456789-') or subject def _get_info_field(self, key, get_val=None): @@ -125,9 +126,9 @@ class Patch(object): @param key: key to fetch @type key: C{str} @param get_val: alternate value if key is not in info dict - @type get_val: C{str} + @type get_val: C{()->str} """ - if self.info == None: + if self.info is None: self._read_info() if key in self.info: @@ -205,11 +206,11 @@ class PatchSeries(list): queue = PatchSeries() for line in series: try: - if line[0] in [ '\n', '#' ]: + if line[0] in ['\n', '#']: continue except IndexError: - continue # ignore empty lines - queue.append(klass._parse_line(line, patch_dir)) + continue # ignore empty lines + queue.append(cls._parse_line(line, patch_dir)) return queue @staticmethod @@ -223,7 +224,7 @@ class PatchSeries(list): >>> PatchSeries._get_topic("/asdf") """ topic = os.path.dirname(line) - if topic in [ '', '/' ]: + if topic in ['', '/']: topic = None return topic diff --git a/gbp/paths.py b/gbp/paths.py new file mode 100755 index 00000000..1cb7bcca --- /dev/null +++ b/gbp/paths.py @@ -0,0 +1,26 @@ +# vim: set fileencoding=utf-8 : +# +# (C) 2017 Guido Günther <agx@sigxcpu.org> +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, please see +# <http://www.gnu.org/licenses/> +"Helpers to handle paths" + + +def to_bin(path): + """Convert to binary if not already + + We want paths to be binary since we can't assume an encoding but + it shall still be convenient to pass in unicode strings + """ + return path.encode() if not isinstance(path, bytes) else path diff --git a/gbp/rpm/__init__.py b/gbp/rpm/__init__.py index 0a376e18..62f0c279 100644 --- a/gbp/rpm/__init__.py +++ b/gbp/rpm/__init__.py @@ -38,6 +38,11 @@ from gbp.rpm.linkedlist import LinkedList from gbp.rpm.lib_rpm import librpm, get_librpm_log +def _decode(s): + if s is not None: + return s.decode() + + class NoSpecError(Exception): """Spec file parsing error""" pass @@ -72,8 +77,8 @@ class SrcRpmFile(object): @property def version(self): """Get the (downstream) version of the RPM package""" - version = dict(upstreamversion = self.rpmhdr[librpm.RPMTAG_VERSION], - release = self.rpmhdr[librpm.RPMTAG_RELEASE]) + version = dict(upstreamversion=self.rpmhdr[librpm.RPMTAG_VERSION].decode(), + release=self.rpmhdr[librpm.RPMTAG_RELEASE].decode()) if self.rpmhdr[librpm.RPMTAG_EPOCH] is not None: version['epoch'] = str(self.rpmhdr[librpm.RPMTAG_EPOCH]) return version @@ -81,17 +86,17 @@ class SrcRpmFile(object): @property def name(self): """Get the name of the RPM package""" - return self.rpmhdr[librpm.RPMTAG_NAME] + return self.rpmhdr[librpm.RPMTAG_NAME].decode() @property def upstreamversion(self): """Get the upstream version of the RPM package""" - return self.rpmhdr[librpm.RPMTAG_VERSION] + return self.rpmhdr[librpm.RPMTAG_VERSION].decode() @property def packager(self): """Get the packager of the RPM package""" - return self.rpmhdr[librpm.RPMTAG_PACKAGER] + return _decode(self.rpmhdr[librpm.RPMTAG_PACKAGER]) def unpack(self, dest_dir): """ @@ -159,13 +164,13 @@ class SpecFile(object): # Other initializations source_header = self._specinfo.packages[0].header - self.name = source_header[librpm.RPMTAG_NAME] - self.upstreamversion = source_header[librpm.RPMTAG_VERSION] - self.release = source_header[librpm.RPMTAG_RELEASE] + self.name = source_header[librpm.RPMTAG_NAME].decode() + self.upstreamversion = source_header[librpm.RPMTAG_VERSION].decode() + self.release = source_header[librpm.RPMTAG_RELEASE].decode() # rpm-python returns epoch as 'long', convert that to string self.epoch = str(source_header[librpm.RPMTAG_EPOCH]) \ - if source_header[librpm.RPMTAG_EPOCH] != None else None - self.packager = source_header[librpm.RPMTAG_PACKAGER] + if source_header[librpm.RPMTAG_EPOCH] is not None else None + self.packager = _decode(source_header[librpm.RPMTAG_PACKAGER]) self._tags = {} self._special_directives = defaultdict(list) self._gbp_tags = defaultdict(list) @@ -184,7 +189,7 @@ class SpecFile(object): def _parse_filtered_spec(self, skip_tags): """Parse a filtered spec file in rpm-python""" skip_tags = [tag.lower() for tag in skip_tags] - with tempfile.NamedTemporaryFile(prefix='gbp') as filtered: + with tempfile.NamedTemporaryFile(prefix='gbp', mode='w+') as filtered: filtered.writelines(str(line) for line in self._content if str(line).split(":")[0].strip().lower() not in skip_tags) filtered.flush() @@ -303,7 +308,7 @@ class SpecFile(object): tagvalue = None # We don't support "multivalue" tags like "Provides:" or "SourceX:" # Rpm python doesn't support many of these, thus the explicit list - if type(tagvalue) is int or type(tagvalue) is int: + if isinstance(tagvalue, int): tagvalue = str(tagvalue) elif type(tagvalue) is list or tagname in self._listtags: tagvalue = None @@ -853,11 +858,11 @@ def guess_spec_repo(repo, treeish, topdir='', recursive=True, preferred_name=Non """ topdir = topdir.rstrip('/') + ('/') if topdir else '' try: - file_list = [nam for (mod, typ, sha, nam) in - repo.list_tree(treeish, recursive, topdir) if typ == 'blob'] + file_list = [nam.decode() for (mod, typ, sha, nam) in + repo.list_tree(treeish, recursive, topdir) if typ == 'blob'] except GitRepositoryError as err: raise NoSpecError("Cannot find spec file from treeish %s, Git error: %s" - % (treeish, err)) + % (treeish, err)) spec_path = guess_spec_fn(file_list, preferred_name) return spec_from_repo(repo, treeish, spec_path) @@ -865,7 +870,7 @@ def guess_spec_repo(repo, treeish, topdir='', recursive=True, preferred_name=Non def spec_from_repo(repo, treeish, spec_path): """Get and parse a spec file from a give Git treeish""" try: - spec = SpecFile(filedata=repo.show('%s:%s' % (treeish, spec_path))) + spec = SpecFile(filedata=repo.show('%s:%s' % (treeish, spec_path)).decode()) spec.specdir = os.path.dirname(spec_path) spec.specfile = os.path.basename(spec_path) return spec diff --git a/gbp/rpm/linkedlist.py b/gbp/rpm/linkedlist.py index 4d223422..c622f603 100644 --- a/gbp/rpm/linkedlist.py +++ b/gbp/rpm/linkedlist.py @@ -193,7 +193,7 @@ class LinkedList(collections.abc.Iterable): 'foo' >>> [str(data) for data in list] ['foo', 'bar'] - >>> print "%s" % node3 + >>> print("%s" % node3) <BLANKLINE> >>> str(list.delete(node1)) 'bar' diff --git a/gbp/scripts/common/buildpackage.py b/gbp/scripts/common/buildpackage.py index a2122866..12eede9e 100644 --- a/gbp/scripts/common/buildpackage.py +++ b/gbp/scripts/common/buildpackage.py @@ -150,8 +150,9 @@ def dump_tree(repo, export_dir, treeish, with_submodules, recursive=True): if recursive: paths = '' else: - paths = [nam for _mod, typ, _sha, nam in repo.list_tree(treeish) if - typ == 'blob'] + paths = ["'%s'" % nam.decode() for _mod, typ, _sha, nam in + repo.list_tree(treeish) if typ == 'blob'] + try: data = repo.archive('tar', '', None, treeish, paths) untar_data(export_dir, data) diff --git a/gbp/scripts/common/import_orig.py b/gbp/scripts/common/import_orig.py index 30df6101..55516689 100644 --- a/gbp/scripts/common/import_orig.py +++ b/gbp/scripts/common/import_orig.py @@ -26,7 +26,7 @@ import gbp.log # Try to import readline, since that will cause raw_input to get fancy # line editing and history capabilities. However, if readline is not -# available, raw_input will still work. +# available, input() will still work. try: import readline except ImportError: @@ -48,7 +48,7 @@ def ask_package_name(default, name_validator_func, err_msg): """ while True: sourcepackage = input("What will be the source package name? [%s] " % default) - if not sourcepackage: # No input, use the default. + if not sourcepackage: # No input, use the default. sourcepackage = default # Valid package name, return it. if name_validator_func(sourcepackage): @@ -67,7 +67,7 @@ def ask_package_version(default, ver_validator_func, err_msg): """ while True: version = input("What is the upstream version? [%s] " % default) - if not version: # No input, use the default. + if not version: # No input, use the default. version = default # Valid version, return it. if ver_validator_func(version): diff --git a/gbp/scripts/common/pq.py b/gbp/scripts/common/pq.py index 60157b2f..0ea9f9e8 100644 --- a/gbp/scripts/common/pq.py +++ b/gbp/scripts/common/pq.py @@ -151,7 +151,7 @@ def pq_branch_base(pq_branch, options): def parse_gbp_commands(info, cmd_tag, noarg_cmds, arg_cmds): """Parse gbp commands from commit message""" cmd_re = re.compile(r'^%s:\s*(?P<cmd>[a-z-]+)(\s+(?P<args>\S.*))?' % - cmd_tag, flags=re.I) + cmd_tag, flags=re.I) commands = {} other_lines = [] for line in info['body'].splitlines(): @@ -168,7 +168,7 @@ def parse_gbp_commands(info, cmd_tag, noarg_cmds, arg_cmds): commands[cmd] = match.group('args') else: gbp.log.warn("Ignoring unknown gbp-command '%s' in commit %s" - % (line, info['id'])) + % (line, info['id'])) else: other_lines.append(line) return commands, other_lines @@ -196,7 +196,7 @@ def write_patch_file(filename, commit_info, diff): gbp.log.debug("I won't generate empty diff %s" % filename) return None try: - with open(filename, 'w') as patch: + with open(filename, 'wb') as patch: msg = Message() charset = Charset('utf-8') charset.body_encoding = None @@ -208,13 +208,13 @@ def write_patch_file(filename, commit_info, diff): # Git compat: put name in quotes if special characters found if re.search("[,.@()\[\]\\\:;]", name): name = '"%s"' % name - from_header = Header(str(name, 'utf-8'), charset, 77, 'from') - from_header.append(str('<%s>' % email)) + from_header = Header(name.encode('utf-8'), charset, 77, 'from') + from_header.append(email.encode('utf-8')) msg['From'] = from_header date = commit_info['author'].datetime datestr = date.strftime('%a, %-d %b %Y %H:%M:%S %z') - msg['Date'] = Header(str(datestr, 'utf-8'), charset, 77, 'date') - msg['Subject'] = Header(str(commit_info['subject'], 'utf-8'), + msg['Date'] = Header(datestr.encode('utf-8'), charset, 77, 'date') + msg['Subject'] = Header(commit_info['subject'].encode('utf-8'), charset, 77, 'subject') # Write message body if commit_info['body']: @@ -224,11 +224,11 @@ def write_patch_file(filename, commit_info, diff): msg.set_payload(body.encode('ascii')) except UnicodeDecodeError: msg.set_payload(body, charset) - patch.write(msg.as_string(unixfrom=False)) + patch.write(msg.as_string(unixfrom=False).encode('utf-8')) # Write diff - patch.write('---\n') - patch.write(diff) + patch.write(b'---\n') + patch.write(diff.encode()) except IOError as err: raise GbpError('Unable to create patch file: %s' % err) return filename @@ -278,7 +278,7 @@ def format_diff(outdir, filename, repo, start, end, path_exclude_regex=None): info['subject'] = "Raw diff %s..%s" % (start, end) info['body'] = ("Raw diff between %s '%s' and\n%s '%s'\n" % (repo.get_obj_type(start), start, - repo.get_obj_type(end), end)) + repo.get_obj_type(end), end)) if not filename: filename = '%s-to-%s.diff' % (start, end) filename = os.path.join(outdir, filename) @@ -323,7 +323,7 @@ def get_maintainer_from_control(repo): stdout=subprocess.PIPE).stdout.readlines() if len(cmdout) > 0: - maintainer = cmdout[0].strip() + maintainer = cmdout[0].decode().strip() m = re.match('(?P<name>.*[^ ]) *<(?P<email>.*)>', maintainer) if m: return GitModifier(m.group('name'), m.group('email')) @@ -361,7 +361,7 @@ def apply_and_commit_patch(repo, patch, fallback_author, topic=None): """apply a single patch 'patch', add topic 'topic' and commit it""" author = {'name': patch.author, 'email': patch.email, - 'date': patch.date } + 'date': patch.date} patch_fn = os.path.basename(patch.path) if not (author['name'] and author['email']): diff --git a/gbp/scripts/import_dscs.py b/gbp/scripts/import_dscs.py index c37cea80..7ed5e70f 100644 --- a/gbp/scripts/import_dscs.py +++ b/gbp/scripts/import_dscs.py @@ -1,6 +1,6 @@ # vim: set fileencoding=utf-8 : # -# (C) 2008, 2009, 2010 Guido Guenther <agx@sigxcpu.org> +# (C) 2008, 2009, 2010, 2017 Guido Günther <agx@sigxcpu.org> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or @@ -12,9 +12,9 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -"""Import multiple dsc files into GIT in one go""" +# along with this program; if not, please see +# <http://www.gnu.org/licenses/> +"""Import multiple dsc files into Git in one go""" import glob import os @@ -37,6 +37,32 @@ class DscCompareVersions(DpkgCompareVersions): return DpkgCompareVersions.__call__(self, dsc1.version, dsc2.version) +def cmp_to_key(mycmp): + 'Convert a cmp= function into a key= function' + class K(object): + def __init__(self, obj, *args): + self.obj = obj + + def __lt__(self, other): + return mycmp(self.obj, other.obj) < 0 + + def __gt__(self, other): + return mycmp(self.obj, other.obj) > 0 + + def __eq__(self, other): + return mycmp(self.obj, other.obj) == 0 + + def __le__(self, other): + return mycmp(self.obj, other.obj) <= 0 + + def __ge__(self, other): + return mycmp(self.obj, other.obj) >= 0 + + def __ne__(self, other): + return mycmp(self.obj, other.obj) != 0 + return K + + class GitImportDsc(object): def __init__(self, args): self.args = args @@ -46,7 +72,7 @@ class GitImportDsc(object): def fetch_snapshots(pkg, downloaddir): - "Fetch snapshots using debsnap von snapshots.debian.org" + "Fetch snapshots using debsnap from snapshots.debian.org" dscs = None gbp.log.info("Downloading snapshots of '%s' to '%s'..." % @@ -93,7 +119,7 @@ def main(argv): dscs = [] ret = 0 verbose = False - dsc_cmp = DscCompareVersions() + dsc_key = cmp_to_key(DscCompareVersions()) use_debsnap = False try: @@ -128,9 +154,9 @@ def main(argv): if use_debsnap: dirs['tmp'] = os.path.abspath(tempfile.mkdtemp()) - dscs = [ DscFile.parse(f) for f in fetch_snapshots(pkg, dirs['tmp']) ] + dscs = [DscFile.parse(f) for f in fetch_snapshots(pkg, dirs['tmp'])] - dscs.sort(cmp=dsc_cmp) + dscs.sort(key=dsc_key) importer = GitImportDsc(import_args) try: diff --git a/gbp/scripts/import_srpm.py b/gbp/scripts/import_srpm.py index 0712288e..88ca4819 100755 --- a/gbp/scripts/import_srpm.py +++ b/gbp/scripts/import_srpm.py @@ -81,7 +81,7 @@ def download_file(target_dir, url): def download_source(pkg, dirs): """Download package from a remote location""" if re.match(r'[a-z]{1,5}://', pkg): - mode = 'python urllib2' + mode = 'python urllib' else: mode = 'yumdownloader' diff --git a/gbp/scripts/pq.py b/gbp/scripts/pq.py index 029e7182..4430d5fa 100755 --- a/gbp/scripts/pq.py +++ b/gbp/scripts/pq.py @@ -167,9 +167,9 @@ def export_patches(repo, branch, options): pq_branch = pq_branch_name(branch, options) try: shutil.rmtree(PATCH_DIR) - except OSError as msg: - if msg.errno != errno.ENOENT: - raise GbpError("Failed to remove patch dir: %s" % msg) + except OSError as e: + if e.errno != errno.ENOENT: + raise GbpError("Failed to remove patch dir: %s" % e.strerror) else: gbp.log.debug("%s does not exist." % PATCH_DIR) diff --git a/gbp/scripts/pq_rpm.py b/gbp/scripts/pq_rpm.py index 011c4165..92954eec 100755 --- a/gbp/scripts/pq_rpm.py +++ b/gbp/scripts/pq_rpm.py @@ -292,8 +292,8 @@ def safe_patches(queue, tmpdir_base): safequeue = PatchSeries() if len(queue) > 0: - gbp.log.debug("Safeing patches '%s' in '%s'" % - (os.path.dirname(queue[0].path), tmpdir)) + gbp.log.debug("Saving patches '%s' in '%s'" % + (os.path.dirname(queue[0].path), tmpdir)) for patch in queue: base, _archive_fmt, comp = parse_archive_filename(patch.path) uncompressors = {'gzip': gzip.open, 'bzip2': bz2.BZ2File} @@ -308,11 +308,11 @@ def safe_patches(queue, tmpdir_base): raise GbpError("Unsupported patch compression '%s', giving up" % comp) else: - src = open(patch.path, 'r') + src = open(patch.path, 'rb') dst_name = os.path.join(tmpdir, os.path.basename(patch.path)) - dst = open(dst_name, 'w') - dst.writelines(src) + dst = open(dst_name, 'wb') + dst.write(src.read()) src.close() dst.close() if _archive_fmt: diff --git a/gbp/scripts/rpm_ch.py b/gbp/scripts/rpm_ch.py index e5fddb4e..b2a836aa 100755 --- a/gbp/scripts/rpm_ch.py +++ b/gbp/scripts/rpm_ch.py @@ -92,7 +92,8 @@ def load_customizations(customization_file): return customizations = {} try: - exec(compile(open(customization_file, "rb").read(), customization_file, 'exec'), customizations, customizations) + with open(customization_file) as f: + exec(f.read(), customizations, customizations) except Exception as err: raise GbpError("Failed to load customization file: %s" % err) diff --git a/gbp/scripts/supercommand.py b/gbp/scripts/supercommand.py index 7a91625b..7e35877a 100644 --- a/gbp/scripts/supercommand.py +++ b/gbp/scripts/supercommand.py @@ -53,7 +53,7 @@ def version(prog): from gbp.version import gbp_version except ImportError: gbp_version = '[Unknown version]' - print(("%s %s" % (os.path.basename(prog), gbp_version))) + print("%s %s" % (os.path.basename(prog), gbp_version)) def import_command(cmd): @@ -62,7 +62,7 @@ def import_command(cmd): """ modulename = sanitize(cmd) if (not re.match(r'[a-z][a-z0-9_]', modulename) or - modulename in invalid_modules): + modulename in invalid_modules): raise ImportError('Illegal module name %s' % modulename) return __import__('gbp.scripts.%s' % modulename, fromlist='main', level=0) @@ -90,7 +90,7 @@ def list_available_commands(): path = os.path.dirname(mod.__file__) maxlen = 0 - print(("Available commands in %s\n" % path)) + print("Available commands in %s\n" % path) cmds = sorted(get_available_commands(path)) for cmd in cmds: if len(cmd[0]) > maxlen: @@ -98,7 +98,7 @@ def list_available_commands(): for cmd in cmds: mod = import_command(cmd[0]) doc = mod.__doc__ - print((" %s - %s" % (cmd[0].rjust(maxlen), doc))) + print(" %s - %s" % (cmd[0].rjust(maxlen), doc)) print('') diff --git a/packaging/git-buildpackage.spec b/packaging/git-buildpackage.spec index 3132dc05..f680d4ed 100755 --- a/packaging/git-buildpackage.spec +++ b/packaging/git-buildpackage.spec @@ -151,7 +151,7 @@ Debian and the RPM tool set. %build -WITHOUT_NOSETESTS=1 python3 ./setup.py build +WITHOUT_NOSETESTS=1 %{__python3} ./setup.py build %if %{with docs} # Prepare apidocs @@ -168,13 +168,13 @@ HAVE_SGML2X=0 make -C docs/ GIT_CEILING_DIRECTORIES=%{_builddir} \ GIT_AUTHOR_EMAIL=rpmbuild@example.com GIT_AUTHOR_NAME=rpmbuild \ GIT_COMMITTER_NAME=$GIT_AUTHOR_NAME GIT_COMMITTER_EMAIL=$GIT_AUTHOR_EMAIL \ - python3 setup.py nosetests + %{__python3} setup.py nosetests %endif %install rm -rf %{buildroot} -WITHOUT_NOSETESTS=1 python3 ./setup.py install --root=%{buildroot} --prefix=/usr +WITHOUT_NOSETESTS=1 %{__python3} ./setup.py install --root=%{buildroot} --prefix=/usr rm -rf %{buildroot}%{python3_sitelib}/*info #remove __pycache directory @@ -29,7 +29,7 @@ def fetch_version(): try: popen = subprocess.Popen('dpkg-parsechangelog', stdout=subprocess.PIPE) out, ret = popen.communicate() - for line in out.decode().split('\n'): + for line in out.decode('utf-8').split('\n'): if line.startswith('Version:'): version = line.split(' ')[1].strip() break @@ -38,7 +38,7 @@ def fetch_version(): with open('gbp/version.py', 'w') as f: f.write('"The current gbp version number"\n') - f.write('gbp_version="%s"\n' % version) + f.write('gbp_version = "%s"\n' % version) return version @@ -49,7 +49,7 @@ def readme(): setup(name = "gbp", version = fetch_version(), - author = 'Guido Günther', + author=u'Guido Günther', author_email = 'agx@sigxcpu.org', url = 'https://honk.sigxcpu.org/piki/projects/git-buildpackage/', description = 'Suite to help with Debian packages in Git repositories', @@ -57,8 +57,8 @@ setup(name = "gbp", long_description = readme(), classifiers = [ 'Environment :: Console', - 'Programming Language :: Python :: 2', - 'Topic :: Software Development :: Version Control :: Git', + 'Programming Language :: Python :: 3', + 'Topic :: Software Development :: Version Control', 'Operating System :: POSIX :: Linux', ], scripts = [ 'bin/git-buildpackage', @@ -78,6 +78,11 @@ setup(name = "gbp", 'bin/git-rpm-ch'], packages = find_packages(exclude=['tests', 'tests.*']), data_files = [("/etc/git-buildpackage/", ["gbp.conf"]),], + requires=['dateutil'], + install_requires=[ + 'python-dateutil', + ], + python_requires='>=3.5', setup_requires=['nose>=0.11.1', 'coverage>=2.85'] if \ os.getenv('WITHOUT_NOSETESTS') is None else [], entry_points = { diff --git a/tests/01_test_help.py b/tests/01_test_help.py index a421eb8d..4fe279e9 100644 --- a/tests/01_test_help.py +++ b/tests/01_test_help.py @@ -24,7 +24,7 @@ class TestHelp(unittest.TestCase): 'pull', 'pq']: module = 'gbp.scripts.%s' % script - m = __import__(module, globals(), locals(), ['main'], -1) + m = __import__(module, globals(), locals(), ['main'], 0) self.assertRaises(SystemExit, m.main, ['doesnotmatter', '--help']) @@ -36,7 +36,7 @@ class TestHelp(unittest.TestCase): 'buildpackage_rpm', 'import_orig_rpm']: module = 'gbp.scripts.%s' % script - m = __import__(module, globals(), locals(), ['main'], -1) + m = __import__(module, globals(), locals(), ['main'], 0) self.assertRaises(SystemExit, m.main, ['doesnotmatter', '--help']) diff --git a/tests/07_test_fastimport.py b/tests/07_test_fastimport.py index 0a14d38d..c3ca8188 100644 --- a/tests/07_test_fastimport.py +++ b/tests/07_test_fastimport.py @@ -5,8 +5,6 @@ from . import context import os -import shutil -import tempfile import gbp.log import gbp.git @@ -16,40 +14,47 @@ fastimport = None tf_name = 'testfile' tl_name = 'a_testlink' + def setup(): global repo tmpdir = context.new_tmpdir(__name__) repo = gbp.git.GitRepository.create(tmpdir.join('test_repo')) + def teardown(): context.teardown() + def test_init_fastimport(): """Create a fastimport object""" global fastimport fastimport = gbp.git.FastImport(repo) assert fastimport, "Failed to init FastImport" + def test_add_file(): """Add a file via fastimport""" author = repo.get_author_info() fastimport.start_commit('master', author, "a commit") fastimport.deleteall() testfile = os.path.join(repo.path, '.git', 'description') - fastimport.add_file('./testfile', - open(testfile), + fastimport.add_file(b'./testfile', + open(testfile, 'rb'), os.path.getsize(testfile)) + def test_add_symlink(): """Add a symbolic link via fastimport""" author = repo.get_author_info() fastimport.start_commit('master', author, "a 2nd commit") fastimport.add_symlink(tl_name, tf_name) + def test_close(): fastimport.close() + def test_result(): repo.force_head('master', hard=True) @@ -59,4 +64,3 @@ def test_result(): assert os.path.exists(testfile), "%s doesn't exist" % testfile assert os.path.lexists(testlink), "%s doesn't exist" % testlink assert os.readlink(testlink) == tf_name - diff --git a/tests/09_test_write_tree.py b/tests/09_test_write_tree.py index 9ae636e3..f0511811 100644 --- a/tests/09_test_write_tree.py +++ b/tests/09_test_write_tree.py @@ -3,11 +3,9 @@ """Test L{GitRepository}'s write_tree method""" from . import context - +from . import testutils import os -import tests.testutils as testutils - import gbp.log import gbp.git import gbp.errors diff --git a/tests/10_test_get_upstream_tree.py b/tests/10_test_get_upstream_tree.py index f489f2bc..df877562 100644 --- a/tests/10_test_get_upstream_tree.py +++ b/tests/10_test_get_upstream_tree.py @@ -4,7 +4,7 @@ from . import context -import tests.testutils as testutils +from . import testutils import gbp.errors import gbp.scripts.buildpackage as buildpackage diff --git a/tests/11_test_dch_main.py b/tests/11_test_dch_main.py index 9bdc5c5b..9394b8fe 100644 --- a/tests/11_test_dch_main.py +++ b/tests/11_test_dch_main.py @@ -4,15 +4,9 @@ from . import context -# Try unittest2 for CentOS -try: - import unittest2 as unittest -except ImportError: - import unittest - -from tests.testutils import (DebianGitTestRepo, OsReleaseFile, - get_dch_default_urgency) - +from .testutils import (DebianGitTestRepo, OsReleaseFile, + get_dch_default_urgency) +import unittest from gbp.scripts import dch import os diff --git a/tests/12_test_deb.py b/tests/12_test_deb.py index 2be30976..2c937dfc 100644 --- a/tests/12_test_deb.py +++ b/tests/12_test_deb.py @@ -4,12 +4,10 @@ from . import context -import os, tempfile -# Try unittest2 for CentOS -try: - import unittest2 as unittest -except ImportError: - import unittest +import os +import tempfile +import platform +import unittest import gbp.deb @@ -53,7 +51,7 @@ Files: def setUp(self): with tempfile.NamedTemporaryFile(delete=False) as self.dscfile: - self.dscfile.write(self.content) + self.dscfile.write(self.content.encode()) def tearDown(self): os.unlink(self.dscfile.name) diff --git a/tests/13_test_gbp_pq.py b/tests/13_test_gbp_pq.py index f71c5420..6af51ee7 100644 --- a/tests/13_test_gbp_pq.py +++ b/tests/13_test_gbp_pq.py @@ -16,19 +16,14 @@ """Test L{gbp.pq}""" from . import context +from . import testutils import os import logging -# Try unittest2 for CentOS -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest from gbp.scripts.pq import generate_patches, switch_pq, export_patches import gbp.scripts.common.pq as pq -import gbp.patch_series -import tests.testutils as testutils class TestApplyAndCommit(testutils.DebianGitTestRepo): """Test L{gbp.pq}'s apply_and_commit""" @@ -42,7 +37,7 @@ class TestApplyAndCommit(testutils.DebianGitTestRepo): patch = gbp.patch_series.Patch(_patch_path('foo.patch')) pq.apply_and_commit_patch(self.repo, patch, None) - self.assertIn('foo', self.repo.list_files()) + self.assertIn(b'foo', self.repo.list_files()) def test_topic(self): @@ -61,7 +56,7 @@ class TestApplyAndCommit(testutils.DebianGitTestRepo): """ def _check_log(msg): self.assertEqual(msg, "Patch 'foo.patch' has no authorship " - "information, using 'Guido Günther <gg@godiug.net>'") + "information, using 'Guido Günther <gg@godiug.net>'") patch = gbp.patch_series.Patch(_patch_path('foo.patch')) @@ -72,7 +67,8 @@ class TestApplyAndCommit(testutils.DebianGitTestRepo): # Fake a control file self.add_file("debian/control", - "Maintainer: Guido Günther <gg@godiug.net>") + "Maintainer: Guido Günther <gg@godiug.net>".encode('utf-8'), + mode='wb+') maintainer = pq.get_maintainer_from_control(self.repo) orig_warn = gbp.log.warn @@ -81,7 +77,8 @@ class TestApplyAndCommit(testutils.DebianGitTestRepo): gbp.log.warn = orig_warn info = self.repo.get_commit_info('HEAD') self.assertEqual(info['author'].email, 'gg@godiug.net') - self.assertIn('foo', self.repo.list_files()) + self.assertIn(b'foo', self.repo.list_files()) + class TestApplySinglePatch(testutils.DebianGitTestRepo): """Test L{gbp.pq}'s apply_single_patch""" @@ -97,7 +94,7 @@ class TestApplySinglePatch(testutils.DebianGitTestRepo): dummy_opts = object() pq.apply_single_patch(self.repo, 'master', patch, None, dummy_opts) - self.assertIn('foo', self.repo.list_files()) + self.assertIn(b'foo', self.repo.list_files()) class TestWritePatch(testutils.DebianGitTestRepo): """Test L{gbp.pq}'s write_patch """ @@ -126,7 +123,7 @@ class TestWritePatch(testutils.DebianGitTestRepo): expected = os.path.join(str(d), 'gbptest', 'added-foo.patch') self.assertTrue(os.path.exists(expected)) - logging.debug(file(expected).read()) + logging.debug(open(expected).read()) # Reapply the patch to a new branch self.repo.create_branch('testapply', 'HEAD^') diff --git a/tests/14_test_gbp_import_dscs.py b/tests/14_test_gbp_import_dscs.py index 2fdc2e6e..eab896b3 100644 --- a/tests/14_test_gbp_import_dscs.py +++ b/tests/14_test_gbp_import_dscs.py @@ -68,7 +68,7 @@ class TestImportDscs(testutils.DebianGitTestRepo): def _check_err_msg(self, err): self.assertIsInstance(err, GbpError) - self.assertIn("Failed to import", err.message) + self.assertIn("Failed to import", str(err)) def test_import_success(self): """Test importing success with stub""" diff --git a/tests/15_test_DebianSource.py b/tests/15_test_DebianSource.py index a4ea5562..aa2776a4 100644 --- a/tests/15_test_DebianSource.py +++ b/tests/15_test_DebianSource.py @@ -16,9 +16,9 @@ """Test L{gbp.pq}""" from . import context +from . import testutils import os -from . import testutils from gbp.deb.source import DebianSource, DebianSourceError from gbp.deb.format import DebianSourceFormat from gbp.git.vfs import GitVfs diff --git a/tests/18_test_Config.py b/tests/18_test_Config.py index 0bb7354e..ba1a42dc 100644 --- a/tests/18_test_Config.py +++ b/tests/18_test_Config.py @@ -1,11 +1,8 @@ # vim: set fileencoding=utf-8 : import os -# Try unittest2 for CentOS -try: - import unittest2 as unittest -except ImportError: - import unittest + +import unittest from gbp.config import GbpOptionParser, GbpOptionGroup from . import context diff --git a/tests/component/__init__.py b/tests/component/__init__.py index 66a5e2f4..f1522f96 100644 --- a/tests/component/__init__.py +++ b/tests/component/__init__.py @@ -43,7 +43,7 @@ class ComponentTestGitRepository(GitRepository): raise GitRepositoryError("Cannot get submodule status: %s" % err.strip()) submodules = {} - for line in out.splitlines(): + for line in out.decode().splitlines(): module = line.strip() # Uninitialized status = module[0] diff --git a/tests/component/rpm/test_buildpackage_rpm.py b/tests/component/rpm/test_buildpackage_rpm.py index 49773e87..6589132a 100644 --- a/tests/component/rpm/test_buildpackage_rpm.py +++ b/tests/component/rpm/test_buildpackage_rpm.py @@ -269,7 +269,7 @@ class TestGbpRpm(RpmRepoTestBase): # Dummy update to upstream branch pkg_branch = repo.get_branch() upstr_branch = 'srcdata/gbp-test/upstream' - orig_files = ['gbp-test/' + path for \ + orig_files = ['gbp-test/' + path.decode() for \ path in self.ls_tree(repo, upstr_branch)] + ['gbp-test'] repo.set_branch(upstr_branch) with open('new-file', 'w') as fobj: @@ -409,7 +409,7 @@ class TestGbpRpm(RpmRepoTestBase): repo.set_branch(pkg_branch) sub_files = self.ls_tree(sub_repo, 'HEAD') - upstr_files = ['gbp-test/' + path for + upstr_files = ['gbp-test/' + path.decode() for path in self.ls_tree(repo, upstr_branch)] # Test the "no" option @@ -423,7 +423,7 @@ class TestGbpRpm(RpmRepoTestBase): eq_(mock_gbp(['--git-submodules', '--git-upstream-tree=%s' % upstr_branch, '--git-ignore-untracked']), 0) tar_files = ls_tar('../rpmbuild/SOURCES/gbp-test-1.1.tar.bz2', False) - ref_files = upstr_files + ['gbp-test/gbp-test-native.repo/' + path for + ref_files = upstr_files + ['gbp-test/gbp-test-native.repo/' + path.decode() for path in sub_files] self.check_files(ref_files, tar_files) shutil.rmtree('../rpmbuild') @@ -444,7 +444,7 @@ class TestGbpRpm(RpmRepoTestBase): repo.commit_all('Add submodule') sub_files = self.ls_tree(sub_repo, 'HEAD') - master_files = ['gbp-test-native-1.0/' + path for + master_files = ['gbp-test-native-1.0/' + path.decode() for path in self.ls_tree(repo, 'HEAD')] # Test diff --git a/tests/component/rpm/test_import_srpm.py b/tests/component/rpm/test_import_srpm.py index 7dcfe223..48cbfb3f 100644 --- a/tests/component/rpm/test_import_srpm.py +++ b/tests/component/rpm/test_import_srpm.py @@ -288,7 +288,7 @@ class TestDownloadImport(ComponentTestBase): # Mock to use local files instead of really downloading local_fn = os.path.join(DATA_DIR, os.path.basename(srpm)) urllib.request.urlopen = Mock() - urllib.request.urlopen.return_value = open(local_fn, 'r') + urllib.request.urlopen.return_value = open(local_fn, 'rb') eq_(mock_import(['--no-pristine-tar', '--download', srpm]), 0) # Check repository state diff --git a/tests/component/rpm/test_pq_rpm.py b/tests/component/rpm/test_pq_rpm.py index c14ea681..83230cfb 100644 --- a/tests/component/rpm/test_pq_rpm.py +++ b/tests/component/rpm/test_pq_rpm.py @@ -96,7 +96,7 @@ class TestPqRpm(RpmRepoTestBase): 'gbp-test.spec', '0001-my-gz.patch', '0002-my-bzip2.patch', '0003-my2.patch', 'my.patch'] self._check_repo_state(repo, 'master', branches, files) - eq_(repo.status()[' M'], ['gbp-test.spec']) + eq_(repo.status()[' M'], [b'gbp-test.spec']) # Another export after removing some patches os.unlink('0001-my-gz.patch') @@ -118,7 +118,7 @@ class TestPqRpm(RpmRepoTestBase): # Test export eq_(mock_pq(['export']), 0) self._check_repo_state(repo, 'master-orphan', branches) - eq_(repo.status()[' M'], ['packaging/gbp-test2.spec']) + eq_(repo.status()[' M'], [b'packaging/gbp-test2.spec']) def test_import_in_subdir(self): """Test running gbp-rpm-pq from a subdir in the git tree""" @@ -202,11 +202,11 @@ class TestPqRpm(RpmRepoTestBase): def test_force_import(self): """Test force import""" repo = self.init_test_repo('gbp-test') - pkg_files = repo.list_files() + pkg_files = [f.decode() for f in repo.list_files()] repo.rename_branch('pq/master', 'development/master') repo.set_branch('development/master') branches = repo.get_local_branches() - pq_files = repo.list_files() + pq_files = [f.decode() for f in repo.list_files()] # Re-import should fail eq_(mock_pq(['import']), 1) @@ -486,7 +486,7 @@ class TestPqRpm(RpmRepoTestBase): repo.commit_dir('.', 'Merge with master', 'development/master', ['master']) merge_rev = repo.rev_parse('HEAD', short=7) - eq_(mock_pq(['apply', patches[0]]), 0) + eq_(mock_pq(['apply', patches[0].decode()]), 0) upstr_rev = repo.rev_parse('upstream', short=7) os.unlink(patches[0]) diff --git a/tests/test_Changelog.py b/tests/test_Changelog.py index 30f25e52..b717761c 100644 --- a/tests/test_Changelog.py +++ b/tests/test_Changelog.py @@ -229,7 +229,7 @@ def test_add_section(): >>> import tempfile >>> import shutil >>> import gbp.deb.changelog - >>> from tests.testutils import OsReleaseFile + >>> from .testutils import OsReleaseFile >>> os_release = OsReleaseFile('/etc/lsb-release') >>> olddir = os.path.abspath(os.path.curdir) >>> testdir = tempfile.mkdtemp(prefix='gbp-test-changelog-') @@ -275,7 +275,7 @@ def test_add_entry(): >>> import tempfile >>> import shutil >>> import gbp.deb.changelog - >>> from tests.testutils import OsReleaseFile + >>> from .testutils import OsReleaseFile >>> os_release = OsReleaseFile('/etc/lsb-release') >>> olddir = os.path.abspath(os.path.curdir) >>> testdir = tempfile.mkdtemp(prefix='gbp-test-changelog-') diff --git a/tests/test_GitModifier.py b/tests/test_GitModifier.py index 0a05d4b8..8e7930e8 100644 --- a/tests/test_GitModifier.py +++ b/tests/test_GitModifier.py @@ -19,10 +19,14 @@ def test_author(): 'foo' >>> modifier.email 'bar' - >>> modifier.get_author_env() - {'GIT_AUTHOR_EMAIL': 'bar', 'GIT_AUTHOR_NAME': 'foo'} - >>> modifier.get_committer_env() - {'GIT_COMMITTER_NAME': 'foo', 'GIT_COMMITTER_EMAIL': 'bar'} + >>> modifier.get_author_env()['GIT_AUTHOR_EMAIL'] + 'bar' + >>> modifier.get_author_env()['GIT_AUTHOR_NAME'] + 'foo' + >>> modifier.get_committer_env()['GIT_COMMITTER_NAME'] + 'foo' + >>> modifier.get_committer_env()['GIT_COMMITTER_EMAIL'] + 'bar' >>> modifier._get_env('foo') Traceback (most recent call last): ... diff --git a/tests/test_GitRepository.py b/tests/test_GitRepository.py index f8cfafec..15651e2e 100644 --- a/tests/test_GitRepository.py +++ b/tests/test_GitRepository.py @@ -82,10 +82,10 @@ def test_add_files(): >>> repo.is_clean(ignore_untracked=True)[0] True >>> repo.add_files('testfile', force=True, untracked=False) - >>> repo.status().items() + >>> list(repo.status().items()) [('??', ['testfile'])] >>> repo.add_files(repo.path, force=True) - >>> repo.status().items() + >>> list(repo.status().items()) [('A ', ['testfile'])] >>> repo.commit_all(msg="foo") >>> repo.is_clean()[0] @@ -897,16 +897,16 @@ def test_status(): >>> repo = gbp.git.GitRepository(repo_dir) >>> fname = os.path.join(repo.path, "test_status") >>> shutil.copy(os.path.join(repo.path, ".git/HEAD"), fname) - >>> repo.status().items() + >>> list(repo.status().items()) [('??', ['test_status'])] - >>> repo.status(['bla*']).items() + >>> list(repo.status().items()) [] - >>> repo.status(['te*']).items() + >>> list(repo.status().items()) [('??', ['test_status'])] >>> repo.add_files(repo.path, force=True) >>> repo.commit_all(msg='added %s' % fname) >>> _ = repo._git_inout('mv', [fname, fname + 'new']) - >>> repo.status().items() + >>> list(repo.status().items()) [('R ', ['test_status\x00test_statusnew'])] """ |