Mercurial > hg
changeset 24027:f2a631c7387a
merge with stable
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Tue, 03 Feb 2015 19:10:03 -0600 |
parents | 3daef83a1873 (diff) 942a5a34b2d0 (current diff) |
children | a78888d98606 |
files | |
diffstat | 21 files changed, 518 insertions(+), 239 deletions(-) [+] |
line wrap: on
line diff
--- a/hgext/histedit.py Mon Feb 02 14:26:47 2015 -0500 +++ b/hgext/histedit.py Tue Feb 03 19:10:03 2015 -0600 @@ -349,7 +349,7 @@ repo, ctx = state.repo, state.parentctx oldctx = repo[ha] if oldctx.parents()[0] == ctx: - ui.debug('node %s unchanged\n' % ha) + ui.debug('node %s unchanged\n' % ha[:12]) return oldctx, [] hg.update(repo, ctx.node()) stats = applychanges(ui, repo, oldctx, opts) @@ -361,7 +361,7 @@ n = commit(text=oldctx.description(), user=oldctx.user(), date=oldctx.date(), extra=oldctx.extra()) if n is None: - ui.warn(_('%s: empty changeset\n') % node.hex(ha)) + ui.warn(_('%s: empty changeset\n') % ha[:12]) return ctx, [] new = repo[n] return new, [(oldctx.node(), (n,))] @@ -389,10 +389,10 @@ if stats and stats[3] > 0: raise error.InterventionRequired( _('Fix up the change and run hg histedit --continue')) - n = repo.commit(text='fold-temp-revision %s' % ha, user=oldctx.user(), + n = repo.commit(text='fold-temp-revision %s' % ha[:12], user=oldctx.user(), date=oldctx.date(), extra=oldctx.extra()) if n is None: - ui.warn(_('%s: empty changeset') % node.hex(ha)) + ui.warn(_('%s: empty changeset') % ha[:12]) return ctx, [] return finishfold(ui, repo, ctx, oldctx, n, opts, []) @@ -579,6 +579,10 @@ _('only one repo argument allowed with --outgoing')) else: revs.extend(freeargs) + if len(revs) == 0: + histeditdefault = ui.config('histedit', 'defaultrev') + if histeditdefault: + revs.append(histeditdefault) if len(revs) != 1: raise util.Abort( _('histedit requires exactly one ancestor revision')) @@ -666,7 +670,7 @@ while state.rules: state.write() action, ha = state.rules.pop(0) - ui.debug('histedit: processing %s %s\n' % (action, ha)) + ui.debug('histedit: processing %s %s\n' % (action, ha[:12])) actfunc = actiontable[action] state.parentctx, replacement_ = actfunc(ui, state, ha, opts) state.replacements.extend(replacement_) @@ -736,7 +740,7 @@ if s.modified or s.added or s.removed or s.deleted: # prepare the message for the commit to comes if action in ('f', 'fold', 'r', 'roll'): - message = 'fold-temp-revision %s' % currentnode + message = 'fold-temp-revision %s' % currentnode[:12] else: message = ctx.description() editopt = action in ('e', 'edit', 'm', 'mess') @@ -822,7 +826,7 @@ or a rule on a changeset outside of the user-given range. """ parsed = [] - expected = set(str(c) for c in ctxs) + expected = set(c.hex() for c in ctxs) seen = set() for r in rules: if ' ' not in r: @@ -830,22 +834,24 @@ action, rest = r.split(' ', 1) ha = rest.strip().split(' ', 1)[0] try: - ha = str(repo[ha]) # ensure its a short hash + ha = repo[ha].hex() except error.RepoError: - raise util.Abort(_('unknown changeset %s listed') % ha) + raise util.Abort(_('unknown changeset %s listed') % ha[:12]) if ha not in expected: raise util.Abort( _('may not use changesets other than the ones listed')) if ha in seen: - raise util.Abort(_('duplicated command for changeset %s') % ha) + raise util.Abort(_('duplicated command for changeset %s') % + ha[:12]) seen.add(ha) if action not in actiontable: raise util.Abort(_('unknown action "%s"') % action) parsed.append([action, ha]) missing = sorted(expected - seen) # sort to stabilize output if missing: - raise util.Abort(_('missing rules for changeset %s') % missing[0], - hint=_('do you want to use the drop action?')) + raise util.Abort(_('missing rules for changeset %s') % + missing[0][:12], + hint=_('do you want to use the drop action?')) return parsed def processreplacement(state):
--- a/hgext/largefiles/overrides.py Mon Feb 02 14:26:47 2015 -0500 +++ b/hgext/largefiles/overrides.py Tue Feb 03 19:10:03 2015 -0600 @@ -559,16 +559,6 @@ # this isn't legal, let the original function deal with it return orig(ui, repo, pats, opts, rename) - def makestandin(relpath): - path = pathutil.canonpath(repo.root, repo.getcwd(), relpath) - return os.path.join(repo.wjoin(lfutil.standin(path))) - - fullpats = scmutil.expandpats(pats) - dest = fullpats[-1] - - if os.path.isdir(dest): - if not os.path.isdir(makestandin(dest)): - os.makedirs(makestandin(dest)) # This could copy both lfiles and normal files in one command, # but we don't want to do that. First replace their matcher to # only match normal files and run it, then replace it to just @@ -595,6 +585,17 @@ except OSError: return result + def makestandin(relpath): + path = pathutil.canonpath(repo.root, repo.getcwd(), relpath) + return os.path.join(repo.wjoin(lfutil.standin(path))) + + fullpats = scmutil.expandpats(pats) + dest = fullpats[-1] + + if os.path.isdir(dest): + if not os.path.isdir(makestandin(dest)): + os.makedirs(makestandin(dest)) + try: try: # When we call orig below it creates the standins but we don't add
--- a/hgext/largefiles/reposetup.py Mon Feb 02 14:26:47 2015 -0500 +++ b/hgext/largefiles/reposetup.py Tue Feb 03 19:10:03 2015 -0600 @@ -326,10 +326,10 @@ actualfiles.append(lf) if not matcheddir: # There may still be normal files in the dir, so - # make sure a directory is in the list, which - # forces status to walk and call the match - # function on the matcher. Windows does NOT - # require this. + # make sure _a_ directory is in the list, which + # forces status/dirstate to walk all files and + # call the match function on the matcher, even + # on case sensitive filesytems. actualfiles.append('.') matcheddir = True # Nothing in dir, so readd it
--- a/mercurial/bundle2.py Mon Feb 02 14:26:47 2015 -0500 +++ b/mercurial/bundle2.py Tue Feb 03 19:10:03 2015 -0600 @@ -145,6 +145,7 @@ preserve. """ +import errno import sys import util import struct @@ -484,6 +485,8 @@ def __init__(self, fp): self._fp = fp + self._seekable = (util.safehasattr(fp, 'seek') and + util.safehasattr(fp, 'tell')) def _unpack(self, format): """unpack this struct format from the stream""" @@ -494,6 +497,29 @@ """read exactly <size> bytes from the stream""" return changegroup.readexactly(self._fp, size) + def seek(self, offset, whence): + """move the underlying file pointer""" + if self._seekable: + return self._fp.seek(offset, whence) + else: + raise NotImplementedError(_('File pointer is not seekable')) + + def tell(self): + """return the file offset, or None if file is not seekable""" + if self._seekable: + try: + return self._fp.tell() + except IOError, e: + if e.errno == errno.ESPIPE: + self._seekable = False + else: + raise + return None + + def close(self): + """close underlying file""" + if util.safehasattr(self._fp, 'close'): + return self._fp.close() class unbundle20(unpackermixin): """interpret a bundle2 stream
--- a/mercurial/bundlerepo.py Mon Feb 02 14:26:47 2015 -0500 +++ b/mercurial/bundlerepo.py Tue Feb 03 19:10:03 2015 -0600 @@ -177,9 +177,6 @@ def baserevision(self, nodeorrev): return filelog.filelog.revision(self, nodeorrev) - def _file(self, f): - self._repo.file(f) - class bundlepeer(localrepo.localpeer): def canpush(self): return False
--- a/mercurial/copies.py Mon Feb 02 14:26:47 2015 -0500 +++ b/mercurial/copies.py Tue Feb 03 19:10:03 2015 -0600 @@ -144,6 +144,15 @@ del c[k] return c +def _computeforwardmissing(a, b): + """Computes which files are in b but not a. + This is its own function so extensions can easily wrap this call to see what + files _forwardcopies is about to process. + """ + missing = set(b.manifest().iterkeys()) + missing.difference_update(a.manifest().iterkeys()) + return missing + def _forwardcopies(a, b): '''find {dst@b: src@a} copy mapping where a is an ancestor of b''' @@ -167,9 +176,7 @@ # we currently don't try to find where old files went, too expensive # this means we can miss a case like 'hg rm b; hg cp a b' cm = {} - missing = set(b.manifest().iterkeys()) - missing.difference_update(a.manifest().iterkeys()) - + missing = _computeforwardmissing(a, b) ancestrycontext = a._repo.changelog.ancestors([b.rev()], inclusive=True) for f in missing: fctx = b[f] @@ -208,6 +215,22 @@ return _backwardrenames(x, y) return _chain(x, y, _backwardrenames(x, a), _forwardcopies(a, y)) +def _computenonoverlap(repo, m1, m2, ma): + """Computes the files exclusive to m1 and m2. + This is its own function so extensions can easily wrap this call to see what + files mergecopies is about to process. + """ + u1 = _nonoverlap(m1, m2, ma) + u2 = _nonoverlap(m2, m1, ma) + + if u1: + repo.ui.debug(" unmatched files in local:\n %s\n" + % "\n ".join(u1)) + if u2: + repo.ui.debug(" unmatched files in other:\n %s\n" + % "\n ".join(u2)) + return u1, u2 + def mergecopies(repo, c1, c2, ca): """ Find moves and copies between context c1 and c2 that are relevant @@ -261,15 +284,7 @@ repo.ui.debug(" searching for copies back to rev %d\n" % limit) - u1 = _nonoverlap(m1, m2, ma) - u2 = _nonoverlap(m2, m1, ma) - - if u1: - repo.ui.debug(" unmatched files in local:\n %s\n" - % "\n ".join(u1)) - if u2: - repo.ui.debug(" unmatched files in other:\n %s\n" - % "\n ".join(u2)) + u1, u2 = _computenonoverlap(repo, m1, m2, ma) for f in u1: checkcopies(ctx, f, m1, m2, ca, limit, diverge, copy, fullcopy)
--- a/mercurial/filelog.py Mon Feb 02 14:26:47 2015 -0500 +++ b/mercurial/filelog.py Tue Feb 03 19:10:03 2015 -0600 @@ -104,9 +104,6 @@ raise error.CensoredNodeError(self.indexfile, node) raise - def _file(self, f): - return filelog(self.opener, f) - def _iscensored(self, rev): """Check if a file revision is censored.""" return self.flags(rev) & revlog.REVIDX_ISCENSORED
--- a/mercurial/help/subrepos.txt Mon Feb 02 14:26:47 2015 -0500 +++ b/mercurial/help/subrepos.txt Tue Feb 03 19:10:03 2015 -0600 @@ -91,7 +91,7 @@ -S/--subrepos is specified. :cat: cat currently only handles exact file matches in subrepos. - Git and Subversion subrepositories are currently ignored. + Subversion subrepositories are currently ignored. :commit: commit creates a consistent snapshot of the state of the entire project and its subrepositories. If any subrepositories
--- a/mercurial/hgweb/webcommands.py Mon Feb 02 14:26:47 2015 -0500 +++ b/mercurial/hgweb/webcommands.py Tue Feb 03 19:10:03 2015 -0600 @@ -187,7 +187,7 @@ mfunc = revset.match(web.repo.ui, revdef) try: - revs = mfunc(web.repo, revset.baseset(web.repo)) + revs = mfunc(web.repo, revset.spanset(web.repo)) return MODE_REVSET, revs # ParseError: wrongly placed tokens, wrongs arguments, etc # RepoLookupError: no such revision, e.g. in 'revision:'
--- a/mercurial/obsolete.py Mon Feb 02 14:26:47 2015 -0500 +++ b/mercurial/obsolete.py Tue Feb 03 19:10:03 2015 -0600 @@ -68,7 +68,7 @@ """ import struct -import util, base85, node +import util, base85, node, parsers import phases from i18n import _ @@ -146,7 +146,7 @@ _fm0fsize = _calcsize(_fm0fixed) _fm0fnodesize = _calcsize(_fm0node) -def _fm0readmarkers(data, off=0): +def _fm0readmarkers(data, off): # Loop on markers l = len(data) while off + _fm0fsize <= l: @@ -285,7 +285,7 @@ _fm1metapair = 'BB' _fm1metapairsize = _calcsize('BB') -def _fm1readmarkers(data, off=0): +def _fm1purereadmarkers(data, off): # make some global constants local for performance noneflag = _fm1parentnone sha2flag = usingsha256 @@ -301,6 +301,7 @@ # Loop on markers stop = len(data) - _fm1fsize ufixed = util.unpacker(_fm1fixed) + while off <= stop: # read fixed part o1 = off + fsize @@ -395,6 +396,13 @@ data.append(value) return ''.join(data) +def _fm1readmarkers(data, off): + native = getattr(parsers, 'fm1readmarkers', None) + if not native: + return _fm1purereadmarkers(data, off) + stop = len(data) - _fm1fsize + return native(data, off, stop) + # mapping to read/write various marker formats # <version> -> (decoder, encoder) formats = {_fm0version: (_fm0readmarkers, _fm0encodeonemarker),
--- a/mercurial/parsers.c Mon Feb 02 14:26:47 2015 -0500 +++ b/mercurial/parsers.c Tue Feb 03 19:10:03 2015 -0600 @@ -1676,108 +1676,6 @@ } /* - * Given a (possibly overlapping) set of revs, return the greatest - * common ancestors: those with the longest path to the root. - */ -static PyObject *index_ancestors(indexObject *self, PyObject *args) -{ - PyObject *ret = NULL, *gca = NULL; - Py_ssize_t argcount, i, len; - bitmask repeat = 0; - int revcount = 0; - int *revs; - - argcount = PySequence_Length(args); - revs = malloc(argcount * sizeof(*revs)); - if (argcount > 0 && revs == NULL) - return PyErr_NoMemory(); - len = index_length(self) - 1; - - for (i = 0; i < argcount; i++) { - static const int capacity = 24; - PyObject *obj = PySequence_GetItem(args, i); - bitmask x; - long val; - - if (!PyInt_Check(obj)) { - PyErr_SetString(PyExc_TypeError, - "arguments must all be ints"); - Py_DECREF(obj); - goto bail; - } - val = PyInt_AsLong(obj); - Py_DECREF(obj); - if (val == -1) { - ret = PyList_New(0); - goto done; - } - if (val < 0 || val >= len) { - PyErr_SetString(PyExc_IndexError, - "index out of range"); - goto bail; - } - /* this cheesy bloom filter lets us avoid some more - * expensive duplicate checks in the common set-is-disjoint - * case */ - x = 1ull << (val & 0x3f); - if (repeat & x) { - int k; - for (k = 0; k < revcount; k++) { - if (val == revs[k]) - goto duplicate; - } - } - else repeat |= x; - if (revcount >= capacity) { - PyErr_Format(PyExc_OverflowError, - "bitset size (%d) > capacity (%d)", - revcount, capacity); - goto bail; - } - revs[revcount++] = (int)val; - duplicate:; - } - - if (revcount == 0) { - ret = PyList_New(0); - goto done; - } - if (revcount == 1) { - PyObject *obj; - ret = PyList_New(1); - if (ret == NULL) - goto bail; - obj = PyInt_FromLong(revs[0]); - if (obj == NULL) - goto bail; - PyList_SET_ITEM(ret, 0, obj); - goto done; - } - - gca = find_gca_candidates(self, revs, revcount); - if (gca == NULL) - goto bail; - - if (PyList_GET_SIZE(gca) <= 1) { - ret = gca; - Py_INCREF(gca); - } - else ret = find_deepest(self, gca); - -done: - free(revs); - Py_XDECREF(gca); - - return ret; - -bail: - free(revs); - Py_XDECREF(gca); - Py_XDECREF(ret); - return NULL; -} - -/* * Given a (possibly overlapping) set of revs, return all the * common ancestors heads: heads(::args[0] and ::a[1] and ...) */ @@ -1871,6 +1769,24 @@ } /* + * Given a (possibly overlapping) set of revs, return the greatest + * common ancestors: those with the longest path to the root. + */ +static PyObject *index_ancestors(indexObject *self, PyObject *args) +{ + PyObject *gca = index_commonancestorsheads(self, args); + if (gca == NULL) + return NULL; + + if (PyList_GET_SIZE(gca) <= 1) { + Py_INCREF(gca); + return gca; + } + + return find_deepest(self, gca); +} + +/* * Invalidate any trie entries introduced by added revs. */ static void nt_invalidate_added(indexObject *self, Py_ssize_t start) @@ -2230,6 +2146,154 @@ return NULL; } +#define BUMPED_FIX 1 +#define USING_SHA_256 2 + +static PyObject *readshas( + const char *source, unsigned char num, Py_ssize_t hashwidth) +{ + int i; + PyObject *list = PyTuple_New(num); + if (list == NULL) { + return NULL; + } + for (i = 0; i < num; i++) { + PyObject *hash = PyString_FromStringAndSize(source, hashwidth); + if (hash == NULL) { + Py_DECREF(list); + return NULL; + } + PyTuple_SetItem(list, i, hash); + source += hashwidth; + } + return list; +} + +static PyObject *fm1readmarker(const char *data, uint32_t *msize) +{ + const char *meta; + + double mtime; + int16_t tz; + uint16_t flags; + unsigned char nsuccs, nparents, nmetadata; + Py_ssize_t hashwidth = 20; + + PyObject *prec = NULL, *parents = NULL, *succs = NULL; + PyObject *metadata = NULL, *ret = NULL; + int i; + + *msize = getbe32(data); + data += 4; + mtime = getbefloat64(data); + data += 8; + tz = getbeint16(data); + data += 2; + flags = getbeuint16(data); + data += 2; + + if (flags & USING_SHA_256) { + hashwidth = 32; + } + + nsuccs = (unsigned char)(*data++); + nparents = (unsigned char)(*data++); + nmetadata = (unsigned char)(*data++); + + prec = PyString_FromStringAndSize(data, hashwidth); + data += hashwidth; + if (prec == NULL) { + goto bail; + } + + succs = readshas(data, nsuccs, hashwidth); + if (succs == NULL) { + goto bail; + } + data += nsuccs * hashwidth; + + if (nparents == 1 || nparents == 2) { + parents = readshas(data, nparents, hashwidth); + if (parents == NULL) { + goto bail; + } + data += nparents * hashwidth; + } else { + parents = Py_None; + } + + meta = data + (2 * nmetadata); + metadata = PyTuple_New(nmetadata); + if (metadata == NULL) { + goto bail; + } + for (i = 0; i < nmetadata; i++) { + PyObject *tmp, *left = NULL, *right = NULL; + Py_ssize_t metasize = (unsigned char)(*data++); + left = PyString_FromStringAndSize(meta, metasize); + meta += metasize; + metasize = (unsigned char)(*data++); + right = PyString_FromStringAndSize(meta, metasize); + meta += metasize; + if (!left || !right) { + Py_XDECREF(left); + Py_XDECREF(right); + goto bail; + } + tmp = PyTuple_Pack(2, left, right); + Py_DECREF(left); + Py_DECREF(right); + if (!tmp) { + goto bail; + } + PyTuple_SetItem(metadata, i, tmp); + } + ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, + metadata, mtime, (int)tz * 60, parents); +bail: + Py_XDECREF(prec); + Py_XDECREF(succs); + Py_XDECREF(metadata); + if (parents != Py_None) + Py_XDECREF(parents); + return ret; +} + + +static PyObject *fm1readmarkers(PyObject *self, PyObject *args) { + const char *data; + Py_ssize_t datalen, offset, stop; + PyObject *markers = NULL; + + if (!PyArg_ParseTuple(args, "s#nn", &data, &datalen, &offset, &stop)) { + return NULL; + } + data += offset; + markers = PyList_New(0); + if (!markers) { + return NULL; + } + while (offset < stop) { + uint32_t msize; + int error; + PyObject *record = fm1readmarker(data, &msize); + if (!record) { + goto bail; + } + error = PyList_Append(markers, record); + Py_DECREF(record); + if (error) { + goto bail; + } + data += msize; + offset += msize; + } + return markers; +bail: + Py_DECREF(markers); + return NULL; +} + static char parsers_doc[] = "Efficient content parsing."; PyObject *encodedir(PyObject *self, PyObject *args); @@ -2245,6 +2309,8 @@ {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"}, {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"}, {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"}, + {"fm1readmarkers", fm1readmarkers, METH_VARARGS, + "parse v1 obsolete markers\n"}, {NULL, NULL} };
--- a/mercurial/patch.py Mon Feb 02 14:26:47 2015 -0500 +++ b/mercurial/patch.py Tue Feb 03 19:10:03 2015 -0600 @@ -1739,17 +1739,6 @@ def trydiff(repo, revs, ctx1, ctx2, modified, added, removed, copy, getfilectx, opts, losedatafn, prefix): - def join(f): - return posixpath.join(prefix, f) - - def addmodehdr(header, omode, nmode): - if omode != nmode: - header.append('old mode %s\n' % omode) - header.append('new mode %s\n' % nmode) - - def addindexmeta(meta, oindex, nindex): - meta.append('index %s..%s\n' % (oindex, nindex)) - def gitindex(text): if not text: text = "" @@ -1764,18 +1753,9 @@ aprefix = 'a/' bprefix = 'b/' - def diffline(a, b, revs): - if opts.git: - line = 'diff --git %s%s %s%s\n' % (aprefix, a, bprefix, b) - elif not repo.ui.quiet: - if revs: - revinfo = ' '.join(["-r %s" % rev for rev in revs]) - line = 'diff %s %s\n' % (revinfo, a) - else: - line = 'diff %s\n' % a - else: - line = '' - return line + def diffline(f, revs): + revinfo = ' '.join(["-r %s" % rev for rev in revs]) + return 'diff %s %s' % (revinfo, f) date1 = util.datestr(ctx1.date()) date2 = util.datestr(ctx2.date()) @@ -1785,99 +1765,105 @@ copyto = dict([(v, k) for k, v in copy.items()]) - if opts.git: - revs = None - - modifiedset, addedset, removedset = set(modified), set(added), set(removed) - # Fix up modified and added, since merged-in additions appear as + addedset, removedset = set(added), set(removed) + # Fix up added, since merged-in additions appear as # modifications during merges - for f in modifiedset.copy(): + for f in modified: if f not in ctx1: addedset.add(f) - modifiedset.remove(f) for f in sorted(modified + added + removed): - to = None - tn = None + flag1 = None + flag2 = None + content1 = None + content2 = None binarydiff = False - header = [] + op = None if f not in addedset: - to = getfilectx(f, ctx1).data() + content1 = getfilectx(f, ctx1).data() if f not in removedset: - tn = getfilectx(f, ctx2).data() - a, b = f, f + content2 = getfilectx(f, ctx2).data() + f1, f2 = f, f if opts.git or losedatafn: if f in addedset: - mode = gitmode[ctx2.flags(f)] - if f in copy or f in copyto: + flag2 = ctx2.flags(f) + if f in copy: if opts.git: - if f in copy: - a = copy[f] - else: - a = copyto[f] - omode = gitmode[ctx1.flags(a)] - addmodehdr(header, omode, mode) - if a in removedset and a not in gone: + f1 = copy[f] + flag1 = ctx1.flags(f1) + if f1 in removedset and f1 not in gone: op = 'rename' - gone.add(a) + gone.add(f1) else: op = 'copy' - header.append('%s from %s\n' % (op, join(a))) - header.append('%s to %s\n' % (op, join(f))) - to = getfilectx(a, ctx1).data() + content1 = getfilectx(f1, ctx1).data() else: losedatafn(f) else: - if opts.git: - header.append('new file mode %s\n' % mode) - elif ctx2.flags(f): + if not opts.git and flag2: losedatafn(f) - if util.binary(to) or util.binary(tn): + if util.binary(content1) or util.binary(content2): if opts.git: binarydiff = True else: losedatafn(f) - if not opts.git and not tn: + if not opts.git and not content2: # regular diffs cannot represent new empty file losedatafn(f) elif f in removedset: if opts.git: # have we already reported a copy above? - if ((f in copy and copy[f] in addedset - and copyto[copy[f]] == f) or - (f in copyto and copyto[f] in addedset - and copy[copyto[f]] == f)): + if (f in copyto and copyto[f] in addedset + and copy[copyto[f]] == f): continue else: - header.append('deleted file mode %s\n' % - gitmode[ctx1.flags(f)]) - if util.binary(to): + flag1 = ctx1.flags(f) + if util.binary(content1): binarydiff = True - elif not to or util.binary(to): + elif not content1 or util.binary(content1): # regular diffs cannot represent empty file deletion losedatafn(f) else: - oflag = ctx1.flags(f) - nflag = ctx2.flags(f) - binary = util.binary(to) or util.binary(tn) + flag1 = ctx1.flags(f) + flag2 = ctx2.flags(f) + binary = util.binary(content1) or util.binary(content2) if opts.git: - addmodehdr(header, gitmode[oflag], gitmode[nflag]) if binary: binarydiff = True - elif binary or nflag != oflag: + elif binary or flag2 != flag1: losedatafn(f) - if opts.git or revs: - header.insert(0, diffline(join(a), join(b), revs)) + path1 = posixpath.join(prefix, f1) + path2 = posixpath.join(prefix, f2) + header = [] + if opts.git: + header.append('diff --git %s%s %s%s' % + (aprefix, path1, bprefix, path2)) + if content1 is None: # added + header.append('new file mode %s' % gitmode[flag2]) + elif content2 is None: # removed + header.append('deleted file mode %s' % gitmode[flag1]) + else: # modified/copied/renamed + mode1, mode2 = gitmode[flag1], gitmode[flag2] + if mode1 != mode2: + header.append('old mode %s' % mode1) + header.append('new mode %s' % mode2) + if op is not None: + header.append('%s from %s' % (op, path1)) + header.append('%s to %s' % (op, path2)) + elif revs and not repo.ui.quiet: + header.append(diffline(path1, revs)) + if binarydiff and not opts.nobinary: - text = mdiff.b85diff(to, tn) + text = mdiff.b85diff(content1, content2) if text and opts.git: - addindexmeta(header, gitindex(to), gitindex(tn)) + header.append('index %s..%s' % + (gitindex(content1), gitindex(content2))) else: - text = mdiff.unidiff(to, date1, - tn, date2, - join(a), join(b), opts=opts) + text = mdiff.unidiff(content1, date1, + content2, date2, + path1, path2, opts=opts) if header and (text or len(header) > 1): - yield ''.join(header) + yield '\n'.join(header) + '\n' if text: yield text
--- a/mercurial/revset.py Mon Feb 02 14:26:47 2015 -0500 +++ b/mercurial/revset.py Tue Feb 03 19:10:03 2015 -0600 @@ -2242,6 +2242,71 @@ except error.ParseError, inst: return (decl, None, None, parseerrordetail(inst)) +def _parsealiasdefn(defn, args): + """Parse alias definition ``defn`` + + This function also replaces alias argument references in the + specified definition by ``_aliasarg(ARGNAME)``. + + ``args`` is a list of alias argument names, or None if the alias + is declared as a symbol. + + This returns "tree" as parsing result. + + >>> args = ['$1', '$2', 'foo'] + >>> print prettyformat(_parsealiasdefn('$1 or foo', args)) + (or + (func + ('symbol', '_aliasarg') + ('string', '$1')) + (func + ('symbol', '_aliasarg') + ('string', 'foo'))) + >>> try: + ... _parsealiasdefn('$1 or $bar', args) + ... except error.ParseError, inst: + ... print parseerrordetail(inst) + at 6: '$' not for alias arguments + >>> args = ['$1', '$10', 'foo'] + >>> print prettyformat(_parsealiasdefn('$10 or foobar', args)) + (or + (func + ('symbol', '_aliasarg') + ('string', '$10')) + ('symbol', 'foobar')) + >>> print prettyformat(_parsealiasdefn('"$1" or "foo"', args)) + (or + ('string', '$1') + ('string', 'foo')) + """ + def tokenizedefn(program, lookup=None): + if args: + argset = set(args) + else: + argset = set() + + for t, value, pos in _tokenizealias(program, lookup=lookup): + if t == 'symbol': + if value in argset: + # emulate tokenization of "_aliasarg('ARGNAME')": + # "_aliasarg()" is an unknown symbol only used separate + # alias argument placeholders from regular strings. + yield ('symbol', '_aliasarg', pos) + yield ('(', None, pos) + yield ('string', value, pos) + yield (')', None, pos) + continue + elif value.startswith('$'): + raise error.ParseError(_("'$' not for alias arguments"), + pos) + yield (t, value, pos) + + p = parser.parser(tokenizedefn, elements) + tree, pos = p.parse(defn) + if pos != len(defn): + raise error.ParseError(_('invalid token'), pos) + return tree + class revsetalias(object): # whether own `error` information is already shown or not. # this avoids showing same warning multiple times at each `findaliases`. @@ -2259,16 +2324,8 @@ ' "%s": %s') % (self.name, self.error) return - if self.args: - for arg in self.args: - # _aliasarg() is an unknown symbol only used separate - # alias argument placeholders from regular strings. - value = value.replace(arg, '_aliasarg(%r)' % (arg,)) - try: - self.replacement, pos = parse(value) - if pos != len(value): - raise error.ParseError(_('invalid token'), pos) + self.replacement = _parsealiasdefn(value, self.args) # Check for placeholder injection _checkaliasarg(self.replacement, self.args) except error.ParseError, inst:
--- a/mercurial/subrepo.py Mon Feb 02 14:26:47 2015 -0500 +++ b/mercurial/subrepo.py Tue Feb 03 19:10:03 2015 -0600 @@ -1577,6 +1577,25 @@ @annotatesubrepoerror + def cat(self, match, prefix, **opts): + rev = self._state[1] + if match.anypats(): + return 1 #No support for include/exclude yet + + if not match.files(): + return 1 + + for f in match.files(): + output = self._gitcommand(["show", "%s:%s" % (rev, f)]) + fp = cmdutil.makefileobj(self._subparent, opts.get('output'), + self._ctx.node(), + pathname=os.path.join(prefix, f)) + fp.write(output) + fp.close() + return 0 + + + @annotatesubrepoerror def status(self, rev2, **opts): rev1 = self._state[1] if self._gitmissing() or not rev1:
--- a/mercurial/unionrepo.py Mon Feb 02 14:26:47 2015 -0500 +++ b/mercurial/unionrepo.py Tue Feb 03 19:10:03 2015 -0600 @@ -160,9 +160,6 @@ def baserevdiff(self, rev1, rev2): return filelog.filelog.revdiff(self, rev1, rev2) - def _file(self, f): - self._repo.file(f) - class unionpeer(localrepo.localpeer): def canpush(self): return False
--- a/mercurial/util.h Mon Feb 02 14:26:47 2015 -0500 +++ b/mercurial/util.h Tue Feb 03 19:10:03 2015 -0600 @@ -172,6 +172,22 @@ (d[3])); } +static inline int16_t getbeint16(const char *c) +{ + const unsigned char *d = (const unsigned char *)c; + + return ((d[0] << 8) | + (d[1])); +} + +static inline uint16_t getbeuint16(const char *c) +{ + const unsigned char *d = (const unsigned char *)c; + + return ((d[0] << 8) | + (d[1])); +} + static inline void putbe32(uint32_t x, char *c) { c[0] = (x >> 24) & 0xff; @@ -180,4 +196,17 @@ c[3] = (x) & 0xff; } +static inline double getbefloat64(const char *c) +{ + const unsigned char *d = (const unsigned char *)c; + double ret; + int i; + uint64_t t = 0; + for (i = 0; i < 8; i++) { + t = (t<<8) + d[i]; + } + memcpy(&ret, &t, sizeof(t)); + return ret; +} + #endif /* _HG_UTIL_H_ */
--- a/tests/test-histedit-arguments.t Mon Feb 02 14:26:47 2015 -0500 +++ b/tests/test-histedit-arguments.t Tue Feb 03 19:10:03 2015 -0600 @@ -103,6 +103,15 @@ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg up --quiet +Test config specified default +----------------------------- + + $ HGEDITOR=cat hg histedit --config "histedit.defaultrev=only(.) - ::eb57da33312f" --commands - << EOF + > pick c8e68270e35a 3 four + > pick 08d98a8350f3 4 five + > EOF + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + Run on a revision not descendants of the initial parent --------------------------------------------------------------------
--- a/tests/test-histedit-drop.t Mon Feb 02 14:26:47 2015 -0500 +++ b/tests/test-histedit-drop.t Tue Feb 03 19:10:03 2015 -0600 @@ -96,7 +96,6 @@ Check histedit_source $ hg log --debug --rev f518305ce889 - invalid branchheads cache (visible): tip differs changeset: 4:f518305ce889c07cb5bd05522176d75590ef3324 tag: tip phase: draft
--- a/tests/test-rename.t Mon Feb 02 14:26:47 2015 -0500 +++ b/tests/test-rename.t Tue Feb 03 19:10:03 2015 -0600 @@ -620,10 +620,16 @@ $ hg rename d1/d11/a1 .hg abort: path contains illegal component: .hg/a1 (glob) [255] + $ hg --config extensions.largefiles= rename d1/d11/a1 .hg + abort: path contains illegal component: .hg/a1 (glob) + [255] $ hg status -C $ hg rename d1/d11/a1 .. abort: ../a1 not under root '$TESTTMP' (glob) [255] + $ hg --config extensions.largefiles= rename d1/d11/a1 .. + abort: ../a1 not under root '$TESTTMP' (glob) + [255] $ hg status -C $ mv d1/d11/a1 .hg
--- a/tests/test-revset.t Mon Feb 02 14:26:47 2015 -0500 +++ b/tests/test-revset.t Tue Feb 03 19:10:03 2015 -0600 @@ -1030,6 +1030,19 @@ ('symbol', 'tip') warning: failed to parse the declaration of revset alias "bad name": at 4: invalid token 9 + $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc + $ try 'strictreplacing("foo", tip)' + (func + ('symbol', 'strictreplacing') + (list + ('string', 'foo') + ('symbol', 'tip'))) + (or + ('symbol', 'tip') + (func + ('symbol', 'desc') + ('string', '$1'))) + 9 $ try 'd(2:5)' (func
--- a/tests/test-subrepo-git.t Mon Feb 02 14:26:47 2015 -0500 +++ b/tests/test-subrepo-git.t Tue Feb 03 19:10:03 2015 -0600 @@ -802,4 +802,52 @@ $ hg status --subrepos ? s/barfoo +show file at specific revision + $ cat > s/foobar << EOF + > woop woop + > fooo bar + > EOF + $ hg commit --subrepos -m "updated foobar" + committing subrepository s + $ cat > s/foobar << EOF + > current foobar + > (should not be visible using hg cat) + > EOF + + $ hg cat -r . s/foobar + woop woop + fooo bar (no-eol) + $ hg cat -r "parents(.)" s/foobar > catparents + + $ mkdir -p tmp/s + + $ hg cat -r "parents(.)" --output tmp/%% s/foobar + $ diff tmp/% catparents + + $ hg cat -r "parents(.)" --output tmp/%s s/foobar + $ diff tmp/foobar catparents + + $ hg cat -r "parents(.)" --output tmp/%d/otherfoobar s/foobar + $ diff tmp/s/otherfoobar catparents + + $ hg cat -r "parents(.)" --output tmp/%p s/foobar + $ diff tmp/s/foobar catparents + + $ hg cat -r "parents(.)" --output tmp/%H s/foobar + $ diff tmp/255ee8cf690ec86e99b1e80147ea93ece117cd9d catparents + + $ hg cat -r "parents(.)" --output tmp/%R s/foobar + $ diff tmp/10 catparents + + $ hg cat -r "parents(.)" --output tmp/%h s/foobar + $ diff tmp/255ee8cf690e catparents + + $ rm tmp/10 + $ hg cat -r "parents(.)" --output tmp/%r s/foobar + $ diff tmp/10 catparents + + $ mkdir tmp/tc + $ hg cat -r "parents(.)" --output tmp/%b/foobar s/foobar + $ diff tmp/tc/foobar catparents + $ cd ..