# HG changeset patch # User Thomas Arendsen Hein # Date 1155633749 -7200 # Node ID 75bcb8210a372c7f5b455ed364681cd05ecb5f13 # Parent 8b02af86599076a57635eca2e503156874a6185a# Parent 2497fa1c6b76cb5c2f85e74b9f45354b176ab892 merge with jeffpc diff -r 2497fa1c6b76 -r 75bcb8210a37 contrib/mercurial.el --- a/contrib/mercurial.el Tue Aug 15 05:12:27 2006 -0400 +++ b/contrib/mercurial.el Tue Aug 15 11:22:29 2006 +0200 @@ -722,7 +722,7 @@ (if (not hg-root-dir) (error "error: %s: directory is not part of a Mercurial repository." default-directory) - (cd (hg-root)))))) + (cd hg-root-dir))))) (defun hg-add (path) "Add PATH to the Mercurial repository on the next commit. diff -r 2497fa1c6b76 -r 75bcb8210a37 doc/hg.1.txt --- a/doc/hg.1.txt Tue Aug 15 05:12:27 2006 -0400 +++ b/doc/hg.1.txt Tue Aug 15 11:22:29 2006 +0200 @@ -216,6 +216,6 @@ COPYING ------- -Copyright \(C) 2005 Matt Mackall. +Copyright \(C) 2005, 2006 Matt Mackall. Free use of this software is granted under the terms of the GNU General Public License (GPL). diff -r 2497fa1c6b76 -r 75bcb8210a37 doc/hgmerge.1.txt --- a/doc/hgmerge.1.txt Tue Aug 15 05:12:27 2006 -0400 +++ b/doc/hgmerge.1.txt Tue Aug 15 11:22:29 2006 +0200 @@ -30,6 +30,6 @@ COPYING ------- -Copyright \(C) 2005 Matt Mackall. +Copyright \(C) 2005, 2006 Matt Mackall. Free use of this software is granted under the terms of the GNU General Public License (GPL). diff -r 2497fa1c6b76 -r 75bcb8210a37 doc/hgrc.5.txt --- a/doc/hgrc.5.txt Tue Aug 15 05:12:27 2006 -0400 +++ b/doc/hgrc.5.txt Tue Aug 15 11:22:29 2006 +0200 @@ -306,7 +306,7 @@ smtp:: Configuration for extensions that need to send email messages. host;; - Optional. Host name of mail server. Default: "mail". + Host name of mail server, e.g. "mail.example.com". port;; Optional. Port to connect to on mail server. Default: 25. tls;; diff -r 2497fa1c6b76 -r 75bcb8210a37 doc/ja/hg.1.ja.txt --- a/doc/ja/hg.1.ja.txt Tue Aug 15 05:12:27 2006 -0400 +++ b/doc/ja/hg.1.ja.txt Tue Aug 15 11:22:29 2006 +0200 @@ -862,6 +862,6 @@ 著作権情報 ----- -Copyright (C) 2005 Matt Mackall. +Copyright (C) 2005, 2006 Matt Mackall. このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで 認められます。 diff -r 2497fa1c6b76 -r 75bcb8210a37 doc/ja/hgmerge.1.ja.txt --- a/doc/ja/hgmerge.1.ja.txt Tue Aug 15 05:12:27 2006 -0400 +++ b/doc/ja/hgmerge.1.ja.txt Tue Aug 15 11:22:29 2006 +0200 @@ -32,6 +32,6 @@ 著作権情報 ---- -Copyright (C) 2005 Matt Mackall. +Copyright (C) 2005, 2006 Matt Mackall. このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで 認められます。 diff -r 2497fa1c6b76 -r 75bcb8210a37 hgext/extdiff.py --- a/hgext/extdiff.py Tue Aug 15 05:12:27 2006 -0400 +++ b/hgext/extdiff.py Tue Aug 15 11:22:29 2006 +0200 @@ -33,9 +33,9 @@ from mercurial.demandload import demandload from mercurial.i18n import gettext as _ from mercurial.node import * -demandload(globals(), 'mercurial:commands,util os shutil tempfile') +demandload(globals(), 'mercurial:commands,cmdutil,util os shutil tempfile') -def dodiff(ui, repo, diffcmd, pats, opts): +def dodiff(ui, repo, diffcmd, diffopts, pats, opts): def snapshot_node(files, node): '''snapshot files as of some revision''' changes = repo.changelog.read(node) @@ -79,9 +79,9 @@ return dirname node1, node2 = commands.revpair(ui, repo, opts['rev']) - files, matchfn, anypats = commands.matchpats(repo, pats, opts) - modified, added, removed, deleted, unknown = repo.changes( - node1, node2, files, match=matchfn) + files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) + modified, added, removed, deleted, unknown = repo.status( + node1, node2, files, match=matchfn)[:5] if not (modified or added or removed): return 0 @@ -92,9 +92,12 @@ dir2 = snapshot_node(modified + added, node2) else: dir2 = snapshot_wdir(modified + added) - util.system('%s %s "%s" "%s"' % - (diffcmd, ' '.join(opts['option']), dir1, dir2), - cwd=tmproot) + cmdline = ('%s %s %s %s' % + (util.shellquote(diffcmd), + ' '.join(map(util.shellquote, diffopts)), + util.shellquote(dir1), util.shellquote(dir2))) + ui.debug('running %r in %s\n' % (cmdline, tmproot)) + util.system(cmdline, cwd=tmproot) return 1 finally: ui.note(_('cleaning up temp directory\n')) @@ -104,7 +107,9 @@ '''use external program to diff repository (or selected files) Show differences between revisions for the specified files, using - an external program. The default program used is "diff -Npru". + an external program. The default program used is diff, with + default options "-Npru". + To select a different program, use the -p option. The program will be passed the names of two directories to compare. To pass additional options to the program, use the -o option. These will @@ -115,7 +120,8 @@ specified then that revision is compared to the working directory, and, when no revisions are specified, the working directory files are compared to its parent.''' - return dodiff(ui, repo, opts['program'] or 'diff -Npru', pats, opts) + return dodiff(ui, repo, opts['program'] or 'diff', + opts['option'] or ['-Npru'], pats, opts) cmdtable = { "extdiff": @@ -133,20 +139,24 @@ if not cmd.startswith('cmd.'): continue cmd = cmd[4:] if not path: path = cmd + diffopts = ui.config('extdiff', 'opts.' + cmd, '') + diffopts = diffopts and [diffopts] or [] def save(cmd, path): '''use closure to save diff command to use''' def mydiff(ui, repo, *pats, **opts): - return dodiff(ui, repo, path, pats, opts) - mydiff.__doc__ = '''use %s to diff repository (or selected files) + return dodiff(ui, repo, path, diffopts, pats, opts) + mydiff.__doc__ = '''use %(path)r to diff repository (or selected files) Show differences between revisions for the specified - files, using the %s program. + files, using the %(path)r program. When two revision arguments are given, then changes are shown between those revisions. If only one revision is specified then that revision is compared to the working directory, and, when no revisions are specified, the - working directory files are compared to its parent.''' % (cmd, cmd) + working directory files are compared to its parent.''' % { + 'path': path, + } return mydiff cmdtable[cmd] = (save(cmd, path), cmdtable['extdiff'][1][1:], diff -r 2497fa1c6b76 -r 75bcb8210a37 hgext/fetch.py --- a/hgext/fetch.py Tue Aug 15 05:12:27 2006 -0400 +++ b/hgext/fetch.py Tue Aug 15 11:22:29 2006 +0200 @@ -24,13 +24,13 @@ if modheads == 0: return 0 if modheads == 1: - return hg.update(repo, repo.changelog.tip(), wlock=wlock) + return hg.clean(repo, repo.changelog.tip(), wlock=wlock) newheads = repo.heads(parent) newchildren = [n for n in repo.heads(parent) if n != parent] newparent = parent if newchildren: newparent = newchildren[0] - hg.update(repo, newparent, wlock=wlock) + hg.clean(repo, newparent, wlock=wlock) newheads = [n for n in repo.heads() if n != newparent] err = False if newheads: diff -r 2497fa1c6b76 -r 75bcb8210a37 hgext/gpg.py --- a/hgext/gpg.py Tue Aug 15 05:12:27 2006 -0400 +++ b/hgext/gpg.py Tue Aug 15 11:22:29 2006 +0200 @@ -221,7 +221,7 @@ repo.opener("localsigs", "ab").write(sigmessage) return - for x in repo.changes(): + for x in repo.status()[:5]: if ".hgsigs" in x and not opts["force"]: raise util.Abort(_("working copy of .hgsigs is changed " "(please commit .hgsigs manually " diff -r 2497fa1c6b76 -r 75bcb8210a37 hgext/hbisect.py --- a/hgext/hbisect.py Tue Aug 15 05:12:27 2006 -0400 +++ b/hgext/hbisect.py Tue Aug 15 11:22:29 2006 +0200 @@ -23,10 +23,10 @@ return parents.pop() def check_clean(ui, repo): - modified, added, removed, deleted, unknown = repo.changes() - if modified or added or removed: - ui.warn("Repository is not clean, please commit or revert\n") - sys.exit(1) + modified, added, removed, deleted, unknown = repo.status()[:5] + if modified or added or removed: + ui.warn("Repository is not clean, please commit or revert\n") + sys.exit(1) class bisect(object): """dichotomic search in the DAG of changesets""" diff -r 2497fa1c6b76 -r 75bcb8210a37 hgext/hgk.py --- a/hgext/hgk.py Tue Aug 15 05:12:27 2006 -0400 +++ b/hgext/hgk.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,6 +1,6 @@ # Minimal support for git commands on an hg repository # -# Copyright 2005 Chris Mason +# Copyright 2005, 2006 Chris Mason # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. @@ -15,7 +15,7 @@ return time.asctime(time.gmtime(c[2][0])) if not changes: - changes = repo.changes(node1, node2, files, match=match) + changes = repo.status(node1, node2, files, match=match)[:5] modified, added, removed, deleted, unknown = changes if files: modified, added, removed = map(lambda x: filterfiles(files, x), @@ -68,12 +68,12 @@ if node2: change = repo.changelog.read(node2) mmap2 = repo.manifest.read(change[0]) - modified, added, removed, deleted, unknown = repo.changes(node1, node2) + modified, added, removed, deleted, unknown = repo.status(node1, node2)[:5] def read(f): return repo.file(f).read(mmap2[f]) date2 = date(change) else: date2 = time.asctime() - modified, added, removed, deleted, unknown = repo.changes(node1) + modified, added, removed, deleted, unknown = repo.status(node1)[:5] if not node1: node1 = repo.dirstate.parents()[0] def read(f): return file(os.path.join(repo.root, f)).read() diff -r 2497fa1c6b76 -r 75bcb8210a37 hgext/mq.py --- a/hgext/mq.py Tue Aug 15 05:12:27 2006 -0400 +++ b/hgext/mq.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,7 +1,6 @@ - # queue.py - patch queues for mercurial # -# Copyright 2005 Chris Mason +# Copyright 2005, 2006 Chris Mason # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. @@ -31,9 +30,9 @@ ''' from mercurial.demandload import * +from mercurial.i18n import gettext as _ demandload(globals(), "os sys re struct traceback errno bz2") -from mercurial.i18n import gettext as _ -from mercurial import ui, hg, revlog, commands, util +demandload(globals(), "mercurial:cmdutil,commands,hg,patch,revlog,ui,util") commands.norepo += " qclone qversion" @@ -66,6 +65,7 @@ self.guards_path = "guards" self.active_guards = None self.guards_dirty = False + self._diffopts = None if os.path.exists(self.join(self.series_path)): self.full_series = self.opener(self.series_path).read().splitlines() @@ -75,6 +75,11 @@ lines = self.opener(self.status_path).read().splitlines() self.applied = [statusentry(l) for l in lines] + def diffopts(self): + if self._diffopts is None: + self._diffopts = self.ui.diffopts() + return self._diffopts + def join(self, *p): return os.path.join(self.path, *p) @@ -176,11 +181,11 @@ if exactneg: return False, exactneg[0] pos = [g for g in patchguards if g[0] == '+'] - nonpos = [g for g in pos if g[1:] not in guards] + exactpos = [g for g in pos if g[1:] in guards] if pos: - if not nonpos: - return True, '' - return False, nonpos + if exactpos: + return True, exactpos[0] + return False, pos return True, '' def explain_pushable(self, idx, all_patches=False): @@ -292,6 +297,11 @@ message.insert(0, subject) return (message, comments, user, date, diffstart > 1) + def printdiff(self, repo, node1, node2=None, files=None, + fp=None, changes=None, opts=None): + patch.diff(repo, node1, node2, files, + fp=fp, changes=changes, opts=self.diffopts()) + def mergeone(self, repo, mergeq, head, patch, rev, wlock): # first try just applying the patch (err, n) = self.apply(repo, [ patch ], update_status=False, @@ -325,7 +335,7 @@ if comments: comments = "\n".join(comments) + '\n\n' patchf.write(comments) - commands.dodiff(patchf, self.ui, repo, head, n) + self.printdiff(repo, head, n, fp=patchf) patchf.close() return (0, n) @@ -470,8 +480,7 @@ cfiles = files if cwd: cfiles = [util.pathto(cwd, f) for f in files] - commands.addremove_lock(self.ui, repo, cfiles, - opts={}, wlock=wlock) + cmdutil.addremove(repo, cfiles, wlock=wlock) n = repo.commit(files, message, user, date, force=1, lock=lock, wlock=wlock) @@ -497,21 +506,28 @@ tr.close() return (err, n) - def delete(self, repo, patch, force=False): - patch = self.lookup(patch, strict=True) - info = self.isapplied(patch) - if info: - raise util.Abort(_("cannot delete applied patch %s") % patch) - if patch not in self.series: - raise util.Abort(_("patch %s not in series file") % patch) - if force: + def delete(self, repo, patches, keep=False): + realpatches = [] + for patch in patches: + patch = self.lookup(patch, strict=True) + info = self.isapplied(patch) + if info: + raise util.Abort(_("cannot delete applied patch %s") % patch) + if patch not in self.series: + raise util.Abort(_("patch %s not in series file") % patch) + realpatches.append(patch) + + if not keep: r = self.qrepo() if r: - r.remove([patch], True) + r.remove(realpatches, True) else: os.unlink(self.join(patch)) - i = self.find_series(patch) - del self.full_series[i] + + indices = [self.find_series(p) for p in realpatches] + indices.sort() + for i in indices[-1::-1]: + del self.full_series[i] self.parse_series() self.series_dirty = 1 @@ -523,19 +539,20 @@ raise util.Abort(_("queue top not at same revision as working directory")) return top return None - def check_localchanges(self, repo): - (c, a, r, d, u) = repo.changes(None, None) - if c or a or d or r: - raise util.Abort(_("local changes found, refresh first")) + def check_localchanges(self, repo, force=False, refresh=True): + m, a, r, d = repo.status()[:4] + if m or a or r or d: + if not force: + if refresh: + raise util.Abort(_("local changes found, refresh first")) + else: + raise util.Abort(_("local changes found")) + return m, a, r, d def new(self, repo, patch, msg=None, force=None): if os.path.exists(self.join(patch)): raise util.Abort(_('patch "%s" already exists') % patch) - commitfiles = [] - (c, a, r, d, u) = repo.changes(None, None) - if c or a or d or r: - if not force: - raise util.Abort(_("local changes found, refresh first")) - commitfiles = c + a + r + m, a, r, d = self.check_localchanges(repo, force) + commitfiles = m + a + r self.check_toppatch(repo) wlock = repo.wlock() insert = self.full_series_end() @@ -561,7 +578,7 @@ r = self.qrepo() if r: r.add([patch]) if commitfiles: - self.refresh(repo, msg=None, short=True) + self.refresh(repo, short=True) def strip(self, repo, rev, update=True, backup="all", wlock=None): def limitheads(chlog, stop): @@ -649,9 +666,7 @@ revnum = chlog.rev(rev) if update: - (c, a, r, d, u) = repo.changes(None, None) - if c or a or d or r: - raise util.Abort(_("local changes found")) + self.check_localchanges(repo, refresh=False) urev = self.qparents(repo, rev) hg.clean(repo, urev, wlock=wlock) repo.dirstate.write() @@ -725,6 +740,8 @@ # 2) a unique substring of the patch name was given # 3) patchname[-+]num to indicate an offset in the series file def lookup(self, patch, strict=False): + patch = patch and str(patch) + def partial_name(s): if s in self.series: return s @@ -887,15 +904,15 @@ qp = self.qparents(repo, rev) changes = repo.changelog.read(qp) mmap = repo.manifest.read(changes[0]) - (c, a, r, d, u) = repo.changes(qp, top) + m, a, r, d, u = repo.status(qp, top)[:5] if d: raise util.Abort("deletions found between repo revs") - for f in c: + for f in m: getfile(f, mmap[f]) for f in r: getfile(f, mmap[f]) - util.set_exec(repo.wjoin(f), mmap.execf[f]) - repo.dirstate.update(c + r, 'n') + util.set_exec(repo.wjoin(f), mmap.execf(f)) + repo.dirstate.update(m + r, 'n') for f in a: try: os.unlink(repo.wjoin(f)) except: raise @@ -917,9 +934,9 @@ self.ui.write("No patches applied\n") return qp = self.qparents(repo, top) - commands.dodiff(sys.stdout, self.ui, repo, qp, None, files) + self.printdiff(repo, qp, files=files) - def refresh(self, repo, msg=None, short=False): + def refresh(self, repo, msg='', short=False): if len(self.applied) == 0: self.ui.write("No patches applied\n") return @@ -958,30 +975,30 @@ # patch already # # this should really read: - #(cc, dd, aa, aa2, uu) = repo.changes(tip, patchparent) + # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5] # but we do it backwards to take advantage of manifest/chlog - # caching against the next repo.changes call + # caching against the next repo.status call # - (cc, aa, dd, aa2, uu) = repo.changes(patchparent, tip) + mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5] if short: - filelist = cc + aa + dd + filelist = mm + aa + dd else: filelist = None - (c, a, r, d, u) = repo.changes(None, None, filelist) + m, a, r, d, u = repo.status(files=filelist)[:5] # we might end up with files that were added between tip and # the dirstate parent, but then changed in the local dirstate. # in this case, we want them to only show up in the added section - for x in c: + for x in m: if x not in aa: - cc.append(x) + mm.append(x) # we might end up with files added by the local dirstate that # were deleted by the patch. In this case, they should only # show up in the changed section. for x in a: if x in dd: del dd[dd.index(x)] - cc.append(x) + mm.append(x) else: aa.append(x) # make sure any files deleted in the local dirstate @@ -992,23 +1009,23 @@ del aa[aa.index(x)] forget.append(x) continue - elif x in cc: - del cc[cc.index(x)] + elif x in mm: + del mm[mm.index(x)] dd.append(x) - c = list(util.unique(cc)) + m = list(util.unique(mm)) r = list(util.unique(dd)) a = list(util.unique(aa)) - filelist = list(util.unique(c + r + a )) - commands.dodiff(patchf, self.ui, repo, patchparent, None, - filelist, changes=(c, a, r, [], u)) + filelist = list(util.unique(m + r + a)) + self.printdiff(repo, patchparent, files=filelist, + changes=(m, a, r, [], u), fp=patchf) patchf.close() changes = repo.changelog.read(tip) repo.dirstate.setparents(*cparents) repo.dirstate.update(a, 'a') repo.dirstate.update(r, 'r') - repo.dirstate.update(c, 'n') + repo.dirstate.update(m, 'n') repo.dirstate.forget(forget) if not msg: @@ -1024,7 +1041,7 @@ self.applied[-1] = statusentry(revlog.hex(n), patch) self.applied_dirty = 1 else: - commands.dodiff(patchf, self.ui, repo, patchparent, None) + self.printdiff(repo, patchparent, fp=patchf) patchf.close() self.pop(repo, force=True, wlock=wlock) self.push(repo, force=True, wlock=wlock) @@ -1290,13 +1307,13 @@ if qrepo: qrepo.add(added) -def delete(ui, repo, patch, **opts): - """remove a patch from the series file +def delete(ui, repo, patch, *patches, **opts): + """remove patches from queue - The patch must not be applied. - With -f, deletes the patch file as well as the series entry.""" + The patches must not be applied. + With -k, the patch files are preserved in the patch directory.""" q = repo.mq - q.delete(repo, patch, force=opts.get('force')) + q.delete(repo, (patch,) + patches, keep=opts.get('keep')) q.save_dirty() return 0 @@ -1454,7 +1471,7 @@ applied to the current patch in the order given. If all the patches apply successfully, the current patch will be refreshed with the new cumulative patch, and the folded patches will - be deleted. With -f/--force, the folded patch files will + be deleted. With -k/--keep, the folded patch files will not be removed afterwards. The header for each folded patch will be concatenated with @@ -1504,7 +1521,7 @@ q.refresh(repo, msg=message) for patch in patches: - q.delete(repo, patch, force=opts['force']) + q.delete(repo, patch, keep=opts['keep']) q.save_dirty() @@ -1739,7 +1756,7 @@ this sets "stable" guard. mq will skip foo.patch (because it has nagative match) but push bar.patch (because it has posative - match). patch is pushed only if all posative guards match and no + match). patch is pushed if any posative guards match and no nagative guards match. with no arguments, default is to print current active guards. @@ -1749,19 +1766,36 @@ when no guards active, patches with posative guards are skipped, patches with nagative guards are pushed. + qselect can change guards of applied patches. it does not pop + guarded patches by default. use --pop to pop back to last applied + patch that is not guarded. use --reapply (implies --pop) to push + back to current patch afterwards, but skip guarded patches. + use -s/--series to print list of all guards in series file (no other arguments needed). use -v for more information.''' q = repo.mq guards = q.active() if args or opts['none']: + old_unapplied = q.unapplied(repo) + old_guarded = [i for i in xrange(len(q.applied)) if + not q.pushable(i)[0]] q.set_active(args) q.save_dirty() if not args: ui.status(_('guards deactivated\n')) - if q.series: - ui.status(_('%d of %d unapplied patches active\n') % - (len(q.unapplied(repo)), len(q.series))) + if not opts['pop'] and not opts['reapply']: + unapplied = q.unapplied(repo) + guarded = [i for i in xrange(len(q.applied)) + if not q.pushable(i)[0]] + if len(unapplied) != len(old_unapplied): + ui.status(_('number of unguarded, unapplied patches has ' + 'changed from %d to %d\n') % + (len(old_unapplied), len(unapplied))) + if len(guarded) != len(old_guarded): + ui.status(_('number of guarded, applied patches has changed ' + 'from %d to %d\n') % + (len(old_guarded), len(guarded))) elif opts['series']: guards = {} noguards = 0 @@ -1789,9 +1823,51 @@ ui.write(g, '\n') else: ui.write(_('no active guards\n')) + reapply = opts['reapply'] and q.applied and q.appliedname(-1) + popped = False + if opts['pop'] or opts['reapply']: + for i in xrange(len(q.applied)): + pushable, reason = q.pushable(i) + if not pushable: + ui.status(_('popping guarded patches\n')) + popped = True + if i == 0: + q.pop(repo, all=True) + else: + q.pop(repo, i-1) + break + if popped: + try: + if reapply: + ui.status(_('reapplying unguarded patches\n')) + q.push(repo, reapply) + finally: + q.save_dirty() def reposetup(ui, repo): class mqrepo(repo.__class__): + def abort_if_wdir_patched(self, errmsg, force=False): + if self.mq.applied and not force: + parent = revlog.hex(self.dirstate.parents()[0]) + if parent in [s.rev for s in self.mq.applied]: + raise util.Abort(errmsg) + + def commit(self, *args, **opts): + if len(args) >= 6: + force = args[5] + else: + force = opts.get('force') + self.abort_if_wdir_patched( + _('cannot commit over an applied mq patch'), + force) + + return super(mqrepo, self).commit(*args, **opts) + + def push(self, remote, force=False, revs=None): + if self.mq.applied and not force: + raise util.Abort(_('source has mq patches applied')) + return super(mqrepo, self).push(remote, force, revs) + def tags(self): if self.tagscache: return self.tagscache @@ -1813,8 +1889,9 @@ return tagscache - repo.__class__ = mqrepo - repo.mq = queue(ui, repo.join("")) + if repo.local(): + repo.__class__ = mqrepo + repo.mq = queue(ui, repo.join("")) cmdtable = { "qapplied": (applied, [], 'hg qapplied [PATCH]'), @@ -1833,14 +1910,14 @@ commands.table["^commit|ci"][1], 'hg qcommit [OPTION]... [FILE]...'), "^qdiff": (diff, [], 'hg qdiff [FILE]...'), - "qdelete": + "qdelete|qremove|qrm": (delete, - [('f', 'force', None, _('delete patch file'))], - 'hg qdelete [-f] PATCH'), + [('k', 'keep', None, _('keep patch file'))], + 'hg qdelete [-k] PATCH'), 'qfold': (fold, [('e', 'edit', None, _('edit patch header')), - ('f', 'force', None, _('delete folded patch files')), + ('k', 'keep', None, _('keep folded patch files')), ('m', 'message', '', _('set patch header to ')), ('l', 'logfile', '', _('set patch header to contents of '))], 'hg qfold [-e] [-m ] [-l 0 and len(difflines) > maxdiff: self.sio.write(_('\ndiffs (truncated from %d to %d lines):\n\n') % diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/archival.py --- a/mercurial/archival.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/archival.py Tue Aug 15 11:22:29 2006 +0200 @@ -163,11 +163,12 @@ change = repo.changelog.read(node) mn = change[0] archiver = archivers[kind](dest, prefix, mtime or change[2][0]) - mf = repo.manifest.read(mn).items() - mf.sort() + m = repo.manifest.read(mn) + items = m.items() + items.sort() write('.hg_archival.txt', 0644, 'repo: %s\nnode: %s\n' % (hex(repo.changelog.node(0)), hex(node))) - for filename, filenode in mf: - write(filename, mf.execf(filename) and 0755 or 0644, + for filename, filenode in items: + write(filename, m.execf(filename) and 0755 or 0644, repo.file(filename).read(filenode)) archiver.done() diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/bdiff.c --- a/mercurial/bdiff.c Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/bdiff.c Tue Aug 15 11:22:29 2006 +0200 @@ -1,7 +1,7 @@ /* bdiff.c - efficient binary diff extension for Mercurial - Copyright 2005 Matt Mackall + Copyright 2005, 2006 Matt Mackall This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/changelog.py --- a/mercurial/changelog.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/changelog.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,6 +1,6 @@ # changelog.py - changelog class for mercurial # -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/cmdutil.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial/cmdutil.py Tue Aug 15 11:22:29 2006 +0200 @@ -0,0 +1,111 @@ +# commands.py - command processing for mercurial +# +# Copyright 2005, 2006 Matt Mackall +# +# This software may be used and distributed according to the terms +# of the GNU General Public License, incorporated herein by reference. + +from demandload import demandload +from node import * +from i18n import gettext as _ +demandload(globals(), 'util') +demandload(globals(), 'os sys') + +def make_filename(repo, pat, node, + total=None, seqno=None, revwidth=None, pathname=None): + node_expander = { + 'H': lambda: hex(node), + 'R': lambda: str(repo.changelog.rev(node)), + 'h': lambda: short(node), + } + expander = { + '%': lambda: '%', + 'b': lambda: os.path.basename(repo.root), + } + + try: + if node: + expander.update(node_expander) + if node and revwidth is not None: + expander['r'] = (lambda: + str(repo.changelog.rev(node)).zfill(revwidth)) + if total is not None: + expander['N'] = lambda: str(total) + if seqno is not None: + expander['n'] = lambda: str(seqno) + if total is not None and seqno is not None: + expander['n'] = lambda:str(seqno).zfill(len(str(total))) + if pathname is not None: + expander['s'] = lambda: os.path.basename(pathname) + expander['d'] = lambda: os.path.dirname(pathname) or '.' + expander['p'] = lambda: pathname + + newname = [] + patlen = len(pat) + i = 0 + while i < patlen: + c = pat[i] + if c == '%': + i += 1 + c = pat[i] + c = expander[c]() + newname.append(c) + i += 1 + return ''.join(newname) + except KeyError, inst: + raise util.Abort(_("invalid format spec '%%%s' in output file name"), + inst.args[0]) + +def make_file(repo, pat, node=None, + total=None, seqno=None, revwidth=None, mode='wb', pathname=None): + if not pat or pat == '-': + return 'w' in mode and sys.stdout or sys.stdin + if hasattr(pat, 'write') and 'w' in mode: + return pat + if hasattr(pat, 'read') and 'r' in mode: + return pat + return open(make_filename(repo, pat, node, total, seqno, revwidth, + pathname), + mode) + +def matchpats(repo, pats=[], opts={}, head=''): + cwd = repo.getcwd() + if not pats and cwd: + opts['include'] = [os.path.join(cwd, i) + for i in opts.get('include', [])] + opts['exclude'] = [os.path.join(cwd, x) + for x in opts.get('exclude', [])] + cwd = '' + return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'), + opts.get('exclude'), head) + +def makewalk(repo, pats=[], opts={}, node=None, head='', badmatch=None): + files, matchfn, anypats = matchpats(repo, pats, opts, head) + exact = dict(zip(files, files)) + def walk(): + for src, fn in repo.walk(node=node, files=files, match=matchfn, + badmatch=badmatch): + yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact + return files, matchfn, walk() + +def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None): + files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch) + for r in results: + yield r + +def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None): + if dry_run is None: + dry_run = opts.get('dry_run') + add, remove = [], [] + for src, abs, rel, exact in walk(repo, pats, opts): + if src == 'f' and repo.dirstate.state(abs) == '?': + add.append(abs) + if repo.ui.verbose or not exact: + repo.ui.status(_('adding %s\n') % ((pats and rel) or abs)) + if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel): + remove.append(abs) + if repo.ui.verbose or not exact: + repo.ui.status(_('removing %s\n') % ((pats and rel) or abs)) + if not dry_run: + repo.add(add, wlock=wlock) + repo.remove(remove, wlock=wlock) diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/commands.py --- a/mercurial/commands.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/commands.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,6 +1,6 @@ # commands.py - command processing for mercurial # -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. @@ -10,10 +10,10 @@ from i18n import gettext as _ demandload(globals(), "os re sys signal shutil imp urllib pdb") demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo") -demandload(globals(), "fnmatch mdiff random signal tempfile time") +demandload(globals(), "fnmatch difflib patch random signal tempfile time") demandload(globals(), "traceback errno socket version struct atexit sets bz2") -demandload(globals(), "archival cStringIO changegroup email.Parser") -demandload(globals(), "hgweb.server sshserver") +demandload(globals(), "archival cStringIO changegroup") +demandload(globals(), "cmdutil hgweb.server sshserver") class UnknownCommand(Exception): """Exception raised if command is not in the command table.""" @@ -21,19 +21,10 @@ """Exception raised if command shortcut matches more than one command.""" def bail_if_changed(repo): - modified, added, removed, deleted, unknown = repo.changes() + modified, added, removed, deleted = repo.status()[:4] if modified or added or removed or deleted: raise util.Abort(_("outstanding uncommitted changes")) -def filterfiles(filters, files): - l = [x for x in files if x in filters] - - for t in filters: - if t and t[-1] != "/": - t += "/" - l += [x for x in files if x.startswith(t)] - return l - def relpath(repo, args): cwd = repo.getcwd() if cwd: @@ -59,29 +50,6 @@ (logfile, inst.strerror)) return message -def matchpats(repo, pats=[], opts={}, head=''): - cwd = repo.getcwd() - if not pats and cwd: - opts['include'] = [os.path.join(cwd, i) for i in opts['include']] - opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']] - cwd = '' - return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'), - opts.get('exclude'), head) - -def makewalk(repo, pats, opts, node=None, head='', badmatch=None): - files, matchfn, anypats = matchpats(repo, pats, opts, head) - exact = dict(zip(files, files)) - def walk(): - for src, fn in repo.walk(node=node, files=files, match=matchfn, - badmatch=badmatch): - yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact - return files, matchfn, walk() - -def walk(repo, pats, opts, node=None, head='', badmatch=None): - files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch) - for r in results: - yield r - def walkchangerevs(ui, repo, pats, opts): '''Iterate over files and the revs they changed in. @@ -124,7 +92,7 @@ windowsize *= 2 - files, matchfn, anypats = matchpats(repo, pats, opts) + files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) follow = opts.get('follow') or opts.get('follow_first') if repo.changelog.count() == 0: @@ -215,49 +183,59 @@ fncache[rev] = matches wanted[rev] = 1 - def iterate(): - class followfilter: - def __init__(self, onlyfirst=False): - self.startrev = -1 - self.roots = [] - self.onlyfirst = onlyfirst - - def match(self, rev): - def realparents(rev): - if self.onlyfirst: - return repo.changelog.parentrevs(rev)[0:1] - else: - return filter(lambda x: x != -1, repo.changelog.parentrevs(rev)) - - if self.startrev == -1: - self.startrev = rev + class followfilter: + def __init__(self, onlyfirst=False): + self.startrev = -1 + self.roots = [] + self.onlyfirst = onlyfirst + + def match(self, rev): + def realparents(rev): + if self.onlyfirst: + return repo.changelog.parentrevs(rev)[0:1] + else: + return filter(lambda x: x != -1, repo.changelog.parentrevs(rev)) + + if self.startrev == -1: + self.startrev = rev + return True + + if rev > self.startrev: + # forward: all descendants + if not self.roots: + self.roots.append(self.startrev) + for parent in realparents(rev): + if parent in self.roots: + self.roots.append(rev) + return True + else: + # backwards: all parents + if not self.roots: + self.roots.extend(realparents(self.startrev)) + if rev in self.roots: + self.roots.remove(rev) + self.roots.extend(realparents(rev)) return True - if rev > self.startrev: - # forward: all descendants - if not self.roots: - self.roots.append(self.startrev) - for parent in realparents(rev): - if parent in self.roots: - self.roots.append(rev) - return True - else: - # backwards: all parents - if not self.roots: - self.roots.extend(realparents(self.startrev)) - if rev in self.roots: - self.roots.remove(rev) - self.roots.extend(realparents(rev)) - return True - - return False - + return False + + # it might be worthwhile to do this in the iterator if the rev range + # is descending and the prune args are all within that range + for rev in opts.get('prune'): + rev = repo.changelog.rev(repo.lookup(rev)) + ff = followfilter() + stop = min(revs[0], revs[-1]) + for x in range(rev, stop-1, -1): + if ff.match(x) and wanted.has_key(x): + del wanted[x] + + def iterate(): if follow and not files: ff = followfilter(onlyfirst=opts.get('follow_first')) def want(rev): - if rev not in wanted: - return False - return ff.match(rev) + if ff.match(rev) and rev in wanted: + return True + return False else: def want(rev): return rev in wanted @@ -344,63 +322,6 @@ seen[rev] = 1 yield str(rev) -def make_filename(repo, pat, node, - total=None, seqno=None, revwidth=None, pathname=None): - node_expander = { - 'H': lambda: hex(node), - 'R': lambda: str(repo.changelog.rev(node)), - 'h': lambda: short(node), - } - expander = { - '%': lambda: '%', - 'b': lambda: os.path.basename(repo.root), - } - - try: - if node: - expander.update(node_expander) - if node and revwidth is not None: - expander['r'] = (lambda: - str(repo.changelog.rev(node)).zfill(revwidth)) - if total is not None: - expander['N'] = lambda: str(total) - if seqno is not None: - expander['n'] = lambda: str(seqno) - if total is not None and seqno is not None: - expander['n'] = lambda:str(seqno).zfill(len(str(total))) - if pathname is not None: - expander['s'] = lambda: os.path.basename(pathname) - expander['d'] = lambda: os.path.dirname(pathname) or '.' - expander['p'] = lambda: pathname - - newname = [] - patlen = len(pat) - i = 0 - while i < patlen: - c = pat[i] - if c == '%': - i += 1 - c = pat[i] - c = expander[c]() - newname.append(c) - i += 1 - return ''.join(newname) - except KeyError, inst: - raise util.Abort(_("invalid format spec '%%%s' in output file name"), - inst.args[0]) - -def make_file(repo, pat, node=None, - total=None, seqno=None, revwidth=None, mode='wb', pathname=None): - if not pat or pat == '-': - return 'w' in mode and sys.stdout or sys.stdin - if hasattr(pat, 'write') and 'w' in mode: - return pat - if hasattr(pat, 'read') and 'r' in mode: - return pat - return open(make_filename(repo, pat, node, total, seqno, revwidth, - pathname), - mode) - def write_bundle(cg, filename=None, compress=True): """Write a bundle file and return its filename. @@ -453,74 +374,6 @@ if cleanup is not None: os.unlink(cleanup) -def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always, - changes=None, text=False, opts={}): - if not node1: - node1 = repo.dirstate.parents()[0] - # reading the data for node1 early allows it to play nicely - # with repo.changes and the revlog cache. - change = repo.changelog.read(node1) - mmap = repo.manifest.read(change[0]) - date1 = util.datestr(change[2]) - - if not changes: - changes = repo.changes(node1, node2, files, match=match) - modified, added, removed, deleted, unknown = changes - if files: - modified, added, removed = map(lambda x: filterfiles(files, x), - (modified, added, removed)) - - if not modified and not added and not removed: - return - - if node2: - change = repo.changelog.read(node2) - mmap2 = repo.manifest.read(change[0]) - _date2 = util.datestr(change[2]) - def date2(f): - return _date2 - def read(f): - return repo.file(f).read(mmap2[f]) - else: - tz = util.makedate()[1] - _date2 = util.datestr() - def date2(f): - try: - return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz)) - except OSError, err: - if err.errno != errno.ENOENT: raise - return _date2 - def read(f): - return repo.wread(f) - - if ui.quiet: - r = None - else: - hexfunc = ui.verbose and hex or short - r = [hexfunc(node) for node in [node1, node2] if node] - - diffopts = ui.diffopts() - showfunc = opts.get('show_function') or diffopts['showfunc'] - ignorews = opts.get('ignore_all_space') or diffopts['ignorews'] - ignorewsamount = opts.get('ignore_space_change') or \ - diffopts['ignorewsamount'] - ignoreblanklines = opts.get('ignore_blank_lines') or \ - diffopts['ignoreblanklines'] - - all = modified + added + removed - all.sort() - for f in all: - to = None - tn = None - if f in mmap: - to = repo.file(f).read(mmap[f]) - if f not in removed: - tn = read(f) - fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text, - showfunc=showfunc, ignorews=ignorews, - ignorewsamount=ignorewsamount, - ignoreblanklines=ignoreblanklines)) - def trimuser(ui, name, rev, revcache): """trim the name of the user who committed a change""" user = revcache.get(rev) @@ -577,7 +430,7 @@ self.ui.status(_("date: %s\n") % date) if self.ui.debugflag: - files = self.repo.changes(log.parents(changenode)[0], changenode) + files = self.repo.status(log.parents(changenode)[0], changenode)[:3] for key, value in zip([_("files:"), _("files+:"), _("files-:")], files): if value: @@ -633,7 +486,7 @@ ui.write(_("Mercurial Distributed SCM (version %s)\n") % version.get_version()) ui.status(_( - "\nCopyright (C) 2005 Matt Mackall \n" + "\nCopyright (C) 2005, 2006 Matt Mackall \n" "This is free software; see the source for copying conditions. " "There is NO\nwarranty; " "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" @@ -787,7 +640,7 @@ """ names = [] - for src, abs, rel, exact in walk(repo, pats, opts): + for src, abs, rel, exact in cmdutil.walk(repo, pats, opts): if exact: if ui.verbose: ui.status(_('adding %s\n') % rel) @@ -812,22 +665,7 @@ """ ui.warn(_('(the addremove command is deprecated; use add and remove ' '--after instead)\n')) - return addremove_lock(ui, repo, pats, opts) - -def addremove_lock(ui, repo, pats, opts, wlock=None): - add, remove = [], [] - for src, abs, rel, exact in walk(repo, pats, opts): - if src == 'f' and repo.dirstate.state(abs) == '?': - add.append(abs) - if ui.verbose or not exact: - ui.status(_('adding %s\n') % ((pats and rel) or abs)) - if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel): - remove.append(abs) - if ui.verbose or not exact: - ui.status(_('removing %s\n') % ((pats and rel) or abs)) - if not opts.get('dry_run'): - repo.add(add, wlock=wlock) - repo.remove(remove, wlock=wlock) + return cmdutil.addremove(repo, pats, opts) def annotate(ui, repo, *pats, **opts): """show changeset information per file line @@ -870,7 +708,8 @@ ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0]) - for src, abs, rel, exact in walk(repo, pats, opts, node=ctx.node()): + for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, + node=ctx.node()): fctx = ctx.filectx(abs) if not opts['text'] and util.binary(fctx.data()): ui.write(_("%s: binary file\n") % ((pats and rel) or abs)) @@ -922,10 +761,10 @@ raise util.Abort(_('uncommitted merge - please provide a ' 'specific revision')) - dest = make_filename(repo, dest, node) + dest = cmdutil.make_filename(repo, dest, node) if os.path.realpath(dest) == repo.root: raise util.Abort(_('repository root cannot be destination')) - dummy, matchfn, dummy = matchpats(repo, [], opts) + dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts) kind = opts.get('type') or 'files' prefix = opts['prefix'] if dest == '-': @@ -933,7 +772,7 @@ raise util.Abort(_('cannot archive plain files to stdout')) dest = sys.stdout if not prefix: prefix = os.path.basename(repo.root) + '-%h' - prefix = make_filename(repo, prefix, node) + prefix = cmdutil.make_filename(repo, prefix, node) archival.archive(repo, dest, node, kind, not opts['no_decode'], matchfn, prefix) @@ -1037,8 +876,9 @@ %p root-relative path name of file being printed """ ctx = repo.changectx(opts['rev'] or "-1") - for src, abs, rel, exact in walk(repo, (file1,) + pats, opts, ctx.node()): - fp = make_file(repo, opts['output'], ctx.node(), pathname=abs) + for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts, + ctx.node()): + fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs) fp.write(ctx.filectx(abs).data()) def clone(ui, source, dest=None, **opts): @@ -1100,11 +940,10 @@ message = logmessage(opts) if opts['addremove']: - addremove_lock(ui, repo, pats, opts) - fns, match, anypats = matchpats(repo, pats, opts) + cmdutil.addremove(repo, pats, opts) + fns, match, anypats = cmdutil.matchpats(repo, pats, opts) if pats: - modified, added, removed, deleted, unknown = ( - repo.changes(files=fns, match=match)) + modified, added, removed = repo.status(files=fns, match=match)[:3] files = modified + added + removed else: files = [] @@ -1259,7 +1098,7 @@ copylist = [] for pat in pats: srcs = [] - for tag, abssrc, relsrc, exact in walk(repo, [pat], opts): + for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts): origsrc = okaytocopy(abssrc, relsrc, exact) if origsrc: srcs.append((origsrc, abssrc, relsrc, exact)) @@ -1476,7 +1315,7 @@ def debugwalk(ui, repo, *pats, **opts): """show how files match on given patterns""" - items = list(walk(repo, pats, opts)) + items = list(cmdutil.walk(repo, pats, opts)) if not items: return fmt = '%%s %%-%ds %%-%ds %%s' % ( @@ -1505,37 +1344,10 @@ """ node1, node2 = revpair(ui, repo, opts['rev']) - fns, matchfn, anypats = matchpats(repo, pats, opts) - - dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn, - text=opts['text'], opts=opts) - -def doexport(ui, repo, changeset, seqno, total, revwidth, opts): - node = repo.lookup(changeset) - parents = [p for p in repo.changelog.parents(node) if p != nullid] - if opts['switch_parent']: - parents.reverse() - prev = (parents and parents[0]) or nullid - change = repo.changelog.read(node) - - fp = make_file(repo, opts['output'], node, total=total, seqno=seqno, - revwidth=revwidth) - if fp != sys.stdout: - ui.note("%s\n" % fp.name) - - fp.write("# HG changeset patch\n") - fp.write("# User %s\n" % change[1]) - fp.write("# Date %d %d\n" % change[2]) - fp.write("# Node ID %s\n" % hex(node)) - fp.write("# Parent %s\n" % hex(prev)) - if len(parents) > 1: - fp.write("# Parent %s\n" % hex(parents[1])) - fp.write(change[4].rstrip()) - fp.write("\n\n") - - dodiff(fp, ui, repo, prev, node, text=opts['text']) - if fp != sys.stdout: - fp.close() + fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) + + patch.diff(repo, node1, node2, fns, match=matchfn, + opts=ui.diffopts(opts)) def export(ui, repo, *changesets, **opts): """dump the header and diffs for one or more changesets @@ -1566,15 +1378,13 @@ """ if not changesets: raise util.Abort(_("export requires at least one changeset")) - seqno = 0 revs = list(revrange(ui, repo, changesets)) - total = len(revs) - revwidth = max(map(len, revs)) - msg = len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n") - ui.note(msg) - for cset in revs: - seqno += 1 - doexport(ui, repo, cset, seqno, total, revwidth, opts) + if len(revs) > 1: + ui.note(_('exporting patches:\n')) + else: + ui.note(_('exporting patch:\n')) + patch.export(repo, map(repo.lookup, revs), template=opts['output'], + switch_parent=opts['switch_parent'], opts=ui.diffopts(opts)) def forget(ui, repo, *pats, **opts): """don't add the specified files on the next commit (DEPRECATED) @@ -1587,7 +1397,7 @@ """ ui.warn(_("(the forget command is deprecated; use revert instead)\n")) forget = [] - for src, abs, rel, exact in walk(repo, pats, opts): + for src, abs, rel, exact in cmdutil.walk(repo, pats, opts): if repo.dirstate.state(abs) == 'a': forget.append(abs) if ui.verbose or not exact: @@ -1644,42 +1454,56 @@ self.linenum = linenum self.colstart = colstart self.colend = colend + def __eq__(self, other): return self.line == other.line - def __hash__(self): - return hash(self.line) matches = {} + copies = {} def grepbody(fn, rev, body): - matches[rev].setdefault(fn, {}) + matches[rev].setdefault(fn, []) m = matches[rev][fn] for lnum, cstart, cend, line in matchlines(body): s = linestate(line, lnum, cstart, cend) - m[s] = s - - # FIXME: prev isn't used, why ? + m.append(s) + + def difflinestates(a, b): + sm = difflib.SequenceMatcher(None, a, b) + for tag, alo, ahi, blo, bhi in sm.get_opcodes(): + if tag == 'insert': + for i in range(blo, bhi): + yield ('+', b[i]) + elif tag == 'delete': + for i in range(alo, ahi): + yield ('-', a[i]) + elif tag == 'replace': + for i in range(alo, ahi): + yield ('-', a[i]) + for i in range(blo, bhi): + yield ('+', b[i]) + prev = {} ucache = {} def display(fn, rev, states, prevstates): - diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates))) - diff.sort(lambda x, y: cmp(x.linenum, y.linenum)) counts = {'-': 0, '+': 0} filerevmatches = {} - for l in diff: + if incrementing or not opts['all']: + a, b = prevstates, states + else: + a, b = states, prevstates + for change, l in difflinestates(a, b): if incrementing or not opts['all']: - change = ((l in prevstates) and '-') or '+' r = rev else: - change = ((l in states) and '-') or '+' r = prev[fn] - cols = [fn, str(rev)] + cols = [fn, str(r)] if opts['line_number']: cols.append(str(l.linenum)) if opts['all']: cols.append(change) if opts['user']: - cols.append(trimuser(ui, getchange(rev)[1], rev, - ucache)) + cols.append(trimuser(ui, getchange(r)[1], rev, + ucache)) if opts['files_with_matches']: c = (fn, rev) if c in filerevmatches: @@ -1696,10 +1520,12 @@ changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts) count = 0 incrementing = False + follow = opts.get('follow') for st, rev, fns in changeiter: if st == 'window': incrementing = rev matches.clear() + copies.clear() elif st == 'add': change = repo.changelog.read(repo.lookup(str(rev))) mf = repo.manifest.read(change[0]) @@ -1708,22 +1534,34 @@ if fn in skip: continue fstate.setdefault(fn, {}) + copies.setdefault(rev, {}) try: grepbody(fn, rev, getfile(fn).read(mf[fn])) + if follow: + copied = getfile(fn).renamed(mf[fn]) + if copied: + copies[rev][fn] = copied[0] except KeyError: pass elif st == 'iter': states = matches[rev].items() states.sort() for fn, m in states: + copy = copies[rev].get(fn) if fn in skip: + if copy: + skip[copy] = True continue if incrementing or not opts['all'] or fstate[fn]: pos, neg = display(fn, rev, m, fstate[fn]) count += pos + neg if pos and not opts['all']: skip[fn] = True + if copy: + skip[copy] = True fstate[fn] = m + if copy: + fstate[copy] = m prev[fn] = rev if not incrementing: @@ -1732,7 +1570,8 @@ for fn, state in fstate: if fn in skip: continue - display(fn, rev, {}, state) + if fn not in copies[prev[fn]]: + display(fn, rev, {}, state) return (count == 0 and 1) or 0 def heads(ui, repo, **opts): @@ -1770,7 +1609,7 @@ return hexfunc = ui.verbose and hex or short - modified, added, removed, deleted, unknown = repo.changes() + modified, added, removed, deleted = repo.status()[:4] output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]), (modified or added or removed or deleted) and "+" or "")] @@ -1814,81 +1653,23 @@ d = opts["base"] strip = opts["strip"] - mailre = re.compile(r'(?:From |[\w-]+:)') - - # attempt to detect the start of a patch - # (this heuristic is borrowed from quilt) - diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' + - 'retrieving revision [0-9]+(\.[0-9]+)*$|' + - '(---|\*\*\*)[ \t])', re.MULTILINE) - - for patch in patches: - pf = os.path.join(d, patch) - - message = None - user = None - date = None - hgpatch = False - - p = email.Parser.Parser() + wlock = repo.wlock() + lock = repo.lock() + + for p in patches: + pf = os.path.join(d, p) + if pf == '-': - msg = p.parse(sys.stdin) ui.status(_("applying patch from stdin\n")) + tmpname, message, user, date = patch.extract(ui, sys.stdin) else: - msg = p.parse(file(pf)) - ui.status(_("applying %s\n") % patch) - - fd, tmpname = tempfile.mkstemp(prefix='hg-patch-') - tmpfp = os.fdopen(fd, 'w') + ui.status(_("applying %s\n") % p) + tmpname, message, user, date = patch.extract(ui, file(pf)) + + if tmpname is None: + raise util.Abort(_('no diffs found')) + try: - message = msg['Subject'] - if message: - message = message.replace('\n\t', ' ') - ui.debug('Subject: %s\n' % message) - user = msg['From'] - if user: - ui.debug('From: %s\n' % user) - diffs_seen = 0 - ok_types = ('text/plain', 'text/x-diff', 'text/x-patch') - for part in msg.walk(): - content_type = part.get_content_type() - ui.debug('Content-Type: %s\n' % content_type) - if content_type not in ok_types: - continue - payload = part.get_payload(decode=True) - m = diffre.search(payload) - if m: - ui.debug(_('found patch at byte %d\n') % m.start(0)) - diffs_seen += 1 - hgpatch = False - fp = cStringIO.StringIO() - if message: - fp.write(message) - fp.write('\n') - for line in payload[:m.start(0)].splitlines(): - if line.startswith('# HG changeset patch'): - ui.debug(_('patch generated by hg export\n')) - hgpatch = True - # drop earlier commit message content - fp.seek(0) - fp.truncate() - elif hgpatch: - if line.startswith('# User '): - user = line[7:] - ui.debug('From: %s\n' % user) - elif line.startswith("# Date "): - date = line[7:] - if not line.startswith('# '): - fp.write(line) - fp.write('\n') - message = fp.getvalue() - if tmpfp: - tmpfp.write(payload) - if not payload.endswith('\n'): - tmpfp.write('\n') - elif not diffs_seen and message and content_type == 'text/plain': - message += '\n' + payload - if opts['message']: # pickup the cmdline msg message = opts['message'] @@ -1900,18 +1681,46 @@ message = None ui.debug(_('message:\n%s\n') % message) - tmpfp.close() - if not diffs_seen: - raise util.Abort(_('no diffs found')) - - files = util.patch(strip, tmpname, ui, cwd=repo.root) + files = patch.patch(strip, tmpname, ui, cwd=repo.root) + removes = [] if len(files) > 0: - cfiles = files + cfiles = files.keys() + copies = [] + copts = {'after': False, 'force': False} cwd = repo.getcwd() if cwd: - cfiles = [util.pathto(cwd, f) for f in files] - addremove_lock(ui, repo, cfiles, {}) - repo.commit(files, message, user, date) + cfiles = [util.pathto(cwd, f) for f in files.keys()] + for f in files: + ctype, gp = files[f] + if ctype == 'RENAME': + copies.append((gp.oldpath, gp.path, gp.copymod)) + removes.append(gp.oldpath) + elif ctype == 'COPY': + copies.append((gp.oldpath, gp.path, gp.copymod)) + elif ctype == 'DELETE': + removes.append(gp.path) + for src, dst, after in copies: + absdst = os.path.join(repo.root, dst) + if not after and os.path.exists(absdst): + raise util.Abort(_('patch creates existing file %s') % dst) + if cwd: + src, dst = [util.pathto(cwd, f) for f in (src, dst)] + copts['after'] = after + errs, copied = docopy(ui, repo, (src, dst), copts, wlock=wlock) + if errs: + raise util.Abort(errs) + if removes: + repo.remove(removes, True, wlock=wlock) + for f in files: + ctype, gp = files[f] + if gp and gp.mode: + x = gp.mode & 0100 != 0 + dst = os.path.join(repo.root, gp.path) + util.set_exec(dst, x) + cmdutil.addremove(repo, cfiles, wlock=wlock) + files = files.keys() + files.extend([r for r in removes if r not in files]) + repo.commit(files, message, user, date, wlock=wlock, lock=lock) finally: os.unlink(tmpname) @@ -1964,7 +1773,7 @@ displayer.show(changenode=n) if opts['patch']: prev = (parents and parents[0]) or nullid - dodiff(ui, ui, other, prev, n) + patch.diff(repo, other, prev, n) ui.write("\n") finally: if hasattr(other, 'close'): @@ -2012,8 +1821,8 @@ else: node = None - for src, abs, rel, exact in walk(repo, pats, opts, node=node, - head='(?:.*/|)'): + for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node, + head='(?:.*/|)'): if not node and repo.dirstate.state(abs) == '?': continue if opts['fullpath']: @@ -2115,7 +1924,7 @@ displayer.show(rev, brinfo=br) if opts['patch']: prev = (parents and parents[0]) or nullid - dodiff(du, du, repo, prev, changenode, match=matchfn) + patch.diff(repo, prev, changenode, match=matchfn, fp=du) du.write("\n\n") elif st == 'iter': if count == limit: break @@ -2196,7 +2005,7 @@ displayer.show(changenode=n) if opts['patch']: prev = (parents and parents[0]) or nullid - dodiff(ui, ui, repo, prev, n) + patch.diff(repo, prev, n) ui.write("\n") def parents(ui, repo, file_=None, rev=None, branches=None, **opts): @@ -2409,12 +2218,12 @@ names = [] if not opts['after'] and not pats: raise util.Abort(_('no files specified')) - files, matchfn, anypats = matchpats(repo, pats, opts) + files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) exact = dict.fromkeys(files) - mardu = map(dict.fromkeys, repo.changes(files=files, match=matchfn)) + mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5] modified, added, removed, deleted, unknown = mardu remove, forget = [], [] - for src, abs, rel, exact in walk(repo, pats, opts): + for src, abs, rel, exact in cmdutil.walk(repo, pats, opts): reason = None if abs not in deleted and opts['after']: reason = _('is still present') @@ -2521,20 +2330,21 @@ # walk dirstate. - for src, abs, rel, exact in walk(repo, pats, opts, badmatch=mf.has_key): + for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, + badmatch=mf.has_key): names[abs] = (rel, exact) if src == 'b': target_only[abs] = True # walk target manifest. - for src, abs, rel, exact in walk(repo, pats, opts, node=node, - badmatch=names.has_key): + for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node, + badmatch=names.has_key): if abs in names: continue names[abs] = (rel, exact) target_only[abs] = True - changes = repo.changes(match=names.has_key, wlock=wlock) + changes = repo.status(match=names.has_key, wlock=wlock)[:5] modified, added, removed, deleted, unknown = map(dict.fromkeys, changes) revert = ([], _('reverting %s\n')) @@ -2741,7 +2551,7 @@ all = opts['all'] - files, matchfn, anypats = matchpats(repo, pats, opts) + files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) cwd = (pats and repo.getcwd()) or '' modified, added, removed, deleted, unknown, ignored, clean = [ [util.pathto(cwd, x) for x in n] @@ -2844,7 +2654,7 @@ br = repo.branchlookup([n]) show_changeset(ui, repo, opts).show(changenode=n, brinfo=br) if opts['patch']: - dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n) + patch.diff(repo, repo.changelog.parents(n)[0], n) def unbundle(ui, repo, fname, **opts): """apply a changegroup file @@ -3067,6 +2877,7 @@ ('a', 'text', None, _('treat all files as text')), ('p', 'show-function', None, _('show which function each change is in')), + ('g', 'git', None, _('use git extended diff format')), ('w', 'ignore-all-space', None, _('ignore white space when comparing lines')), ('b', 'ignore-space-change', None, @@ -3091,6 +2902,8 @@ (grep, [('0', 'print0', None, _('end fields with NUL')), ('', 'all', None, _('print all revisions that match')), + ('f', 'follow', None, + _('follow changeset history, or file history across copies and renames')), ('i', 'ignore-case', None, _('ignore case when matching')), ('l', 'files-with-matches', None, _('print only filenames and revs that match')), @@ -3127,7 +2940,7 @@ ('n', 'newest-first', None, _('show newest record first')), ('', 'bundle', '', _('file to store the bundles into')), ('p', 'patch', None, _('show patch')), - ('r', 'rev', [], _('a specific revision you would like to pull')), + ('r', 'rev', [], _('a specific revision up to which you would like to pull')), ('', 'template', '', _('display with template')), ('e', 'ssh', '', _('specify ssh command to use')), ('', 'remotecmd', '', @@ -3164,6 +2977,7 @@ ('', 'style', '', _('display using template map file')), ('m', 'only-merges', None, _('show only merges')), ('p', 'patch', None, _('show patch')), + ('P', 'prune', [], _('do not display revision or any of its ancestors')), ('', 'template', '', _('display with template')), ('I', 'include', [], _('include names matching the given patterns')), ('X', 'exclude', [], _('exclude names matching the given patterns'))], @@ -3202,7 +3016,7 @@ ('e', 'ssh', '', _('specify ssh command to use')), ('f', 'force', None, _('run even when remote repository is unrelated')), - ('r', 'rev', [], _('a specific revision you would like to pull')), + ('r', 'rev', [], _('a specific revision up to which you would like to pull')), ('', 'remotecmd', '', _('specify hg command to run on the remote side'))], _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')), @@ -3545,6 +3359,7 @@ mod = sys.modules[name] if hasattr(mod, 'reposetup'): mod.reposetup(u, repo) + hg.repo_setup_hooks.append(mod.reposetup) except hg.RepoError: if cmd not in optionalrepo.split(): raise diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/context.py --- a/mercurial/context.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/context.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,6 +1,6 @@ # context.py - changeset and file context objects for mercurial # -# Copyright 2005 Matt Mackall +# Copyright 2006 Matt Mackall # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/dirstate.py --- a/mercurial/dirstate.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/dirstate.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,7 +1,7 @@ """ dirstate.py - working directory tracking for mercurial -Copyright 2005 Matt Mackall +Copyright 2005, 2006 Matt Mackall This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/filelog.py --- a/mercurial/filelog.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/filelog.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,6 +1,6 @@ # filelog.py - file history class for mercurial # -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/hg.py --- a/mercurial/hg.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/hg.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,6 +1,7 @@ # hg.py - repository classes for mercurial # -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall +# Copyright 2006 Vadim Gelfer # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. @@ -48,9 +49,14 @@ return False return repo.local() +repo_setup_hooks = [] + def repository(ui, path=None, create=False): """return a repository object for the specified path""" - return _lookup(path).instance(ui, path, create) + repo = _lookup(path).instance(ui, path, create) + for hook in repo_setup_hooks: + hook(ui, repo) + return repo def defaultdest(source): '''return default destination of clone if none is given''' diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/hgweb/common.py --- a/mercurial/hgweb/common.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/hgweb/common.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,7 +1,7 @@ # hgweb/common.py - Utility functions needed by hgweb_mod and hgwebdir_mod # # Copyright 21 May 2005 - (c) 2005 Jake Edge -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/hgweb/hgweb_mod.py --- a/mercurial/hgweb/hgweb_mod.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/hgweb/hgweb_mod.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,7 +1,7 @@ # hgweb/hgweb_mod.py - Web interface for a repository. # # Copyright 21 May 2005 - (c) 2005 Jake Edge -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. @@ -129,37 +129,27 @@ date1 = util.datestr(change1[2]) date2 = util.datestr(change2[2]) - modified, added, removed, deleted, unknown = r.changes(node1, node2) + modified, added, removed, deleted, unknown = r.status(node1, node2)[:5] if files: modified, added, removed = map(lambda x: filterfiles(files, x), (modified, added, removed)) diffopts = self.repo.ui.diffopts() - showfunc = diffopts['showfunc'] - ignorews = diffopts['ignorews'] - ignorewsamount = diffopts['ignorewsamount'] - ignoreblanklines = diffopts['ignoreblanklines'] for f in modified: to = r.file(f).read(mmap1[f]) tn = r.file(f).read(mmap2[f]) yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, - showfunc=showfunc, ignorews=ignorews, - ignorewsamount=ignorewsamount, - ignoreblanklines=ignoreblanklines), f, tn) + opts=diffopts), f, tn) for f in added: to = None tn = r.file(f).read(mmap2[f]) yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, - showfunc=showfunc, ignorews=ignorews, - ignorewsamount=ignorewsamount, - ignoreblanklines=ignoreblanklines), f, tn) + opts=diffopts), f, tn) for f in removed: to = r.file(f).read(mmap1[f]) tn = None yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, - showfunc=showfunc, ignorews=ignorews, - ignorewsamount=ignorewsamount, - ignoreblanklines=ignoreblanklines), f, tn) + opts=diffopts), f, tn) def changelog(self, pos, shortlog=False): def changenav(**map): @@ -398,7 +388,7 @@ parent=self.siblings(fl.parents(n), fl.rev, file=f), child=self.siblings(fl.children(n), fl.rev, file=f), rename=self.renamelink(fl, n), - permissions=self.repo.manifest.read(mfn).execf[f]) + permissions=self.repo.manifest.read(mfn).execf(f)) def fileannotate(self, f, node): bcache = {} @@ -452,7 +442,7 @@ rename=self.renamelink(fl, n), parent=self.siblings(fl.parents(n), fl.rev, file=f), child=self.siblings(fl.children(n), fl.rev, file=f), - permissions=self.repo.manifest.read(mfn).execf[f]) + permissions=self.repo.manifest.read(mfn).execf(f)) def manifest(self, mnode, path): man = self.repo.manifest @@ -495,7 +485,7 @@ "filenode": hex(fnode), "parity": self.stripes(parity), "basename": f, - "permissions": mf.execf[full]} + "permissions": mf.execf(full)} parity += 1 def dirlist(**map): diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/hgweb/hgwebdir_mod.py --- a/mercurial/hgweb/hgwebdir_mod.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/hgweb/hgwebdir_mod.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,7 +1,7 @@ # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories. # # Copyright 21 May 2005 - (c) 2005 Jake Edge -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/hgweb/request.py --- a/mercurial/hgweb/request.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/hgweb/request.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,7 +1,7 @@ # hgweb/request.py - An http request from either CGI or the standalone server. # # Copyright 21 May 2005 - (c) 2005 Jake Edge -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/hgweb/server.py --- a/mercurial/hgweb/server.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/hgweb/server.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,7 +1,7 @@ # hgweb/server.py - The standalone hg web server. # # Copyright 21 May 2005 - (c) 2005 Jake Edge -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/httprangereader.py --- a/mercurial/httprangereader.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/httprangereader.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,6 +1,6 @@ # httprangereader.py - just what it says # -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/httprepo.py --- a/mercurial/httprepo.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/httprepo.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,6 +1,7 @@ # httprepo.py - HTTP repository proxy classes for mercurial # -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall +# Copyright 2006 Vadim Gelfer # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/i18n.py --- a/mercurial/i18n.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/i18n.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,7 +1,7 @@ """ i18n.py - internationalization support for mercurial -Copyright 2005 Matt Mackall +Copyright 2005, 2006 Matt Mackall This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/localrepo.py --- a/mercurial/localrepo.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/localrepo.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,6 +1,6 @@ # localrepo.py - read/write repository class for mercurial # -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. @@ -198,7 +198,7 @@ self.hook('tag', node=node, tag=name, local=local) return - for x in self.changes(): + for x in self.status()[:5]: if '.hgtags' in x: raise util.Abort(_('working copy of .hgtags is changed ' '(please commit .hgtags manually)')) @@ -502,7 +502,6 @@ except IOError: try: del m1[f] - del m1[f] if update_dirstate: self.dirstate.forget([f]) except: @@ -533,7 +532,7 @@ else: self.ui.warn(_("%s not tracked!\n") % f) else: - modified, added, removed, deleted, unknown = self.changes(match=match) + modified, added, removed, deleted, unknown = self.status(match=match)[:5] commit = modified + added remove = removed @@ -752,16 +751,6 @@ l.sort() return (modified, added, removed, deleted, unknown, ignored, clean) - def changes(self, node1=None, node2=None, files=[], match=util.always, - wlock=None, list_ignored=False, list_clean=False): - '''DEPRECATED - use status instead''' - marduit = self.status(node1, node2, files, match, wlock, - list_ignored, list_clean) - if list_ignored: - return marduit[:-1] - else: - return marduit[:-2] - def add(self, list, wlock=None): if not wlock: wlock = self.wlock() diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/lock.py --- a/mercurial/lock.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/lock.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,6 +1,6 @@ # lock.py - simple locking scheme for mercurial # -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/manifest.py --- a/mercurial/manifest.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/manifest.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,6 +1,6 @@ # manifest.py - manifest revision class for mercurial # -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. @@ -11,7 +11,9 @@ demandload(globals(), "array bisect struct") class manifestdict(dict): - def __init__(self, mapping={}, flags={}): + def __init__(self, mapping=None, flags=None): + if mapping is None: mapping = {} + if flags is None: flags = {} dict.__init__(self, mapping) self._flags = flags def flags(self, f): @@ -27,8 +29,9 @@ fl = entry[40:-1] if fl: self._flags[f] = fl def set(self, f, execf=False, linkf=False): - if execf: self._flags[f] = "x" - if linkf: self._flags[f] = "x" + if linkf: self._flags[f] = "l" + elif execf: self._flags[f] = "x" + else: self._flags[f] = "" def copy(self): return manifestdict(dict.copy(self), dict.copy(self._flags)) diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/mdiff.py --- a/mercurial/mdiff.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/mdiff.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,6 +1,6 @@ # mdiff.py - diff and patch routines for mercurial # -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. @@ -19,14 +19,41 @@ lines[-1] = lines[-1][:-1] return lines -def unidiff(a, ad, b, bd, fn, r=None, text=False, - showfunc=False, ignorews=False, ignorewsamount=False, - ignoreblanklines=False): +class diffopts(object): + '''context is the number of context lines + text treats all files as text + showfunc enables diff -p output + git enables the git extended patch format + ignorews ignores all whitespace changes in the diff + ignorewsamount ignores changes in the amount of whitespace + ignoreblanklines ignores changes whose lines are all blank''' + defaults = { + 'context': 3, + 'text': False, + 'showfunc': True, + 'git': False, + 'ignorews': False, + 'ignorewsamount': False, + 'ignoreblanklines': False, + } + + __slots__ = defaults.keys() + + def __init__(self, **opts): + for k in self.__slots__: + v = opts.get(k) + if v is None: + v = self.defaults[k] + setattr(self, k, v) + +defaultopts = diffopts() + +def unidiff(a, ad, b, bd, fn, r=None, opts=defaultopts): if not a and not b: return "" epoch = util.datestr((0, 0)) - if not text and (util.binary(a) or util.binary(b)): + if not opts.text and (util.binary(a) or util.binary(b)): l = ['Binary file %s has changed\n' % fn] elif not a: b = splitnewlines(b) @@ -49,10 +76,7 @@ else: al = splitnewlines(a) bl = splitnewlines(b) - l = list(bunidiff(a, b, al, bl, "a/" + fn, "b/" + fn, - showfunc=showfunc, ignorews=ignorews, - ignorewsamount=ignorewsamount, - ignoreblanklines=ignoreblanklines)) + l = list(bunidiff(a, b, al, bl, "a/" + fn, "b/" + fn, opts=opts)) if not l: return "" # difflib uses a space, rather than a tab l[0] = "%s\t%s\n" % (l[0][:-2], ad) @@ -72,21 +96,15 @@ # t1 and t2 are the text to be diffed # l1 and l2 are the text broken up into lines # header1 and header2 are the filenames for the diff output -# context is the number of context lines -# showfunc enables diff -p output -# ignorews ignores all whitespace changes in the diff -# ignorewsamount ignores changes in the amount of whitespace -# ignoreblanklines ignores changes whose lines are all blank -def bunidiff(t1, t2, l1, l2, header1, header2, context=3, showfunc=False, - ignorews=False, ignorewsamount=False, ignoreblanklines=False): +def bunidiff(t1, t2, l1, l2, header1, header2, opts=defaultopts): def contextend(l, len): - ret = l + context + ret = l + opts.context if ret > len: ret = len return ret def contextstart(l): - ret = l - context + ret = l - opts.context if ret < 0: return 0 return ret @@ -101,7 +119,7 @@ blen = b2 - bstart + aend - a2 func = "" - if showfunc: + if opts.showfunc: # walk backwards from the start of the context # to find a line starting with an alphanumeric char. for x in xrange(astart, -1, -1): @@ -119,14 +137,14 @@ header = [ "--- %s\t\n" % header1, "+++ %s\t\n" % header2 ] - if showfunc: + if opts.showfunc: funcre = re.compile('\w') - if ignorewsamount: + if opts.ignorewsamount: wsamountre = re.compile('[ \t]+') wsappendedre = re.compile(' \n') - if ignoreblanklines: + if opts.ignoreblanklines: wsblanklinesre = re.compile('\n') - if ignorews: + if opts.ignorews: wsre = re.compile('[ \t]') # bdiff.blocks gives us the matching sequences in the files. The loop @@ -159,13 +177,13 @@ if not old and not new: continue - if ignoreblanklines: + if opts.ignoreblanklines: wsold = wsblanklinesre.sub('', "".join(old)) wsnew = wsblanklinesre.sub('', "".join(new)) if wsold == wsnew: continue - if ignorewsamount: + if opts.ignorewsamount: wsold = wsamountre.sub(' ', "".join(old)) wsold = wsappendedre.sub('\n', wsold) wsnew = wsamountre.sub(' ', "".join(new)) @@ -173,7 +191,7 @@ if wsold == wsnew: continue - if ignorews: + if opts.ignorews: wsold = wsre.sub('', "".join(old)) wsnew = wsre.sub('', "".join(new)) if wsold == wsnew: @@ -184,7 +202,7 @@ prev = None if hunk: # join with the previous hunk if it falls inside the context - if astart < hunk[1] + context + 1: + if astart < hunk[1] + opts.context + 1: prev = hunk astart = hunk[1] bstart = hunk[3] diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/merge.py --- a/mercurial/merge.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/merge.py Tue Aug 15 11:22:29 2006 +0200 @@ -75,7 +75,7 @@ raise util.Abort(_("update spans branches, use 'hg merge' " "or 'hg update -C' to lose changes")) - modified, added, removed, deleted, unknown = repo.changes() + modified, added, removed, deleted, unknown = repo.status()[:5] if branchmerge and not forcemerge: if modified or added or removed: raise util.Abort(_("outstanding uncommitted changes")) diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/mpatch.c --- a/mercurial/mpatch.c Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/mpatch.c Tue Aug 15 11:22:29 2006 +0200 @@ -14,7 +14,7 @@ allocation of intermediate Python objects. Working memory is about 2x the total number of hunks. - Copyright 2005 Matt Mackall + Copyright 2005, 2006 Matt Mackall This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/node.py --- a/mercurial/node.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/node.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,7 +1,7 @@ """ node.py - basic nodeid manipulation for mercurial -Copyright 2005 Matt Mackall +Copyright 2005, 2006 Matt Mackall This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/packagescan.py --- a/mercurial/packagescan.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/packagescan.py Tue Aug 15 11:22:29 2006 +0200 @@ -2,7 +2,7 @@ # Used for the py2exe distutil. # This module must be the first mercurial module imported in setup.py # -# Copyright 2005 Volker Kleinfeld +# Copyright 2005, 2006 Volker Kleinfeld # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/patch.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial/patch.py Tue Aug 15 11:22:29 2006 +0200 @@ -0,0 +1,419 @@ +# patch.py - patch file parsing routines +# +# Copyright 2006 Brendan Cully +# +# This software may be used and distributed according to the terms +# of the GNU General Public License, incorporated herein by reference. + +from demandload import demandload +from i18n import gettext as _ +from node import * +demandload(globals(), "cmdutil mdiff util") +demandload(globals(), "cStringIO email.Parser os re shutil sys tempfile") + +def extract(ui, fileobj): + '''extract patch from data read from fileobj. + + patch can be normal patch or contained in email message. + + return tuple (filename, message, user, date). any item in returned + tuple can be None. if filename is None, fileobj did not contain + patch. caller must unlink filename when done.''' + + # attempt to detect the start of a patch + # (this heuristic is borrowed from quilt) + diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' + + 'retrieving revision [0-9]+(\.[0-9]+)*$|' + + '(---|\*\*\*)[ \t])', re.MULTILINE) + + fd, tmpname = tempfile.mkstemp(prefix='hg-patch-') + tmpfp = os.fdopen(fd, 'w') + try: + hgpatch = False + + msg = email.Parser.Parser().parse(fileobj) + + message = msg['Subject'] + user = msg['From'] + # should try to parse msg['Date'] + date = None + + if message: + message = message.replace('\n\t', ' ') + ui.debug('Subject: %s\n' % message) + if user: + ui.debug('From: %s\n' % user) + diffs_seen = 0 + ok_types = ('text/plain', 'text/x-diff', 'text/x-patch') + + for part in msg.walk(): + content_type = part.get_content_type() + ui.debug('Content-Type: %s\n' % content_type) + if content_type not in ok_types: + continue + payload = part.get_payload(decode=True) + m = diffre.search(payload) + if m: + ui.debug(_('found patch at byte %d\n') % m.start(0)) + diffs_seen += 1 + cfp = cStringIO.StringIO() + if message: + cfp.write(message) + cfp.write('\n') + for line in payload[:m.start(0)].splitlines(): + if line.startswith('# HG changeset patch'): + ui.debug(_('patch generated by hg export\n')) + hgpatch = True + # drop earlier commit message content + cfp.seek(0) + cfp.truncate() + elif hgpatch: + if line.startswith('# User '): + user = line[7:] + ui.debug('From: %s\n' % user) + elif line.startswith("# Date "): + date = line[7:] + if not line.startswith('# '): + cfp.write(line) + cfp.write('\n') + message = cfp.getvalue() + if tmpfp: + tmpfp.write(payload) + if not payload.endswith('\n'): + tmpfp.write('\n') + elif not diffs_seen and message and content_type == 'text/plain': + message += '\n' + payload + except: + tmpfp.close() + os.unlink(tmpname) + raise + + tmpfp.close() + if not diffs_seen: + os.unlink(tmpname) + return None, message, user, date + return tmpname, message, user, date + +def readgitpatch(patchname): + """extract git-style metadata about patches from """ + class gitpatch: + "op is one of ADD, DELETE, RENAME, MODIFY or COPY" + def __init__(self, path): + self.path = path + self.oldpath = None + self.mode = None + self.op = 'MODIFY' + self.copymod = False + self.lineno = 0 + + # Filter patch for git information + gitre = re.compile('diff --git a/(.*) b/(.*)') + pf = file(patchname) + gp = None + gitpatches = [] + # Can have a git patch with only metadata, causing patch to complain + dopatch = False + + lineno = 0 + for line in pf: + lineno += 1 + if line.startswith('diff --git'): + m = gitre.match(line) + if m: + if gp: + gitpatches.append(gp) + src, dst = m.group(1,2) + gp = gitpatch(dst) + gp.lineno = lineno + elif gp: + if line.startswith('--- '): + if gp.op in ('COPY', 'RENAME'): + gp.copymod = True + dopatch = 'filter' + gitpatches.append(gp) + gp = None + if not dopatch: + dopatch = True + continue + if line.startswith('rename from '): + gp.op = 'RENAME' + gp.oldpath = line[12:].rstrip() + elif line.startswith('rename to '): + gp.path = line[10:].rstrip() + elif line.startswith('copy from '): + gp.op = 'COPY' + gp.oldpath = line[10:].rstrip() + elif line.startswith('copy to '): + gp.path = line[8:].rstrip() + elif line.startswith('deleted file'): + gp.op = 'DELETE' + elif line.startswith('new file mode '): + gp.op = 'ADD' + gp.mode = int(line.rstrip()[-3:], 8) + elif line.startswith('new mode '): + gp.mode = int(line.rstrip()[-3:], 8) + if gp: + gitpatches.append(gp) + + if not gitpatches: + dopatch = True + + return (dopatch, gitpatches) + +def dogitpatch(patchname, gitpatches): + """Preprocess git patch so that vanilla patch can handle it""" + pf = file(patchname) + pfline = 1 + + fd, patchname = tempfile.mkstemp(prefix='hg-patch-') + tmpfp = os.fdopen(fd, 'w') + + try: + for i in range(len(gitpatches)): + p = gitpatches[i] + if not p.copymod: + continue + + if os.path.exists(p.path): + raise util.Abort(_("cannot create %s: destination already exists") % + p.path) + + (src, dst) = [os.path.join(os.getcwd(), n) + for n in (p.oldpath, p.path)] + + targetdir = os.path.dirname(dst) + if not os.path.isdir(targetdir): + os.makedirs(targetdir) + try: + shutil.copyfile(src, dst) + shutil.copymode(src, dst) + except shutil.Error, inst: + raise util.Abort(str(inst)) + + # rewrite patch hunk + while pfline < p.lineno: + tmpfp.write(pf.readline()) + pfline += 1 + tmpfp.write('diff --git a/%s b/%s\n' % (p.path, p.path)) + line = pf.readline() + pfline += 1 + while not line.startswith('--- a/'): + tmpfp.write(line) + line = pf.readline() + pfline += 1 + tmpfp.write('--- a/%s\n' % p.path) + + line = pf.readline() + while line: + tmpfp.write(line) + line = pf.readline() + except: + tmpfp.close() + os.unlink(patchname) + raise + + tmpfp.close() + return patchname + +def patch(strip, patchname, ui, cwd=None): + """apply the patch to the working directory. + a list of patched files is returned""" + + (dopatch, gitpatches) = readgitpatch(patchname) + + files = {} + if dopatch: + if dopatch == 'filter': + patchname = dogitpatch(patchname, gitpatches) + patcher = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch') + args = [] + if cwd: + args.append('-d %s' % util.shellquote(cwd)) + fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip, + util.shellquote(patchname))) + + if dopatch == 'filter': + False and os.unlink(patchname) + + for line in fp: + line = line.rstrip() + ui.status("%s\n" % line) + if line.startswith('patching file '): + pf = util.parse_patch_output(line) + files.setdefault(pf, (None, None)) + code = fp.close() + if code: + raise util.Abort(_("patch command failed: %s") % + util.explain_exit(code)[0]) + + for gp in gitpatches: + files[gp.path] = (gp.op, gp) + + return files + +def diff(repo, node1=None, node2=None, files=None, match=util.always, + fp=None, changes=None, opts=None): + '''print diff of changes to files between two nodes, or node and + working directory. + + if node1 is None, use first dirstate parent instead. + if node2 is None, compare node1 with working directory.''' + + if opts is None: + opts = mdiff.defaultopts + if fp is None: + fp = repo.ui + + if not node1: + node1 = repo.dirstate.parents()[0] + # reading the data for node1 early allows it to play nicely + # with repo.status and the revlog cache. + change = repo.changelog.read(node1) + mmap = repo.manifest.read(change[0]) + date1 = util.datestr(change[2]) + + if not changes: + changes = repo.status(node1, node2, files, match=match)[:5] + modified, added, removed, deleted, unknown = changes + if files: + def filterfiles(filters): + l = [x for x in filters if x in files] + + for t in files: + if not t.endswith("/"): + t += "/" + l += [x for x in filters if x.startswith(t)] + return l + + modified, added, removed = map(filterfiles, (modified, added, removed)) + + if not modified and not added and not removed: + return + + if node2: + change = repo.changelog.read(node2) + mmap2 = repo.manifest.read(change[0]) + _date2 = util.datestr(change[2]) + def date2(f): + return _date2 + def read(f): + return repo.file(f).read(mmap2[f]) + def renamed(f): + src = repo.file(f).renamed(mmap2[f]) + return src and src[0] or None + else: + tz = util.makedate()[1] + _date2 = util.datestr() + def date2(f): + try: + return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz)) + except OSError, err: + if err.errno != errno.ENOENT: raise + return _date2 + def read(f): + return repo.wread(f) + def renamed(f): + return repo.dirstate.copies.get(f) + + if repo.ui.quiet: + r = None + else: + hexfunc = repo.ui.verbose and hex or short + r = [hexfunc(node) for node in [node1, node2] if node] + + if opts.git: + copied = {} + for f in added: + src = renamed(f) + if src: + copied[f] = src + srcs = [x[1] for x in copied.items()] + + all = modified + added + removed + all.sort() + for f in all: + to = None + tn = None + dodiff = True + if f in mmap: + to = repo.file(f).read(mmap[f]) + if f not in removed: + tn = read(f) + if opts.git: + def gitmode(x): + return x and '100755' or '100644' + def addmodehdr(header, omode, nmode): + if omode != nmode: + header.append('old mode %s\n' % omode) + header.append('new mode %s\n' % nmode) + + a, b = f, f + header = [] + if f in added: + if node2: + mode = gitmode(mmap2.execf(f)) + else: + mode = gitmode(util.is_exec(repo.wjoin(f), None)) + if f in copied: + a = copied[f] + omode = gitmode(mmap.execf(a)) + addmodehdr(header, omode, mode) + op = a in removed and 'rename' or 'copy' + header.append('%s from %s\n' % (op, a)) + header.append('%s to %s\n' % (op, f)) + to = repo.file(a).read(mmap[a]) + else: + header.append('new file mode %s\n' % mode) + elif f in removed: + if f in srcs: + dodiff = False + else: + mode = gitmode(mmap.execf(f)) + header.append('deleted file mode %s\n' % mode) + else: + omode = gitmode(mmap.execf(f)) + nmode = gitmode(util.is_exec(repo.wjoin(f), mmap.execf(f))) + addmodehdr(header, omode, nmode) + r = None + if dodiff: + header.insert(0, 'diff --git a/%s b/%s\n' % (a, b)) + fp.write(''.join(header)) + if dodiff: + fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, opts=opts)) + +def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False, + opts=None): + '''export changesets as hg patches.''' + + total = len(revs) + revwidth = max(map(len, revs)) + + def single(node, seqno, fp): + parents = [p for p in repo.changelog.parents(node) if p != nullid] + if switch_parent: + parents.reverse() + prev = (parents and parents[0]) or nullid + change = repo.changelog.read(node) + + if not fp: + fp = cmdutil.make_file(repo, template, node, total=total, + seqno=seqno, revwidth=revwidth) + if fp not in (sys.stdout, repo.ui): + repo.ui.note("%s\n" % fp.name) + + fp.write("# HG changeset patch\n") + fp.write("# User %s\n" % change[1]) + fp.write("# Date %d %d\n" % change[2]) + fp.write("# Node ID %s\n" % hex(node)) + fp.write("# Parent %s\n" % hex(prev)) + if len(parents) > 1: + fp.write("# Parent %s\n" % hex(parents[1])) + fp.write(change[4].rstrip()) + fp.write("\n\n") + + diff(repo, prev, node, fp=fp, opts=opts) + if fp not in (sys.stdout, repo.ui): + fp.close() + + for seqno, cset in enumerate(revs): + single(cset, seqno, fp) diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/remoterepo.py --- a/mercurial/remoterepo.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/remoterepo.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,6 +1,6 @@ -# remoterepo - remote repositort proxy classes for mercurial +# remoterepo - remote repository proxy classes for mercurial # -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/repo.py --- a/mercurial/repo.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/repo.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,6 +1,7 @@ # repo.py - repository base classes for mercurial # # Copyright 2005 Matt Mackall +# Copyright 2006 Vadim Gelfer # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/revlog.py --- a/mercurial/revlog.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/revlog.py Tue Aug 15 11:22:29 2006 +0200 @@ -4,7 +4,7 @@ This provides efficient delta storage with O(1) retrieve and append and O(changes) merge between branches -Copyright 2005 Matt Mackall +Copyright 2005, 2006 Matt Mackall This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/sshrepo.py --- a/mercurial/sshrepo.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/sshrepo.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,6 +1,6 @@ # sshrepo.py - ssh repository proxy class for mercurial # -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/sshserver.py --- a/mercurial/sshserver.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/sshserver.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,6 +1,7 @@ # sshserver.py - ssh protocol server support for mercurial # # Copyright 2005 Matt Mackall +# Copyright 2006 Vadim Gelfer # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/statichttprepo.py --- a/mercurial/statichttprepo.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/statichttprepo.py Tue Aug 15 11:22:29 2006 +0200 @@ -2,7 +2,7 @@ # # This provides read-only repo access to repositories exported via static http # -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/templater.py --- a/mercurial/templater.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/templater.py Tue Aug 15 11:22:29 2006 +0200 @@ -459,7 +459,7 @@ yield x if self.ui.debugflag: - files = self.repo.changes(log.parents(changenode)[0], changenode) + files = self.repo.status(log.parents(changenode)[0], changenode)[:3] def showfiles(**args): for x in showlist('file', files[0], **args): yield x def showadds(**args): diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/transaction.py --- a/mercurial/transaction.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/transaction.py Tue Aug 15 11:22:29 2006 +0200 @@ -6,7 +6,7 @@ # effectively log-structured, this should amount to simply truncating # anything that isn't referenced in the changelog. # -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/ui.py --- a/mercurial/ui.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/ui.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,6 +1,6 @@ # ui.py - user interface bits for mercurial # -# Copyright 2005 Matt Mackall +# Copyright 2005, 2006 Matt Mackall # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. @@ -8,7 +8,7 @@ from i18n import gettext as _ from demandload import * demandload(globals(), "errno getpass os re smtplib socket sys tempfile") -demandload(globals(), "ConfigParser templater traceback util") +demandload(globals(), "ConfigParser mdiff templater traceback util") class ui(object): def __init__(self, verbose=False, debug=False, quiet=False, @@ -169,16 +169,19 @@ result[key.lower()] = value return result - def diffopts(self): - if self.diffcache: - return self.diffcache - result = {'showfunc': True, 'ignorews': False, - 'ignorewsamount': False, 'ignoreblanklines': False} - for key, value in self.configitems("diff"): - if value: - result[key.lower()] = (value.lower() == 'true') - self.diffcache = result - return result + def diffopts(self, opts={}): + return mdiff.diffopts( + text=opts.get('text'), + showfunc=(opts.get('show_function') or + self.configbool('diff', 'showfunc', None)), + git=(opts.get('git') or + self.configbool('diff', 'git', None)), + ignorews=(opts.get('ignore_all_space') or + self.configbool('diff', 'ignorews', None)), + ignorewsamount=(opts.get('ignore_space_change') or + self.configbool('diff', 'ignorewsamount', None)), + ignoreblanklines=(opts.get('ignore_blank_lines') or + self.configbool('diff', 'ignoreblanklines', None))) def username(self): """Return default username to be used in commits. diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/util.py --- a/mercurial/util.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/util.py Tue Aug 15 11:22:29 2006 +0200 @@ -2,6 +2,8 @@ util.py - Mercurial utility functions and platform specfic implementations Copyright 2005 K. Thananchayan + Copyright 2005, 2006 Matt Mackall + Copyright 2006 Vadim Gelfer This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. @@ -93,27 +95,6 @@ return p_name return default -def patch(strip, patchname, ui, cwd=None): - """apply the patch to the working directory. - a list of patched files is returned""" - patcher = find_in_path('gpatch', os.environ.get('PATH', ''), 'patch') - args = [] - if cwd: - args.append('-d %s' % shellquote(cwd)) - fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip, - shellquote(patchname))) - files = {} - for line in fp: - line = line.rstrip() - ui.status("%s\n" % line) - if line.startswith('patching file '): - pf = parse_patch_output(line) - files.setdefault(pf, 1) - code = fp.close() - if code: - raise Abort(_("patch command failed: %s") % explain_exit(code)[0]) - return files.keys() - def binary(s): """return true if a string is binary data using diff's heuristic""" if s and '\0' in s[:4096]: @@ -1014,3 +995,4 @@ if path.startswith('//'): path = path[2:] return path + diff -r 2497fa1c6b76 -r 75bcb8210a37 mercurial/version.py --- a/mercurial/version.py Tue Aug 15 05:12:27 2006 -0400 +++ b/mercurial/version.py Tue Aug 15 11:22:29 2006 +0200 @@ -1,4 +1,4 @@ -# Copyright (C) 2005 by Intevation GmbH +# Copyright (C) 2005, 2006 by Intevation GmbH # Author(s): # Thomas Arendsen Hein # diff -r 2497fa1c6b76 -r 75bcb8210a37 tests/test-abort-checkin --- a/tests/test-abort-checkin Tue Aug 15 05:12:27 2006 -0400 +++ b/tests/test-abort-checkin Tue Aug 15 11:22:29 2006 +0200 @@ -3,6 +3,11 @@ HGRCPATH=$HGTMP/.hgrc; export HGRCPATH echo "[extensions]" >> $HGTMP/.hgrc echo "mq=" >> $HGTMP/.hgrc +cat > $HGTMP/false < alpha/one +echo 2 > beta/two + +echo EVERYTHING +hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ + -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" + +echo BETA ONLY +hg diff beta | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ + -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" + +echo INSIDE BETA +cd beta +hg diff . | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ + -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" diff -r 2497fa1c6b76 -r 75bcb8210a37 tests/test-diff-subdir.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-diff-subdir.out Tue Aug 15 11:22:29 2006 +0200 @@ -0,0 +1,23 @@ +EVERYTHING +diff -r ec612a6291f1 alpha/one +--- a/alpha/one ++++ b/alpha/one +@@ -0,0 +1,1 @@ ++1 +diff -r ec612a6291f1 beta/two +--- a/beta/two ++++ b/beta/two +@@ -0,0 +1,1 @@ ++2 +BETA ONLY +diff -r ec612a6291f1 beta/two +--- a/beta/two ++++ b/beta/two +@@ -0,0 +1,1 @@ ++2 +INSIDE BETA +diff -r ec612a6291f1 beta/two +--- a/beta/two ++++ b/beta/two +@@ -0,0 +1,1 @@ ++2 diff -r 2497fa1c6b76 -r 75bcb8210a37 tests/test-extdiff --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-extdiff Tue Aug 15 11:22:29 2006 +0200 @@ -0,0 +1,26 @@ +#!/bin/sh + +HGRCPATH=$HGTMP/.hgrc; export HGRCPATH +echo "[extensions]" >> $HGTMP/.hgrc +echo "extdiff=" >> $HGTMP/.hgrc + +hg init a +cd a +echo a > a +hg add +hg extdiff -o -Nr + +echo "[extdiff]" >> $HGTMP/.hgrc +echo "cmd.falabala=echo" >> $HGTMP/.hgrc +echo "opts.falabala=diffing" >> $HGTMP/.hgrc + +hg falabala + +hg help falabala + +hg ci -d '0 0' -mtest1 + +echo b >> a +hg ci -d '1 0' -mtest2 + +hg falabala -r 0:1 diff -r 2497fa1c6b76 -r 75bcb8210a37 tests/test-extdiff.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-extdiff.out Tue Aug 15 11:22:29 2006 +0200 @@ -0,0 +1,31 @@ +adding a +making snapshot of 0 files from rev 000000000000 +making snapshot of 1 files from working dir +diff -Nr a.000000000000/a a/a +0a1 +> a +making snapshot of 0 files from rev 000000000000 +making snapshot of 1 files from working dir +diffing a.000000000000 a +hg falabala [OPT]... [FILE]... + +use 'echo' to diff repository (or selected files) + + Show differences between revisions for the specified + files, using the 'echo' program. + + When two revision arguments are given, then changes are + shown between those revisions. If only one revision is + specified then that revision is compared to the working + directory, and, when no revisions are specified, the + working directory files are compared to its parent. + +options: + + -o --option pass option to comparison program + -r --rev revision + -I --include include names matching the given patterns + -X --exclude exclude names matching the given patterns +making snapshot of 1 files from rev e27a2475d60a +making snapshot of 1 files from rev 5e49ec8d3f05 +diffing a.e27a2475d60a a.5e49ec8d3f05 diff -r 2497fa1c6b76 -r 75bcb8210a37 tests/test-git-export --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-git-export Tue Aug 15 11:22:29 2006 +0200 @@ -0,0 +1,46 @@ +#!/bin/sh + +hg init a +cd a + +echo start > start +hg ci -Amstart -d '0 0' +echo new > new +hg ci -Amnew -d '0 0' +echo '% new file' +hg diff --git -r 0 | sed "s/\(\(---\|+++\) [a-zA-Z0-9_/.-]*\).*/\1/" + +hg cp new copy +hg ci -mcopy -d '0 0' +echo '% copy' +hg diff --git -r 1:tip | sed "s/\(\(---\|+++\) [a-zA-Z0-9_/.-]*\).*/\1/" + +hg mv copy rename +hg ci -mrename -d '0 0' +echo '% rename' +hg diff --git -r 2:tip | sed "s/\(\(---\|+++\) [a-zA-Z0-9_/.-]*\).*/\1/" + +hg rm rename +hg ci -mdelete -d '0 0' +echo '% delete' +hg diff --git -r 3:tip | sed "s/\(\(---\|+++\) [a-zA-Z0-9_/.-]*\).*/\1/" + +cat > src <> dst +hg ci -mrenamemod -d '0 0' +echo '% rename+mod+chmod' +hg diff --git -r 6:tip | sed "s/\(\(---\|+++\) [a-zA-Z0-9_/.-]*\).*/\1/" diff -r 2497fa1c6b76 -r 75bcb8210a37 tests/test-git-export.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-git-export.out Tue Aug 15 11:22:29 2006 +0200 @@ -0,0 +1,42 @@ +adding start +adding new +% new file +diff --git a/new b/new +new file mode 100644 +--- /dev/null ++++ b/new +@@ -0,0 +1,1 @@ ++new +% copy +diff --git a/new b/copy +copy from new +copy to copy +% rename +diff --git a/copy b/rename +rename from copy +rename to rename +% delete +diff --git a/rename b/rename +deleted file mode 100644 +--- a/rename ++++ /dev/null +@@ -1,1 +0,0 @@ +-new +adding src +% chmod 644 +diff --git a/src b/src +old mode 100644 +new mode 100755 +% rename+mod+chmod +diff --git a/src b/dst +old mode 100755 +new mode 100644 +rename from src +rename to dst +--- a/dst ++++ b/dst +@@ -3,3 +3,4 @@ 3 + 3 + 4 + 5 ++a diff -r 2497fa1c6b76 -r 75bcb8210a37 tests/test-git-import --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-git-import Tue Aug 15 11:22:29 2006 +0200 @@ -0,0 +1,122 @@ +#!/bin/sh + +hg init a +cd a + +echo % new file +hg import -mnew - < /dev/null && echo quuxfoo hg --cwd c --config '' tip -q hg --cwd c --config a.b tip -q hg --cwd c --config a tip -q diff -r 2497fa1c6b76 -r 75bcb8210a37 tests/test-grep --- a/tests/test-grep Tue Aug 15 05:12:27 2006 -0400 +++ b/tests/test-grep Tue Aug 15 11:22:29 2006 +0200 @@ -18,6 +18,13 @@ mv port1 port hg commit -m 4 -u spam -d '4 0' hg grep port port -echo 'FIXME: history is wrong here' hg grep --all -nu port port hg grep import port + +hg cp port port2 +hg commit -m 4 -u spam -d '5 0' +echo '% follow' +hg grep -f 'import$' port2 +echo deport >> port2 +hg commit -m 5 -u eggs -d '6 0' +hg grep -f --all -nu port port2 diff -r 2497fa1c6b76 -r 75bcb8210a37 tests/test-grep.out --- a/tests/test-grep.out Tue Aug 15 05:12:27 2006 -0400 +++ b/tests/test-grep.out Tue Aug 15 11:22:29 2006 +0200 @@ -1,10 +1,25 @@ port:4:export port:4:vaportight port:4:import/export -FIXME: history is wrong here -port:1:1:-:eggs:import -port:1:2:+:eggs:vaportight -port:1:3:+:eggs:import/export -port:0:2:+:spam:export -port:0:1:+:spam:import +port:4:4:-:spam:import/export +port:3:4:+:eggs:import/export +port:2:1:-:spam:import +port:2:2:-:spam:export +port:2:1:+:spam:export +port:2:2:+:spam:vaportight +port:2:3:+:spam:import/export +port:1:2:+:eggs:export +port:0:1:+:eggs:import port:4:import/export +% follow +port:0:import +port2:6:4:+:eggs:deport +port:4:4:-:spam:import/export +port:3:4:+:eggs:import/export +port:2:1:-:spam:import +port:2:2:-:spam:export +port:2:1:+:spam:export +port:2:2:+:spam:vaportight +port:2:3:+:spam:import/export +port:1:2:+:eggs:export +port:0:1:+:eggs:import diff -r 2497fa1c6b76 -r 75bcb8210a37 tests/test-help.out --- a/tests/test-help.out Tue Aug 15 05:12:27 2006 -0400 +++ b/tests/test-help.out Tue Aug 15 11:22:29 2006 +0200 @@ -176,6 +176,7 @@ -r --rev revision -a --text treat all files as text -p --show-function show which function each change is in + -g --git use git extended diff format -w --ignore-all-space ignore white space when comparing lines -b --ignore-space-change ignore changes in the amount of white space -B --ignore-blank-lines ignore changes whose lines are all blank diff -r 2497fa1c6b76 -r 75bcb8210a37 tests/test-import --- a/tests/test-import Tue Aug 15 05:12:27 2006 -0400 +++ b/tests/test-import Tue Aug 15 11:22:29 2006 +0200 @@ -72,7 +72,7 @@ echo % plain diff in email, no subject, no message body, should fail hg clone -r0 a b -grep -v '^\(Subject\|email\)' msg.patch | hg --cwd b import - +egrep -v '^(Subject|email)' msg.patch | hg --cwd b import - rm -rf b echo % hg export in email, should use patch header @@ -89,9 +89,10 @@ echo % hg import in a subdirectory hg clone -r0 a b hg --cwd a export tip | sed -e 's/d1\/d2\///' > tip.patch -pushd b/d1/d2 2>&1 > /dev/null +dir=`pwd` +cd b/d1/d2 2>&1 > /dev/null hg import ../../../tip.patch -popd 2>&1 > /dev/null +cd $dir echo "% message should be 'subdir change'" hg --cwd b tip | grep 'subdir change' echo "% committer should be 'someoneelse'" diff -r 2497fa1c6b76 -r 75bcb8210a37 tests/test-log --- a/tests/test-log Tue Aug 15 05:12:27 2006 -0400 +++ b/tests/test-log Tue Aug 15 11:22:29 2006 +0200 @@ -63,3 +63,6 @@ echo % log --follow-first hg log --follow-first + +echo % log -P 2 +hg log -P 2 diff -r 2497fa1c6b76 -r 75bcb8210a37 tests/test-log.out --- a/tests/test-log.out Tue Aug 15 05:12:27 2006 -0400 +++ b/tests/test-log.out Tue Aug 15 11:22:29 2006 +0200 @@ -149,3 +149,29 @@ date: Thu Jan 01 00:00:01 1970 +0000 summary: base +% log -P 2 +changeset: 6:2404bbcab562 +tag: tip +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: b1.1 + +changeset: 5:302e9dd6890d +parent: 3:e62f78d544b4 +parent: 4:ddb82e70d1a1 +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: m12 + +changeset: 4:ddb82e70d1a1 +parent: 0:67e992f2c4f3 +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: b2 + +changeset: 3:e62f78d544b4 +parent: 1:3d5bf5654eda +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: b1 + diff -r 2497fa1c6b76 -r 75bcb8210a37 tests/test-mq --- a/tests/test-mq Tue Aug 15 05:12:27 2006 -0400 +++ b/tests/test-mq Tue Aug 15 11:22:29 2006 +0200 @@ -10,6 +10,10 @@ hg init a cd a echo a > a +hg ci -Ama + +hg clone . ../k + mkdir b echo z > b/z hg ci -Ama @@ -48,7 +52,7 @@ echo a >> a hg qrefresh -sed -e "s/\(^diff -r \)\([a-f0-9]* \)/\1 x/" \ +sed -e "s/^\(diff -r \)\([a-f0-9]* \)/\1 x/" \ -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/test.patch @@ -103,9 +107,19 @@ hg qprev hg qapplied +echo % commit should fail +hg commit + +echo % push should fail +hg push ../../k + echo % qunapplied hg qunapplied +echo % push should succeed +hg qpop -a +hg push ../../k + echo % strip cd ../../b echo x>x diff -r 2497fa1c6b76 -r 75bcb8210a37 tests/test-mq-guards --- a/tests/test-mq-guards Tue Aug 15 05:12:27 2006 -0400 +++ b/tests/test-mq-guards Tue Aug 15 11:22:29 2006 +0200 @@ -63,22 +63,39 @@ hg qpush -a hg qpop -a -hg qguard a.patch +1 +2 +hg qguard a.patch +1 +hg qguard b.patch +2 hg qselect 1 +echo % should push a.patch, not b.patch +hg qpush +hg qpush +hg qpop -a + +hg qselect 2 echo % should push b.patch hg qpush hg qpop -a -hg qselect 2 +hg qselect 1 2 +echo % should push a.patch, b.patch hg qpush -hg qpop -a - -hg qselect 1 2 -echo % should push a.patch hg qpush hg qpop -a hg qguard a.patch +1 +2 -3 hg qselect 1 2 3 +echo % list patches and guards +hg qguard -l +echo % list series +hg qseries -v +echo % list guards +hg qselect echo % should push b.patch hg qpush + +hg qpush -a +hg qselect -n --reapply +echo % guards in series file: +1 +2 -3 +hg qselect -s +echo % should show c.patch +hg qapplied diff -r 2497fa1c6b76 -r 75bcb8210a37 tests/test-mq-guards.out --- a/tests/test-mq-guards.out Tue Aug 15 05:12:27 2006 -0400 +++ b/tests/test-mq-guards.out Tue Aug 15 11:22:29 2006 +0200 @@ -13,7 +13,7 @@ applying b.patch Now at: b.patch Patch queue now empty -3 of 3 unapplied patches active +number of unguarded, unapplied patches has changed from 2 to 3 % should push a.patch applying a.patch Now at: a.patch @@ -28,27 +28,57 @@ Now at: c.patch Patch queue now empty guards deactivated -2 of 3 unapplied patches active +number of unguarded, unapplied patches has changed from 3 to 2 % should push all applying b.patch applying c.patch Now at: c.patch Patch queue now empty -2 of 3 unapplied patches active +number of unguarded, unapplied patches has changed from 1 to 2 +% should push a.patch, not b.patch +applying a.patch +Now at: a.patch +applying c.patch +Now at: c.patch +Patch queue now empty % should push b.patch applying b.patch Now at: b.patch Patch queue now empty -2 of 3 unapplied patches active +number of unguarded, unapplied patches has changed from 2 to 3 +% should push a.patch, b.patch +applying a.patch +Now at: a.patch applying b.patch Now at: b.patch Patch queue now empty -3 of 3 unapplied patches active -% should push a.patch -applying a.patch -Now at: a.patch -Patch queue now empty -2 of 3 unapplied patches active +number of unguarded, unapplied patches has changed from 3 to 2 +% list patches and guards +a.patch: +1 +2 -3 +b.patch: +2 +c.patch: unguarded +% list series +0 G a.patch +1 U b.patch +2 U c.patch +% list guards +1 +2 +3 % should push b.patch applying b.patch Now at: b.patch +applying c.patch +Now at: c.patch +guards deactivated +popping guarded patches +Patch queue now empty +reapplying unguarded patches +applying c.patch +Now at: c.patch +% guards in series file: +1 +2 -3 ++1 ++2 +-3 +% should show c.patch +c.patch diff -r 2497fa1c6b76 -r 75bcb8210a37 tests/test-mq-qrefresh-replace-log-message --- a/tests/test-mq-qrefresh-replace-log-message Tue Aug 15 05:12:27 2006 -0400 +++ b/tests/test-mq-qrefresh-replace-log-message Tue Aug 15 11:22:29 2006 +0200 @@ -33,7 +33,7 @@ echo bbbb > file hg qrefresh -l logfile echo ======================= -echo "Should display 'Third commit message\n This is the 3rd log message'" +printf "Should display 'Third commit message\\\n This is the 3rd log message'\n" hg log -l1 -v | sed -n '/description/,$p' echo @@ -46,6 +46,6 @@ echo " This is the 5th log message" >> logfile) |\ hg qrefresh -l- echo ======================= -echo "Should display 'Fifth commit message\n This is the 5th log message'" +printf "Should display 'Fifth commit message\\\n This is the 5th log message'\n" hg log -l1 -v | sed -n '/description/,$p' echo diff -r 2497fa1c6b76 -r 75bcb8210a37 tests/test-mq.out --- a/tests/test-mq.out Tue Aug 15 05:12:27 2006 -0400 +++ b/tests/test-mq.out Tue Aug 15 11:22:29 2006 +0200 @@ -49,6 +49,7 @@ qunapplied print the patches not yet applied strip strip a revision and all later revs on the same branch adding a +1 files updated, 0 files merged, 0 files removed, 0 files unresolved adding b/z % qinit % -R qinit @@ -102,8 +103,21 @@ test2.patch Only one patch applied test.patch +% commit should fail +abort: cannot commit over an applied mq patch +% push should fail +pushing to ../../k +abort: source has mq patches applied % qunapplied test2.patch +% push should succeed +Patch queue now empty +pushing to ../../k +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files % strip adding x 0 files updated, 0 files merged, 1 files removed, 0 files unresolved