diff -r 2372284d9457 -r 687b865b95ad hgext/convert/git.py --- a/hgext/convert/git.py Sun Oct 06 09:45:02 2019 -0400 +++ b/hgext/convert/git.py Sun Oct 06 09:48:39 2019 -0400 @@ -26,22 +26,22 @@ self.url = url def hgsub(self): - return "%s = [git]%s" % (self.path, self.url) + return b"%s = [git]%s" % (self.path, self.url) def hgsubstate(self): - return "%s %s" % (self.node, self.path) + return b"%s %s" % (self.node, self.path) # Keys in extra fields that should not be copied if the user requests. bannedextrakeys = { # Git commit object built-ins. - 'tree', - 'parent', - 'author', - 'committer', + b'tree', + b'parent', + b'author', + b'committer', # Mercurial built-ins. - 'branch', - 'close', + b'branch', + b'close', } @@ -51,7 +51,7 @@ # both issues. def _gitcmd(self, cmd, *args, **kwargs): - return cmd('--git-dir=%s' % self.path, *args, **kwargs) + return cmd(b'--git-dir=%s' % self.path, *args, **kwargs) def gitrun0(self, *args, **kwargs): return self._gitcmd(self.run0, *args, **kwargs) @@ -70,100 +70,104 @@ def __init__(self, ui, repotype, path, revs=None): super(convert_git, self).__init__(ui, repotype, path, revs=revs) - common.commandline.__init__(self, ui, 'git') + common.commandline.__init__(self, ui, b'git') # Pass an absolute path to git to prevent from ever being interpreted # as a URL path = os.path.abspath(path) - if os.path.isdir(path + "/.git"): - path += "/.git" - if not os.path.exists(path + "/objects"): + if os.path.isdir(path + b"/.git"): + path += b"/.git" + if not os.path.exists(path + b"/objects"): raise common.NoRepo( - _("%s does not look like a Git repository") % path + _(b"%s does not look like a Git repository") % path ) # The default value (50) is based on the default for 'git diff'. - similarity = ui.configint('convert', 'git.similarity') + similarity = ui.configint(b'convert', b'git.similarity') if similarity < 0 or similarity > 100: - raise error.Abort(_('similarity must be between 0 and 100')) + raise error.Abort(_(b'similarity must be between 0 and 100')) if similarity > 0: - self.simopt = ['-C%d%%' % similarity] - findcopiesharder = ui.configbool('convert', 'git.findcopiesharder') + self.simopt = [b'-C%d%%' % similarity] + findcopiesharder = ui.configbool( + b'convert', b'git.findcopiesharder' + ) if findcopiesharder: - self.simopt.append('--find-copies-harder') + self.simopt.append(b'--find-copies-harder') - renamelimit = ui.configint('convert', 'git.renamelimit') - self.simopt.append('-l%d' % renamelimit) + renamelimit = ui.configint(b'convert', b'git.renamelimit') + self.simopt.append(b'-l%d' % renamelimit) else: self.simopt = [] - common.checktool('git', 'git') + common.checktool(b'git', b'git') self.path = path self.submodules = [] - self.catfilepipe = self.gitpipe('cat-file', '--batch') + self.catfilepipe = self.gitpipe(b'cat-file', b'--batch') - self.copyextrakeys = self.ui.configlist('convert', 'git.extrakeys') + self.copyextrakeys = self.ui.configlist(b'convert', b'git.extrakeys') banned = set(self.copyextrakeys) & bannedextrakeys if banned: raise error.Abort( - _('copying of extra key is forbidden: %s') - % _(', ').join(sorted(banned)) + _(b'copying of extra key is forbidden: %s') + % _(b', ').join(sorted(banned)) ) - committeractions = self.ui.configlist('convert', 'git.committeractions') + committeractions = self.ui.configlist( + b'convert', b'git.committeractions' + ) messagedifferent = None messagealways = None for a in committeractions: - if a.startswith(('messagedifferent', 'messagealways')): + if a.startswith((b'messagedifferent', b'messagealways')): k = a v = None - if '=' in a: - k, v = a.split('=', 1) + if b'=' in a: + k, v = a.split(b'=', 1) - if k == 'messagedifferent': - messagedifferent = v or 'committer:' - elif k == 'messagealways': - messagealways = v or 'committer:' + if k == b'messagedifferent': + messagedifferent = v or b'committer:' + elif k == b'messagealways': + messagealways = v or b'committer:' if messagedifferent and messagealways: raise error.Abort( _( - 'committeractions cannot define both ' - 'messagedifferent and messagealways' + b'committeractions cannot define both ' + b'messagedifferent and messagealways' ) ) - dropcommitter = 'dropcommitter' in committeractions - replaceauthor = 'replaceauthor' in committeractions + dropcommitter = b'dropcommitter' in committeractions + replaceauthor = b'replaceauthor' in committeractions if dropcommitter and replaceauthor: raise error.Abort( _( - 'committeractions cannot define both ' - 'dropcommitter and replaceauthor' + b'committeractions cannot define both ' + b'dropcommitter and replaceauthor' ) ) if dropcommitter and messagealways: raise error.Abort( _( - 'committeractions cannot define both ' - 'dropcommitter and messagealways' + b'committeractions cannot define both ' + b'dropcommitter and messagealways' ) ) if not messagedifferent and not messagealways: - messagedifferent = 'committer:' + messagedifferent = b'committer:' self.committeractions = { - 'dropcommitter': dropcommitter, - 'replaceauthor': replaceauthor, - 'messagedifferent': messagedifferent, - 'messagealways': messagealways, + b'dropcommitter': dropcommitter, + b'replaceauthor': replaceauthor, + b'messagedifferent': messagedifferent, + b'messagealways': messagealways, } def after(self): @@ -172,35 +176,38 @@ def getheads(self): if not self.revs: - output, status = self.gitrun('rev-parse', '--branches', '--remotes') + output, status = self.gitrun( + b'rev-parse', b'--branches', b'--remotes' + ) heads = output.splitlines() if status: - raise error.Abort(_('cannot retrieve git heads')) + raise error.Abort(_(b'cannot retrieve git heads')) else: heads = [] for rev in self.revs: - rawhead, ret = self.gitrun('rev-parse', '--verify', rev) + rawhead, ret = self.gitrun(b'rev-parse', b'--verify', rev) heads.append(rawhead[:-1]) if ret: - raise error.Abort(_('cannot retrieve git head "%s"') % rev) + raise error.Abort(_(b'cannot retrieve git head "%s"') % rev) return heads def catfile(self, rev, ftype): if rev == nodemod.nullhex: raise IOError - self.catfilepipe[0].write(rev + '\n') + self.catfilepipe[0].write(rev + b'\n') self.catfilepipe[0].flush() info = self.catfilepipe[1].readline().split() if info[1] != ftype: raise error.Abort( - _('cannot read %r object at %s') + _(b'cannot read %r object at %s') % (pycompat.bytestr(ftype), rev) ) size = int(info[2]) data = self.catfilepipe[1].read(size) if len(data) < size: raise error.Abort( - _('cannot read %r object at %s: unexpected size') % (ftype, rev) + _(b'cannot read %r object at %s: unexpected size') + % (ftype, rev) ) # read the trailing newline self.catfilepipe[1].read(1) @@ -209,14 +216,14 @@ def getfile(self, name, rev): if rev == nodemod.nullhex: return None, None - if name == '.hgsub': - data = '\n'.join([m.hgsub() for m in self.submoditer()]) - mode = '' - elif name == '.hgsubstate': - data = '\n'.join([m.hgsubstate() for m in self.submoditer()]) - mode = '' + if name == b'.hgsub': + data = b'\n'.join([m.hgsub() for m in self.submoditer()]) + mode = b'' + elif name == b'.hgsubstate': + data = b'\n'.join([m.hgsubstate() for m in self.submoditer()]) + mode = b'' else: - data = self.catfile(rev, "blob") + data = self.catfile(rev, b"blob") mode = self.modecache[(name, rev)] return data, mode @@ -236,21 +243,23 @@ c = config.config() # Each item in .gitmodules starts with whitespace that cant be parsed c.parse( - '.gitmodules', - '\n'.join(line.strip() for line in content.split('\n')), + b'.gitmodules', + b'\n'.join(line.strip() for line in content.split(b'\n')), ) for sec in c.sections(): s = c[sec] - if 'url' in s and 'path' in s: - self.submodules.append(submodule(s['path'], '', s['url'])) + if b'url' in s and b'path' in s: + self.submodules.append(submodule(s[b'path'], b'', s[b'url'])) def retrievegitmodules(self, version): - modules, ret = self.gitrun('show', '%s:%s' % (version, '.gitmodules')) + modules, ret = self.gitrun( + b'show', b'%s:%s' % (version, b'.gitmodules') + ) if ret: # This can happen if a file is in the repo that has permissions # 160000, but there is no .gitmodules file. self.ui.warn( - _("warning: cannot read submodules config file in " "%s\n") + _(b"warning: cannot read submodules config file in " b"%s\n") % version ) return @@ -259,74 +268,76 @@ self.parsegitmodules(modules) except error.ParseError: self.ui.warn( - _("warning: unable to parse .gitmodules in %s\n") % version + _(b"warning: unable to parse .gitmodules in %s\n") % version ) return for m in self.submodules: - node, ret = self.gitrun('rev-parse', '%s:%s' % (version, m.path)) + node, ret = self.gitrun(b'rev-parse', b'%s:%s' % (version, m.path)) if ret: continue m.node = node.strip() def getchanges(self, version, full): if full: - raise error.Abort(_("convert from git does not support --full")) + raise error.Abort(_(b"convert from git does not support --full")) self.modecache = {} cmd = ( - ['diff-tree', '-z', '--root', '-m', '-r'] + self.simopt + [version] + [b'diff-tree', b'-z', b'--root', b'-m', b'-r'] + + self.simopt + + [version] ) output, status = self.gitrun(*cmd) if status: - raise error.Abort(_('cannot read changes in %s') % version) + raise error.Abort(_(b'cannot read changes in %s') % version) changes = [] copies = {} seen = set() entry = None subexists = [False] subdeleted = [False] - difftree = output.split('\x00') + difftree = output.split(b'\x00') lcount = len(difftree) i = 0 - skipsubmodules = self.ui.configbool('convert', 'git.skipsubmodules') + skipsubmodules = self.ui.configbool(b'convert', b'git.skipsubmodules') def add(entry, f, isdest): seen.add(f) h = entry[3] - p = entry[1] == "100755" - s = entry[1] == "120000" - renamesource = not isdest and entry[4][0] == 'R' + p = entry[1] == b"100755" + s = entry[1] == b"120000" + renamesource = not isdest and entry[4][0] == b'R' - if f == '.gitmodules': + if f == b'.gitmodules': if skipsubmodules: return subexists[0] = True - if entry[4] == 'D' or renamesource: + if entry[4] == b'D' or renamesource: subdeleted[0] = True - changes.append(('.hgsub', nodemod.nullhex)) + changes.append((b'.hgsub', nodemod.nullhex)) else: - changes.append(('.hgsub', '')) - elif entry[1] == '160000' or entry[0] == ':160000': + changes.append((b'.hgsub', b'')) + elif entry[1] == b'160000' or entry[0] == b':160000': if not skipsubmodules: subexists[0] = True else: if renamesource: h = nodemod.nullhex - self.modecache[(f, h)] = (p and "x") or (s and "l") or "" + self.modecache[(f, h)] = (p and b"x") or (s and b"l") or b"" changes.append((f, h)) while i < lcount: l = difftree[i] i += 1 if not entry: - if not l.startswith(':'): + if not l.startswith(b':'): continue entry = tuple(pycompat.bytestr(p) for p in l.split()) continue f = l - if entry[4][0] == 'C': + if entry[4][0] == b'C': copysrc = f copydest = difftree[i] i += 1 @@ -336,7 +347,7 @@ add(entry, f, False) # A file can be copied multiple times, or modified and copied # simultaneously. So f can be repeated even if fdest isn't. - if entry[4][0] == 'R': + if entry[4][0] == b'R': # rename: next line is the destination fdest = difftree[i] i += 1 @@ -344,21 +355,21 @@ add(entry, fdest, True) # .gitmodules isn't imported at all, so it being copied to # and fro doesn't really make sense - if f != '.gitmodules' and fdest != '.gitmodules': + if f != b'.gitmodules' and fdest != b'.gitmodules': copies[fdest] = f entry = None if subexists[0]: if subdeleted[0]: - changes.append(('.hgsubstate', nodemod.nullhex)) + changes.append((b'.hgsubstate', nodemod.nullhex)) else: self.retrievegitmodules(version) - changes.append(('.hgsubstate', '')) + changes.append((b'.hgsubstate', b'')) return (changes, copies, set()) def getcommit(self, version): - c = self.catfile(version, "commit") # read the commit hash - end = c.find("\n\n") + c = self.catfile(version, b"commit") # read the commit hash + end = c.find(b"\n\n") message = c[end + 2 :] message = self.recode(message) l = c[:end].splitlines() @@ -366,43 +377,43 @@ author = committer = None extra = {} for e in l[1:]: - n, v = e.split(" ", 1) - if n == "author": + n, v = e.split(b" ", 1) + if n == b"author": p = v.split() tm, tz = p[-2:] - author = " ".join(p[:-2]) - if author[0] == "<": + author = b" ".join(p[:-2]) + if author[0] == b"<": author = author[1:-1] author = self.recode(author) - if n == "committer": + if n == b"committer": p = v.split() tm, tz = p[-2:] - committer = " ".join(p[:-2]) - if committer[0] == "<": + committer = b" ".join(p[:-2]) + if committer[0] == b"<": committer = committer[1:-1] committer = self.recode(committer) - if n == "parent": + if n == b"parent": parents.append(v) if n in self.copyextrakeys: extra[n] = v - if self.committeractions['dropcommitter']: + if self.committeractions[b'dropcommitter']: committer = None - elif self.committeractions['replaceauthor']: + elif self.committeractions[b'replaceauthor']: author = committer if committer: - messagealways = self.committeractions['messagealways'] - messagedifferent = self.committeractions['messagedifferent'] + messagealways = self.committeractions[b'messagealways'] + messagedifferent = self.committeractions[b'messagedifferent'] if messagealways: - message += '\n%s %s\n' % (messagealways, committer) + message += b'\n%s %s\n' % (messagealways, committer) elif messagedifferent and author != committer: - message += '\n%s %s\n' % (messagedifferent, committer) + message += b'\n%s %s\n' % (messagedifferent, committer) - tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:] + tzs, tzh, tzm = tz[-5:-4] + b"1", tz[-4:-2], tz[-2:] tz = -int(tzs) * (int(tzh) * 3600 + int(tzm)) - date = tm + " " + (b"%d" % tz) - saverev = self.ui.configbool('convert', 'git.saverev') + date = tm + b" " + (b"%d" % tz) + saverev = self.ui.configbool(b'convert', b'git.saverev') c = common.commit( parents=parents, @@ -416,27 +427,27 @@ return c def numcommits(self): - output, ret = self.gitrunlines('rev-list', '--all') + output, ret = self.gitrunlines(b'rev-list', b'--all') if ret: raise error.Abort( - _('cannot retrieve number of commits in %s') % self.path + _(b'cannot retrieve number of commits in %s') % self.path ) return len(output) def gettags(self): tags = {} alltags = {} - output, status = self.gitrunlines('ls-remote', '--tags', self.path) + output, status = self.gitrunlines(b'ls-remote', b'--tags', self.path) if status: - raise error.Abort(_('cannot read tags from %s') % self.path) - prefix = 'refs/tags/' + raise error.Abort(_(b'cannot read tags from %s') % self.path) + prefix = b'refs/tags/' # Build complete list of tags, both annotated and bare ones for line in output: line = line.strip() - if line.startswith("error:") or line.startswith("fatal:"): - raise error.Abort(_('cannot read tags from %s') % self.path) + if line.startswith(b"error:") or line.startswith(b"fatal:"): + raise error.Abort(_(b'cannot read tags from %s') % self.path) node, tag = line.split(None, 1) if not tag.startswith(prefix): continue @@ -444,10 +455,10 @@ # Filter out tag objects for annotated tag refs for tag in alltags: - if tag.endswith('^{}'): + if tag.endswith(b'^{}'): tags[tag[:-3]] = alltags[tag] else: - if tag + '^{}' in alltags: + if tag + b'^{}' in alltags: continue else: tags[tag] = alltags[tag] @@ -458,28 +469,28 @@ changes = [] if i is None: output, status = self.gitrunlines( - 'diff-tree', '--root', '-m', '-r', version + b'diff-tree', b'--root', b'-m', b'-r', version ) if status: - raise error.Abort(_('cannot read changes in %s') % version) + raise error.Abort(_(b'cannot read changes in %s') % version) for l in output: - if "\t" not in l: + if b"\t" not in l: continue - m, f = l[:-1].split("\t") + m, f = l[:-1].split(b"\t") changes.append(f) else: output, status = self.gitrunlines( - 'diff-tree', - '--name-only', - '--root', - '-r', + b'diff-tree', + b'--name-only', + b'--root', + b'-r', version, - '%s^%d' % (version, i + 1), - '--', + b'%s^%d' % (version, i + 1), + b'--', ) if status: - raise error.Abort(_('cannot read changes in %s') % version) - changes = [f.rstrip('\n') for f in output] + raise error.Abort(_(b'cannot read changes in %s') % version) + changes = [f.rstrip(b'\n') for f in output] return changes @@ -487,19 +498,19 @@ bookmarks = {} # Handle local and remote branches - remoteprefix = self.ui.config('convert', 'git.remoteprefix') + remoteprefix = self.ui.config(b'convert', b'git.remoteprefix') reftypes = [ # (git prefix, hg prefix) - ('refs/remotes/origin/', remoteprefix + '/'), - ('refs/heads/', ''), + (b'refs/remotes/origin/', remoteprefix + b'/'), + (b'refs/heads/', b''), ] exclude = { - 'refs/remotes/origin/HEAD', + b'refs/remotes/origin/HEAD', } try: - output, status = self.gitrunlines('show-ref') + output, status = self.gitrunlines(b'show-ref') for line in output: line = line.strip() rev, name = line.split(None, 1) @@ -507,13 +518,13 @@ for gitprefix, hgprefix in reftypes: if not name.startswith(gitprefix) or name in exclude: continue - name = '%s%s' % (hgprefix, name[len(gitprefix) :]) + name = b'%s%s' % (hgprefix, name[len(gitprefix) :]) bookmarks[name] = rev except Exception: pass return bookmarks - def checkrevformat(self, revstr, mapname='splicemap'): + def checkrevformat(self, revstr, mapname=b'splicemap'): """ git revision string is a 40 byte hex """ self.checkhexformat(revstr, mapname)