Mercurial > hg > mercurial-crew
changeset 429:688d03d6997a
Pull from TAH
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Pull from TAH
manifest hash: 600d04efbd836d555d11a3bd9d821d1d8c0a9790
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.0 (GNU/Linux)
iD8DBQFCuPFxywK+sNU5EO8RAjfzAKC18Zc2EOkXhy1zcpgGnyPHnFMdmgCfW5Ut
I5HSWqZMt8H0WJx1Or7ajNc=
=27D5
-----END PGP SIGNATURE-----
author | mpm@selenic.com |
---|---|
date | Tue, 21 Jun 2005 21:04:49 -0800 |
parents | 183c87d4e1a0 (diff) 36e644d28edf (current diff) |
children | 5b22029b5aa2 |
files | .hgignore TODO contrib/hgit mercurial/commands.py mercurial/hg.py mercurial/lock.py mercurial/mpatch.c mercurial/transaction.py mercurial/version.py setup.py tests/run-tests tests/test-help tests/test-help.out tests/test-simple-update.out |
diffstat | 33 files changed, 1095 insertions(+), 63 deletions(-) [+] |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/contrib/git-viz/git-cat-file @@ -0,0 +1,5 @@ +#!/bin/sh + +op=`basename $0 | sed -e 's/^git-//'` +exec hgit $op "$@" +
new file mode 100644 --- /dev/null +++ b/contrib/git-viz/git-diff-tree @@ -0,0 +1,5 @@ +#!/bin/sh + +op=`basename $0 | sed -e 's/^git-//'` +exec hgit $op "$@" +
new file mode 100644 --- /dev/null +++ b/contrib/git-viz/git-rev-list @@ -0,0 +1,5 @@ +#!/bin/sh + +op=`basename $0 | sed -e 's/^git-//'` +exec hgit $op "$@" +
new file mode 100644 --- /dev/null +++ b/contrib/git-viz/git-rev-tree @@ -0,0 +1,5 @@ +#!/bin/sh + +op=`basename $0 | sed -e 's/^git-//'` +exec hgit $op "$@" +
new file mode 100644 --- /dev/null +++ b/contrib/git-viz/hg-viz @@ -0,0 +1,26 @@ +#!/bin/sh + +set -e + +if test x"$1" != x ; then + cd $1 +fi + +if [ ! -d ".hg" ]; then + echo "${1:-.} is not a mercurial repository" 1>&2 + echo "Aborting" 1>&2 + exit 1 +fi +if [ ! -d ".git" ]; then + mkdir -v ".git" +fi +if [ -e ".git/HEAD" ]; then + if [ ! -e ".git/HEAD.hg-viz-save" ]; then + mv -v ".git/HEAD" ".git/HEAD.hg-viz-save" + else + rm -vf ".git/HEAD" + fi +fi +hg history | head -1 | awk -F: '{print $3}' > .git/HEAD +git-viz +
--- a/contrib/hgit +++ b/contrib/hgit @@ -38,12 +38,12 @@ for f in c: # TODO get file permissions - print ":100664 100664 %s %s %s %s" % (hg.hex(mmap[f]), + print ":100664 100664 %s %s M\t%s\t%s" % (hg.hex(mmap[f]), hg.hex(mmap2[f]), f, f) for f in a: - print ":000000 100664 %s %s %s %s" % (empty, hg.hex(mmap2[f]), f, f) + print ":000000 100664 %s %s N\t%s\t%s" % (empty, hg.hex(mmap2[f]), f, f) for f in d: - print ":100664 000000 %s %s %s %s" % (hg.hex(mmap[f]), empty, f, f) + print ":100664 000000 %s %s D\t%s\t%s" % (hg.hex(mmap[f]), empty, f, f) ## revs = []
new file mode 100644 --- /dev/null +++ b/mercurial/bdiff.c @@ -0,0 +1,293 @@ +/* + bdiff.c - efficient binary diff extension for Mercurial + + Copyright 2005 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. + + Based roughly on Python difflib +*/ + +#include <Python.h> +#include <stdlib.h> +#include <string.h> +#ifdef _WIN32 + +typedef unsigned long uint32_t; + +static uint32_t htonl(uint32_t x) +{ + return ((x & 0x000000ffUL) << 24) | + ((x & 0x0000ff00UL) << 8) | + ((x & 0x00ff0000UL) >> 8) | + ((x & 0xff000000UL) >> 24); +} + +#else + #include <netinet/in.h> + #include <sys/types.h> +#endif + +struct line { + int h, len, n; + const char *l; +}; + +struct hunk { + int a1, a2, b1, b2; +}; + +struct hunklist { + struct hunk *base, *head; +}; + +static inline uint32_t rol32(uint32_t word, unsigned int shift) +{ + return (word << shift) | (word >> (32 - shift)); +} + +int splitlines(const char *a, int len, struct line **lr) +{ + int h, i; + const char *p, *b = a; + struct line *l; + + /* count the lines */ + i = 1; /* extra line for sentinel */ + for (p = a; p < a + len; p++) + if (*p == '\n' || p == a + len - 1) + i++; + + *lr = l = malloc(sizeof(struct line) * i); + if (!l) + return -1; + + /* build the line array and calculate hashes */ + h = 0; + for (p = a; p < a + len; p++) { + h = *p + rol32(h, 7); /* a simple hash from GNU diff */ + if (*p == '\n' || p == a + len - 1) { + l->len = p - b + 1; + l->h = h; + l->l = b; + l->n = -1; + l++; + b = p + 1; + h = 0; + } + } + + /* set up a sentinel */ + l->h = l->len = 0; + l->l = a + len; + return i - 1; +} + +int inline cmp(struct line *a, struct line *b) +{ + return a->len != b->len || memcmp(a->l, b->l, a->len); +} + +static int equatelines(struct line *a, int an, struct line *b, int bn) +{ + int i, j, buckets = 1, t, *h, *l; + + /* build a hash table of the next highest power of 2 */ + while (buckets < bn + 1) + buckets *= 2; + + h = malloc(buckets * sizeof(int)); + l = calloc(buckets, sizeof(int)); + buckets = buckets - 1; + if (!h || !l) { + free(h); + return 0; + } + + /* clear the hash table */ + for (i = 0; i <= buckets; i++) + h[i] = -1; + + /* add lines to the hash table chains */ + for (i = bn - 1; i >= 0; i--) { + /* find the equivalence class */ + for (j = b[i].h & buckets; h[j] != -1; j = (j + 1) & buckets) + if (!cmp(b + i, b + h[j])) + break; + + /* add to the head of the equivalence class */ + b[i].n = h[j]; + b[i].h = j; + h[j] = i; + l[j]++; /* keep track of popularity */ + } + + /* compute popularity threshold */ + t = (bn >= 200) ? bn / 100 : bn + 1; + + /* match items in a to their equivalence class in b */ + for (i = 0; i < an; i++) { + /* find the equivalence class */ + for (j = a[i].h & buckets; h[j] != -1; j = (j + 1) & buckets) + if (!cmp(a + i, b + h[j])) + break; + + a[i].h = j; /* use equivalence class for quick compare */ + if(l[j] <= t) + a[i].n = h[j]; /* point to head of match list */ + else + a[i].n = -1; /* too popular */ + } + + /* discard hash tables */ + free(h); + free(l); + return 1; +} + +static int longest_match(struct line *a, struct line *b, int *jpos, int *jlen, + int a1, int a2, int b1, int b2, int *omi, int *omj) +{ + int mi = a1, mj = b1, mk = 0, mb = 0, i, j, k; + + for (i = a1; i < a2; i++) { + /* skip things before the current block */ + for (j = a[i].n; j != -1 && j < b1; j = b[j].n) + ; + + /* loop through all lines match a[i] in b */ + for (; j != -1 && j < b2; j = b[j].n) { + /* does this extend an earlier match? */ + if (i > a1 && j > b1 && jpos[j - 1] == i) + k = jlen[j - 1] + 1; + else + k = 1; + jpos[j] = i + 1; + jlen[j] = k; + + /* best match so far? */ + if (k > mk) { + mi = i; + mj = j; + mk = k; + } + } + } + + if (mk) { + mi = mi - mk + 1; + mj = mj - mk + 1; + } + + /* expand match to include neighboring popular lines */ + while (mi - mb > a1 && mj - mb > b1 && + a[mi - mb - 1].h == b[mj - mb - 1].h) + mb++; + while (mi + mk < a2 && mj + mk < b2 && + a[mi + mk].h == b[mj + mk].h) + mk++; + + *omi = mi - mb; + *omj = mj - mb; + return mk + mb; +} + +static void recurse(struct line *a, struct line *b, int *jpos, int *jlen, + int a1, int a2, int b1, int b2, struct hunklist *l) +{ + int i, j, k; + + /* find the longest match in this chunk */ + k = longest_match(a, b, jpos, jlen, a1, a2, b1, b2, &i, &j); + if (!k) + return; + + /* and recurse on the remaining chunks on either side */ + recurse(a, b, jpos, jlen, a1, i, b1, j, l); + l->head->a1 = i; + l->head->a2 = i + k; + l->head->b1 = j; + l->head->b2 = j + k; + l->head++; + recurse(a, b, jpos, jlen, i + k, a2, j + k, b2, l); +} + +static PyObject *bdiff(PyObject *self, PyObject *args) +{ + PyObject *sa, *sb, *result = NULL; + struct hunklist l; + struct hunk *h; + struct line *al, *bl; + char encode[12], *rb; + int an, bn, len = 0, t, la = 0, lb = 0, *jpos, *jlen; + + if (!PyArg_ParseTuple(args, "SS:bdiff", &sa, &sb)) + return NULL; + + /* allocate and fill arrays */ + an = splitlines(PyString_AsString(sa), PyString_Size(sa), &al); + bn = splitlines(PyString_AsString(sb), PyString_Size(sb), &bl); + t = equatelines(al, an, bl, bn); + jpos = calloc(bn, sizeof(int)); + jlen = calloc(bn, sizeof(int)); + l.head = l.base = malloc(sizeof(struct hunk) * ((an + bn) / 4 + 2)); + if (!al || !bl || !jpos || !jlen || !l.base || !t) + goto nomem; + + /* generate the matching block list */ + recurse(al, bl, jpos, jlen, 0, an, 0, bn, &l); + l.head->a1 = an; + l.head->b1 = bn; + l.head++; + + /* calculate length of output */ + for(h = l.base; h != l.head; h++) { + if (h->a1 != la || h->b1 != lb) + len += 12 + bl[h->b1].l - bl[lb].l; + la = h->a2; + lb = h->b2; + } + + result = PyString_FromStringAndSize(NULL, len); + if (!result) + goto nomem; + + /* build binary patch */ + rb = PyString_AsString(result); + la = lb = 0; + + for(h = l.base; h != l.head; h++) { + if (h->a1 != la || h->b1 != lb) { + len = bl[h->b1].l - bl[lb].l; + *(uint32_t *)(encode) = htonl(al[la].l - al->l); + *(uint32_t *)(encode + 4) = htonl(al[h->a1].l - al->l); + *(uint32_t *)(encode + 8) = htonl(len); + memcpy(rb, encode, 12); + memcpy(rb + 12, bl[lb].l, len); + rb += 12 + len; + } + la = h->a2; + lb = h->b2; + } + +nomem: + free(al); + free(bl); + free(jpos); + free(jlen); + free(l.base); + return result ? result : PyErr_NoMemory(); +} + +static char mdiff_doc[] = "Efficient binary diff."; + +static PyMethodDef methods[] = { + {"bdiff", bdiff, METH_VARARGS, "calculate a binary diff\n"}, + {NULL, NULL} +}; + +PyMODINIT_FUNC initbdiff(void) +{ + Py_InitModule3("bdiff", methods, mdiff_doc); +}
--- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -6,7 +6,7 @@ # of the GNU General Public License, incorporated herein by reference. import os, re, sys, signal -import fancyopts, ui, hg +import fancyopts, ui, hg, util from demandload import * demandload(globals(), "mdiff time hgweb traceback random signal errno version") @@ -16,20 +16,20 @@ l = [ x for x in files if x in filters ] for t in filters: - if t and t[-1] != os.sep: t += os.sep + if t and t[-1] != "/": t += "/" l += [ x for x in files if x.startswith(t) ] return l def relfilter(repo, files): if os.getcwd() != repo.root: p = os.getcwd()[len(repo.root) + 1: ] - return filterfiles([p], files) + return filterfiles([util.pconvert(p)], files) return files def relpath(repo, args): if os.getcwd() != repo.root: p = os.getcwd()[len(repo.root) + 1: ] - return [ os.path.normpath(os.path.join(p, x)) for x in args ] + return [ util.pconvert(os.path.normpath(os.path.join(p, x))) for x in args ] return args def dodiff(ui, repo, path, files = None, node1 = None, node2 = None): @@ -47,7 +47,7 @@ (c, a, d, u) = repo.diffdir(path, node1) if not node1: node1 = repo.dirstate.parents()[0] - def read(f): return file(os.path.join(repo.root, f)).read() + def read(f): return repo.wfile(f).read() if ui.quiet: r = None @@ -285,7 +285,7 @@ sys.stdout.write(chunk) def debugindex(ui, file): - r = hg.revlog(open, file, "") + r = hg.revlog(hg.opener(""), file, "") print " rev offset length base linkrev"+\ " p1 p2 nodeid" for i in range(r.count()): @@ -295,7 +295,7 @@ hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])) def debugindexdot(ui, file): - r = hg.revlog(open, file, "") + r = hg.revlog(hg.opener(""), file, "") print "digraph G {" for i in range(r.count()): e = r.index[i] @@ -485,17 +485,27 @@ addremove(ui, repo, *files) repo.commit(files, text) -def pull(ui, repo, source="default"): +def pull(ui, repo, source="default", **opts): """pull changes from the specified source""" paths = {} for name, path in ui.configitems("paths"): paths[name] = path - if source in paths: source = paths[source] + if source in paths: + source = paths[source] + + ui.status('pulling from %s\n' % (source)) other = hg.repository(ui, source) cg = repo.getchangegroup(other) - repo.addchangegroup(cg) + r = repo.addchangegroup(cg) + if cg and not r: + if opts['update']: + return update(ui, repo) + else: + ui.status("(run 'hg update' to get a working copy)\n") + + return r def push(ui, repo, dest="default-push"): """push changes to the specified destination""" @@ -533,7 +543,7 @@ os.kill(child, signal.SIGTERM) return r -def rawcommit(ui, repo, flist, **rc): +def rawcommit(ui, repo, *flist, **rc): "raw commit interface" text = rc['text'] @@ -544,7 +554,7 @@ print "missing commit text" return 1 - files = relpath(repo, flist) + files = relpath(repo, list(flist)) if rc['files']: files += open(rc['files']).read().splitlines() @@ -579,6 +589,35 @@ for f in d: print "R", f for f in u: print "?", f +def tag(ui, repo, name, rev = None, **opts): + """add a tag for the current tip or a given revision""" + + if name == "tip": + ui.warn("abort: 'tip' is a reserved name!\n") + return -1 + + (c, a, d, u) = repo.diffdir(repo.root) + for x in (c, a, d, u): + if ".hgtags" in x: + ui.warn("abort: working copy of .hgtags is changed!\n") + ui.status("(please commit .hgtags manually)\n") + return -1 + + if rev: + r = hg.hex(repo.lookup(rev)) + else: + r = hg.hex(repo.changelog.tip()) + + add = 0 + if not os.path.exists(repo.wjoin(".hgtags")): add = 1 + repo.wfile(".hgtags", "a").write("%s %s\n" % (r, name)) + if add: repo.add([".hgtags"]) + + if not opts['text']: + opts['text'] = "Added tag %s for changeset %s" % (name, r) + + repo.commit([".hgtags"], opts['text'], opts['user'], opts['date']) + def tags(ui, repo): """list repository tags""" @@ -662,7 +701,9 @@ ('b', 'base', "", 'base path'), ('q', 'quiet', "", 'silence diff')], "hg import [options] patches"), - "pull|merge": (pull, [], 'hg pull [source]'), + "pull|merge": (pull, + [('u', 'update', None, 'update working directory')], + 'hg pull [options] [source]'), "push": (push, [], 'hg push <destination>'), "rawcommit": (rawcommit, [('p', 'parent', [], 'parent'), @@ -680,6 +721,10 @@ ('t', 'templates', "", 'template map')], "hg serve [options]"), "status": (status, [], 'hg status'), + "tag": (tag, [('t', 'text', "", 'commit text'), + ('d', 'date', "", 'date'), + ('u', 'user', "", 'user')], + 'hg tag [options] <name> [rev]'), "tags": (tags, [], 'hg tags'), "tip": (tip, [], 'hg tip'), "undo": (undo, [], 'hg undo'),
--- a/mercurial/hg.py +++ b/mercurial/hg.py @@ -6,6 +6,7 @@ # of the GNU General Public License, incorporated herein by reference. import sys, struct, os +import util from revlog import * from demandload import * demandload(globals(), "re lock urllib urllib2 transaction time socket") @@ -336,8 +337,8 @@ os.makedirs(d) else: if s.st_nlink > 1: - file(f + ".tmp", "w").write(file(f).read()) - os.rename(f+".tmp", f) + file(f + ".tmp", "wb").write(file(f, "rb").read()) + util.rename(f+".tmp", f) return file(f, mode) @@ -353,11 +354,15 @@ if not path: p = os.getcwd() while not os.path.isdir(os.path.join(p, ".hg")): + oldp = p p = os.path.dirname(p) - if p == "/": raise "No repo found" + if p == oldp: raise "No repo found" path = p self.path = os.path.join(path, ".hg") + if not create and not os.path.isdir(self.path): + raise "repository %s not found" % self.path + self.root = path self.ui = ui @@ -383,10 +388,10 @@ if self.ignorelist is None: self.ignorelist = [] try: - l = self.wfile(".hgignore") + l = file(self.wjoin(".hgignore")) for pat in l: if pat != "\n": - self.ignorelist.append(re.compile(pat[:-1])) + self.ignorelist.append(re.compile(util.pconvert(pat[:-1]))) except IOError: pass for pat in self.ignorelist: if pat.search(f): return True @@ -477,7 +482,7 @@ self.ui.status("attempting to rollback last transaction\n") transaction.rollback(self.opener, self.join("undo")) self.dirstate = None - os.rename(self.join("undo.dirstate"), self.join("dirstate")) + util.rename(self.join("undo.dirstate"), self.join("dirstate")) self.dirstate = dirstate(self.opener, self.ui, self.root) else: self.ui.warn("no undo information available\n") @@ -566,7 +571,7 @@ try: fp = self.wjoin(f) mf1[f] = is_exec(fp) - t = file(fp).read() + t = self.wfile(f).read() except IOError: self.warn("trouble committing %s!\n" % f) raise @@ -585,7 +590,9 @@ # update manifest m1.update(new) - for f in remove: del m1[f] + for f in remove: + if f in m1: + del m1[f] mn = self.manifest.add(m1, mf1, tr, linkrev, c1[0], c2[0]) # add changeset @@ -634,7 +641,7 @@ if ".hg" in subdirs: subdirs.remove(".hg") for f in files: - fn = os.path.join(d, f) + fn = util.pconvert(os.path.join(d, f)) try: s = os.stat(os.path.join(self.root, fn)) except: continue if fn in dc: @@ -706,6 +713,9 @@ p = self.wjoin(f) if os.path.isfile(p): self.ui.warn("%s still exists!\n" % f) + elif self.dirstate.state(f) == 'a': + self.ui.warn("%s never committed!\n" % f) + self.dirstate.forget(f) elif f not in self.dirstate: self.ui.warn("%s not tracked!\n" % f) else: @@ -1001,10 +1011,14 @@ m2 = self.manifest.read(m2n) mf2 = self.manifest.readflags(m2n) ma = self.manifest.read(man) - mfa = self.manifest.readflags(m2n) + mfa = self.manifest.readflags(man) (c, a, d, u) = self.diffdir(self.root) + # is this a jump, or a merge? i.e. is there a linear path + # from p1 to p2? + linear_path = (pa == p1 or pa == p2) + # resolve the manifest to determine which files # we care about merging self.ui.note("resolving manifests\n") @@ -1025,17 +1039,33 @@ for f in d: if f in mw: del mw[f] + # If we're jumping between revisions (as opposed to merging), + # and if neither the working directory nor the target rev has + # the file, then we need to remove it from the dirstate, to + # prevent the dirstate from listing the file when it is no + # longer in the manifest. + if linear_path and f not in m2: + self.dirstate.forget((f,)) + for f, n in mw.iteritems(): if f in m2: s = 0 + # is the wfile new since m1, and match m2? + if f not in m1: + t1 = self.wfile(f).read() + t2 = self.file(f).revision(m2[f]) + if cmp(t1, t2) == 0: + mark[f] = 1 + n = m2[f] + del t1, t2 + # are files different? if n != m2[f]: a = ma.get(f, nullid) # are both different from the ancestor? if n != a and m2[f] != a: self.ui.debug(" %s versions differ, resolve\n" % f) - merge[f] = (m1.get(f, nullid), m2[f]) # merge executable bits # "if we changed or they changed, change in merge" a, b, c = mfa.get(f, 0), mfw[f], mf2[f] @@ -1066,9 +1096,11 @@ del m2[f] elif f in ma: if not force and n != ma[f]: - r = self.ui.prompt( - (" local changed %s which remote deleted\n" % f) + - "(k)eep or (d)elete?", "[kd]", "k") + r = "" + if linear_path or allow: + r = self.ui.prompt( + (" local changed %s which remote deleted\n" % f) + + "(k)eep or (d)elete?", "[kd]", "k") if r == "d": remove.append(f) else: @@ -1087,9 +1119,11 @@ for f, n in m2.iteritems(): if f[0] == "/": continue if not force and f in ma and n != ma[f]: - r = self.ui.prompt( - ("remote changed %s which local deleted\n" % f) + - "(k)eep or (d)elete?", "[kd]", "k") + r = "" + if linear_path or allow: + r = self.ui.prompt( + ("remote changed %s which local deleted\n" % f) + + "(k)eep or (d)elete?", "[kd]", "k") if r == "d": remove.append(f) else: self.ui.debug("remote created %s\n" % f) @@ -1102,7 +1136,7 @@ get[f] = merge[f][1] merge = {} - if pa == p1 or pa == p2: + if linear_path: # we don't need to do any magic, just jump to the new rev mode = 'n' p1, p2 = p2, nullid @@ -1166,7 +1200,7 @@ def temp(prefix, node): pre = "%s~%s." % (os.path.basename(fn), prefix) (fd, name) = tempfile.mkstemp("", pre) - f = os.fdopen(fd, "w") + f = os.fdopen(fd, "wb") f.write(fl.revision(node)) f.close() return name
--- a/mercurial/lock.py +++ b/mercurial/lock.py @@ -6,6 +6,7 @@ # of the GNU General Public License, incorporated herein by reference. import os, time +import util class LockHeld(Exception): pass @@ -34,10 +35,10 @@ def trylock(self): pid = os.getpid() try: - os.symlink(str(pid), self.f) + util.makelock(str(pid), self.f) self.held = 1 except: - raise LockHeld(os.readlink(self.f)) + raise LockHeld(util.readlock(self.f)) def release(self): if self.held:
--- a/mercurial/mpatch.c +++ b/mercurial/mpatch.c @@ -23,8 +23,22 @@ #include <Python.h> #include <stdlib.h> #include <string.h> -#include <netinet/in.h> -#include <sys/types.h> +#ifdef _WIN32 + +typedef unsigned long uint32_t; + +static uint32_t ntohl(uint32_t x) +{ + return ((x & 0x000000ffUL) << 24) | + ((x & 0x0000ff00UL) << 8) | + ((x & 0x00ff0000UL) >> 8) | + ((x & 0xff000000UL) >> 24); +} + +#else + #include <netinet/in.h> + #include <sys/types.h> +#endif static char mpatch_doc[] = "Efficient binary patching.";
--- a/mercurial/transaction.py +++ b/mercurial/transaction.py @@ -12,6 +12,7 @@ # of the GNU General Public License, incorporated herein by reference. import os +import util class transaction: def __init__(self, opener, journal, after = None): @@ -46,7 +47,7 @@ self.file.close() self.entries = [] if self.after: - os.rename(self.journal, self.after) + util.rename(self.journal, self.after) else: os.unlink(self.journal)
new file mode 100644 --- /dev/null +++ b/mercurial/util.py @@ -0,0 +1,39 @@ +# util.py - utility functions and platform specfic implementations +# +# Copyright 2005 K. Thananchayan <thananck@yahoo.com> +# +# This software may be used and distributed according to the terms +# of the GNU General Public License, incorporated herein by reference. + +import os + +def rename(src, dst): + try: + os.rename(src, dst) + except: + os.unlink(dst) + os.rename(src, dst) + +# Platfor specific varients +if os.name == 'nt': + def pconvert(path): + return path.replace("\\", "/") + + def makelock(info, pathname): + ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL) + os.write(ld, info) + os.close(ld) + + def readlock(pathname): + return file(pathname).read() +else: + def pconvert(path): + return path + + def makelock(info, pathname): + os.symlink(info, pathname) + + def readlock(pathname): + return os.readlink(pathname) + +
--- a/setup.py +++ b/setup.py @@ -23,19 +23,20 @@ try: mercurial.version.remember_version(version) setup(name='mercurial', - version=mercurial.version.get_version(), - author='Matt Mackall', - author_email='mpm@selenic.com', - url='http://selenic.com/mercurial', - description='scalable distributed SCM', - license='GNU GPL', - packages=['mercurial'], - ext_modules=[Extension('mercurial.mpatch', ['mercurial/mpatch.c'])], - data_files=[('mercurial/templates', - ['templates/map'] + - glob.glob('templates/map-*') + - glob.glob('templates/*.tmpl'))], - cmdclass = { 'install_data' : install_package_data }, - scripts=['hg', 'hgmerge']) + version=mercurial.version.get_version(), + author='Matt Mackall', + author_email='mpm@selenic.com', + url='http://selenic.com/mercurial', + description='scalable distributed SCM', + license='GNU GPL', + packages=['mercurial'], + ext_modules=[Extension('mercurial.mpatch', ['mercurial/mpatch.c']), + Extension('mercurial.bdiff', ['mercurial/bdiff.c'])], + data_files=[('mercurial/templates', + ['templates/map'] + + glob.glob('templates/map-*') + + glob.glob('templates/*.tmpl'))], + cmdclass = { 'install_data' : install_package_data }, + scripts=['hg', 'hgmerge']) finally: mercurial.version.forget_version()
--- a/tests/run-tests +++ b/tests/run-tests @@ -6,8 +6,22 @@ failed=0 H=$PWD +TESTPATH=$PWD/install/bin +export PATH=$TESTPATH:$PATH +export PYTHONPATH=$PWD/install/lib/python + +rm -rf install +cd .. +${PYTHON:-python} setup.py install --home=tests/install > tests/install.err +if [ $? != 0 ] ; then + cat tests/install.err +fi +cd $H +rm install.err + function run_one { + rm -f $1.err export TZ=GMT D=`mktemp -d` if [ "$D" == "" ] ; then @@ -17,20 +31,20 @@ cd $D fail=0 - if ! $H/$f > .out 2>&1 ; then - echo $f failed with error code $? + if ! $H/$1 > .out 2>&1 ; then + echo $1 failed with error code $? fail=1 fi - if [ -s .out -a ! -r $H/$f.out ] ; then - echo $f generated unexpected output: + if [ -s .out -a ! -r $H/$1.out ] ; then + echo $1 generated unexpected output: cat .out - cp .out $H/$f.err + cp .out $H/$1.err fail=1 - elif [ -r $H/$f.out ] && ! diff -u $H/$f.out .out > /dev/null ; then - echo $f output changed: - diff -u $H/$f.out .out && true - cp .out $H/$f.err + elif [ -r $H/$1.out ] && ! diff -u $H/$1.out .out > /dev/null ; then + echo $1 output changed: + diff -u $H/$1.out .out && true + cp .out $H/$1.err fail=1 fi @@ -52,6 +66,8 @@ tests=$[$tests + 1] done +rm -rf install + echo echo Ran $tests tests, $failed failed
new file mode 100755 --- /dev/null +++ b/tests/test-bdiff @@ -0,0 +1,42 @@ +#!/usr/bin/env python + +import sys +from mercurial import bdiff, mpatch + +def test1(a, b): + d = bdiff.bdiff(a, b) + c = a + if d: + c = mpatch.patches(a, [d]) + if c != b: + print "***", `a`, `b` + print "bad:" + print `c`[:200] + print `d` + +def test(a, b): + print "***", `a`, `b` + test1(a, b) + test1(b, a) + +test("a\nc\n\n\n\n", "a\nb\n\n\n") +test("a\nb\nc\n", "a\nc\n") +test("", "") +test("a\nb\nc", "a\nb\nc") +test("a\nb\nc\nd\n", "a\nd\n") +test("a\nb\nc\nd\n", "a\nc\ne\n") +test("a\nb\nc\n", "a\nc\n") +test("a\n", "c\na\nb\n") +test("a\n", "") +test("a\n", "b\nc\n") +test("a\n", "c\na\n") +test("", "adjfkjdjksdhfksj") +test("", "ab") +test("", "abc") +test("a", "a") +test("ab", "ab") +test("abc", "abc") +test("a\n", "a\n") +test("a\nb", "a\nb") + +print "done"
new file mode 100644 --- /dev/null +++ b/tests/test-bdiff.out @@ -0,0 +1,20 @@ +*** 'a\nc\n\n\n\n' 'a\nb\n\n\n' +*** 'a\nb\nc\n' 'a\nc\n' +*** '' '' +*** 'a\nb\nc' 'a\nb\nc' +*** 'a\nb\nc\nd\n' 'a\nd\n' +*** 'a\nb\nc\nd\n' 'a\nc\ne\n' +*** 'a\nb\nc\n' 'a\nc\n' +*** 'a\n' 'c\na\nb\n' +*** 'a\n' '' +*** 'a\n' 'b\nc\n' +*** 'a\n' 'c\na\n' +*** '' 'adjfkjdjksdhfksj' +*** '' 'ab' +*** '' 'abc' +*** 'a' 'a' +*** 'ab' 'ab' +*** 'abc' 'abc' +*** 'a\n' 'a\n' +*** 'a\nb' 'a\nb' +done
new file mode 100755 --- /dev/null +++ b/tests/test-flags @@ -0,0 +1,33 @@ +#!/bin/sh +ex + +mkdir test1 +cd test1 + +hg init +touch a b +hg add a b +hg ci -t "added a b" -u test -d "0 0" + +cd .. +mkdir test2 +cd test2 + +hg init +hg merge ../test1 +hg co +chmod +x a +hg ci -t "chmod +x a" -u test -d "0 0" + +cd ../test1 +echo 123 >>a +hg ci -t "a updated" -u test -d "0 0" + +hg merge ../test2 +hg heads +hg history + +hg -dv co -m + +ls -l ../test[12]/a > foo +cut -b 0-10 < foo +
new file mode 100644 --- /dev/null +++ b/tests/test-flags.out @@ -0,0 +1,51 @@ +pulling from ../test1 +requesting all changes +adding changesets +adding manifests +adding file revisions +modified 2 files, added 1 changesets and 2 new revisions +(run 'hg update' to get a working copy) +pulling from ../test2 +searching for changes +adding changesets +adding manifests +adding file revisions +modified 1 files, added 1 changesets and 1 new revisions +(run 'hg update' to get a working copy) +changeset: 2:3ef54330565526bebf37a0d9bf540c283fd133a1 +tag: tip +parent: 0:22a449e20da501ca558394c083ca470e9c81b9f7 +user: test +date: Thu Jan 1 00:00:00 1970 +summary: chmod +x a + +changeset: 1:c6ecefc45368ed556d965f1c1086c6561a8b2ac5 +user: test +date: Thu Jan 1 00:00:00 1970 +summary: a updated + +changeset: 2:3ef54330565526bebf37a0d9bf540c283fd133a1 +tag: tip +parent: 0:22a449e20da501ca558394c083ca470e9c81b9f7 +user: test +date: Thu Jan 1 00:00:00 1970 +summary: chmod +x a + +changeset: 1:c6ecefc45368ed556d965f1c1086c6561a8b2ac5 +user: test +date: Thu Jan 1 00:00:00 1970 +summary: a updated + +changeset: 0:22a449e20da501ca558394c083ca470e9c81b9f7 +user: test +date: Thu Jan 1 00:00:00 1970 +summary: added a b + +resolving manifests + ancestor f328b97f7c11 local e7f06daf1cdb remote 629f0b785e0e + a versions differ, resolve +merging a +resolving a +file a: other 37c42bd6cc03 ancestor b80de5d13875 +-rwxr-xr-x +-rwxr-xr-x
--- a/tests/test-help.out +++ b/tests/test-help.out @@ -26,6 +26,7 @@ remove remove the specified files on the next commit serve export the repository via HTTP status show changed files in the working directory + tag add a tag for the current tip or a given revision tags list repository tags tip show the tip revision undo undo the last transaction @@ -74,6 +75,7 @@ remove remove the specified files on the next commit serve export the repository via HTTP status show changed files in the working directory + tag add a tag for the current tip or a given revision tags list repository tags tip show the tip revision undo undo the last transaction
new file mode 100755 --- /dev/null +++ b/tests/test-merge1 @@ -0,0 +1,85 @@ +#!/bin/sh -x + +cat <<'EOF' > merge +#!/bin/sh +echo merging for `basename $1` +EOF +chmod +x merge + +mkdir t +cd t +hg init +echo This is file a1 > a +hg add a +hg commit -t "commit #0" -d "0 0" -u user +echo This is file b1 > b +hg add b +hg commit -t "commit #1" -d "0 0" -u user + +hg update 0 +echo This is file c1 > c +hg add c +hg commit -t "commit #2" -d "0 0" -u user +echo This is file b1 > b +env HGMERGE=../merge hg update -m 1 +# no merges expected +cd ..; /bin/rm -rf t + +mkdir t +cd t +hg init +echo This is file a1 > a +hg add a +hg commit -t "commit #0" -d "0 0" -u user +echo This is file b1 > b +hg add b +hg commit -t "commit #1" -d "0 0" -u user + +hg update 0 +echo This is file c1 > c +hg add c +hg commit -t "commit #2" -d "0 0" -u user +echo This is file b2 > b +env HGMERGE=../merge hg update -m 1 +# merge of b expected +cd ..; /bin/rm -rf t + +mkdir t +cd t +hg init +echo This is file a1 > a +hg add a +hg commit -t "commit #0" -d "0 0" -u user +echo This is file b1 > b +hg add b +hg commit -t "commit #1" -d "0 0" -u user +echo This is file b22 > b +hg commit -t "commit #2" -d "0 0" -u user +hg update 1 +echo This is file c1 > c +hg add c +hg commit -t "commit #3" -d "0 0" -u user +echo This is file b22 > b +env HGMERGE=../merge hg update -m 2 +# no merges expected +cd ..; /bin/rm -rf t + +mkdir t +cd t +hg init +echo This is file a1 > a +hg add a +hg commit -t "commit #0" -d "0 0" -u user +echo This is file b1 > b +hg add b +hg commit -t "commit #1" -d "0 0" -u user +echo This is file b22 > b +hg commit -t "commit #2" -d "0 0" -u user +hg update 1 +echo This is file c1 > c +hg add c +hg commit -t "commit #3" -d "0 0" -u user +echo This is file b33 > b +env HGMERGE=../merge hg update -m 2 +# merge of b expected +cd ..; /bin/rm -rf t
new file mode 100644 --- /dev/null +++ b/tests/test-merge1.out @@ -0,0 +1,78 @@ ++ cat ++ chmod +x merge ++ mkdir t ++ cd t ++ hg init ++ echo This is file a1 ++ hg add a ++ hg commit -t 'commit #0' -d '0 0' -u user ++ echo This is file b1 ++ hg add b ++ hg commit -t 'commit #1' -d '0 0' -u user ++ hg update 0 ++ echo This is file c1 ++ hg add c ++ hg commit -t 'commit #2' -d '0 0' -u user ++ echo This is file b1 ++ env HGMERGE=../merge hg update -m 1 ++ cd .. ++ /bin/rm -rf t ++ mkdir t ++ cd t ++ hg init ++ echo This is file a1 ++ hg add a ++ hg commit -t 'commit #0' -d '0 0' -u user ++ echo This is file b1 ++ hg add b ++ hg commit -t 'commit #1' -d '0 0' -u user ++ hg update 0 ++ echo This is file c1 ++ hg add c ++ hg commit -t 'commit #2' -d '0 0' -u user ++ echo This is file b2 ++ env HGMERGE=../merge hg update -m 1 +merging for b +merging b ++ cd .. ++ /bin/rm -rf t ++ mkdir t ++ cd t ++ hg init ++ echo This is file a1 ++ hg add a ++ hg commit -t 'commit #0' -d '0 0' -u user ++ echo This is file b1 ++ hg add b ++ hg commit -t 'commit #1' -d '0 0' -u user ++ echo This is file b22 ++ hg commit -t 'commit #2' -d '0 0' -u user ++ hg update 1 ++ echo This is file c1 ++ hg add c ++ hg commit -t 'commit #3' -d '0 0' -u user ++ echo This is file b22 ++ env HGMERGE=../merge hg update -m 2 ++ cd .. ++ /bin/rm -rf t ++ mkdir t ++ cd t ++ hg init ++ echo This is file a1 ++ hg add a ++ hg commit -t 'commit #0' -d '0 0' -u user ++ echo This is file b1 ++ hg add b ++ hg commit -t 'commit #1' -d '0 0' -u user ++ echo This is file b22 ++ hg commit -t 'commit #2' -d '0 0' -u user ++ hg update 1 ++ echo This is file c1 ++ hg add c ++ hg commit -t 'commit #3' -d '0 0' -u user ++ echo This is file b33 ++ env HGMERGE=../merge hg update -m 2 +merging for b +merging b ++ cd .. ++ /bin/rm -rf t
new file mode 100755 --- /dev/null +++ b/tests/test-merge2 @@ -0,0 +1,48 @@ +#!/bin/sh -x + +mkdir t +cd t +hg init +echo This is file a1 > a +hg add a +hg commit -t "commit #0" -d "0 0" -u user +echo This is file b1 > b +hg add b +hg commit -t "commit #1" -d "0 0" -u user +rm b +hg update 0 +echo This is file b2 > b +hg add b +hg commit -t "commit #2" -d "0 0" -u user +cd ..; /bin/rm -rf t + +mkdir t +cd t +hg init +echo This is file a1 > a +hg add a +hg commit -t "commit #0" -d "0 0" -u user +echo This is file b1 > b +hg add b +hg commit -t "commit #1" -d "0 0" -u user +rm b +hg update 0 +echo This is file b2 > b +hg commit -A -t "commit #2" -d "0 0" -u user +cd ..; /bin/rm -rf t + +mkdir t +cd t +hg init +echo This is file a1 > a +hg add a +hg commit -t "commit #0" -d "0 0" -u user +echo This is file b1 > b +hg add b +hg commit -t "commit #1" -d "0 0" -u user +rm b +hg remove b +hg update 0 +echo This is file b2 > b +hg commit -A -t "commit #2" -d "0 0" -u user +cd ..; /bin/rm -rf t
new file mode 100644 --- /dev/null +++ b/tests/test-merge2.out @@ -0,0 +1,47 @@ ++ mkdir t ++ cd t ++ hg init ++ echo This is file a1 ++ hg add a ++ hg commit -t 'commit #0' -d '0 0' -u user ++ echo This is file b1 ++ hg add b ++ hg commit -t 'commit #1' -d '0 0' -u user ++ rm b ++ hg update 0 ++ echo This is file b2 ++ hg add b ++ hg commit -t 'commit #2' -d '0 0' -u user ++ cd .. ++ /bin/rm -rf t ++ mkdir t ++ cd t ++ hg init ++ echo This is file a1 ++ hg add a ++ hg commit -t 'commit #0' -d '0 0' -u user ++ echo This is file b1 ++ hg add b ++ hg commit -t 'commit #1' -d '0 0' -u user ++ rm b ++ hg update 0 ++ echo This is file b2 ++ hg commit -A -t 'commit #2' -d '0 0' -u user ++ cd .. ++ /bin/rm -rf t ++ mkdir t ++ cd t ++ hg init ++ echo This is file a1 ++ hg add a ++ hg commit -t 'commit #0' -d '0 0' -u user ++ echo This is file b1 ++ hg add b ++ hg commit -t 'commit #1' -d '0 0' -u user ++ rm b ++ hg remove b ++ hg update 0 ++ echo This is file b2 ++ hg commit -A -t 'commit #2' -d '0 0' -u user ++ cd .. ++ /bin/rm -rf t
new file mode 100755 --- /dev/null +++ b/tests/test-merge3 @@ -0,0 +1,10 @@ +#!/bin/sh -x + +hg init +echo This is file a1 > a +hg add a +hg commit -t "commit #0" -d "0 0" -u user +touch b +hg add b +rm b +hg commit -A -t"comment #1" -d "0 0" -u user
new file mode 100644 --- /dev/null +++ b/tests/test-merge3.out @@ -0,0 +1,9 @@ ++ hg init ++ echo This is file a1 ++ hg add a ++ hg commit -t 'commit #0' -d '0 0' -u user ++ touch b ++ hg add b ++ rm b ++ hg commit -A '-tcomment #1' -d '0 0' -u user +b never committed!
new file mode 100755 --- /dev/null +++ b/tests/test-merge4 @@ -0,0 +1,17 @@ +#!/bin/sh -x + +hg init +echo This is file a1 > a +hg add a +hg commit -t "commit #0" -d "0 0" -u user +echo This is file b1 > b +hg add b +hg commit -t "commit #1" -d "0 0" -u user +hg update 0 +echo This is file c1 > c +hg add c +hg commit -t "commit #2" -d "0 0" -u user +hg update -m 1 +rm b +echo This is file c22 > c +hg commit -t "commit #3" -d "0 0" -u user
new file mode 100644 --- /dev/null +++ b/tests/test-merge4.out @@ -0,0 +1,15 @@ ++ hg init ++ echo This is file a1 ++ hg add a ++ hg commit -t 'commit #0' -d '0 0' -u user ++ echo This is file b1 ++ hg add b ++ hg commit -t 'commit #1' -d '0 0' -u user ++ hg update 0 ++ echo This is file c1 ++ hg add c ++ hg commit -t 'commit #2' -d '0 0' -u user ++ hg update -m 1 ++ rm b ++ echo This is file c22 ++ hg commit -t 'commit #3' -d '0 0' -u user
new file mode 100755 --- /dev/null +++ b/tests/test-merge5 @@ -0,0 +1,21 @@ +#!/bin/sh -x + +mkdir t +cd t +hg init +echo This is file a1 > a +echo This is file b1 > b +hg add a b +hg commit -t "commit #0" -d "0 0" -u user +echo This is file b22 > b +hg commit -t"comment #1" -d "0 0" -u user +hg update 0 +rm b +hg commit -A -t"comment #2" -d "0 0" -u user +# in theory, we shouldn't need the "yes k" below, but it prevents +# this test from hanging when "hg update" erroneously prompts the +# user for "keep or delete" +yes k | hg update 1 +# we exit with 0 to avoid the unavoidable SIGPIPE from above causing +# us to fail this test +exit 0
new file mode 100644 --- /dev/null +++ b/tests/test-merge5.out @@ -0,0 +1,18 @@ ++ mkdir t ++ cd t ++ hg init ++ echo This is file a1 ++ echo This is file b1 ++ hg add a b ++ hg commit -t 'commit #0' -d '0 0' -u user ++ echo This is file b22 ++ hg commit '-tcomment #1' -d '0 0' -u user ++ hg update 0 ++ rm b ++ hg commit -A '-tcomment #2' -d '0 0' -u user ++ yes k ++ hg update 1 +this update spans a branch affecting the following files: +aborting update spanning branches! +(use update -m to perform a branch merge) ++ exit 0
--- a/tests/test-simple-update.out +++ b/tests/test-simple-update.out @@ -19,11 +19,13 @@ + hg commit -t 2 + cd ../test + hg pull ../branch +pulling from ../branch searching for changes adding changesets adding manifests adding file revisions modified 1 files, added 1 changesets and 1 new revisions +(run 'hg update' to get a working copy) + hg verify checking changesets checking manifests
new file mode 100755 --- /dev/null +++ b/tests/test-tag @@ -0,0 +1,13 @@ +#!/bin/sh -x + +hg init +echo a > a +hg add a +hg commit -t "test" -u test -d "0 0" +hg history +hg tag -u test -d "0 0" "bleah" +hg history + +echo foo >> .hgtags +hg tag -u test -d "0 0" "bleah2" || echo "failed" +
new file mode 100644 --- /dev/null +++ b/tests/test-tag.out @@ -0,0 +1,31 @@ ++ hg init ++ echo a ++ hg add a ++ hg commit -t test -u test -d '0 0' ++ hg history +changeset: 0:acb14030fe0a21b60322c440ad2d20cf7685a376 +tag: tip +user: test +date: Thu Jan 1 00:00:00 1970 +summary: test + ++ hg tag -u test -d '0 0' bleah ++ hg history +changeset: 1:863197ef03781c4fc00276d83eb66c4cb9cd91df +tag: tip +user: test +date: Thu Jan 1 00:00:00 1970 +summary: Added tag bleah for changeset acb14030fe0a21b60322c440ad2d20cf7685a376 + +changeset: 0:acb14030fe0a21b60322c440ad2d20cf7685a376 +tag: bleah +user: test +date: Thu Jan 1 00:00:00 1970 +summary: test + ++ echo foo ++ hg tag -u test -d '0 0' bleah2 +abort: working copy of .hgtags is changed! +(please commit .hgtags manually) ++ echo failed +failed