Mercurial > python-hglib
comparison hglib/client.py @ 142:fe74d5599539
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.
author | Brett Cannon <brett@python.org> |
---|---|
date | Sun, 08 Mar 2015 13:08:37 -0400 |
parents | dc63978871ed |
children | f3c430afa598 |
comparison
equal
deleted
inserted
replaced
141:ea80bd2775f6 | 142:fe74d5599539 |
---|---|
1 import subprocess, os, struct, cStringIO, re, datetime | 1 import subprocess, os, struct, cStringIO, re, datetime |
2 import hglib, error, util, templates, merge, context | 2 import hglib, error, util, templates, merge, context |
3 | 3 |
4 from util import cmdbuilder | 4 from util import b, cmdbuilder |
5 | 5 |
6 class revision(tuple): | 6 class revision(tuple): |
7 def __new__(cls, rev, node, tags, branch, author, desc, date): | 7 def __new__(cls, rev, node, tags, branch, author, desc, date): |
8 return tuple.__new__(cls, (rev, node, tags, branch, author, desc, date)) | 8 return tuple.__new__(cls, (rev, node, tags, branch, author, desc, date)) |
9 | 9 |
70 self.close() | 70 self.close() |
71 | 71 |
72 def _readhello(self): | 72 def _readhello(self): |
73 """ read the hello message the server sends when started """ | 73 """ read the hello message the server sends when started """ |
74 ch, msg = self._readchannel() | 74 ch, msg = self._readchannel() |
75 assert ch == 'o' | 75 assert ch == b('o') |
76 | 76 |
77 msg = msg.split('\n') | 77 msg = msg.split(b('\n')) |
78 | 78 |
79 self.capabilities = msg[0][len('capabilities: '):] | 79 self.capabilities = msg[0][len(b('capabilities: ')):] |
80 if not self.capabilities: | 80 if not self.capabilities: |
81 raise error.ResponseError( | 81 raise error.ResponseError( |
82 "bad hello message: expected 'capabilities: '" | 82 "bad hello message: expected 'capabilities: '" |
83 ", got %r" % msg[0]) | 83 ", got %r" % msg[0]) |
84 | 84 |
85 self.capabilities = set(self.capabilities.split()) | 85 self.capabilities = set(self.capabilities.split()) |
86 | 86 |
87 # at the very least the server should be able to run commands | 87 # at the very least the server should be able to run commands |
88 assert 'runcommand' in self.capabilities | 88 assert b('runcommand') in self.capabilities |
89 | 89 |
90 self._encoding = msg[1][len('encoding: '):] | 90 self._encoding = msg[1][len(b('encoding: ')):] |
91 if not self._encoding: | 91 if not self._encoding: |
92 raise error.ResponseError("bad hello message: expected 'encoding: '" | 92 raise error.ResponseError("bad hello message: expected 'encoding: '" |
93 ", got %r" % msg[1]) | 93 ", got %r" % msg[1]) |
94 | 94 |
95 def _readchannel(self): | 95 def _readchannel(self): |
96 data = self.server.stdout.read(hgclient.outputfmtsize) | 96 data = self.server.stdout.read(hgclient.outputfmtsize) |
97 if not data: | 97 if not data: |
98 raise error.ServerError() | 98 raise error.ServerError() |
99 channel, length = struct.unpack(hgclient.outputfmt, data) | 99 channel, length = struct.unpack(hgclient.outputfmt, data) |
100 if channel in 'IL': | 100 if channel in b('IL'): |
101 return channel, length | 101 return channel, length |
102 else: | 102 else: |
103 return channel, self.server.stdout.read(length) | 103 return channel, self.server.stdout.read(length) |
104 | 104 |
105 @staticmethod | 105 @staticmethod |
108 each 6 fields compose one revision. | 108 each 6 fields compose one revision. |
109 ''' | 109 ''' |
110 revs = [] | 110 revs = [] |
111 for rev in util.grouper(7, splitted): | 111 for rev in util.grouper(7, splitted): |
112 # truncate the timezone and convert to a local datetime | 112 # truncate the timezone and convert to a local datetime |
113 posixtime = float(rev[6].split('.', 1)[0]) | 113 posixtime = float(rev[6].split(b('.'), 1)[0]) |
114 dt = datetime.datetime.fromtimestamp(posixtime) | 114 dt = datetime.datetime.fromtimestamp(posixtime) |
115 revs.append(revision(rev[0], rev[1], rev[2], rev[3], | 115 revs.append(revision(rev[0], rev[1], rev[2], rev[3], |
116 rev[4], rev[5], dt)) | 116 rev[4], rev[5], dt)) |
117 return revs | 117 return revs |
118 | 118 |
123 self.server.stdin.flush() | 123 self.server.stdin.flush() |
124 | 124 |
125 if not self.server: | 125 if not self.server: |
126 raise ValueError("server not connected") | 126 raise ValueError("server not connected") |
127 | 127 |
128 self.server.stdin.write('runcommand\n') | 128 self.server.stdin.write(b('runcommand\n')) |
129 writeblock('\0'.join(args)) | 129 writeblock(b('\0').join(args)) |
130 | 130 |
131 while True: | 131 while True: |
132 channel, data = self._readchannel() | 132 channel, data = self._readchannel() |
133 | 133 |
134 # input channels | 134 # input channels |
136 writeblock(inchannels[channel](data)) | 136 writeblock(inchannels[channel](data)) |
137 # output channels | 137 # output channels |
138 elif channel in outchannels: | 138 elif channel in outchannels: |
139 outchannels[channel](data) | 139 outchannels[channel](data) |
140 # result channel, command finished | 140 # result channel, command finished |
141 elif channel == 'r': | 141 elif channel == b('r'): |
142 return struct.unpack(hgclient.retfmt, data)[0] | 142 return struct.unpack(hgclient.retfmt, data)[0] |
143 # a channel that we don't know and can't ignore | 143 # a channel that we don't know and can't ignore |
144 elif channel.isupper(): | 144 elif channel.isupper(): |
145 raise error.ResponseError( | 145 raise error.ResponseError( |
146 "unexpected data on required channel '%s'" % channel) | 146 "unexpected data on required channel '%s'" % channel) |
160 received so far | 160 received so far |
161 | 161 |
162 input is used to reply to bulk data requests by the server | 162 input is used to reply to bulk data requests by the server |
163 It receives the max number of bytes to return | 163 It receives the max number of bytes to return |
164 """ | 164 """ |
165 | |
166 out, err = cStringIO.StringIO(), cStringIO.StringIO() | 165 out, err = cStringIO.StringIO(), cStringIO.StringIO() |
167 outchannels = {'o' : out.write, 'e' : err.write} | 166 outchannels = {b('o') : out.write, b('e') : err.write} |
168 | 167 |
169 inchannels = {} | 168 inchannels = {} |
170 if prompt is not None: | 169 if prompt is not None: |
171 def func(size): | 170 def func(size): |
172 reply = prompt(size, out.getvalue()) | 171 reply = prompt(size, out.getvalue()) |
173 return str(reply) | 172 return reply |
174 inchannels['L'] = func | 173 inchannels[b('L')] = func |
175 if input is not None: | 174 if input is not None: |
176 inchannels['I'] = input | 175 inchannels[b('I')] = input |
177 | 176 |
178 ret = self.runcommand(args, inchannels, outchannels) | 177 ret = self.runcommand(args, inchannels, outchannels) |
179 out, err = out.getvalue(), err.getvalue() | 178 out, err = out.getvalue(), err.getvalue() |
180 | 179 |
181 if ret: | 180 if ret: |
220 Return whether all given files were added. | 219 Return whether all given files were added. |
221 """ | 220 """ |
222 if not isinstance(files, list): | 221 if not isinstance(files, list): |
223 files = [files] | 222 files = [files] |
224 | 223 |
225 args = cmdbuilder('add', n=dryrun, S=subrepos, I=include, X=exclude, | 224 args = cmdbuilder(b('add'), n=dryrun, S=subrepos, I=include, X=exclude, |
226 *files) | 225 *files) |
227 | 226 |
228 eh = util.reterrorhandler(args) | 227 eh = util.reterrorhandler(args) |
229 self.rawcommand(args, eh=eh) | 228 self.rawcommand(args, eh=eh) |
230 | 229 |
255 | 254 |
256 """ | 255 """ |
257 if not isinstance(files, list): | 256 if not isinstance(files, list): |
258 files = [files] | 257 files = [files] |
259 | 258 |
260 args = cmdbuilder('addremove', s=similarity, n=dryrun, I=include, | 259 args = cmdbuilder(b('addremove'), s=similarity, n=dryrun, I=include, |
261 X=exclude, *files) | 260 X=exclude, *files) |
262 | 261 |
263 eh = util.reterrorhandler(args) | 262 eh = util.reterrorhandler(args) |
264 self.rawcommand(args, eh=eh) | 263 self.rawcommand(args, eh=eh) |
265 | 264 |
287 separated string according to the given options. | 286 separated string according to the given options. |
288 """ | 287 """ |
289 if not isinstance(files, list): | 288 if not isinstance(files, list): |
290 files = [files] | 289 files = [files] |
291 | 290 |
292 args = cmdbuilder('annotate', r=rev, no_follow=nofollow, a=text, | 291 args = cmdbuilder(b('annotate'), r=rev, no_follow=nofollow, a=text, |
293 u=user, f=file, d=date, n=number, c=changeset, | 292 u=user, f=file, d=date, n=number, c=changeset, |
294 l=line, v=verbose, I=include, X=exclude, | 293 l=line, v=verbose, I=include, X=exclude, |
295 hidden=self.hidden, *files) | 294 hidden=self.hidden, *files) |
296 | 295 |
297 out = self.rawcommand(args) | 296 out = self.rawcommand(args) |
298 | 297 |
299 for line in out.splitlines(): | 298 for line in out.splitlines(): |
300 yield tuple(line.split(': ', 1)) | 299 yield tuple(line.split(b(': '), 1)) |
301 | 300 |
302 def archive(self, dest, rev=None, nodecode=False, prefix=None, type=None, | 301 def archive(self, dest, rev=None, nodecode=False, prefix=None, type=None, |
303 subrepos=False, include=None, exclude=None): | 302 subrepos=False, include=None, exclude=None): |
304 """Create an unversioned archive of a repository revision. | 303 """Create an unversioned archive of a repository revision. |
305 | 304 |
332 subrepos - recurse into subrepositories | 331 subrepos - recurse into subrepositories |
333 include - include names matching the given patterns | 332 include - include names matching the given patterns |
334 exclude - exclude names matching the given patterns | 333 exclude - exclude names matching the given patterns |
335 | 334 |
336 """ | 335 """ |
337 args = cmdbuilder('archive', dest, r=rev, no_decode=nodecode, p=prefix, | 336 args = cmdbuilder(b('archive'), dest, r=rev, |
337 no_decode=nodecode, p=prefix, | |
338 t=type, S=subrepos, I=include, X=exclude, | 338 t=type, S=subrepos, I=include, X=exclude, |
339 hidden=self.hidden) | 339 hidden=self.hidden) |
340 | 340 |
341 self.rawcommand(args) | 341 self.rawcommand(args) |
342 | 342 |
360 | 360 |
361 """ | 361 """ |
362 if message and logfile: | 362 if message and logfile: |
363 raise ValueError("cannot specify both a message and a logfile") | 363 raise ValueError("cannot specify both a message and a logfile") |
364 | 364 |
365 args = cmdbuilder('backout', r=rev, merge=merge, parent=parent, t=tool, | 365 args = cmdbuilder(b('backout'), r=rev, merge=merge, parent=parent, |
366 m=message, l=logfile, d=date, u=user, | 366 t=tool, m=message, l=logfile, d=date, u=user, |
367 hidden=self.hidden) | 367 hidden=self.hidden) |
368 | 368 |
369 self.rawcommand(args) | 369 self.rawcommand(args) |
370 | 370 |
371 def bookmark(self, name, rev=None, force=False, delete=False, | 371 def bookmark(self, name, rev=None, force=False, delete=False, |
379 force - bookmark even if another bookmark with the same name exists | 379 force - bookmark even if another bookmark with the same name exists |
380 delete - delete the given bookmark | 380 delete - delete the given bookmark |
381 inactive - do not mark the new bookmark active | 381 inactive - do not mark the new bookmark active |
382 rename - rename the bookmark given by rename to name | 382 rename - rename the bookmark given by rename to name |
383 """ | 383 """ |
384 args = cmdbuilder('bookmark', name, r=rev, f=force, d=delete, | 384 args = cmdbuilder(b('bookmark'), name, r=rev, f=force, d=delete, |
385 i=inactive, m=rename) | 385 i=inactive, m=rename) |
386 | 386 |
387 self.rawcommand(args) | 387 self.rawcommand(args) |
388 | 388 |
389 def bookmarks(self): | 389 def bookmarks(self): |
391 Return the bookmarks as a list of (name, rev, node) and the index of the | 391 Return the bookmarks as a list of (name, rev, node) and the index of the |
392 current one. | 392 current one. |
393 | 393 |
394 If there isn't a current one, -1 is returned as the index. | 394 If there isn't a current one, -1 is returned as the index. |
395 """ | 395 """ |
396 args = cmdbuilder('bookmarks', hidden=self.hidden) | 396 args = cmdbuilder(b('bookmarks'), hidden=self.hidden) |
397 out = self.rawcommand(args) | 397 out = self.rawcommand(args) |
398 | 398 |
399 bms = [] | 399 bms = [] |
400 current = -1 | 400 current = -1 |
401 if out.rstrip() != 'no bookmarks set': | 401 if out.rstrip() != b('no bookmarks set'): |
402 for line in out.splitlines(): | 402 for line in out.splitlines(): |
403 iscurrent, line = line[0:3], line[3:] | 403 iscurrent, line = line[0:3], line[3:] |
404 if '*' in iscurrent: | 404 if b('*') in iscurrent: |
405 current = len(bms) | 405 current = len(bms) |
406 name, line = line.split(' ', 1) | 406 name, line = line.split(b(' '), 1) |
407 rev, node = line.split(':') | 407 rev, node = line.split(b(':')) |
408 bms.append((name, int(rev), node)) | 408 bms.append((name, int(rev), node)) |
409 return bms, current | 409 return bms, current |
410 | 410 |
411 def branch(self, name=None, clean=False, force=False): | 411 def branch(self, name=None, clean=False, force=False): |
412 """When name isn't given, return the current branch name. Otherwise | 412 """When name isn't given, return the current branch name. Otherwise |
425 | 425 |
426 """ | 426 """ |
427 if name and clean: | 427 if name and clean: |
428 raise ValueError('cannot use both name and clean') | 428 raise ValueError('cannot use both name and clean') |
429 | 429 |
430 args = cmdbuilder('branch', name, f=force, C=clean) | 430 args = cmdbuilder(b('branch'), name, f=force, C=clean) |
431 out = self.rawcommand(args).rstrip() | 431 out = self.rawcommand(args).rstrip() |
432 | 432 |
433 if name: | 433 if name: |
434 return name | 434 return name |
435 elif not clean: | 435 elif not clean: |
443 Returns the repository's named branches as a list of (name, rev, node). | 443 Returns the repository's named branches as a list of (name, rev, node). |
444 | 444 |
445 active - show only branches that have unmerged heads | 445 active - show only branches that have unmerged heads |
446 closed - show normal and closed branches | 446 closed - show normal and closed branches |
447 """ | 447 """ |
448 args = cmdbuilder('branches', a=active, c=closed, hidden=self.hidden) | 448 args = cmdbuilder(b('branches'), a=active, c=closed, hidden=self.hidden) |
449 out = self.rawcommand(args) | 449 out = self.rawcommand(args) |
450 | 450 |
451 branches = [] | 451 branches = [] |
452 for line in out.rstrip().splitlines(): | 452 for line in out.rstrip().splitlines(): |
453 namerev, node = line.rsplit(':', 1) | 453 namerev, node = line.rsplit(b(':'), 1) |
454 name, rev = namerev.rsplit(' ', 1) | 454 name, rev = namerev.rsplit(b(' '), 1) |
455 name = name.rstrip() | 455 name = name.rstrip() |
456 node = node.split()[0] # get rid of ' (inactive)' | 456 node = node.split()[0] # get rid of ' (inactive)' |
457 branches.append((name, int(rev), node)) | 457 branches.append((name, int(rev), node)) |
458 return branches | 458 return branches |
459 | 459 |
483 web.cacerts config) | 483 web.cacerts config) |
484 | 484 |
485 Return True if a bundle was created, False if no changes were found. | 485 Return True if a bundle was created, False if no changes were found. |
486 | 486 |
487 """ | 487 """ |
488 args = cmdbuilder('bundle', file, destrepo, f=force, r=rev, b=branch, | 488 args = cmdbuilder(b('bundle'), file, destrepo, f=force, r=rev, b=branch, |
489 base=base, a=all, t=type, e=ssh, remotecmd=remotecmd, | 489 base=base, a=all, t=type, e=ssh, remotecmd=remotecmd, |
490 insecure=insecure, hidden=self.hidden) | 490 insecure=insecure, hidden=self.hidden) |
491 | 491 |
492 eh = util.reterrorhandler(args) | 492 eh = util.reterrorhandler(args) |
493 self.rawcommand(args, eh=eh) | 493 self.rawcommand(args, eh=eh) |
507 "%s" basename of file being printed | 507 "%s" basename of file being printed |
508 "%d" dirname of file being printed, or '.' if in repository root | 508 "%d" dirname of file being printed, or '.' if in repository root |
509 "%p" root-relative path name of file being printed | 509 "%p" root-relative path name of file being printed |
510 | 510 |
511 """ | 511 """ |
512 args = cmdbuilder('cat', r=rev, o=output, hidden=self.hidden, *files) | 512 args = cmdbuilder(b('cat'), r=rev, o=output, hidden=self.hidden, *files) |
513 out = self.rawcommand(args) | 513 out = self.rawcommand(args) |
514 | 514 |
515 if not output: | 515 if not output: |
516 return out | 516 return out |
517 | 517 |
518 def clone(self, source='.', dest=None, branch=None, updaterev=None, | 518 def clone(self, source=b('.'), dest=None, branch=None, updaterev=None, |
519 revrange=None): | 519 revrange=None): |
520 """ | 520 """ |
521 Create a copy of an existing repository specified by source in a new | 521 Create a copy of an existing repository specified by source in a new |
522 directory dest. | 522 directory dest. |
523 | 523 |
525 | 525 |
526 branch - clone only the specified branch | 526 branch - clone only the specified branch |
527 updaterev - revision, tag or branch to check out | 527 updaterev - revision, tag or branch to check out |
528 revrange - include the specified changeset | 528 revrange - include the specified changeset |
529 """ | 529 """ |
530 args = cmdbuilder('clone', source, dest, b=branch, | 530 args = cmdbuilder(b('clone'), source, dest, b=branch, |
531 u=updaterev, r=revrange) | 531 u=updaterev, r=revrange) |
532 self.rawcommand(args) | 532 self.rawcommand(args) |
533 | 533 |
534 def commit(self, message=None, logfile=None, addremove=False, | 534 def commit(self, message=None, logfile=None, addremove=False, |
535 closebranch=False, date=None, user=None, include=None, | 535 closebranch=False, date=None, user=None, include=None, |
547 exclude - exclude names matching the given patterns | 547 exclude - exclude names matching the given patterns |
548 amend - amend the parent of the working dir | 548 amend - amend the parent of the working dir |
549 """ | 549 """ |
550 if amend and message is None and logfile is None: | 550 if amend and message is None and logfile is None: |
551 # retrieve current commit message | 551 # retrieve current commit message |
552 message = self.log('.')[0][5] | 552 message = self.log(b('.'))[0][5] |
553 if message is None and logfile is None and not amend: | 553 if message is None and logfile is None and not amend: |
554 raise ValueError("must provide at least a message or a logfile") | 554 raise ValueError("must provide at least a message or a logfile") |
555 elif message and logfile: | 555 elif message and logfile: |
556 raise ValueError("cannot specify both a message and a logfile") | 556 raise ValueError("cannot specify both a message and a logfile") |
557 | 557 |
558 # --debug will print the committed cset | 558 # --debug will print the committed cset |
559 args = cmdbuilder('commit', debug=True, m=message, A=addremove, | 559 args = cmdbuilder(b('commit'), debug=True, m=message, A=addremove, |
560 close_branch=closebranch, d=date, u=user, l=logfile, | 560 close_branch=closebranch, d=date, u=user, l=logfile, |
561 I=include, X=exclude, amend=amend) | 561 I=include, X=exclude, amend=amend) |
562 out = self.rawcommand(args) | 562 out = self.rawcommand(args) |
563 rev, node = out.splitlines()[-1].rsplit(':') | 563 rev, node = out.splitlines()[-1].rsplit(b(':')) |
564 return int(rev.split()[-1]), node | 564 return int(rev.split()[-1]), node |
565 | 565 |
566 def config(self, names=[], untrusted=False, showsource=False): | 566 def config(self, names=[], untrusted=False, showsource=False): |
567 """Return a list of (section, key, value) config settings from all | 567 """Return a list of (section, key, value) config settings from all |
568 hgrc files | 568 hgrc files |
570 When showsource is specified, return (source, section, key, value) where | 570 When showsource is specified, return (source, section, key, value) where |
571 source is of the form filename:[line] | 571 source is of the form filename:[line] |
572 | 572 |
573 """ | 573 """ |
574 def splitline(s): | 574 def splitline(s): |
575 k, value = s.rstrip().split('=', 1) | 575 k, value = s.rstrip().split(b('='), 1) |
576 section, key = k.split('.', 1) | 576 section, key = k.split(b('.'), 1) |
577 return (section, key, value) | 577 return section, key, value |
578 | 578 |
579 if not isinstance(names, list): | 579 if not isinstance(names, list): |
580 names = [names] | 580 names = [names] |
581 | 581 |
582 args = cmdbuilder('showconfig', u=untrusted, debug=showsource, *names) | 582 args = cmdbuilder(b('showconfig'), u=untrusted, debug=showsource, |
583 *names) | |
583 out = self.rawcommand(args) | 584 out = self.rawcommand(args) |
584 | 585 |
585 conf = [] | 586 conf = [] |
586 if showsource: | 587 if showsource: |
587 out = util.skiplines(out, 'read config from: ') | 588 out = util.skiplines(out, b('read config from: ')) |
588 for line in out.splitlines(): | 589 for line in out.splitlines(): |
589 m = re.match(r"(.+?:(?:\d+:)?) (.*)", line) | 590 m = re.match(b(r"(.+?:(?:\d+:)?) (.*)"), line) |
590 t = splitline(m.group(2)) | 591 t = splitline(m.group(2)) |
591 conf.append((m.group(1)[:-1], t[0], t[1], t[2])) | 592 conf.append((m.group(1)[:-1], t[0], t[1], t[2])) |
592 else: | 593 else: |
593 for line in out.splitlines(): | 594 for line in out.splitlines(): |
594 conf.append(splitline(line)) | 595 conf.append(splitline(line)) |
598 @property | 599 @property |
599 def encoding(self): | 600 def encoding(self): |
600 """ | 601 """ |
601 Return the server's encoding (as reported in the hello message). | 602 Return the server's encoding (as reported in the hello message). |
602 """ | 603 """ |
603 if not 'getencoding' in self.capabilities: | 604 if not b('getencoding') in self.capabilities: |
604 raise CapabilityError('getencoding') | 605 raise CapabilityError('getencoding') |
605 | 606 |
606 if not self._encoding: | 607 if not self._encoding: |
607 self.server.stdin.write('getencoding\n') | 608 self.server.stdin.write(b('getencoding\n')) |
608 self._encoding = self._readfromchannel('r') | 609 self._encoding = self._readfromchannel('r') |
609 | 610 |
610 return self._encoding | 611 return self._encoding |
611 | 612 |
612 def copy(self, source, dest, after=False, force=False, dryrun=False, | 613 def copy(self, source, dest, after=False, force=False, dryrun=False, |
628 """ | 629 """ |
629 if not isinstance(source, list): | 630 if not isinstance(source, list): |
630 source = [source] | 631 source = [source] |
631 | 632 |
632 source.append(dest) | 633 source.append(dest) |
633 args = cmdbuilder('copy', A=after, f=force, n=dryrun, | 634 args = cmdbuilder(b('copy'), A=after, f=force, n=dryrun, |
634 I=include, X=exclude, *source) | 635 I=include, X=exclude, *source) |
635 | 636 |
636 eh = util.reterrorhandler(args) | 637 eh = util.reterrorhandler(args) |
637 self.rawcommand(args, eh=eh) | 638 self.rawcommand(args, eh=eh) |
638 | 639 |
664 exclude - exclude names matching the given patterns | 665 exclude - exclude names matching the given patterns |
665 """ | 666 """ |
666 if change and revs: | 667 if change and revs: |
667 raise ValueError('cannot specify both change and rev') | 668 raise ValueError('cannot specify both change and rev') |
668 | 669 |
669 args = cmdbuilder('diff', r=revs, c=change, | 670 args = cmdbuilder(b('diff'), r=revs, c=change, |
670 a=text, g=git, nodates=nodates, | 671 a=text, g=git, nodates=nodates, |
671 p=showfunction, reverse=reverse, | 672 p=showfunction, reverse=reverse, |
672 w=ignoreallspace, b=ignorespacechange, | 673 w=ignoreallspace, b=ignorespacechange, |
673 B=ignoreblanklines, U=unified, stat=stat, | 674 B=ignoreblanklines, U=unified, stat=stat, |
674 S=subrepos, I=include, X=exclude, hidden=self.hidden, | 675 S=subrepos, I=include, X=exclude, hidden=self.hidden, |
699 nodates - omit dates from diff headers | 700 nodates - omit dates from diff headers |
700 | 701 |
701 """ | 702 """ |
702 if not isinstance(revs, list): | 703 if not isinstance(revs, list): |
703 revs = [revs] | 704 revs = [revs] |
704 args = cmdbuilder('export', o=output, switch_parent=switchparent, | 705 args = cmdbuilder(b('export'), o=output, switch_parent=switchparent, |
705 a=text, g=git, nodates=nodates, hidden=self.hidden, | 706 a=text, g=git, nodates=nodates, hidden=self.hidden, |
706 *revs) | 707 *revs) |
707 | 708 |
708 out = self.rawcommand(args) | 709 out = self.rawcommand(args) |
709 | 710 |
724 | 725 |
725 """ | 726 """ |
726 if not isinstance(files, list): | 727 if not isinstance(files, list): |
727 files = [files] | 728 files = [files] |
728 | 729 |
729 args = cmdbuilder('forget', I=include, X=exclude, *files) | 730 args = cmdbuilder(b('forget'), I=include, X=exclude, *files) |
730 | 731 |
731 eh = util.reterrorhandler(args) | 732 eh = util.reterrorhandler(args) |
732 self.rawcommand(args, eh=eh) | 733 self.rawcommand(args, eh=eh) |
733 | 734 |
734 return bool(eh) | 735 return bool(eh) |
759 | 760 |
760 """ | 761 """ |
761 if not isinstance(files, list): | 762 if not isinstance(files, list): |
762 files = [files] | 763 files = [files] |
763 | 764 |
764 args = cmdbuilder('grep', all=all, a=text, f=follow, i=ignorecase, | 765 args = cmdbuilder(b('grep'), all=all, a=text, f=follow, i=ignorecase, |
765 l=fileswithmatches, n=line, u=user, d=date, | 766 l=fileswithmatches, n=line, u=user, d=date, |
766 I=include, X=exclude, hidden=self.hidden, | 767 I=include, X=exclude, hidden=self.hidden, |
767 *[pattern] + files) | 768 *[pattern] + files) |
768 args.append('-0') | 769 args.append(b('-0')) |
769 | 770 |
770 def eh(ret, out, err): | 771 def eh(ret, out, err): |
771 if ret != 1: | 772 if ret != 1: |
772 raise error.CommandError(args, ret, out, err) | 773 raise error.CommandError(args, ret, out, err) |
773 return '' | 774 return b('') |
774 | 775 |
775 out = self.rawcommand(args, eh=eh).split('\0') | 776 out = self.rawcommand(args, eh=eh).split(b('\0')) |
776 | 777 |
777 fieldcount = 3 | 778 fieldcount = 3 |
778 if user: | 779 if user: |
779 fieldcount += 1 | 780 fieldcount += 1 |
780 if date: | 781 if date: |
802 | 803 |
803 """ | 804 """ |
804 if not isinstance(rev, list): | 805 if not isinstance(rev, list): |
805 rev = [rev] | 806 rev = [rev] |
806 | 807 |
807 args = cmdbuilder('heads', r=startrev, t=topological, c=closed, | 808 args = cmdbuilder(b('heads'), r=startrev, t=topological, c=closed, |
808 template=templates.changeset, hidden=self.hidden, | 809 template=templates.changeset, hidden=self.hidden, |
809 *rev) | 810 *rev) |
810 | 811 |
811 def eh(ret, out, err): | 812 def eh(ret, out, err): |
812 if ret != 1: | 813 if ret != 1: |
813 raise error.CommandError(args, ret, out, err) | 814 raise error.CommandError(args, ret, out, err) |
814 return '' | 815 return b('') |
815 | 816 |
816 out = self.rawcommand(args, eh=eh).split('\0')[:-1] | 817 out = self.rawcommand(args, eh=eh).split(b('\0'))[:-1] |
817 return self._parserevs(out) | 818 return self._parserevs(out) |
818 | 819 |
819 def identify(self, rev=None, source=None, num=False, id=False, branch=False, | 820 def identify(self, rev=None, source=None, num=False, id=False, branch=False, |
820 tags=False, bookmarks=False): | 821 tags=False, bookmarks=False): |
821 """Return a summary string identifying the repository state at rev | 822 """Return a summary string identifying the repository state at rev |
834 branch - show branch | 835 branch - show branch |
835 tags - show tags | 836 tags - show tags |
836 bookmarks - show bookmarks | 837 bookmarks - show bookmarks |
837 | 838 |
838 """ | 839 """ |
839 args = cmdbuilder('identify', source, r=rev, n=num, i=id, | 840 args = cmdbuilder(b('identify'), source, r=rev, n=num, i=id, |
840 b=branch, t=tags, B=bookmarks, | 841 b=branch, t=tags, B=bookmarks, |
841 hidden=self.hidden) | 842 hidden=self.hidden) |
842 | 843 |
843 return self.rawcommand(args) | 844 return self.rawcommand(args) |
844 | 845 |
876 else: | 877 else: |
877 stdin = False | 878 stdin = False |
878 prompt = None | 879 prompt = None |
879 input = None | 880 input = None |
880 | 881 |
881 args = cmdbuilder('import', strip=strip, force=force, | 882 args = cmdbuilder(b('import'), strip=strip, force=force, |
882 no_commit=nocommit, bypass=bypass, exact=exact, | 883 no_commit=nocommit, bypass=bypass, exact=exact, |
883 import_branch=importbranch, message=message, | 884 import_branch=importbranch, message=message, |
884 date=date, user=user, similarity=similarity, _=stdin, | 885 date=date, user=user, similarity=similarity, _=stdin, |
885 *patches) | 886 *patches) |
886 | 887 |
909 remotecmd - specify hg command to run on the remote side | 910 remotecmd - specify hg command to run on the remote side |
910 insecure- do not verify server certificate (ignoring web.cacerts config) | 911 insecure- do not verify server certificate (ignoring web.cacerts config) |
911 subrepos - recurse into subrepositories | 912 subrepos - recurse into subrepositories |
912 | 913 |
913 """ | 914 """ |
914 args = cmdbuilder('incoming', path, | 915 args = cmdbuilder(b('incoming'), path, |
915 template=templates.changeset, r=revrange, | 916 template=templates.changeset, r=revrange, |
916 f=force, n=newest, bundle=bundle, | 917 f=force, n=newest, bundle=bundle, |
917 B=bookmarks, b=branch, l=limit, M=nomerges, | 918 B=bookmarks, b=branch, l=limit, M=nomerges, |
918 S=subrepos) | 919 S=subrepos) |
919 | 920 |
930 bms = [] | 931 bms = [] |
931 for line in out.splitlines(): | 932 for line in out.splitlines(): |
932 bms.append(tuple(line.split())) | 933 bms.append(tuple(line.split())) |
933 return bms | 934 return bms |
934 else: | 935 else: |
935 out = out.split('\0')[:-1] | 936 out = out.split(b('\0'))[:-1] |
936 return self._parserevs(out) | 937 return self._parserevs(out) |
937 | 938 |
938 def log(self, revrange=None, files=[], follow=False, | 939 def log(self, revrange=None, files=[], follow=False, |
939 followfirst=False, date=None, copies=False, keyword=None, | 940 followfirst=False, date=None, copies=False, keyword=None, |
940 removed=False, onlymerges=False, user=None, branch=None, | 941 removed=False, onlymerges=False, user=None, branch=None, |
981 exclude - exclude names matching the given patterns | 982 exclude - exclude names matching the given patterns |
982 | 983 |
983 """ | 984 """ |
984 if hidden is None: | 985 if hidden is None: |
985 hidden = self.hidden | 986 hidden = self.hidden |
986 args = cmdbuilder('log', template=templates.changeset, | 987 args = cmdbuilder(b('log'), template=templates.changeset, |
987 r=revrange, f=follow, follow_first=followfirst, | 988 r=revrange, f=follow, follow_first=followfirst, |
988 d=date, C=copies, k=keyword, removed=removed, | 989 d=date, C=copies, k=keyword, removed=removed, |
989 m=onlymerges, u=user, b=branch, P=prune, | 990 m=onlymerges, u=user, b=branch, P=prune, |
990 l=limit, M=nomerges, I=include, X=exclude, | 991 l=limit, M=nomerges, I=include, X=exclude, |
991 hidden=hidden, *files) | 992 hidden=hidden, *files) |
992 | 993 |
993 out = self.rawcommand(args) | 994 out = self.rawcommand(args) |
994 out = out.split('\0')[:-1] | 995 out = out.split(b('\0'))[:-1] |
995 | 996 |
996 return self._parserevs(out) | 997 return self._parserevs(out) |
997 | 998 |
998 def manifest(self, rev=None, all=False): | 999 def manifest(self, rev=None, all=False): |
999 """Yields (nodeid, permission, executable, symlink, file path) tuples | 1000 """Yields (nodeid, permission, executable, symlink, file path) tuples |
1003 | 1004 |
1004 When all is True, all files from all revisions are yielded | 1005 When all is True, all files from all revisions are yielded |
1005 (just the name). This includes deleted and renamed files. | 1006 (just the name). This includes deleted and renamed files. |
1006 | 1007 |
1007 """ | 1008 """ |
1008 args = cmdbuilder('manifest', r=rev, all=all, debug=True, | 1009 args = cmdbuilder(b('manifest'), r=rev, all=all, debug=True, |
1009 hidden=self.hidden) | 1010 hidden=self.hidden) |
1010 | 1011 |
1011 out = self.rawcommand(args) | 1012 out = self.rawcommand(args) |
1012 | 1013 |
1013 if all: | 1014 if all: |
1015 yield line | 1016 yield line |
1016 else: | 1017 else: |
1017 for line in out.splitlines(): | 1018 for line in out.splitlines(): |
1018 node = line[0:40] | 1019 node = line[0:40] |
1019 perm = line[41:44] | 1020 perm = line[41:44] |
1020 symlink = line[45] == '@' | 1021 symlink = line[45:46] == b('@') |
1021 executable = line[45] == '*' | 1022 executable = line[45:46] == b('*') |
1022 yield (node, perm, executable, symlink, line[47:]) | 1023 yield node, perm, executable, symlink, line[47:] |
1023 | 1024 |
1024 def merge(self, rev=None, force=False, tool=None, cb=merge.handlers.abort): | 1025 def merge(self, rev=None, force=False, tool=None, cb=merge.handlers.abort): |
1025 """Merge working directory with rev. If no revision is specified, the | 1026 """Merge working directory with rev. If no revision is specified, the |
1026 working directory's parent is a head revision, and the current | 1027 working directory's parent is a head revision, and the current |
1027 branch contains exactly one other head, the other head is | 1028 branch contains exactly one other head, the other head is |
1045 which are the contents of stdout. It should return one of the | 1046 which are the contents of stdout. It should return one of the |
1046 expected choices (a single character). | 1047 expected choices (a single character). |
1047 | 1048 |
1048 """ | 1049 """ |
1049 # we can't really use --preview since merge doesn't support --template | 1050 # we can't really use --preview since merge doesn't support --template |
1050 args = cmdbuilder('merge', r=rev, f=force, t=tool) | 1051 args = cmdbuilder(b('merge'), r=rev, f=force, t=tool) |
1051 | 1052 |
1052 prompt = None | 1053 prompt = None |
1053 if cb is merge.handlers.abort: | 1054 if cb is merge.handlers.abort: |
1054 prompt = cb | 1055 prompt = cb |
1055 elif cb is merge.handlers.noninteractive: | 1056 elif cb is merge.handlers.noninteractive: |
1056 args.append('-y') | 1057 args.append(b('-y')) |
1057 else: | 1058 else: |
1058 prompt = lambda size, output: cb(output) + '\n' | 1059 prompt = lambda size, output: cb(output) + b('\n') |
1059 | 1060 |
1060 self.rawcommand(args, prompt=prompt) | 1061 self.rawcommand(args, prompt=prompt) |
1061 | 1062 |
1062 def move(self, source, dest, after=False, force=False, dryrun=False, | 1063 def move(self, source, dest, after=False, force=False, dryrun=False, |
1063 include=None, exclude=None): | 1064 include=None, exclude=None): |
1078 """ | 1079 """ |
1079 if not isinstance(source, list): | 1080 if not isinstance(source, list): |
1080 source = [source] | 1081 source = [source] |
1081 | 1082 |
1082 source.append(dest) | 1083 source.append(dest) |
1083 args = cmdbuilder('move', A=after, f=force, n=dryrun, | 1084 args = cmdbuilder(b('move'), A=after, f=force, n=dryrun, |
1084 I=include, X=exclude, *source) | 1085 I=include, X=exclude, *source) |
1085 | 1086 |
1086 eh = util.reterrorhandler(args) | 1087 eh = util.reterrorhandler(args) |
1087 self.rawcommand(args, eh=eh) | 1088 self.rawcommand(args, eh=eh) |
1088 | 1089 |
1106 the remote side insecure - do not verify server certificate | 1107 the remote side insecure - do not verify server certificate |
1107 (ignoring web.cacerts config) subrepos - recurse into | 1108 (ignoring web.cacerts config) subrepos - recurse into |
1108 subrepositories | 1109 subrepositories |
1109 | 1110 |
1110 """ | 1111 """ |
1111 args = cmdbuilder('outgoing', | 1112 args = cmdbuilder(b('outgoing'), |
1112 path, | 1113 path, |
1113 template=templates.changeset, r=revrange, | 1114 template=templates.changeset, r=revrange, |
1114 f=force, n=newest, B=bookmarks, | 1115 f=force, n=newest, B=bookmarks, |
1115 b=branch, S=subrepos) | 1116 b=branch, S=subrepos) |
1116 | 1117 |
1127 bms = [] | 1128 bms = [] |
1128 for line in out.splitlines(): | 1129 for line in out.splitlines(): |
1129 bms.append(tuple(line.split())) | 1130 bms.append(tuple(line.split())) |
1130 return bms | 1131 return bms |
1131 else: | 1132 else: |
1132 out = out.split('\0')[:-1] | 1133 out = out.split(b('\0'))[:-1] |
1133 return self._parserevs(out) | 1134 return self._parserevs(out) |
1134 | 1135 |
1135 def parents(self, rev=None, file=None): | 1136 def parents(self, rev=None, file=None): |
1136 """Return the working directory's parent revisions. If rev is given, | 1137 """Return the working directory's parent revisions. If rev is given, |
1137 the parent of that revision will be printed. If file is given, | 1138 the parent of that revision will be printed. If file is given, |
1138 the revision in which the file was last changed (before the | 1139 the revision in which the file was last changed (before the |
1139 working directory revision or the revision specified by rev) | 1140 working directory revision or the revision specified by rev) |
1140 is returned. | 1141 is returned. |
1141 | 1142 |
1142 """ | 1143 """ |
1143 args = cmdbuilder('parents', file, template=templates.changeset, r=rev, | 1144 args = cmdbuilder(b('parents'), file, template=templates.changeset, |
1144 hidden=self.hidden) | 1145 r=rev, hidden=self.hidden) |
1145 | 1146 |
1146 out = self.rawcommand(args) | 1147 out = self.rawcommand(args) |
1147 if not out: | 1148 if not out: |
1148 return | 1149 return |
1149 | 1150 |
1150 out = out.split('\0')[:-1] | 1151 out = out.split(b('\0'))[:-1] |
1151 | 1152 |
1152 return self._parserevs(out) | 1153 return self._parserevs(out) |
1153 | 1154 |
1154 def paths(self, name=None): | 1155 def paths(self, name=None): |
1155 """ | 1156 """ |
1159 Path names are defined in the [paths] section of your configuration file | 1160 Path names are defined in the [paths] section of your configuration file |
1160 and in "/etc/mercurial/hgrc". If run inside a repository, ".hg/hgrc" is | 1161 and in "/etc/mercurial/hgrc". If run inside a repository, ".hg/hgrc" is |
1161 used, too. | 1162 used, too. |
1162 """ | 1163 """ |
1163 if not name: | 1164 if not name: |
1164 out = self.rawcommand(['paths']) | 1165 out = self.rawcommand([b('paths')]) |
1165 if not out: | 1166 if not out: |
1166 return {} | 1167 return {} |
1167 | 1168 |
1168 return dict([s.split(' = ') for s in out.rstrip().split('\n')]) | 1169 return dict([s.split(b(' = ')) |
1170 for s in out.rstrip().split(b('\n'))]) | |
1169 else: | 1171 else: |
1170 args = cmdbuilder('paths', name) | 1172 args = cmdbuilder(b('paths'), name) |
1171 out = self.rawcommand(args) | 1173 out = self.rawcommand(args) |
1172 return out.rstrip() | 1174 return out.rstrip() |
1173 | 1175 |
1174 def pull(self, source=None, rev=None, update=False, force=False, | 1176 def pull(self, source=None, rev=None, update=False, force=False, |
1175 bookmark=None, branch=None, ssh=None, remotecmd=None, | 1177 bookmark=None, branch=None, ssh=None, remotecmd=None, |
1194 insecure - do not verify server certificate (ignoring | 1196 insecure - do not verify server certificate (ignoring |
1195 web.cacerts config) | 1197 web.cacerts config) |
1196 tool - specify merge tool for rebase | 1198 tool - specify merge tool for rebase |
1197 | 1199 |
1198 """ | 1200 """ |
1199 args = cmdbuilder('pull', source, r=rev, u=update, f=force, | 1201 args = cmdbuilder(b('pull'), source, r=rev, u=update, f=force, |
1200 B=bookmark, b=branch, e=ssh, | 1202 B=bookmark, b=branch, e=ssh, |
1201 remotecmd=remotecmd, insecure=insecure, | 1203 remotecmd=remotecmd, insecure=insecure, |
1202 t=tool) | 1204 t=tool) |
1203 | 1205 |
1204 eh = util.reterrorhandler(args) | 1206 eh = util.reterrorhandler(args) |
1231 remotecmd - specify hg command to run on the remote side | 1233 remotecmd - specify hg command to run on the remote side |
1232 insecure - do not verify server certificate (ignoring | 1234 insecure - do not verify server certificate (ignoring |
1233 web.cacerts config) | 1235 web.cacerts config) |
1234 | 1236 |
1235 """ | 1237 """ |
1236 args = cmdbuilder('push', dest, r=rev, f=force, B=bookmark, b=branch, | 1238 args = cmdbuilder(b('push'), dest, r=rev, f=force, B=bookmark, b=branch, |
1237 new_branch=newbranch, e=ssh, remotecmd=remotecmd, | 1239 new_branch=newbranch, e=ssh, remotecmd=remotecmd, |
1238 insecure=insecure) | 1240 insecure=insecure) |
1239 | 1241 |
1240 eh = util.reterrorhandler(args) | 1242 eh = util.reterrorhandler(args) |
1241 self.rawcommand(args, eh=eh) | 1243 self.rawcommand(args, eh=eh) |
1257 | 1259 |
1258 """ | 1260 """ |
1259 if not isinstance(files, list): | 1261 if not isinstance(files, list): |
1260 files = [files] | 1262 files = [files] |
1261 | 1263 |
1262 args = cmdbuilder('remove', A=after, f=force, I=include, X=exclude, | 1264 args = cmdbuilder(b('remove'), A=after, f=force, I=include, X=exclude, |
1263 *files) | 1265 *files) |
1264 | 1266 |
1265 eh = util.reterrorhandler(args) | 1267 eh = util.reterrorhandler(args) |
1266 self.rawcommand(args, eh=eh) | 1268 self.rawcommand(args, eh=eh) |
1267 | 1269 |
1285 exclude - exclude names matching the given patterns | 1287 exclude - exclude names matching the given patterns |
1286 """ | 1288 """ |
1287 if not isinstance(file, list): | 1289 if not isinstance(file, list): |
1288 file = [file] | 1290 file = [file] |
1289 | 1291 |
1290 args = cmdbuilder('resolve', a=all, l=listfiles, m=mark, u=unmark, | 1292 args = cmdbuilder(b('resolve'), a=all, l=listfiles, m=mark, u=unmark, |
1291 t=tool, I=include, X=exclude, *file) | 1293 t=tool, I=include, X=exclude, *file) |
1292 | 1294 |
1293 out = self.rawcommand(args) | 1295 out = self.rawcommand(args) |
1294 | 1296 |
1295 if listfiles: | 1297 if listfiles: |
1296 l = [] | 1298 l = [] |
1297 for line in out.splitlines(): | 1299 for line in out.splitlines(): |
1298 l.append(tuple(line.split(' ', 1))) | 1300 l.append(tuple(line.split(b(' '), 1))) |
1299 return l | 1301 return l |
1300 | 1302 |
1301 def revert(self, files, rev=None, all=False, date=None, nobackup=False, | 1303 def revert(self, files, rev=None, all=False, date=None, nobackup=False, |
1302 dryrun=False, include=None, exclude=None): | 1304 dryrun=False, include=None, exclude=None): |
1303 """With no revision specified, revert the specified files or | 1305 """With no revision specified, revert the specified files or |
1328 | 1330 |
1329 """ | 1331 """ |
1330 if not isinstance(files, list): | 1332 if not isinstance(files, list): |
1331 files = [files] | 1333 files = [files] |
1332 | 1334 |
1333 args = cmdbuilder('revert', r=rev, a=all, d=date, | 1335 args = cmdbuilder(b('revert'), r=rev, a=all, d=date, |
1334 no_backup=nobackup, n=dryrun, I=include, X=exclude, | 1336 no_backup=nobackup, n=dryrun, I=include, X=exclude, |
1335 hidden=self.hidden, *files) | 1337 hidden=self.hidden, *files) |
1336 | 1338 |
1337 eh = util.reterrorhandler(args) | 1339 eh = util.reterrorhandler(args) |
1338 self.rawcommand(args, eh=eh) | 1340 self.rawcommand(args, eh=eh) |
1341 | 1343 |
1342 def root(self): | 1344 def root(self): |
1343 """ | 1345 """ |
1344 Return the root directory of the current repository. | 1346 Return the root directory of the current repository. |
1345 """ | 1347 """ |
1346 return self.rawcommand(['root']).rstrip() | 1348 return self.rawcommand([b('root')]).rstrip() |
1347 | 1349 |
1348 def status(self, rev=None, change=None, all=False, modified=False, | 1350 def status(self, rev=None, change=None, all=False, modified=False, |
1349 added=False, removed=False, deleted=False, clean=False, | 1351 added=False, removed=False, deleted=False, clean=False, |
1350 unknown=False, ignored=False, copies=False, | 1352 unknown=False, ignored=False, copies=False, |
1351 subrepos=False, include=None, exclude=None): | 1353 subrepos=False, include=None, exclude=None): |
1378 exclude - exclude names matching the given patterns | 1380 exclude - exclude names matching the given patterns |
1379 """ | 1381 """ |
1380 if rev and change: | 1382 if rev and change: |
1381 raise ValueError('cannot specify both rev and change') | 1383 raise ValueError('cannot specify both rev and change') |
1382 | 1384 |
1383 args = cmdbuilder('status', rev=rev, change=change, A=all, m=modified, | 1385 args = cmdbuilder(b('status'), rev=rev, change=change, A=all, |
1384 a=added, r=removed, d=deleted, c=clean, u=unknown, | 1386 m=modified, a=added, r=removed, d=deleted, c=clean, |
1385 i=ignored, C=copies, S=subrepos, I=include, | 1387 u=unknown, i=ignored, C=copies, S=subrepos, I=include, |
1386 X=exclude, hidden=self.hidden) | 1388 X=exclude, hidden=self.hidden) |
1387 | 1389 |
1388 args.append('-0') | 1390 args.append(b('-0')) |
1389 | 1391 |
1390 out = self.rawcommand(args) | 1392 out = self.rawcommand(args) |
1391 l = [] | 1393 l = [] |
1392 | 1394 |
1393 for entry in out.split('\0'): | 1395 for entry in out.split(b('\0')): |
1394 if entry: | 1396 if entry: |
1395 if entry[0] == ' ': | 1397 if entry[0:1] == b(' '): |
1396 l.append((' ', entry[2:])) | 1398 l.append((b(' '), entry[2:])) |
1397 else: | 1399 else: |
1398 l.append(tuple(entry.split(' ', 1))) | 1400 l.append(tuple(entry.split(b(' '), 1))) |
1399 | 1401 |
1400 return l | 1402 return l |
1401 | 1403 |
1402 def tag(self, names, rev=None, message=None, force=False, local=False, | 1404 def tag(self, names, rev=None, message=None, force=False, local=False, |
1403 remove=False, date=None, user=None): | 1405 remove=False, date=None, user=None): |
1420 | 1422 |
1421 """ | 1423 """ |
1422 if not isinstance(names, list): | 1424 if not isinstance(names, list): |
1423 names = [names] | 1425 names = [names] |
1424 | 1426 |
1425 args = cmdbuilder('tag', r=rev, m=message, f=force, l=local, | 1427 args = cmdbuilder(b('tag'), r=rev, m=message, f=force, l=local, |
1426 remove=remove, d=date, u=user, hidden=self.hidden, | 1428 remove=remove, d=date, u=user, hidden=self.hidden, |
1427 *names) | 1429 *names) |
1428 | 1430 |
1429 self.rawcommand(args) | 1431 self.rawcommand(args) |
1430 | 1432 |
1431 def tags(self): | 1433 def tags(self): |
1432 """ | 1434 """ |
1433 Return a list of repository tags as: (name, rev, node, islocal) | 1435 Return a list of repository tags as: (name, rev, node, islocal) |
1434 """ | 1436 """ |
1435 args = cmdbuilder('tags', v=True) | 1437 args = cmdbuilder(b('tags'), v=True) |
1436 | 1438 |
1437 out = self.rawcommand(args) | 1439 out = self.rawcommand(args) |
1438 | 1440 |
1439 t = [] | 1441 t = [] |
1440 for line in out.splitlines(): | 1442 for line in out.splitlines(): |
1441 taglocal = line.endswith(' local') | 1443 taglocal = line.endswith(b(' local')) |
1442 if taglocal: | 1444 if taglocal: |
1443 line = line[:-6] | 1445 line = line[:-6] |
1444 name, rev = line.rsplit(' ', 1) | 1446 name, rev = line.rsplit(b(' '), 1) |
1445 rev, node = rev.split(':') | 1447 rev, node = rev.split(b(':')) |
1446 t.append((name.rstrip(), int(rev), node, taglocal)) | 1448 t.append((name.rstrip(), int(rev), node, taglocal)) |
1447 return t | 1449 return t |
1448 | 1450 |
1449 def phase(self, revs=(), secret=False, draft=False, public=False, | 1451 def phase(self, revs=(), secret=False, draft=False, public=False, |
1450 force=False): | 1452 force=False): |
1460 | 1462 |
1461 The arguments match the mercurial API. | 1463 The arguments match the mercurial API. |
1462 ''' | 1464 ''' |
1463 if not isinstance(revs, (list, tuple)): | 1465 if not isinstance(revs, (list, tuple)): |
1464 revs = [revs] | 1466 revs = [revs] |
1465 args = util.cmdbuilder('phase', secret=secret, draft=draft, | 1467 args = util.cmdbuilder(b('phase'), secret=secret, draft=draft, |
1466 public=public, force=force, | 1468 public=public, force=force, |
1467 hidden=self.hidden, *revs) | 1469 hidden=self.hidden, *revs) |
1468 out = self.rawcommand(args) | 1470 out = self.rawcommand(args) |
1469 if draft or public or secret: | 1471 if draft or public or secret: |
1470 return | 1472 return |
1471 else: | 1473 else: |
1472 output = [i.split(': ')for i in out.strip().split('\n')] | 1474 output = [i.split(b(': '))for i in out.strip().split(b('\n'))] |
1473 return [(int(num), phase) for (num, phase) in output] | 1475 return [(int(num), phase) for (num, phase) in output] |
1474 | 1476 |
1475 def summary(self, remote=False): | 1477 def summary(self, remote=False): |
1476 """ | 1478 """ |
1477 Return a dictionary with a brief summary of the working directory state, | 1479 Return a dictionary with a brief summary of the working directory state, |
1484 ['remote' : (in, in bookmarks, out, out bookmarks),] | 1486 ['remote' : (in, in bookmarks, out, out bookmarks),] |
1485 ['mq': (applied, unapplied) mq patches,] | 1487 ['mq': (applied, unapplied) mq patches,] |
1486 | 1488 |
1487 unparsed entries will be of them form key : value | 1489 unparsed entries will be of them form key : value |
1488 """ | 1490 """ |
1489 args = cmdbuilder('summary', remote=remote, hidden=self.hidden) | 1491 args = cmdbuilder(b('summary'), remote=remote, hidden=self.hidden) |
1490 | 1492 |
1491 out = self.rawcommand(args).splitlines() | 1493 out = self.rawcommand(args).splitlines() |
1492 | 1494 |
1493 d = {} | 1495 d = {} |
1494 while out: | 1496 while out: |
1495 line = out.pop(0) | 1497 line = out.pop(0) |
1496 name, value = line.split(': ', 1) | 1498 name, value = line.split(b(': '), 1) |
1497 | 1499 |
1498 if name == 'parent': | 1500 if name == b('parent'): |
1499 parent, tags = value.split(' ', 1) | 1501 parent, tags = value.split(b(' '), 1) |
1500 rev, node = parent.split(':') | 1502 rev, node = parent.split(b(':')) |
1501 | 1503 |
1502 if tags: | 1504 if tags: |
1503 tags = tags.replace(' (empty repository)', '') | 1505 tags = tags.replace(b(' (empty repository)'), b('')) |
1504 else: | 1506 else: |
1505 tags = None | 1507 tags = None |
1506 | 1508 |
1507 value = d.get(name, []) | 1509 value = d.get(name, []) |
1508 | 1510 |
1509 if rev == '-1': | 1511 if rev == b('-1'): |
1510 value.append((int(rev), node, tags, None)) | 1512 value.append((int(rev), node, tags, None)) |
1511 else: | 1513 else: |
1512 message = out.pop(0)[1:] | 1514 message = out.pop(0)[1:] |
1513 value.append((int(rev), node, tags, message)) | 1515 value.append((int(rev), node, tags, message)) |
1514 elif name == 'branch': | 1516 elif name == b('branch'): |
1515 pass | 1517 pass |
1516 elif name == 'commit': | 1518 elif name == b('commit'): |
1517 value = value == '(clean)' | 1519 value = value == b('(clean)') |
1518 elif name == 'update': | 1520 elif name == b('update'): |
1519 if value == '(current)': | 1521 if value == b('(current)'): |
1520 value = 0 | 1522 value = 0 |
1521 else: | 1523 else: |
1522 value = int(value.split(' ', 1)[0]) | 1524 value = int(value.split(b(' '), 1)[0]) |
1523 elif remote and name == 'remote': | 1525 elif remote and name == b('remote'): |
1524 if value == '(synced)': | 1526 if value == b('(synced)'): |
1525 value = 0, 0, 0, 0 | 1527 value = 0, 0, 0, 0 |
1526 else: | 1528 else: |
1527 inc = incb = out_ = outb = 0 | 1529 inc = incb = out_ = outb = 0 |
1528 | 1530 |
1529 for v in value.split(', '): | 1531 for v in value.split(b(', ')): |
1530 count, v = v.split(' ', 1) | 1532 count, v = v.split(b(' '), 1) |
1531 if v == 'outgoing': | 1533 if v == b('outgoing'): |
1532 out_ = int(count) | 1534 out_ = int(count) |
1533 elif v.endswith('incoming'): | 1535 elif v.endswith(b('incoming')): |
1534 inc = int(count) | 1536 inc = int(count) |
1535 elif v == 'incoming bookmarks': | 1537 elif v == b('incoming bookmarks'): |
1536 incb = int(count) | 1538 incb = int(count) |
1537 elif v == 'outgoing bookmarks': | 1539 elif v == b('outgoing bookmarks'): |
1538 outb = int(count) | 1540 outb = int(count) |
1539 | 1541 |
1540 value = inc, incb, out_, outb | 1542 value = inc, incb, out_, outb |
1541 elif name == 'mq': | 1543 elif name == b('mq'): |
1542 applied = unapplied = 0 | 1544 applied = unapplied = 0 |
1543 for v in value.split(', '): | 1545 for v in value.split(b(', ')): |
1544 count, v = v.split(' ', 1) | 1546 count, v = v.split(b(' '), 1) |
1545 if v == 'applied': | 1547 if v == b('applied'): |
1546 applied = int(count) | 1548 applied = int(count) |
1547 elif v == 'unapplied': | 1549 elif v == b('unapplied'): |
1548 unapplied = int(count) | 1550 unapplied = int(count) |
1549 value = applied, unapplied | 1551 value = applied, unapplied |
1550 | 1552 |
1551 d[name] = value | 1553 d[name] = value |
1552 | 1554 |
1556 """ | 1558 """ |
1557 Return the tip revision (usually just called the tip) which is the | 1559 Return the tip revision (usually just called the tip) which is the |
1558 changeset most recently added to the repository (and therefore the most | 1560 changeset most recently added to the repository (and therefore the most |
1559 recently changed head). | 1561 recently changed head). |
1560 """ | 1562 """ |
1561 args = cmdbuilder('tip', template=templates.changeset, | 1563 args = cmdbuilder(b('tip'), template=templates.changeset, |
1562 hidden=self.hidden) | 1564 hidden=self.hidden) |
1563 out = self.rawcommand(args) | 1565 out = self.rawcommand(args) |
1564 out = out.split('\0') | 1566 out = out.split(b('\0')) |
1565 | 1567 |
1566 return self._parserevs(out)[0] | 1568 return self._parserevs(out)[0] |
1567 | 1569 |
1568 def update(self, rev=None, clean=False, check=False, date=None): | 1570 def update(self, rev=None, clean=False, check=False, date=None): |
1569 """ | 1571 """ |
1577 date - tipmost revision matching date | 1579 date - tipmost revision matching date |
1578 """ | 1580 """ |
1579 if clean and check: | 1581 if clean and check: |
1580 raise ValueError('clean and check cannot both be True') | 1582 raise ValueError('clean and check cannot both be True') |
1581 | 1583 |
1582 args = cmdbuilder('update', r=rev, C=clean, c=check, d=date, | 1584 args = cmdbuilder(b('update'), r=rev, C=clean, c=check, d=date, |
1583 hidden=self.hidden) | 1585 hidden=self.hidden) |
1584 | 1586 |
1585 def eh(ret, out, err): | 1587 def eh(ret, out, err): |
1586 if ret == 1: | 1588 if ret == 1: |
1587 return out | 1589 return out |
1589 raise error.CommandError(args, ret, out, err) | 1591 raise error.CommandError(args, ret, out, err) |
1590 | 1592 |
1591 | 1593 |
1592 out = self.rawcommand(args, eh=eh) | 1594 out = self.rawcommand(args, eh=eh) |
1593 | 1595 |
1594 m = re.search(r'^(\d+).+, (\d+).+, (\d+).+, (\d+)', out, re.MULTILINE) | 1596 m = re.search(b(r'^(\d+).+, (\d+).+, (\d+).+, (\d+)'), out, |
1597 re.MULTILINE) | |
1595 return tuple(map(int, list(m.groups()))) | 1598 return tuple(map(int, list(m.groups()))) |
1596 | 1599 |
1597 @property | 1600 @property |
1598 def version(self): | 1601 def version(self): |
1599 """Return hg version that runs the command server as a 4 fielded | 1602 """Return hg version that runs the command server as a 4 fielded |
1600 tuple: major, minor, micro and local build info. e.g. (1, 9, | 1603 tuple: major, minor, micro and local build info. e.g. (1, 9, |
1601 1, '+4-3095db9f5c2c') | 1604 1, '+4-3095db9f5c2c') |
1602 """ | 1605 """ |
1603 if self._version is None: | 1606 if self._version is None: |
1604 v = self.rawcommand(cmdbuilder('version', q=True)) | 1607 v = self.rawcommand(cmdbuilder(b('version'), q=True)) |
1605 v = list(re.match(r'.*?(\d+)\.(\d+)\.?(\d+)?(\+[0-9a-f-]+)?', | 1608 v = list(re.match(b(r'.*?(\d+)\.(\d+)\.?(\d+)?(\+[0-9a-f-]+)?'), |
1606 v).groups()) | 1609 v).groups()) |
1607 | 1610 |
1608 for i in range(3): | 1611 for i in range(3): |
1609 try: | 1612 try: |
1610 v[i] = int(v[i]) | 1613 v[i] = int(v[i]) |