# HG changeset patch # User Brett Cannon # Date 1425834517 14400 # Node ID fe74d55995393f6a72abce49da8d43e5fe37cdcd # Parent ea80bd2775f6612399eb3aedf2444fcb11b0cf8a hglib: wrap all application string literals in util.b() (issue4520) Conversion also included changing use of string interpolation to string concatenation as bytes interpolation does not exist in Python 3. Indexing related to bytes was also changed to length-1 bytes through slicing as Python 3 returns an int in this instance. Tests have not been switched to using util.b() so that the change to application code can be independently verified as not being broken. diff -r ea80bd2775f6 -r fe74d5599539 hglib/client.py --- a/hglib/client.py Sat Mar 07 10:08:52 2015 -0500 +++ b/hglib/client.py Sun Mar 08 13:08:37 2015 -0400 @@ -1,7 +1,7 @@ import subprocess, os, struct, cStringIO, re, datetime import hglib, error, util, templates, merge, context -from util import cmdbuilder +from util import b, cmdbuilder class revision(tuple): def __new__(cls, rev, node, tags, branch, author, desc, date): @@ -72,11 +72,11 @@ def _readhello(self): """ read the hello message the server sends when started """ ch, msg = self._readchannel() - assert ch == 'o' + assert ch == b('o') - msg = msg.split('\n') + msg = msg.split(b('\n')) - self.capabilities = msg[0][len('capabilities: '):] + self.capabilities = msg[0][len(b('capabilities: ')):] if not self.capabilities: raise error.ResponseError( "bad hello message: expected 'capabilities: '" @@ -85,9 +85,9 @@ self.capabilities = set(self.capabilities.split()) # at the very least the server should be able to run commands - assert 'runcommand' in self.capabilities + assert b('runcommand') in self.capabilities - self._encoding = msg[1][len('encoding: '):] + self._encoding = msg[1][len(b('encoding: ')):] if not self._encoding: raise error.ResponseError("bad hello message: expected 'encoding: '" ", got %r" % msg[1]) @@ -97,7 +97,7 @@ if not data: raise error.ServerError() channel, length = struct.unpack(hgclient.outputfmt, data) - if channel in 'IL': + if channel in b('IL'): return channel, length else: return channel, self.server.stdout.read(length) @@ -110,7 +110,7 @@ revs = [] for rev in util.grouper(7, splitted): # truncate the timezone and convert to a local datetime - posixtime = float(rev[6].split('.', 1)[0]) + posixtime = float(rev[6].split(b('.'), 1)[0]) dt = datetime.datetime.fromtimestamp(posixtime) revs.append(revision(rev[0], rev[1], rev[2], rev[3], rev[4], rev[5], dt)) @@ -125,8 +125,8 @@ if not self.server: raise ValueError("server not connected") - self.server.stdin.write('runcommand\n') - writeblock('\0'.join(args)) + self.server.stdin.write(b('runcommand\n')) + writeblock(b('\0').join(args)) while True: channel, data = self._readchannel() @@ -138,7 +138,7 @@ elif channel in outchannels: outchannels[channel](data) # result channel, command finished - elif channel == 'r': + elif channel == b('r'): return struct.unpack(hgclient.retfmt, data)[0] # a channel that we don't know and can't ignore elif channel.isupper(): @@ -162,18 +162,17 @@ input is used to reply to bulk data requests by the server It receives the max number of bytes to return """ - out, err = cStringIO.StringIO(), cStringIO.StringIO() - outchannels = {'o' : out.write, 'e' : err.write} + outchannels = {b('o') : out.write, b('e') : err.write} inchannels = {} if prompt is not None: def func(size): reply = prompt(size, out.getvalue()) - return str(reply) - inchannels['L'] = func + return reply + inchannels[b('L')] = func if input is not None: - inchannels['I'] = input + inchannels[b('I')] = input ret = self.runcommand(args, inchannels, outchannels) out, err = out.getvalue(), err.getvalue() @@ -222,7 +221,7 @@ if not isinstance(files, list): files = [files] - args = cmdbuilder('add', n=dryrun, S=subrepos, I=include, X=exclude, + args = cmdbuilder(b('add'), n=dryrun, S=subrepos, I=include, X=exclude, *files) eh = util.reterrorhandler(args) @@ -257,7 +256,7 @@ if not isinstance(files, list): files = [files] - args = cmdbuilder('addremove', s=similarity, n=dryrun, I=include, + args = cmdbuilder(b('addremove'), s=similarity, n=dryrun, I=include, X=exclude, *files) eh = util.reterrorhandler(args) @@ -289,7 +288,7 @@ if not isinstance(files, list): files = [files] - args = cmdbuilder('annotate', r=rev, no_follow=nofollow, a=text, + args = cmdbuilder(b('annotate'), r=rev, no_follow=nofollow, a=text, u=user, f=file, d=date, n=number, c=changeset, l=line, v=verbose, I=include, X=exclude, hidden=self.hidden, *files) @@ -297,7 +296,7 @@ out = self.rawcommand(args) for line in out.splitlines(): - yield tuple(line.split(': ', 1)) + yield tuple(line.split(b(': '), 1)) def archive(self, dest, rev=None, nodecode=False, prefix=None, type=None, subrepos=False, include=None, exclude=None): @@ -334,7 +333,8 @@ exclude - exclude names matching the given patterns """ - args = cmdbuilder('archive', dest, r=rev, no_decode=nodecode, p=prefix, + args = cmdbuilder(b('archive'), dest, r=rev, + no_decode=nodecode, p=prefix, t=type, S=subrepos, I=include, X=exclude, hidden=self.hidden) @@ -362,8 +362,8 @@ if message and logfile: raise ValueError("cannot specify both a message and a logfile") - args = cmdbuilder('backout', r=rev, merge=merge, parent=parent, t=tool, - m=message, l=logfile, d=date, u=user, + args = cmdbuilder(b('backout'), r=rev, merge=merge, parent=parent, + t=tool, m=message, l=logfile, d=date, u=user, hidden=self.hidden) self.rawcommand(args) @@ -381,7 +381,7 @@ inactive - do not mark the new bookmark active rename - rename the bookmark given by rename to name """ - args = cmdbuilder('bookmark', name, r=rev, f=force, d=delete, + args = cmdbuilder(b('bookmark'), name, r=rev, f=force, d=delete, i=inactive, m=rename) self.rawcommand(args) @@ -393,18 +393,18 @@ If there isn't a current one, -1 is returned as the index. """ - args = cmdbuilder('bookmarks', hidden=self.hidden) + args = cmdbuilder(b('bookmarks'), hidden=self.hidden) out = self.rawcommand(args) bms = [] current = -1 - if out.rstrip() != 'no bookmarks set': + if out.rstrip() != b('no bookmarks set'): for line in out.splitlines(): iscurrent, line = line[0:3], line[3:] - if '*' in iscurrent: + if b('*') in iscurrent: current = len(bms) - name, line = line.split(' ', 1) - rev, node = line.split(':') + name, line = line.split(b(' '), 1) + rev, node = line.split(b(':')) bms.append((name, int(rev), node)) return bms, current @@ -427,7 +427,7 @@ if name and clean: raise ValueError('cannot use both name and clean') - args = cmdbuilder('branch', name, f=force, C=clean) + args = cmdbuilder(b('branch'), name, f=force, C=clean) out = self.rawcommand(args).rstrip() if name: @@ -445,13 +445,13 @@ active - show only branches that have unmerged heads closed - show normal and closed branches """ - args = cmdbuilder('branches', a=active, c=closed, hidden=self.hidden) + args = cmdbuilder(b('branches'), a=active, c=closed, hidden=self.hidden) out = self.rawcommand(args) branches = [] for line in out.rstrip().splitlines(): - namerev, node = line.rsplit(':', 1) - name, rev = namerev.rsplit(' ', 1) + namerev, node = line.rsplit(b(':'), 1) + name, rev = namerev.rsplit(b(' '), 1) name = name.rstrip() node = node.split()[0] # get rid of ' (inactive)' branches.append((name, int(rev), node)) @@ -485,7 +485,7 @@ Return True if a bundle was created, False if no changes were found. """ - args = cmdbuilder('bundle', file, destrepo, f=force, r=rev, b=branch, + args = cmdbuilder(b('bundle'), file, destrepo, f=force, r=rev, b=branch, base=base, a=all, t=type, e=ssh, remotecmd=remotecmd, insecure=insecure, hidden=self.hidden) @@ -509,13 +509,13 @@ "%p" root-relative path name of file being printed """ - args = cmdbuilder('cat', r=rev, o=output, hidden=self.hidden, *files) + args = cmdbuilder(b('cat'), r=rev, o=output, hidden=self.hidden, *files) out = self.rawcommand(args) if not output: return out - def clone(self, source='.', dest=None, branch=None, updaterev=None, + def clone(self, source=b('.'), dest=None, branch=None, updaterev=None, revrange=None): """ Create a copy of an existing repository specified by source in a new @@ -527,7 +527,7 @@ updaterev - revision, tag or branch to check out revrange - include the specified changeset """ - args = cmdbuilder('clone', source, dest, b=branch, + args = cmdbuilder(b('clone'), source, dest, b=branch, u=updaterev, r=revrange) self.rawcommand(args) @@ -549,18 +549,18 @@ """ if amend and message is None and logfile is None: # retrieve current commit message - message = self.log('.')[0][5] + message = self.log(b('.'))[0][5] if message is None and logfile is None and not amend: raise ValueError("must provide at least a message or a logfile") elif message and logfile: raise ValueError("cannot specify both a message and a logfile") # --debug will print the committed cset - args = cmdbuilder('commit', debug=True, m=message, A=addremove, + args = cmdbuilder(b('commit'), debug=True, m=message, A=addremove, close_branch=closebranch, d=date, u=user, l=logfile, I=include, X=exclude, amend=amend) out = self.rawcommand(args) - rev, node = out.splitlines()[-1].rsplit(':') + rev, node = out.splitlines()[-1].rsplit(b(':')) return int(rev.split()[-1]), node def config(self, names=[], untrusted=False, showsource=False): @@ -572,21 +572,22 @@ """ def splitline(s): - k, value = s.rstrip().split('=', 1) - section, key = k.split('.', 1) - return (section, key, value) + k, value = s.rstrip().split(b('='), 1) + section, key = k.split(b('.'), 1) + return section, key, value if not isinstance(names, list): names = [names] - args = cmdbuilder('showconfig', u=untrusted, debug=showsource, *names) + args = cmdbuilder(b('showconfig'), u=untrusted, debug=showsource, + *names) out = self.rawcommand(args) conf = [] if showsource: - out = util.skiplines(out, 'read config from: ') + out = util.skiplines(out, b('read config from: ')) for line in out.splitlines(): - m = re.match(r"(.+?:(?:\d+:)?) (.*)", line) + m = re.match(b(r"(.+?:(?:\d+:)?) (.*)"), line) t = splitline(m.group(2)) conf.append((m.group(1)[:-1], t[0], t[1], t[2])) else: @@ -600,11 +601,11 @@ """ Return the server's encoding (as reported in the hello message). """ - if not 'getencoding' in self.capabilities: + if not b('getencoding') in self.capabilities: raise CapabilityError('getencoding') if not self._encoding: - self.server.stdin.write('getencoding\n') + self.server.stdin.write(b('getencoding\n')) self._encoding = self._readfromchannel('r') return self._encoding @@ -630,7 +631,7 @@ source = [source] source.append(dest) - args = cmdbuilder('copy', A=after, f=force, n=dryrun, + args = cmdbuilder(b('copy'), A=after, f=force, n=dryrun, I=include, X=exclude, *source) eh = util.reterrorhandler(args) @@ -666,7 +667,7 @@ if change and revs: raise ValueError('cannot specify both change and rev') - args = cmdbuilder('diff', r=revs, c=change, + args = cmdbuilder(b('diff'), r=revs, c=change, a=text, g=git, nodates=nodates, p=showfunction, reverse=reverse, w=ignoreallspace, b=ignorespacechange, @@ -701,7 +702,7 @@ """ if not isinstance(revs, list): revs = [revs] - args = cmdbuilder('export', o=output, switch_parent=switchparent, + args = cmdbuilder(b('export'), o=output, switch_parent=switchparent, a=text, g=git, nodates=nodates, hidden=self.hidden, *revs) @@ -726,7 +727,7 @@ if not isinstance(files, list): files = [files] - args = cmdbuilder('forget', I=include, X=exclude, *files) + args = cmdbuilder(b('forget'), I=include, X=exclude, *files) eh = util.reterrorhandler(args) self.rawcommand(args, eh=eh) @@ -761,18 +762,18 @@ if not isinstance(files, list): files = [files] - args = cmdbuilder('grep', all=all, a=text, f=follow, i=ignorecase, + args = cmdbuilder(b('grep'), all=all, a=text, f=follow, i=ignorecase, l=fileswithmatches, n=line, u=user, d=date, I=include, X=exclude, hidden=self.hidden, *[pattern] + files) - args.append('-0') + args.append(b('-0')) def eh(ret, out, err): if ret != 1: raise error.CommandError(args, ret, out, err) - return '' + return b('') - out = self.rawcommand(args, eh=eh).split('\0') + out = self.rawcommand(args, eh=eh).split(b('\0')) fieldcount = 3 if user: @@ -804,16 +805,16 @@ if not isinstance(rev, list): rev = [rev] - args = cmdbuilder('heads', r=startrev, t=topological, c=closed, + args = cmdbuilder(b('heads'), r=startrev, t=topological, c=closed, template=templates.changeset, hidden=self.hidden, *rev) def eh(ret, out, err): if ret != 1: raise error.CommandError(args, ret, out, err) - return '' + return b('') - out = self.rawcommand(args, eh=eh).split('\0')[:-1] + out = self.rawcommand(args, eh=eh).split(b('\0'))[:-1] return self._parserevs(out) def identify(self, rev=None, source=None, num=False, id=False, branch=False, @@ -836,7 +837,7 @@ bookmarks - show bookmarks """ - args = cmdbuilder('identify', source, r=rev, n=num, i=id, + args = cmdbuilder(b('identify'), source, r=rev, n=num, i=id, b=branch, t=tags, B=bookmarks, hidden=self.hidden) @@ -878,7 +879,7 @@ prompt = None input = None - args = cmdbuilder('import', strip=strip, force=force, + args = cmdbuilder(b('import'), strip=strip, force=force, no_commit=nocommit, bypass=bypass, exact=exact, import_branch=importbranch, message=message, date=date, user=user, similarity=similarity, _=stdin, @@ -911,7 +912,7 @@ subrepos - recurse into subrepositories """ - args = cmdbuilder('incoming', path, + args = cmdbuilder(b('incoming'), path, template=templates.changeset, r=revrange, f=force, n=newest, bundle=bundle, B=bookmarks, b=branch, l=limit, M=nomerges, @@ -932,7 +933,7 @@ bms.append(tuple(line.split())) return bms else: - out = out.split('\0')[:-1] + out = out.split(b('\0'))[:-1] return self._parserevs(out) def log(self, revrange=None, files=[], follow=False, @@ -983,7 +984,7 @@ """ if hidden is None: hidden = self.hidden - args = cmdbuilder('log', template=templates.changeset, + args = cmdbuilder(b('log'), template=templates.changeset, r=revrange, f=follow, follow_first=followfirst, d=date, C=copies, k=keyword, removed=removed, m=onlymerges, u=user, b=branch, P=prune, @@ -991,7 +992,7 @@ hidden=hidden, *files) out = self.rawcommand(args) - out = out.split('\0')[:-1] + out = out.split(b('\0'))[:-1] return self._parserevs(out) @@ -1005,7 +1006,7 @@ (just the name). This includes deleted and renamed files. """ - args = cmdbuilder('manifest', r=rev, all=all, debug=True, + args = cmdbuilder(b('manifest'), r=rev, all=all, debug=True, hidden=self.hidden) out = self.rawcommand(args) @@ -1017,9 +1018,9 @@ for line in out.splitlines(): node = line[0:40] perm = line[41:44] - symlink = line[45] == '@' - executable = line[45] == '*' - yield (node, perm, executable, symlink, line[47:]) + symlink = line[45:46] == b('@') + executable = line[45:46] == b('*') + yield node, perm, executable, symlink, line[47:] def merge(self, rev=None, force=False, tool=None, cb=merge.handlers.abort): """Merge working directory with rev. If no revision is specified, the @@ -1047,15 +1048,15 @@ """ # we can't really use --preview since merge doesn't support --template - args = cmdbuilder('merge', r=rev, f=force, t=tool) + args = cmdbuilder(b('merge'), r=rev, f=force, t=tool) prompt = None if cb is merge.handlers.abort: prompt = cb elif cb is merge.handlers.noninteractive: - args.append('-y') + args.append(b('-y')) else: - prompt = lambda size, output: cb(output) + '\n' + prompt = lambda size, output: cb(output) + b('\n') self.rawcommand(args, prompt=prompt) @@ -1080,7 +1081,7 @@ source = [source] source.append(dest) - args = cmdbuilder('move', A=after, f=force, n=dryrun, + args = cmdbuilder(b('move'), A=after, f=force, n=dryrun, I=include, X=exclude, *source) eh = util.reterrorhandler(args) @@ -1108,7 +1109,7 @@ subrepositories """ - args = cmdbuilder('outgoing', + args = cmdbuilder(b('outgoing'), path, template=templates.changeset, r=revrange, f=force, n=newest, B=bookmarks, @@ -1129,7 +1130,7 @@ bms.append(tuple(line.split())) return bms else: - out = out.split('\0')[:-1] + out = out.split(b('\0'))[:-1] return self._parserevs(out) def parents(self, rev=None, file=None): @@ -1140,14 +1141,14 @@ is returned. """ - args = cmdbuilder('parents', file, template=templates.changeset, r=rev, - hidden=self.hidden) + args = cmdbuilder(b('parents'), file, template=templates.changeset, + r=rev, hidden=self.hidden) out = self.rawcommand(args) if not out: return - out = out.split('\0')[:-1] + out = out.split(b('\0'))[:-1] return self._parserevs(out) @@ -1161,13 +1162,14 @@ used, too. """ if not name: - out = self.rawcommand(['paths']) + out = self.rawcommand([b('paths')]) if not out: return {} - return dict([s.split(' = ') for s in out.rstrip().split('\n')]) + return dict([s.split(b(' = ')) + for s in out.rstrip().split(b('\n'))]) else: - args = cmdbuilder('paths', name) + args = cmdbuilder(b('paths'), name) out = self.rawcommand(args) return out.rstrip() @@ -1196,7 +1198,7 @@ tool - specify merge tool for rebase """ - args = cmdbuilder('pull', source, r=rev, u=update, f=force, + args = cmdbuilder(b('pull'), source, r=rev, u=update, f=force, B=bookmark, b=branch, e=ssh, remotecmd=remotecmd, insecure=insecure, t=tool) @@ -1233,7 +1235,7 @@ web.cacerts config) """ - args = cmdbuilder('push', dest, r=rev, f=force, B=bookmark, b=branch, + args = cmdbuilder(b('push'), dest, r=rev, f=force, B=bookmark, b=branch, new_branch=newbranch, e=ssh, remotecmd=remotecmd, insecure=insecure) @@ -1259,7 +1261,7 @@ if not isinstance(files, list): files = [files] - args = cmdbuilder('remove', A=after, f=force, I=include, X=exclude, + args = cmdbuilder(b('remove'), A=after, f=force, I=include, X=exclude, *files) eh = util.reterrorhandler(args) @@ -1287,7 +1289,7 @@ if not isinstance(file, list): file = [file] - args = cmdbuilder('resolve', a=all, l=listfiles, m=mark, u=unmark, + args = cmdbuilder(b('resolve'), a=all, l=listfiles, m=mark, u=unmark, t=tool, I=include, X=exclude, *file) out = self.rawcommand(args) @@ -1295,7 +1297,7 @@ if listfiles: l = [] for line in out.splitlines(): - l.append(tuple(line.split(' ', 1))) + l.append(tuple(line.split(b(' '), 1))) return l def revert(self, files, rev=None, all=False, date=None, nobackup=False, @@ -1330,7 +1332,7 @@ if not isinstance(files, list): files = [files] - args = cmdbuilder('revert', r=rev, a=all, d=date, + args = cmdbuilder(b('revert'), r=rev, a=all, d=date, no_backup=nobackup, n=dryrun, I=include, X=exclude, hidden=self.hidden, *files) @@ -1343,7 +1345,7 @@ """ Return the root directory of the current repository. """ - return self.rawcommand(['root']).rstrip() + return self.rawcommand([b('root')]).rstrip() def status(self, rev=None, change=None, all=False, modified=False, added=False, removed=False, deleted=False, clean=False, @@ -1380,22 +1382,22 @@ if rev and change: raise ValueError('cannot specify both rev and change') - args = cmdbuilder('status', rev=rev, change=change, A=all, m=modified, - a=added, r=removed, d=deleted, c=clean, u=unknown, - i=ignored, C=copies, S=subrepos, I=include, + args = cmdbuilder(b('status'), rev=rev, change=change, A=all, + m=modified, a=added, r=removed, d=deleted, c=clean, + u=unknown, i=ignored, C=copies, S=subrepos, I=include, X=exclude, hidden=self.hidden) - args.append('-0') + args.append(b('-0')) out = self.rawcommand(args) l = [] - for entry in out.split('\0'): + for entry in out.split(b('\0')): if entry: - if entry[0] == ' ': - l.append((' ', entry[2:])) + if entry[0:1] == b(' '): + l.append((b(' '), entry[2:])) else: - l.append(tuple(entry.split(' ', 1))) + l.append(tuple(entry.split(b(' '), 1))) return l @@ -1422,7 +1424,7 @@ if not isinstance(names, list): names = [names] - args = cmdbuilder('tag', r=rev, m=message, f=force, l=local, + args = cmdbuilder(b('tag'), r=rev, m=message, f=force, l=local, remove=remove, d=date, u=user, hidden=self.hidden, *names) @@ -1432,17 +1434,17 @@ """ Return a list of repository tags as: (name, rev, node, islocal) """ - args = cmdbuilder('tags', v=True) + args = cmdbuilder(b('tags'), v=True) out = self.rawcommand(args) t = [] for line in out.splitlines(): - taglocal = line.endswith(' local') + taglocal = line.endswith(b(' local')) if taglocal: line = line[:-6] - name, rev = line.rsplit(' ', 1) - rev, node = rev.split(':') + name, rev = line.rsplit(b(' '), 1) + rev, node = rev.split(b(':')) t.append((name.rstrip(), int(rev), node, taglocal)) return t @@ -1462,14 +1464,14 @@ ''' if not isinstance(revs, (list, tuple)): revs = [revs] - args = util.cmdbuilder('phase', secret=secret, draft=draft, + args = util.cmdbuilder(b('phase'), secret=secret, draft=draft, public=public, force=force, hidden=self.hidden, *revs) out = self.rawcommand(args) if draft or public or secret: return else: - output = [i.split(': ')for i in out.strip().split('\n')] + output = [i.split(b(': '))for i in out.strip().split(b('\n'))] return [(int(num), phase) for (num, phase) in output] def summary(self, remote=False): @@ -1486,65 +1488,65 @@ unparsed entries will be of them form key : value """ - args = cmdbuilder('summary', remote=remote, hidden=self.hidden) + args = cmdbuilder(b('summary'), remote=remote, hidden=self.hidden) out = self.rawcommand(args).splitlines() d = {} while out: line = out.pop(0) - name, value = line.split(': ', 1) + name, value = line.split(b(': '), 1) - if name == 'parent': - parent, tags = value.split(' ', 1) - rev, node = parent.split(':') + if name == b('parent'): + parent, tags = value.split(b(' '), 1) + rev, node = parent.split(b(':')) if tags: - tags = tags.replace(' (empty repository)', '') + tags = tags.replace(b(' (empty repository)'), b('')) else: tags = None value = d.get(name, []) - if rev == '-1': + if rev == b('-1'): value.append((int(rev), node, tags, None)) else: message = out.pop(0)[1:] value.append((int(rev), node, tags, message)) - elif name == 'branch': + elif name == b('branch'): pass - elif name == 'commit': - value = value == '(clean)' - elif name == 'update': - if value == '(current)': + elif name == b('commit'): + value = value == b('(clean)') + elif name == b('update'): + if value == b('(current)'): value = 0 else: - value = int(value.split(' ', 1)[0]) - elif remote and name == 'remote': - if value == '(synced)': + value = int(value.split(b(' '), 1)[0]) + elif remote and name == b('remote'): + if value == b('(synced)'): value = 0, 0, 0, 0 else: inc = incb = out_ = outb = 0 - for v in value.split(', '): - count, v = v.split(' ', 1) - if v == 'outgoing': + for v in value.split(b(', ')): + count, v = v.split(b(' '), 1) + if v == b('outgoing'): out_ = int(count) - elif v.endswith('incoming'): + elif v.endswith(b('incoming')): inc = int(count) - elif v == 'incoming bookmarks': + elif v == b('incoming bookmarks'): incb = int(count) - elif v == 'outgoing bookmarks': + elif v == b('outgoing bookmarks'): outb = int(count) value = inc, incb, out_, outb - elif name == 'mq': + elif name == b('mq'): applied = unapplied = 0 - for v in value.split(', '): - count, v = v.split(' ', 1) - if v == 'applied': + for v in value.split(b(', ')): + count, v = v.split(b(' '), 1) + if v == b('applied'): applied = int(count) - elif v == 'unapplied': + elif v == b('unapplied'): unapplied = int(count) value = applied, unapplied @@ -1558,10 +1560,10 @@ changeset most recently added to the repository (and therefore the most recently changed head). """ - args = cmdbuilder('tip', template=templates.changeset, + args = cmdbuilder(b('tip'), template=templates.changeset, hidden=self.hidden) out = self.rawcommand(args) - out = out.split('\0') + out = out.split(b('\0')) return self._parserevs(out)[0] @@ -1579,7 +1581,7 @@ if clean and check: raise ValueError('clean and check cannot both be True') - args = cmdbuilder('update', r=rev, C=clean, c=check, d=date, + args = cmdbuilder(b('update'), r=rev, C=clean, c=check, d=date, hidden=self.hidden) def eh(ret, out, err): @@ -1591,7 +1593,8 @@ out = self.rawcommand(args, eh=eh) - m = re.search(r'^(\d+).+, (\d+).+, (\d+).+, (\d+)', out, re.MULTILINE) + m = re.search(b(r'^(\d+).+, (\d+).+, (\d+).+, (\d+)'), out, + re.MULTILINE) return tuple(map(int, list(m.groups()))) @property @@ -1601,8 +1604,8 @@ 1, '+4-3095db9f5c2c') """ if self._version is None: - v = self.rawcommand(cmdbuilder('version', q=True)) - v = list(re.match(r'.*?(\d+)\.(\d+)\.?(\d+)?(\+[0-9a-f-]+)?', + v = self.rawcommand(cmdbuilder(b('version'), q=True)) + v = list(re.match(b(r'.*?(\d+)\.(\d+)\.?(\d+)?(\+[0-9a-f-]+)?'), v).groups()) for i in range(3): diff -r ea80bd2775f6 -r fe74d5599539 hglib/context.py --- a/hglib/context.py Sat Mar 07 10:08:52 2015 -0500 +++ b/hglib/context.py Sun Mar 08 13:08:37 2015 -0400 @@ -1,16 +1,17 @@ from hglib.error import CommandError import client, util, templates +from hglib.util import b -_nullcset = ['-1', '0000000000000000000000000000000000000000', '', '', - '', '', ''] +_nullcset = [b('-1'), b('0000000000000000000000000000000000000000'), b(''), + b(''), b(''), b(''), b('')] class changectx(object): """A changecontext object makes access to data related to a particular changeset convenient.""" - def __init__(self, repo, changeid=''): + def __init__(self, repo, changeid=b('')): """changeid is a revision number, node, or tag""" - if changeid == '': - changeid = '.' + if changeid == b(''): + changeid = b('.') self._repo = repo if isinstance(changeid, client.revision): cset = changeid @@ -18,7 +19,7 @@ cset = _nullcset else: if isinstance(changeid, (long, int)): - changeid = 'rev(%d)' % changeid + changeid = b('rev(') + str(changeid).encode('latin-1') + b(')') notfound = False try: @@ -43,7 +44,7 @@ self._tags = self._tags.split() try: - self._tags.remove('tip') + self._tags.remove(b('tip')) except ValueError: pass @@ -89,10 +90,13 @@ return self._parsestatus(self._repo.status(change=self))[:4] def _parsestatus(self, stat): - d = dict((c, []) for c in 'MAR!?IC ') + d = dict((c, []) + for c in (b('M'), b('A'), b('R'), b('!'), b('?'), b('I'), + b('C'), b(' '))) for k, path in stat: d[k].append(path) - return d['M'], d['A'], d['R'], d['!'], d['?'], d['I'], d['C'] + return (d[b('M')], d[b('A')], d[b('R')], d[b('!')], d[b('?')], + d[b('I')], d[b('C')]) def status(self, ignored=False, clean=False): """Explicit status query @@ -201,7 +205,7 @@ def hidden(self): """return True if the changeset is hidden, else False""" - return bool(self._repo.log(revrange='%s and hidden()' % self._node, + return bool(self._repo.log(revrange=self._node + b(' and hidden()'), hidden=True)) def phase(self): @@ -210,19 +214,20 @@ def children(self): """return contexts for each child changeset""" - for c in self._repo.log('children(%s)' % self._node): + for c in self._repo.log(b('children(') + self._node + b(')')): yield changectx(self._repo, c) def ancestors(self): - for a in self._repo.log('ancestors(%s)' % self._node): + for a in self._repo.log(b('ancestors(') + self._node + b(')')): yield changectx(self._repo, a) def descendants(self): - for d in self._repo.log('descendants(%s)' % self._node): + for d in self._repo.log(b('descendants(') + self._node + b(')')): yield changectx(self._repo, d) def ancestor(self, c2): """ return the ancestor context of self and c2 """ - return changectx(self._repo, 'ancestor(%s, %s)' % (self, c2)) + return changectx(self._repo, + b('ancestor(') + self + b(', ') + c2 + b(')')) diff -r ea80bd2775f6 -r fe74d5599539 hglib/merge.py --- a/hglib/merge.py Sat Mar 07 10:08:52 2015 -0500 +++ b/hglib/merge.py Sun Mar 08 13:08:37 2015 -0400 @@ -1,3 +1,5 @@ +from hglib.util import b + class handlers(object): """ These can be used as the cb argument to hgclient.merge() to control the @@ -10,7 +12,7 @@ """ Abort the merge if a prompt appears. """ - return '' + return b('') """ This corresponds to Mercurial's -y/--noninteractive global option, which diff -r ea80bd2775f6 -r fe74d5599539 hglib/templates.py --- a/hglib/templates.py Sat Mar 07 10:08:52 2015 -0500 +++ b/hglib/templates.py Sun Mar 08 13:08:37 2015 -0400 @@ -1,1 +1,4 @@ -changeset = '{rev}\\0{node}\\0{tags}\\0{branch}\\0{author}\\0{desc}\\0{date}\\0' +from hglib.util import b + +changeset = b('{rev}\\0{node}\\0{tags}\\0{branch}\\0{author}' + '\\0{desc}\\0{date}\\0') diff -r ea80bd2775f6 -r fe74d5599539 hglib/util.py --- a/hglib/util.py Sat Mar 07 10:08:52 2015 -0500 +++ b/hglib/util.py Sun Mar 08 13:08:37 2015 -0400 @@ -31,7 +31,7 @@ n -= 1 if n == 0: return cs.read() - return '' + return b('') def skiplines(s, prefix): """ @@ -52,7 +52,7 @@ if not line.startswith(prefix): return line + cs.read() - return '' + return b('') def cmdbuilder(name, *args, **kwargs): """ @@ -88,12 +88,12 @@ if val is None: continue - arg = arg.replace('_', '-') - if arg != '-': + arg = arg.replace(b('_'), b('-')) + if arg != b('-'): if len(arg) == 1: - arg = '-' + arg + arg = b('-') + arg else: - arg = '--' + arg + arg = b('--') + arg if isinstance(val, bool): if val: cmd.append(arg)