Mercurial > hg
changeset 2886:bee4b7abcb01
Merge with crew
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Mon, 14 Aug 2006 14:42:15 -0500 |
parents | 06c05c675a35 (current diff) bd29a3067b97 (diff) |
children | 05257fd28591 |
files | mercurial/merge.py |
diffstat | 64 files changed, 1239 insertions(+), 583 deletions(-) [+] |
line wrap: on
line diff
--- a/contrib/mercurial.el Mon Aug 14 14:14:08 2006 -0500 +++ b/contrib/mercurial.el Mon Aug 14 14:42:15 2006 -0500 @@ -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.
--- a/doc/hg.1.txt Mon Aug 14 14:14:08 2006 -0500 +++ b/doc/hg.1.txt Mon Aug 14 14:42:15 2006 -0500 @@ -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).
--- a/doc/hgmerge.1.txt Mon Aug 14 14:14:08 2006 -0500 +++ b/doc/hgmerge.1.txt Mon Aug 14 14:42:15 2006 -0500 @@ -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).
--- a/doc/hgrc.5.txt Mon Aug 14 14:14:08 2006 -0500 +++ b/doc/hgrc.5.txt Mon Aug 14 14:42:15 2006 -0500 @@ -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;;
--- a/doc/ja/hg.1.ja.txt Mon Aug 14 14:14:08 2006 -0500 +++ b/doc/ja/hg.1.ja.txt Mon Aug 14 14:42:15 2006 -0500 @@ -862,6 +862,6 @@ 著作権情報 ----- -Copyright (C) 2005 Matt Mackall. +Copyright (C) 2005, 2006 Matt Mackall. このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで 認められます。
--- a/doc/ja/hgmerge.1.ja.txt Mon Aug 14 14:14:08 2006 -0500 +++ b/doc/ja/hgmerge.1.ja.txt Mon Aug 14 14:42:15 2006 -0500 @@ -32,6 +32,6 @@ 著作権情報 ---- -Copyright (C) 2005 Matt Mackall. +Copyright (C) 2005, 2006 Matt Mackall. このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで 認められます。
--- a/hgext/extdiff.py Mon Aug 14 14:14:08 2006 -0500 +++ b/hgext/extdiff.py Mon Aug 14 14:42:15 2006 -0500 @@ -80,8 +80,8 @@ 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) + modified, added, removed, deleted, unknown = repo.status( + node1, node2, files, match=matchfn)[:5] if not (modified or added or removed): return 0
--- a/hgext/fetch.py Mon Aug 14 14:14:08 2006 -0500 +++ b/hgext/fetch.py Mon Aug 14 14:42:15 2006 -0500 @@ -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:
--- a/hgext/gpg.py Mon Aug 14 14:14:08 2006 -0500 +++ b/hgext/gpg.py Mon Aug 14 14:42:15 2006 -0500 @@ -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 "
--- a/hgext/hbisect.py Mon Aug 14 14:14:08 2006 -0500 +++ b/hgext/hbisect.py Mon Aug 14 14:42:15 2006 -0500 @@ -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"""
--- a/hgext/hgk.py Mon Aug 14 14:14:08 2006 -0500 +++ b/hgext/hgk.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,6 +1,6 @@ # Minimal support for git commands on an hg repository # -# Copyright 2005 Chris Mason <mason@suse.com> +# Copyright 2005, 2006 Chris Mason <mason@suse.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. @@ -14,7 +14,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), @@ -67,12 +67,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()
--- a/hgext/mq.py Mon Aug 14 14:14:08 2006 -0500 +++ b/hgext/mq.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,7 +1,6 @@ - # queue.py - patch queues for mercurial # -# Copyright 2005 Chris Mason <mason@suse.com> +# Copyright 2005, 2006 Chris Mason <mason@suse.com> # # 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) @@ -523,19 +532,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 +571,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 +659,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 +733,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 +897,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 +927,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 +968,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 +1002,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 +1034,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) @@ -1739,7 +1749,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 +1759,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 +1816,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 +1882,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]'), @@ -1906,8 +1976,11 @@ 'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'), "qselect": (select, [('n', 'none', None, _('disable all guards')), - ('s', 'series', None, _('list all guards in series file'))], - 'hg qselect [GUARDS]'), + ('s', 'series', None, _('list all guards in series file')), + ('', 'pop', None, + _('pop to before first guarded applied patch')), + ('', 'reapply', None, _('pop, then reapply patches'))], + 'hg qselect [OPTION...] [GUARD...]'), "qseries": (series, [('m', 'missing', None, 'print patches not in series'), @@ -1922,4 +1995,3 @@ "qtop": (top, [], 'hg qtop'), "qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'), } -
--- a/hgext/notify.py Mon Aug 14 14:14:08 2006 -0500 +++ b/hgext/notify.py Mon Aug 14 14:42:15 2006 -0500 @@ -67,7 +67,7 @@ from mercurial.demandload import * from mercurial.i18n import gettext as _ from mercurial.node import * -demandload(globals(), 'email.Parser mercurial:commands,templater,util') +demandload(globals(), 'email.Parser mercurial:commands,patch,templater,util') demandload(globals(), 'fnmatch socket time') # template for single changeset can include email headers. @@ -238,7 +238,7 @@ return fp = templater.stringio() prev = self.repo.changelog.parents(node)[0] - commands.dodiff(fp, self.ui, self.repo, prev, ref) + patch.diff(self.repo, fp, prev, ref) difflines = fp.getvalue().splitlines(1) if maxdiff > 0 and len(difflines) > maxdiff: self.sio.write(_('\ndiffs (truncated from %d to %d lines):\n\n') %
--- a/mercurial/archival.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/archival.py Mon Aug 14 14:42:15 2006 -0500 @@ -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()
--- a/mercurial/bdiff.c Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/bdiff.c Mon Aug 14 14:42:15 2006 -0500 @@ -1,7 +1,7 @@ /* bdiff.c - efficient binary diff extension for Mercurial - Copyright 2005 Matt Mackall <mpm@selenic.com> + Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/changelog.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/changelog.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,6 +1,6 @@ # changelog.py - changelog class for mercurial # -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial/cmdutil.py Mon Aug 14 14:42:15 2006 -0500 @@ -0,0 +1,111 @@ +# commands.py - command processing for mercurial +# +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> +# +# 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)
--- a/mercurial/commands.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/commands.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,6 +1,6 @@ # commands.py - command processing for mercurial # -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> # # 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: @@ -344,63 +312,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 +364,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 +420,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 +476,7 @@ ui.write(_("Mercurial Distributed SCM (version %s)\n") % version.get_version()) ui.status(_( - "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n" + "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\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 +630,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 +655,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 +698,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 +751,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 +762,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 +866,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 +930,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 +1088,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 +1305,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 +1334,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 +1368,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 +1387,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 +1444,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 +1510,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 +1524,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 +1560,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 +1599,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 +1643,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 +1671,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 +1763,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 +1811,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 +1914,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 +1995,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 +2208,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 +2320,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 +2541,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 +2644,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 @@ -3091,6 +2891,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 +2929,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', '', @@ -3202,7 +3004,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 +3347,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
--- a/mercurial/context.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/context.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,6 +1,6 @@ # context.py - changeset and file context objects for mercurial # -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2006 Matt Mackall <mpm@selenic.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/dirstate.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/dirstate.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,7 +1,7 @@ """ dirstate.py - working directory tracking for mercurial -Copyright 2005 Matt Mackall <mpm@selenic.com> +Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/filelog.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/filelog.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,6 +1,6 @@ # filelog.py - file history class for mercurial # -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/hg.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/hg.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,6 +1,7 @@ # hg.py - repository classes for mercurial # -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> +# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> # # 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'''
--- a/mercurial/hgweb/common.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/hgweb/common.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,7 +1,7 @@ # hgweb/common.py - Utility functions needed by hgweb_mod and hgwebdir_mod # # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/hgweb/hgweb_mod.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/hgweb/hgweb_mod.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,7 +1,7 @@ # hgweb/hgweb_mod.py - Web interface for a repository. # # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> # # 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'] + diffopts = ui.diffopts() 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):
--- a/mercurial/hgweb/hgwebdir_mod.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/hgweb/hgwebdir_mod.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,7 +1,7 @@ # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories. # # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/hgweb/request.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/hgweb/request.py Mon Aug 14 14:42:15 2006 -0500 @@ -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 <jake@edge2.net> -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/hgweb/server.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/hgweb/server.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,7 +1,7 @@ # hgweb/server.py - The standalone hg web server. # # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/httprangereader.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/httprangereader.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,6 +1,6 @@ # httprangereader.py - just what it says # -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/httprepo.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/httprepo.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,6 +1,7 @@ # httprepo.py - HTTP repository proxy classes for mercurial # -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> +# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/i18n.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/i18n.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,7 +1,7 @@ """ i18n.py - internationalization support for mercurial -Copyright 2005 Matt Mackall <mpm@selenic.com> +Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/localrepo.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/localrepo.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,6 +1,6 @@ # localrepo.py - read/write repository class for mercurial # -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> # # 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()
--- a/mercurial/lock.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/lock.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,6 +1,6 @@ # lock.py - simple locking scheme for mercurial # -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/manifest.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/manifest.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,6 +1,6 @@ # manifest.py - manifest revision class for mercurial # -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> # # 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))
--- a/mercurial/mdiff.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/mdiff.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,6 +1,6 @@ # mdiff.py - diff and patch routines for mercurial # -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. @@ -19,14 +19,39 @@ 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 + 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, + '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 +74,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 +94,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 +117,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 +135,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 +175,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 +189,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 +200,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]
--- a/mercurial/merge.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/merge.py Mon Aug 14 14:42:15 2006 -0500 @@ -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"))
--- a/mercurial/mpatch.c Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/mpatch.c Mon Aug 14 14:42:15 2006 -0500 @@ -14,7 +14,7 @@ allocation of intermediate Python objects. Working memory is about 2x the total number of hunks. - Copyright 2005 Matt Mackall <mpm@selenic.com> + Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/node.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/node.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,7 +1,7 @@ """ node.py - basic nodeid manipulation for mercurial -Copyright 2005 Matt Mackall <mpm@selenic.com> +Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/packagescan.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/packagescan.py Mon Aug 14 14:42:15 2006 -0500 @@ -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 <Volker.Kleinfeld@gmx.de> +# Copyright 2005, 2006 Volker Kleinfeld <Volker.Kleinfeld@gmx.de> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial/patch.py Mon Aug 14 14:42:15 2006 -0500 @@ -0,0 +1,365 @@ +# patch.py - patch file parsing routines +# +# Copyright 2006 Brendan Cully <brendan@kublai.com> +# +# 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 <patchname>""" + 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 <patchname> 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]) + 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 repo.ui.quiet: + r = None + else: + hexfunc = repo.ui.verbose and hex or short + r = [hexfunc(node) for node in [node1, node2] if node] + + 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, 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)
--- a/mercurial/remoterepo.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/remoterepo.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,6 +1,6 @@ -# remoterepo - remote repositort proxy classes for mercurial +# remoterepo - remote repository proxy classes for mercurial # -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/repo.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/repo.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,6 +1,7 @@ # repo.py - repository base classes for mercurial # # Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/revlog.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/revlog.py Mon Aug 14 14:42:15 2006 -0500 @@ -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 <mpm@selenic.com> +Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/sshrepo.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/sshrepo.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,6 +1,6 @@ # sshrepo.py - ssh repository proxy class for mercurial # -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/sshserver.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/sshserver.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,6 +1,7 @@ # sshserver.py - ssh protocol server support for mercurial # # Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/statichttprepo.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/statichttprepo.py Mon Aug 14 14:42:15 2006 -0500 @@ -2,7 +2,7 @@ # # This provides read-only repo access to repositories exported via static http # -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/templater.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/templater.py Mon Aug 14 14:42:15 2006 -0500 @@ -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):
--- a/mercurial/transaction.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/transaction.py Mon Aug 14 14:42:15 2006 -0500 @@ -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 <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/ui.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/ui.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,6 +1,6 @@ # ui.py - user interface bits for mercurial # -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> # # 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,17 @@ 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)), + 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.
--- a/mercurial/util.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/util.py Mon Aug 14 14:42:15 2006 -0500 @@ -2,6 +2,8 @@ util.py - Mercurial utility functions and platform specfic implementations Copyright 2005 K. Thananchayan <thananck@yahoo.com> + Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> + Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> 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 <patchname> 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 +
--- a/mercurial/version.py Mon Aug 14 14:14:08 2006 -0500 +++ b/mercurial/version.py Mon Aug 14 14:42:15 2006 -0500 @@ -1,4 +1,4 @@ -# Copyright (C) 2005 by Intevation GmbH +# Copyright (C) 2005, 2006 by Intevation GmbH # Author(s): # Thomas Arendsen Hein <thomas@intevation.de> #
--- a/tests/test-abort-checkin Mon Aug 14 14:14:08 2006 -0500 +++ b/tests/test-abort-checkin Mon Aug 14 14:42:15 2006 -0500 @@ -3,6 +3,11 @@ HGRCPATH=$HGTMP/.hgrc; export HGRCPATH echo "[extensions]" >> $HGTMP/.hgrc echo "mq=" >> $HGTMP/.hgrc +cat > $HGTMP/false <<EOF +#!/bin/sh +exit 1 +EOF +chmod +x $HGTMP/false hg init foo cd foo @@ -11,7 +16,7 @@ # mq may keep a reference to the repository so __del__ will not be called # and .hg/journal.dirstate will not be deleted: -HGEDITOR=false hg ci -HGEDITOR=false hg ci +HGEDITOR=$HGTMP/false hg ci +HGEDITOR=$HGTMP/false hg ci exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-diff-subdir Mon Aug 14 14:42:15 2006 -0500 @@ -0,0 +1,27 @@ +#!/bin/sh + +hg init + +mkdir alpha +touch alpha/one +mkdir beta +touch beta/two + +hg add alpha/one beta/two +hg ci -m "start" -d "1000000 0" + +echo 1 > 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/"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-diff-subdir.out Mon Aug 14 14:42:15 2006 -0500 @@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-git-import Mon Aug 14 14:42:15 2006 -0500 @@ -0,0 +1,122 @@ +#!/bin/sh + +hg init a +cd a + +echo % new file +hg import -mnew - <<EOF +diff --git a/new b/new +new file mode 100644 +index 0000000..7898192 +--- /dev/null ++++ b/new +@@ -0,0 +1 @@ ++a +EOF + +echo % chmod +x +hg import -msetx - <<EOF +diff --git a/new b/new +old mode 100644 +new mode 100755 +EOF + +test -x new || echo failed + +echo % copy +hg import -mcopy - <<EOF +diff --git a/new b/copy +old mode 100755 +new mode 100644 +similarity index 100% +copy from new +copy to copy +diff --git a/new b/copyx +similarity index 100% +copy from new +copy to copyx +EOF + +test -f copy -a ! -x copy || echo failed +test -x copyx || echo failed +cat copy +hg cat copy + +echo % rename +hg import -mrename - <<EOF +diff --git a/copy b/rename +similarity index 100% +rename from copy +rename to rename +EOF + +hg locate + +echo % delete +hg import -mdelete - <<EOF +diff --git a/copyx b/copyx +deleted file mode 100755 +index 7898192..0000000 +--- a/copyx ++++ /dev/null +@@ -1 +0,0 @@ +-a +EOF + +hg locate +test -f copyx && echo failed || true + +echo % regular diff +hg import -mregular - <<EOF +diff --git a/rename b/rename +index 7898192..72e1fe3 100644 +--- a/rename ++++ b/rename +@@ -1 +1,5 @@ + a ++a ++a ++a ++a +EOF + +echo % copy and modify +hg import -mcopymod - <<EOF +diff --git a/rename b/copy2 +similarity index 80% +copy from rename +copy to copy2 +index 72e1fe3..b53c148 100644 +--- a/rename ++++ b/copy2 +@@ -1,5 +1,5 @@ + a + a +-a ++b + a + a +EOF + +hg cat copy2 + +echo % rename and modify +hg import -mrenamemod - <<EOF +diff --git a/copy2 b/rename2 +similarity index 80% +rename from copy2 +rename to rename2 +index b53c148..8f81e29 100644 +--- a/copy2 ++++ b/rename2 +@@ -1,5 +1,5 @@ + a + a + b +-a ++c + a +EOF + +hg locate copy2 +hg cat rename2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-git-import.out Mon Aug 14 14:42:15 2006 -0500 @@ -0,0 +1,39 @@ +% new file +applying patch from stdin +patching file new +% chmod +x +applying patch from stdin +% copy +applying patch from stdin +a +a +% rename +applying patch from stdin +copyx +new +rename +% delete +applying patch from stdin +patching file copyx +new +rename +% regular diff +applying patch from stdin +patching file rename +% copy and modify +applying patch from stdin +patching file copy2 +a +a +b +a +a +% rename and modify +applying patch from stdin +patching file rename2 +copy2: No such file or directory +a +a +b +c +a
--- a/tests/test-globalopts Mon Aug 14 14:14:08 2006 -0500 +++ b/tests/test-globalopts Mon Aug 14 14:42:15 2006 -0500 @@ -45,7 +45,7 @@ hg --cwd b tip --verbose echo %% --config -hg --cwd c --config paths.quuxfoo=bar paths | grep -q quuxfoo && echo quuxfoo +hg --cwd c --config paths.quuxfoo=bar paths | grep quuxfoo > /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
--- a/tests/test-grep Mon Aug 14 14:14:08 2006 -0500 +++ b/tests/test-grep Mon Aug 14 14:42:15 2006 -0500 @@ -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
--- a/tests/test-grep.out Mon Aug 14 14:14:08 2006 -0500 +++ b/tests/test-grep.out Mon Aug 14 14:42:15 2006 -0500 @@ -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
--- a/tests/test-import Mon Aug 14 14:14:08 2006 -0500 +++ b/tests/test-import Mon Aug 14 14:42:15 2006 -0500 @@ -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'"
--- a/tests/test-mq Mon Aug 14 14:14:08 2006 -0500 +++ b/tests/test-mq Mon Aug 14 14:42:15 2006 -0500 @@ -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
--- a/tests/test-mq-guards Mon Aug 14 14:14:08 2006 -0500 +++ b/tests/test-mq-guards Mon Aug 14 14:42:15 2006 -0500 @@ -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
--- a/tests/test-mq-guards.out Mon Aug 14 14:14:08 2006 -0500 +++ b/tests/test-mq-guards.out Mon Aug 14 14:42:15 2006 -0500 @@ -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
--- a/tests/test-mq-qrefresh-replace-log-message Mon Aug 14 14:14:08 2006 -0500 +++ b/tests/test-mq-qrefresh-replace-log-message Mon Aug 14 14:42:15 2006 -0500 @@ -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
--- a/tests/test-mq.out Mon Aug 14 14:14:08 2006 -0500 +++ b/tests/test-mq.out Mon Aug 14 14:42:15 2006 -0500 @@ -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