--- a/Makefile Mon Mar 05 19:48:21 2007 +0100
+++ b/Makefile Mon Mar 05 19:54:21 2007 +0100
@@ -67,10 +67,10 @@
TAR_OPTIONS="--owner=root --group=root --mode=u+w,go-w,a+rX-s" $(PYTHON) setup.py -q sdist
tests:
- cd tests && $(PYTHON) run-tests.py
+ cd tests && $(PYTHON) run-tests.py $(TESTFLAGS)
test-%:
- cd tests && $(PYTHON) run-tests.py $@
+ cd tests && $(PYTHON) run-tests.py $(TESTFLAGS) $@
.PHONY: help all local build doc clean install install-bin install-doc \
--- a/README Mon Mar 05 19:48:21 2007 +0100
+++ b/README Mon Mar 05 19:54:21 2007 +0100
@@ -1,99 +1,10 @@
-MERCURIAL QUICK-START
-
-Setting up Mercurial:
-
- Note: some distributions fails to include bits of distutils by
- default, you'll need python-dev to install. You'll also need a C
- compiler and a 3-way merge tool like merge, tkdiff, or kdiff3.
-
- First, unpack the source:
-
- $ tar xvzf mercurial-<ver>.tar.gz
- $ cd mercurial-<ver>
-
- When installing, change python to python2.3 or python2.4 if 2.2 is the
- default on your system.
-
- To install system-wide:
-
- $ python setup.py install --force
-
- To install in your home directory (~/bin and ~/lib, actually), run:
-
- $ python setup.py install --home=${HOME} --force
- $ export PYTHONPATH=${HOME}/lib/python # (or lib64/ on some systems)
- $ export PATH=${HOME}/bin:$PATH # add these to your .bashrc
-
- And finally:
-
- $ hg debuginstall # run some basic tests
- $ hg # show help
-
- If you get complaints about missing modules, you probably haven't set
- PYTHONPATH correctly.
-
-Setting up a Mercurial project:
-
- $ hg init project # creates project directory
- $ cd project
- # copy files in, edit them
- $ hg add # add all unknown files
- $ hg commit # commit all changes, edit changelog entry
-
- Mercurial will look for a file named .hgignore in the root of your
- repository which contains a set of regular expressions to ignore in
- file paths.
-
-Branching and merging:
+Basic install:
- $ hg clone project project-work # create a new branch
- $ cd project-work
- $ <make changes>
- $ hg commit
- $ cd ../project
- $ hg pull ../project-work # pull changesets from project-work
- $ hg merge # merge the new tip from project-work into
- # our working directory
- $ hg commit # commit the result of the merge
-
-Importing patches:
-
- Simple:
- $ patch < ../p/foo.patch
- $ hg commit -A
-
- Fast:
- $ cat ../p/patchlist | xargs hg import -p1 -b ../p
-
-Exporting a patch:
-
- (make changes)
- $ hg commit
- $ hg export tip > foo.patch # export latest change
+ $ make # see install targets
+ $ make install # do a system-wide install
+ $ hg debuginstall # sanity-check setup
+ $ hg # see help
-Network support:
-
- # pull from the primary Mercurial repo
- foo$ hg clone http://selenic.com/hg/
- foo$ cd hg
-
- # make your current repo available via http://server:8000/
- foo$ hg serve
-
- # pushing and pulling changes to/from a remote repo with SSH
- foo$ hg push ssh://user@example.com/my/repository
- foo$ hg pull ssh://user@example.com//home/somebody/his/repository
+See http://www.selenic.com/mercurial/ for detailed installation
+instructions, platform-specific notes, and Mercurial user information.
- # merge changes from a remote machine (e.g. running 'hg serve')
- bar$ hg pull http://foo:8000/
- bar$ hg merge # merge changes into your working directory
- bar$ hg commit # commit merge in to your local repository
-
- # Set up a CGI server on your webserver
- foo$ cp hgweb.cgi ~/public_html/hg/index.cgi
- foo$ emacs ~/public_html/hg/index.cgi # adjust the defaults
-
-For more info:
-
- Documentation in doc/
- Mercurial website at http://selenic.com/mercurial
--- a/contrib/bash_completion Mon Mar 05 19:48:21 2007 +0100
+++ b/contrib/bash_completion Mon Mar 05 19:54:21 2007 +0100
@@ -145,6 +145,7 @@
# global options
case "$prev" in
-R|--repository)
+ _hg_paths
_hg_repos
return
;;
@@ -477,3 +478,25 @@
{
_hg_tags
}
+
+
+# transplant
+_hg_cmd_transplant()
+{
+ case "$prev" in
+ -s|--source)
+ _hg_paths
+ _hg_repos
+ return
+ ;;
+ --filter)
+ # standard filename completion
+ return
+ ;;
+ esac
+
+ # all other transplant options values and command parameters are revisions
+ _hg_tags
+ return
+}
+
--- a/contrib/churn.py Mon Mar 05 19:48:21 2007 +0100
+++ b/contrib/churn.py Mon Mar 05 19:54:21 2007 +0100
@@ -11,10 +11,9 @@
#
# <alias email> <actual email>
-from mercurial.demandload import *
+import sys
from mercurial.i18n import gettext as _
-demandload(globals(), 'time sys signal os')
-demandload(globals(), 'mercurial:hg,mdiff,fancyopts,cmdutil,ui,util,templater,node')
+from mercurial import hg, mdiff, cmdutil, ui, util, templater, node
def __gather(ui, repo, node1, node2):
def dirtywork(f, mmap1, mmap2):
--- a/contrib/convert-repo Mon Mar 05 19:48:21 2007 +0100
+++ b/contrib/convert-repo Mon Mar 05 19:54:21 2007 +0100
@@ -3,29 +3,49 @@
# This is a generalized framework for converting between SCM
# repository formats.
#
-# In its current form, it's hardcoded to convert incrementally between
-# git and Mercurial.
-#
# To use, run:
#
-# convert-repo <git-dir> <hg-dir> <mapfile>
+# convert-repo <source> [<dest> [<mapfile>]]
#
-# (don't forget to create the <hg-dir> repository beforehand)
+# Currently accepted source formats: git, cvs
+# Currently accepted destination formats: hg
#
-# The <mapfile> is a simple text file that maps a git commit hash to
-# the hash in Mercurial for that version, like so:
+# If destination isn't given, a new Mercurial repo named <src>-hg will
+# be created. If <mapfile> isn't given, it will be put in a default
+# location (<dest>/.hg/shamap by default)
#
-# <git hash> <mercurial hash>
+# The <mapfile> is a simple text file that maps each source commit ID to
+# the destination ID for that revision, like so:
+#
+# <source ID> <destination ID>
#
# If the file doesn't exist, it's automatically created. It's updated
# on each commit copied, so convert-repo can be interrupted and can
# be run repeatedly to copy new commits.
-import sys, os, zlib, sha, time
-
+import sys, os, zlib, sha, time, re, locale, socket
os.environ["HGENCODING"] = "utf-8"
+from mercurial import hg, ui, util, fancyopts
-from mercurial import hg, ui, util
+class Abort(Exception): pass
+class NoRepo(Exception): pass
+
+class commit:
+ def __init__(self, **parts):
+ for x in "author date desc parents".split():
+ if not x in parts:
+ abort("commit missing field %s\n" % x)
+ self.__dict__.update(parts)
+
+quiet = 0
+def status(msg):
+ if not quiet: sys.stdout.write(str(msg))
+
+def warn(msg):
+ sys.stderr.write(str(msg))
+
+def abort(msg):
+ raise Abort(msg)
def recode(s):
try:
@@ -36,9 +56,245 @@
except:
return s.decode("utf-8", "replace").encode("utf-8")
+# CVS conversion code inspired by hg-cvs-import and git-cvsimport
+class convert_cvs:
+ def __init__(self, path):
+ self.path = path
+ cvs = os.path.join(path, "CVS")
+ if not os.path.exists(cvs):
+ raise NoRepo("couldn't open CVS repo %s" % path)
+
+ self.changeset = {}
+ self.files = {}
+ self.tags = {}
+ self.lastbranch = {}
+ self.parent = {}
+ self.socket = None
+ self.cvsroot = file(os.path.join(cvs, "Root")).read()[:-1]
+ self.cvsrepo = file(os.path.join(cvs, "Repository")).read()[:-1]
+ self.encoding = locale.getpreferredencoding()
+ self._parse()
+ self._connect()
+
+ def _parse(self):
+ if self.changeset:
+ return
+
+ d = os.getcwd()
+ try:
+ os.chdir(self.path)
+ id = None
+ state = 0
+ for l in os.popen("cvsps -A -u --cvs-direct -q"):
+ if state == 0: # header
+ if l.startswith("PatchSet"):
+ id = l[9:-2]
+ elif l.startswith("Date"):
+ date = util.parsedate(l[6:-1], ["%Y/%m/%d %H:%M:%S"])
+ date = util.datestr(date)
+ elif l.startswith("Branch"):
+ branch = l[8:-1]
+ self.parent[id] = self.lastbranch.get(branch,'bad')
+ self.lastbranch[branch] = id
+ elif l.startswith("Ancestor branch"):
+ ancestor = l[17:-1]
+ self.parent[id] = self.lastbranch[ancestor]
+ elif l.startswith("Author"):
+ author = self.recode(l[8:-1])
+ elif l.startswith("Tag: "):
+ t = l[5:-1].rstrip()
+ if t != "(none)":
+ self.tags[t] = id
+ elif l.startswith("Log:"):
+ state = 1
+ log = ""
+ elif state == 1: # log
+ if l == "Members: \n":
+ files = {}
+ log = self.recode(log[:-1])
+ if log.isspace():
+ log = "*** empty log message ***\n"
+ state = 2
+ else:
+ log += l
+ elif state == 2:
+ if l == "\n": #
+ state = 0
+ p = [self.parent[id]]
+ if id == "1":
+ p = []
+ c = commit(author=author, date=date, parents=p,
+ desc=log, branch=branch)
+ self.changeset[id] = c
+ self.files[id] = files
+ else:
+ file,rev = l[1:-2].rsplit(':',1)
+ rev = rev.split("->")[1]
+ files[file] = rev
+
+ self.heads = self.lastbranch.values()
+ finally:
+ os.chdir(d)
+
+ def _connect(self):
+ root = self.cvsroot
+ conntype = None
+ user, host = None, None
+ cmd = ['cvs', 'server']
+
+ status("connecting to %s\n" % root)
+
+ if root.startswith(":pserver:"):
+ root = root[9:]
+ m = re.match(r'(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?(.*)', root)
+ if m:
+ conntype = "pserver"
+ user, passw, serv, port, root = m.groups()
+ if not user:
+ user = "anonymous"
+ rr = ":pserver:" + user + "@" + serv + ":" + root
+ if port:
+ rr2, port = "-", int(port)
+ else:
+ rr2, port = rr, 2401
+ rr += str(port)
+
+ if not passw:
+ passw = "A"
+ pf = open(os.path.join(os.environ["HOME"], ".cvspass"))
+ for l in pf:
+ # :pserver:cvs@mea.tmt.tele.fi:/cvsroot/zmailer Ah<Z
+ m = re.match(r'(/\d+\s+/)?(.*)', l)
+ l = m.group(2)
+ w, p = l.split(' ', 1)
+ if w in [rr, rr2]:
+ passw = p
+ break
+ pf.close()
+
+ sck = socket.socket()
+ sck.connect((serv, port))
+ sck.send("\n".join(["BEGIN AUTH REQUEST", root, user, passw, "END AUTH REQUEST", ""]))
+ if sck.recv(128) != "I LOVE YOU\n":
+ raise NoRepo("CVS pserver authentication failed")
+
+ self.writep = self.readp = sck.makefile('r+')
+
+ if not conntype and root.startswith(":local:"):
+ conntype = "local"
+ root = root[7:]
+
+ if not conntype:
+ # :ext:user@host/home/user/path/to/cvsroot
+ if root.startswith(":ext:"):
+ root = root[5:]
+ m = re.match(r'(?:([^@:/]+)@)?([^:/]+):?(.*)', root)
+ if not m:
+ conntype = "local"
+ else:
+ conntype = "rsh"
+ user, host, root = m.group(1), m.group(2), m.group(3)
+
+ if conntype != "pserver":
+ if conntype == "rsh":
+ rsh = os.environ.get("CVS_RSH" or "rsh")
+ if user:
+ cmd = [rsh, '-l', user, host] + cmd
+ else:
+ cmd = [rsh, host] + cmd
+
+ self.writep, self.readp = os.popen2(cmd)
+
+ self.realroot = root
+
+ self.writep.write("Root %s\n" % root)
+ self.writep.write("Valid-responses ok error Valid-requests Mode"
+ " M Mbinary E Checked-in Created Updated"
+ " Merged Removed\n")
+ self.writep.write("valid-requests\n")
+ self.writep.flush()
+ r = self.readp.readline()
+ if not r.startswith("Valid-requests"):
+ abort("server sucks\n")
+ if "UseUnchanged" in r:
+ self.writep.write("UseUnchanged\n")
+ self.writep.flush()
+ r = self.readp.readline()
+
+ def getheads(self):
+ return self.heads
+
+ def _getfile(self, name, rev):
+ if rev.endswith("(DEAD)"):
+ raise IOError
+
+ args = ("-N -P -kk -r %s --" % rev).split()
+ args.append(os.path.join(self.cvsrepo, name))
+ for x in args:
+ self.writep.write("Argument %s\n" % x)
+ self.writep.write("Directory .\n%s\nco\n" % self.realroot)
+ self.writep.flush()
+
+ data = ""
+ while 1:
+ line = self.readp.readline()
+ if line.startswith("Created ") or line.startswith("Updated "):
+ self.readp.readline() # path
+ self.readp.readline() # entries
+ mode = self.readp.readline()[:-1]
+ count = int(self.readp.readline()[:-1])
+ data = self.readp.read(count)
+ elif line.startswith(" "):
+ data += line[1:]
+ elif line.startswith("M "):
+ pass
+ elif line.startswith("Mbinary "):
+ count = int(self.readp.readline()[:-1])
+ data = self.readp.read(count)
+ else:
+ if line == "ok\n":
+ return (data, "x" in mode and "x" or "")
+ elif line.startswith("E "):
+ warn("cvs server: %s\n" % line[2:])
+ elif line.startswith("Remove"):
+ l = self.readp.readline()
+ l = self.readp.readline()
+ if l != "ok\n":
+ abort("unknown CVS response: %s\n" % l)
+ else:
+ abort("unknown CVS response: %s\n" % line)
+
+ def getfile(self, file, rev):
+ data, mode = self._getfile(file, rev)
+ self.modecache[(file, rev)] = mode
+ return data
+
+ def getmode(self, file, rev):
+ return self.modecache[(file, rev)]
+
+ def getchanges(self, rev):
+ self.modecache = {}
+ files = self.files[rev]
+ cl = files.items()
+ cl.sort()
+ return cl
+
+ def recode(self, text):
+ return text.decode(self.encoding, "replace").encode("utf-8")
+
+ def getcommit(self, rev):
+ return self.changeset[rev]
+
+ def gettags(self):
+ return self.tags
+
class convert_git:
def __init__(self, path):
+ if os.path.isdir(path + "/.git"):
+ path += "/.git"
self.path = path
+ if not os.path.exists(path + "/objects"):
+ raise NoRepo("couldn't open GIT repo %s" % path)
def getheads(self):
fh = os.popen("GIT_DIR=%s git-rev-parse --verify HEAD" % self.path)
@@ -52,7 +308,11 @@
def getfile(self, name, rev):
return self.catfile(rev, "blob")
+ def getmode(self, name, rev):
+ return self.modecache[(name, rev)]
+
def getchanges(self, version):
+ self.modecache = {}
fh = os.popen("GIT_DIR=%s git-diff-tree --root -m -r %s" % (self.path, version))
changes = []
for l in fh:
@@ -61,7 +321,9 @@
m = m.split()
h = m[3]
p = (m[1] == "100755")
- changes.append((f, h, p))
+ s = (m[1] == "120000")
+ self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
+ changes.append((f, h))
return changes
def getcommit(self, version):
@@ -92,37 +354,47 @@
tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
date = tm + " " + str(tz)
- return (parents, author, date, message)
+
+ c = commit(parents=parents, date=date, author=author, desc=message)
+ return c
def gettags(self):
tags = {}
- for f in os.listdir(self.path + "/refs/tags"):
- try:
- h = file(self.path + "/refs/tags/" + f).read().strip()
- c = self.catfile(h, "tag") # read the commit hash
- h = c.splitlines()[0].split()[1]
- tags[f] = h
- except:
- pass
+ fh = os.popen('git-ls-remote --tags "%s" 2>/dev/null' % self.path)
+ prefix = 'refs/tags/'
+ for line in fh:
+ line = line.strip()
+ if not line.endswith("^{}"):
+ continue
+ node, tag = line.split(None, 1)
+ if not tag.startswith(prefix):
+ continue
+ tag = tag[len(prefix):-3]
+ tags[tag] = node
+
return tags
class convert_mercurial:
def __init__(self, path):
self.path = path
u = ui.ui()
- self.repo = hg.repository(u, path)
+ try:
+ self.repo = hg.repository(u, path)
+ except:
+ raise NoRepo("could open hg repo %s" % path)
+
+ def mapfile(self):
+ return os.path.join(self.path, ".hg", "shamap")
def getheads(self):
h = self.repo.changelog.heads()
return [ hg.hex(x) for x in h ]
def putfile(self, f, e, data):
- self.repo.wfile(f, "w").write(data)
+ self.repo.wwrite(f, data, e)
if self.repo.dirstate.state(f) == '?':
self.repo.dirstate.update([f], "a")
- util.set_exec(self.repo.wjoin(f), e)
-
def delfile(self, f):
try:
os.unlink(self.repo.wjoin(f))
@@ -130,7 +402,7 @@
except:
pass
- def putcommit(self, files, parents, author, dest, text):
+ def putcommit(self, files, parents, commit):
seen = {}
pl = []
for p in parents:
@@ -143,11 +415,18 @@
if len(parents) < 2: parents.append("0" * 40)
p2 = parents.pop(0)
+ text = commit.desc
+ extra = {}
+ try:
+ extra["branch"] = commit.branch
+ except AttributeError:
+ pass
+
while parents:
p1 = p2
p2 = parents.pop(0)
- self.repo.rawcommit(files, text, author, dest,
- hg.bin(p1), hg.bin(p2))
+ a = self.repo.rawcommit(files, text, commit.author, commit.date,
+ hg.bin(p1), hg.bin(p2), extra=extra)
text = "(octopus merge fixup)\n"
p2 = hg.hex(self.repo.changelog.tip())
@@ -170,7 +449,7 @@
newlines.sort()
if newlines != oldlines:
- #print "updating tags"
+ status("updating tags\n")
f = self.repo.wfile(".hgtags", "w")
f.write("".join(newlines))
f.close()
@@ -180,11 +459,25 @@
date, self.repo.changelog.tip(), hg.nullid)
return hg.hex(self.repo.changelog.tip())
+converters = [convert_cvs, convert_git, convert_mercurial]
+
+def converter(path):
+ if not os.path.isdir(path):
+ abort("%s: not a directory\n" % path)
+ for c in converters:
+ try:
+ return c(path)
+ except NoRepo:
+ pass
+ abort("%s: unknown repository type\n" % path)
+
class convert:
- def __init__(self, source, dest, mapfile):
+ def __init__(self, source, dest, mapfile, opts):
+
self.source = source
self.dest = dest
self.mapfile = mapfile
+ self.opts = opts
self.commitcache = {}
self.map = {}
@@ -204,7 +497,7 @@
if n in known or n in self.map: continue
known[n] = 1
self.commitcache[n] = self.source.getcommit(n)
- cp = self.commitcache[n][0]
+ cp = self.commitcache[n].parents
for p in cp:
parents.setdefault(n, []).append(p)
visit.append(p)
@@ -247,42 +540,60 @@
if not dep:
# all n's parents are in the list
removed[n] = 1
- s.append(n)
+ if n not in self.map:
+ s.append(n)
if n in children:
for c in children[n]:
visit.insert(0, c)
+ if opts.get('datesort'):
+ depth = {}
+ for n in s:
+ depth[n] = 0
+ pl = [p for p in self.commitcache[n].parents if p not in self.map]
+ if pl:
+ depth[n] = max([depth[p] for p in pl]) + 1
+
+ s = [(depth[n], self.commitcache[n].date, n) for n in s]
+ s.sort()
+ s = [e[2] for e in s]
+
return s
def copy(self, rev):
- p, a, d, t = self.commitcache[rev]
+ c = self.commitcache[rev]
files = self.source.getchanges(rev)
- for f,v,e in files:
+ for f,v in files:
try:
data = self.source.getfile(f, v)
except IOError, inst:
self.dest.delfile(f)
else:
+ e = self.source.getmode(f, v)
self.dest.putfile(f, e, data)
- r = [self.map[v] for v in p]
- f = [f for f,v,e in files]
- self.map[rev] = self.dest.putcommit(f, r, a, d, t)
+ r = [self.map[v] for v in c.parents]
+ f = [f for f,v in files]
+ self.map[rev] = self.dest.putcommit(f, r, c)
file(self.mapfile, "a").write("%s %s\n" % (rev, self.map[rev]))
def convert(self):
+ status("scanning source...\n")
heads = self.source.getheads()
parents = self.walktree(heads)
+ status("sorting...\n")
t = self.toposort(parents)
- t = [n for n in t if n not in self.map]
num = len(t)
c = None
+ status("converting...\n")
for c in t:
num -= 1
- desc = self.commitcache[c][3].splitlines()[0]
- #print num, desc
+ desc = self.commitcache[c].desc
+ if "\n" in desc:
+ desc = desc.splitlines()[0]
+ status("%d %s\n" % (num, desc))
self.copy(c)
tags = self.source.gettags()
@@ -299,9 +610,41 @@
if nrev:
file(self.mapfile, "a").write("%s %s\n" % (c, nrev))
-gitpath, hgpath, mapfile = sys.argv[1:]
-if os.path.isdir(gitpath + "/.git"):
- gitpath += "/.git"
+def command(src, dest=None, mapfile=None, **opts):
+ srcc = converter(src)
+ if not hasattr(srcc, "getcommit"):
+ abort("%s: can't read from this repo type\n" % src)
+
+ if not dest:
+ dest = src + "-hg"
+ status("assuming destination %s\n" % dest)
+ if not os.path.isdir(dest):
+ status("creating repository %s\n" % dest)
+ os.system("hg init " + dest)
+ destc = converter(dest)
+ if not hasattr(destc, "putcommit"):
+ abort("%s: can't write to this repo type\n" % src)
-c = convert(convert_git(gitpath), convert_mercurial(hgpath), mapfile)
-c.convert()
+ if not mapfile:
+ try:
+ mapfile = destc.mapfile()
+ except:
+ mapfile = os.path.join(destc, "map")
+
+ c = convert(srcc, destc, mapfile, opts)
+ c.convert()
+
+options = [('q', 'quiet', None, 'suppress output'),
+ ('', 'datesort', None, 'try to sort changesets by date')]
+opts = {}
+args = fancyopts.fancyopts(sys.argv[1:], options, opts)
+
+if opts['quiet']:
+ quiet = 1
+
+try:
+ command(*args, **opts)
+except Abort, inst:
+ warn(inst)
+except KeyboardInterrupt:
+ status("interrupted\n")
--- a/contrib/hgk Mon Mar 05 19:48:21 2007 +0100
+++ b/contrib/hgk Mon Mar 05 19:54:21 2007 +0100
@@ -43,7 +43,9 @@
}
if [catch {
set parse_args [concat --default HEAD $revargs]
- set parsed_args [split [eval exec hg debug-rev-parse $parse_args] "\n"]
+ set parse_temp [eval exec hg debug-rev-parse $parse_args]
+ regsub -all "\r\n" $parse_temp "\n" parse_temp
+ set parsed_args [split $parse_temp "\n"]
} err] {
# if git-rev-parse failed for some reason...
if {$rargs == {}} {
@@ -108,6 +110,7 @@
set leftover {}
}
set start [expr {$i + 1}]
+ regsub -all "\r\n" $cmit "\n" cmit
set j [string first "\n" $cmit]
set ok 0
if {$j >= 0} {
@@ -209,6 +212,7 @@
incr ncleft($p)
}
}
+ regsub -all "\r\n" $contents "\n" contents
foreach line [split $contents "\n"] {
if {$inhdr} {
set line [split $line]
@@ -257,7 +261,8 @@
global tagids idtags headids idheads tagcontents
set tags [exec hg tags]
- set lines [split $tags '\n']
+ regsub -all "\r\n" $tags "\n" tags
+ set lines [split $tags "\n"]
foreach f $lines {
set f [regexp -all -inline {\S+} $f]
set direct [lindex $f 0]
@@ -2856,6 +2861,7 @@
if {$ids != $diffids || $bdf != $blobdifffd($ids)} {
return
}
+ regsub -all "\r" $line "" line
$ctext conf -state normal
if {[regexp {^diff --git a/(.*) b/(.*)} $line match fname newname]} {
# start of a new file
@@ -2914,7 +2920,7 @@
} elseif {$diffinhdr || $x == "\\"} {
# e.g. "\ No newline at end of file"
$ctext insert end "$line\n" filesep
- } else {
+ } elseif {$line != ""} {
# Something else we don't recognize
if {$curdifftag != "Comments"} {
$ctext insert end "\n"
--- a/contrib/purge/purge.py Mon Mar 05 19:48:21 2007 +0100
+++ b/contrib/purge/purge.py Mon Mar 05 19:54:21 2007 +0100
@@ -18,11 +18,9 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
from mercurial import hg, util
+from mercurial.i18n import _
import os
-def _(s):
- return s
-
class Purge(object):
def __init__(self, act=True, abort_on_err=False, eol='\n'):
self._repo = None
@@ -70,24 +68,25 @@
# directory.
if self._repo.dirstate.state(relative_name) != '?':
return
- self._ui.note(_('Removing file %s\n') % name)
+ self._ui.note(_('Removing file %s\n') % relative_name)
if self._act:
try:
os.remove(name)
except OSError, e:
- self._error(_('%s cannot be removed') % name)
+ self._error(_('%s cannot be removed') % relative_name)
else:
- self._ui.write('%s%s' % (name, self._eol))
+ self._ui.write('%s%s' % (relative_name, self._eol))
def _remove_dir(self, name):
- self._ui.note(_('Removing directory %s\n') % name)
+ relative_name = self._relative_name(name)
+ self._ui.note(_('Removing directory %s\n') % relative_name)
if self._act:
try:
os.rmdir(name)
except OSError, e:
- self._error(_('%s cannot be removed') % name)
+ self._error(_('%s cannot be removed') % relative_name)
else:
- self._ui.write('%s%s' % (name, self._eol))
+ self._ui.write('%s%s' % (relative_name, self._eol))
def _relative_name(self, path):
'''
--- a/doc/Makefile Mon Mar 05 19:48:21 2007 +0100
+++ b/doc/Makefile Mon Mar 05 19:54:21 2007 +0100
@@ -2,7 +2,7 @@
MAN=$(SOURCES:%.txt=%)
HTML=$(SOURCES:%.txt=%.html)
PREFIX=/usr/local
-MANDIR=$(PREFIX)/man
+MANDIR=$(PREFIX)/share/man
INSTALL=install -c
all: man html
@@ -36,8 +36,8 @@
install: man
for i in $(MAN) ; do \
subdir=`echo $$i | sed -n 's/..*\.\([0-9]\)$$/man\1/p'` ; \
- mkdir -p $(MANDIR)/$$subdir ; \
- $(INSTALL) $$i $(MANDIR)/$$subdir ; \
+ mkdir -p $(DESTDIR)/$(MANDIR)/$$subdir ; \
+ $(INSTALL) $$i $(DESTDIR)/$(MANDIR)/$$subdir ; \
done
clean:
--- a/doc/hgrc.5.txt Mon Mar 05 19:48:21 2007 +0100
+++ b/doc/hgrc.5.txt Mon Mar 05 19:54:21 2007 +0100
@@ -507,6 +507,11 @@
push_ssl;;
Whether to require that inbound pushes be transported over SSL to
prevent password sniffing. Default is true.
+ staticurl;;
+ Base URL to use for static files. If unset, static files (e.g.
+ the hgicon.png favicon) will be served by the CGI script itself.
+ Use this setting to serve them directly with the HTTP server.
+ Example: "http://hgserver/static/"
stripes;;
How many lines a "zebra stripe" should span in multiline output.
Default is 1; set to 0 to disable.
--- a/hg Mon Mar 05 19:48:21 2007 +0100
+++ b/hg Mon Mar 05 19:54:21 2007 +0100
@@ -7,6 +7,5 @@
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
-from mercurial import commands
-
-commands.run()
+import mercurial.commands
+mercurial.commands.run()
--- a/hgext/acl.py Mon Mar 05 19:48:21 2007 +0100
+++ b/hgext/acl.py Mon Mar 05 19:54:21 2007 +0100
@@ -45,10 +45,10 @@
# glob pattern = user4, user5
# ** = user6
-from mercurial.demandload import *
-from mercurial.i18n import gettext as _
+from mercurial.i18n import _
from mercurial.node import *
-demandload(globals(), 'getpass mercurial:util')
+from mercurial import util
+import getpass
class checker(object):
'''acl checker.'''
@@ -91,7 +91,7 @@
def check(self, node):
'''return if access allowed, raise exception if not.'''
- files = self.repo.changelog.read(node)[3]
+ files = self.repo.changectx(node).files()
if self.deniable:
for f in files:
if self.deny(f):
--- a/hgext/bugzilla.py Mon Mar 05 19:48:21 2007 +0100
+++ b/hgext/bugzilla.py Mon Mar 05 19:54:21 2007 +0100
@@ -52,10 +52,10 @@
# [usermap]
# committer_email = bugzilla_user_name
-from mercurial.demandload import *
-from mercurial.i18n import gettext as _
+from mercurial.i18n import _
from mercurial.node import *
-demandload(globals(), 'mercurial:cmdutil,templater,util os re time')
+from mercurial import cmdutil, templater, util
+import os, re, time
MySQLdb = None
@@ -222,7 +222,7 @@
_bug_re = None
_split_re = None
- def find_bug_ids(self, node, desc):
+ def find_bug_ids(self, ctx):
'''find valid bug ids that are referred to in changeset
comments and that do not already have references to this
changeset.'''
@@ -235,7 +235,7 @@
start = 0
ids = {}
while True:
- m = bugzilla._bug_re.search(desc, start)
+ m = bugzilla._bug_re.search(ctx.description(), start)
if not m:
break
start = m.end()
@@ -246,10 +246,10 @@
if ids:
ids = self.filter_real_bug_ids(ids)
if ids:
- ids = self.filter_unknown_bug_ids(node, ids)
+ ids = self.filter_unknown_bug_ids(ctx.node(), ids)
return ids
- def update(self, bugid, node, changes):
+ def update(self, bugid, ctx):
'''update bugzilla bug with reference to changeset.'''
def webroot(root):
@@ -268,7 +268,7 @@
mapfile = self.ui.config('bugzilla', 'style')
tmpl = self.ui.config('bugzilla', 'template')
t = cmdutil.changeset_templater(self.ui, self.repo,
- False, None, mapfile, False)
+ False, mapfile, False)
if not mapfile and not tmpl:
tmpl = _('changeset {node|short} in repo {root} refers '
'to bug {bug}.\ndetails:\n\t{desc|tabindent}')
@@ -276,13 +276,13 @@
tmpl = templater.parsestring(tmpl, quoted=False)
t.use_template(tmpl)
self.ui.pushbuffer()
- t.show(changenode=node, changes=changes,
+ t.show(changenode=ctx.node(), changes=ctx.changeset(),
bug=str(bugid),
hgweb=self.ui.config('web', 'baseurl'),
root=self.repo.root,
webroot=webroot(self.repo.root))
data = self.ui.popbuffer()
- self.add_comment(bugid, data, templater.email(changes[1]))
+ self.add_comment(bugid, data, templater.email(ctx.user()))
def hook(ui, repo, hooktype, node=None, **kwargs):
'''add comment to bugzilla for each changeset that refers to a
@@ -300,12 +300,11 @@
hooktype)
try:
bz = bugzilla(ui, repo)
- bin_node = bin(node)
- changes = repo.changelog.read(bin_node)
- ids = bz.find_bug_ids(bin_node, changes[4])
+ ctx = repo.changctx(node)
+ ids = bz.find_bug_ids(ctx)
if ids:
for id in ids:
- bz.update(id, bin_node, changes)
+ bz.update(id, ctx)
bz.notify(ids)
except MySQLdb.MySQLError, err:
raise util.Abort(_('database error: %s') % err[1])
--- a/hgext/extdiff.py Mon Mar 05 19:48:21 2007 +0100
+++ b/hgext/extdiff.py Mon Mar 05 19:54:21 2007 +0100
@@ -48,16 +48,15 @@
# needed files, so running the external diff program will actually be
# pretty fast (at least faster than having to compare the entire tree).
-from mercurial.demandload import demandload
-from mercurial.i18n import gettext as _
+from mercurial.i18n import _
from mercurial.node import *
-demandload(globals(), 'mercurial:cmdutil,util os shutil tempfile')
+from mercurial import cmdutil, util
+import os, shutil, tempfile
def dodiff(ui, repo, diffcmd, diffopts, pats, opts):
def snapshot_node(files, node):
'''snapshot files as of some revision'''
- changes = repo.changelog.read(node)
- mf = repo.manifest.read(changes[0])
+ mf = repo.changectx(node).manifest()
dirname = os.path.basename(repo.root)
if dirname == "":
dirname = "root"
@@ -77,7 +76,8 @@
destdir = os.path.dirname(dest)
if not os.path.isdir(destdir):
os.makedirs(destdir)
- repo.wwrite(wfn, repo.file(fn).read(mf[fn]), open(dest, 'wb'))
+ data = repo.wwritedata(wfn, repo.file(wfn).read(mf[wfn]))
+ open(dest, 'wb').write(data)
return dirname
def snapshot_wdir(files):
--- a/hgext/fetch.py Mon Mar 05 19:48:21 2007 +0100
+++ b/hgext/fetch.py Mon Mar 05 19:54:21 2007 +0100
@@ -5,10 +5,9 @@
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
-from mercurial.demandload import *
-from mercurial.i18n import gettext as _
+from mercurial.i18n import _
from mercurial.node import *
-demandload(globals(), 'mercurial:commands,hg,node,util')
+from mercurial import commands, hg, node, util
def fetch(ui, repo, source='default', **opts):
'''Pull changes from a remote repository, merge new changes if needed.
--- a/hgext/gpg.py Mon Mar 05 19:48:21 2007 +0100
+++ b/hgext/gpg.py Mon Mar 05 19:54:21 2007 +0100
@@ -8,7 +8,7 @@
import os, tempfile, binascii
from mercurial import util
from mercurial import node as hgnode
-from mercurial.i18n import gettext as _
+from mercurial.i18n import _
class gpg:
def __init__(self, path, key=None):
--- a/hgext/hbisect.py Mon Mar 05 19:48:21 2007 +0100
+++ b/hgext/hbisect.py Mon Mar 05 19:54:21 2007 +0100
@@ -6,9 +6,9 @@
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
-from mercurial.i18n import gettext as _
-from mercurial.demandload import demandload
-demandload(globals(), "os sys sets mercurial:hg,util,commands,cmdutil")
+from mercurial.i18n import _
+from mercurial import hg, util, commands, cmdutil
+import os, sys, sets
versionstr = "0.0.3"
--- a/hgext/hgk.py Mon Mar 05 19:48:21 2007 +0100
+++ b/hgext/hgk.py Mon Mar 05 19:54:21 2007 +0100
@@ -5,26 +5,18 @@
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
-from mercurial.demandload import *
-demandload(globals(), 'time sys signal os')
-demandload(globals(), 'mercurial:hg,fancyopts,commands,ui,util,patch,revlog')
+import sys, os
+from mercurial import hg, fancyopts, commands, ui, util, patch, revlog
def difftree(ui, repo, node1=None, node2=None, *files, **opts):
"""diff trees from two commits"""
def __difftree(repo, node1, node2, files=[]):
- if node2:
- change = repo.changelog.read(node2)
- mmap2 = repo.manifest.read(change[0])
- status = repo.status(node1, node2, files=files)[:5]
- modified, added, removed, deleted, unknown = status
- else:
- status = repo.status(node1, files=files)[:5]
- modified, added, removed, deleted, unknown = status
- if not node1:
- node1 = repo.dirstate.parents()[0]
+ assert node2 is not None
+ mmap = repo.changectx(node1).manifest()
+ mmap2 = repo.changectx(node2).manifest()
+ status = repo.status(node1, node2, files=files)[:5]
+ modified, added, removed, deleted, unknown = status
- change = repo.changelog.read(node1)
- mmap = repo.manifest.read(change[0])
empty = hg.short(hg.nullid)
for f in modified:
@@ -70,32 +62,30 @@
if not opts['stdin']:
break
-def catcommit(repo, n, prefix, changes=None):
+def catcommit(repo, n, prefix, ctx=None):
nlprefix = '\n' + prefix;
- (p1, p2) = repo.changelog.parents(n)
- (h, h1, h2) = map(hg.short, (n, p1, p2))
- (i1, i2) = map(repo.changelog.rev, (p1, p2))
- if not changes:
- changes = repo.changelog.read(n)
- print "tree %s" % (hg.short(changes[0]))
- if i1 != hg.nullrev: print "parent %s" % (h1)
- if i2 != hg.nullrev: print "parent %s" % (h2)
- date_ar = changes[2]
- date = int(float(date_ar[0]))
- lines = changes[4].splitlines()
+ if ctx is None:
+ ctx = repo.changectx(n)
+ (p1, p2) = ctx.parents()
+ print "tree %s" % (hg.short(ctx.changeset()[0])) # use ctx.node() instead ??
+ if p1: print "parent %s" % (hg.short(p1.node()))
+ if p2: print "parent %s" % (hg.short(p2.node()))
+ date = ctx.date()
+ description = ctx.description().replace("\0", "")
+ lines = description.splitlines()
if lines and lines[-1].startswith('committer:'):
committer = lines[-1].split(': ')[1].rstrip()
else:
- committer = changes[1]
+ committer = ctx.user()
- print "author %s %s %s" % (changes[1], date, date_ar[1])
- print "committer %s %s %s" % (committer, date, date_ar[1])
- print "revision %d" % repo.changelog.rev(n)
+ print "author %s %s %s" % (ctx.user(), int(date[0]), date[1])
+ print "committer %s %s %s" % (committer, int(date[0]), date[1])
+ print "revision %d" % ctx.rev()
print ""
if prefix != "":
- print "%s%s" % (prefix, changes[4].replace('\n', nlprefix).strip())
+ print "%s%s" % (prefix, description.replace('\n', nlprefix).strip())
else:
- print changes[4]
+ print description
if prefix:
sys.stdout.write('\0')
@@ -146,8 +136,7 @@
# you can specify a commit to stop at by starting the sha1 with ^
def revtree(args, repo, full="tree", maxnr=0, parents=False):
def chlogwalk():
- ch = repo.changelog
- count = ch.count()
+ count = repo.changelog.count()
i = count
l = [0] * 100
chunk = 100
@@ -163,7 +152,8 @@
l[chunk - x:] = [0] * (chunk - x)
break
if full != None:
- l[x] = ch.read(ch.node(i + x))
+ l[x] = repo.changectx(i + x)
+ l[x].changeset() # force reading
else:
l[x] = 1
for x in xrange(chunk-1, -1, -1):
@@ -217,7 +207,7 @@
# walk the repository looking for commits that are in our
# reachability graph
- for i, changes in chlogwalk():
+ for i, ctx in chlogwalk():
n = repo.changelog.node(i)
mask = is_reachable(want_sha1, reachable, n)
if mask:
@@ -232,13 +222,13 @@
print hg.short(n) + parentstr
elif full == "commit":
print hg.short(n) + parentstr
- catcommit(repo, n, ' ', changes)
+ catcommit(repo, n, ' ', ctx)
else:
(p1, p2) = repo.changelog.parents(n)
(h, h1, h2) = map(hg.short, (n, p1, p2))
(i1, i2) = map(repo.changelog.rev, (p1, p2))
- date = changes[2][0]
+ date = ctx.date()[0]
print "%s %s:%s" % (date, h, mask),
mask = is_reachable(want_sha1, reachable, p1)
if i1 != hg.nullrev and mask > 0:
--- a/hgext/mq.py Mon Mar 05 19:48:21 2007 +0100
+++ b/hgext/mq.py Mon Mar 05 19:54:21 2007 +0100
@@ -29,14 +29,16 @@
refresh contents of top applied patch qrefresh
'''
-from mercurial.demandload import *
-from mercurial.i18n import gettext as _
-from mercurial import commands
-demandload(globals(), "os sys re struct traceback errno bz2")
-demandload(globals(), "mercurial:cmdutil,hg,patch,revlog,util,changegroup")
+from mercurial.i18n import _
+from mercurial import commands, cmdutil, hg, patch, revlog, util, changegroup
+import os, sys, re, errno
commands.norepo += " qclone qversion"
+# Patch names looks like unix-file names.
+# They must be joinable with queue directory and result in the patch path.
+normname = util.normpath
+
class statusentry:
def __init__(self, rev, name=None):
if not name:
@@ -328,11 +330,12 @@
hg.clean(repo, head, wlock=wlock)
self.strip(repo, n, update=False, backup='strip', wlock=wlock)
- c = repo.changelog.read(rev)
+ ctx = repo.changectx(rev)
ret = hg.merge(repo, rev, wlock=wlock)
if ret:
raise util.Abort(_("update returned %d") % ret)
- n = repo.commit(None, c[4], c[1], force=1, wlock=wlock)
+ n = repo.commit(None, ctx.description(), ctx.user(),
+ force=1, wlock=wlock)
if n == None:
raise util.Abort(_("repo commit failed"))
try:
@@ -614,15 +617,12 @@
self.ui.warn("saving bundle to %s\n" % name)
return changegroup.writebundle(cg, name, "HG10BZ")
- def stripall(rev, revnum):
- cl = repo.changelog
- c = cl.read(rev)
- mm = repo.manifest.read(c[0])
+ def stripall(revnum):
+ mm = repo.changectx(rev).manifest()
seen = {}
- for x in xrange(revnum, cl.count()):
- c = cl.read(cl.node(x))
- for f in c[3]:
+ for x in xrange(revnum, repo.changelog.count()):
+ for f in repo.changectx(x).files():
if f in seen:
continue
seen[f] = 1
@@ -704,7 +704,7 @@
backupch = repo.changegroupsubset(savebases.keys(), saveheads, 'strip')
chgrpfile = bundle(backupch)
- stripall(rev, revnum)
+ stripall(revnum)
change = chlog.read(rev)
chlog.strip(revnum, revnum)
@@ -802,10 +802,29 @@
if not wlock:
wlock = repo.wlock()
patch = self.lookup(patch)
- if patch and self.isapplied(patch):
- raise util.Abort(_("patch %s is already applied") % patch)
+ # Suppose our series file is: A B C and the current 'top' patch is B.
+ # qpush C should be performed (moving forward)
+ # qpush B is a NOP (no change)
+ # qpush A is an error (can't go backwards with qpush)
+ if patch:
+ info = self.isapplied(patch)
+ if info:
+ if info[0] < len(self.applied) - 1:
+ raise util.Abort(_("cannot push to a previous patch: %s") %
+ patch)
+ if info[0] < len(self.series) - 1:
+ self.ui.warn(_('qpush: %s is already at the top\n') % patch)
+ else:
+ self.ui.warn(_('all patches are currently applied\n'))
+ return
+
+ # Following the above example, starting at 'top' of B:
+ # qpush should be performed (pushes C), but a subsequent qpush without
+ # an argument is an error (nothing to apply). This allows a loop
+ # of "...while hg qpush..." to work as it detects an error when done
if self.series_end() == len(self.series):
- raise util.Abort(_("patch series fully applied"))
+ self.ui.warn(_('patch series already fully applied\n'))
+ return 1
if not force:
self.check_localchanges(repo)
@@ -835,14 +854,7 @@
wlock=None):
def getfile(f, rev):
t = repo.file(f).read(rev)
- try:
- repo.wfile(f, "w").write(t)
- except IOError:
- try:
- os.makedirs(os.path.dirname(repo.wjoin(f)))
- except OSError, err:
- if err.errno != errno.EEXIST: raise
- repo.wfile(f, "w").write(t)
+ repo.wfile(f, "w").write(t)
if not wlock:
wlock = repo.wlock()
@@ -854,8 +866,12 @@
info = self.isapplied(patch)
if not info:
raise util.Abort(_("patch %s is not applied") % patch)
+
if len(self.applied) == 0:
- raise util.Abort(_("no patches applied"))
+ # Allow qpop -a to work repeatedly,
+ # but not qpop without an argument
+ self.ui.warn(_("no patches applied\n"))
+ return not all
if not update:
parents = repo.dirstate.parents()
@@ -1089,9 +1105,13 @@
self.push(repo, force=True, wlock=wlock)
def init(self, repo, create=False):
- if os.path.isdir(self.path):
+ if not create and os.path.isdir(self.path):
raise util.Abort(_("patch queue directory already exists"))
- os.mkdir(self.path)
+ try:
+ os.mkdir(self.path)
+ except OSError, inst:
+ if inst.errno != errno.EEXIST or not create:
+ raise
if create:
return self.qrepo(create=True)
@@ -1347,7 +1367,7 @@
lastparent = p1
if not patchname:
- patchname = '%d.diff' % r
+ patchname = normname('%d.diff' % r)
checkseries(patchname)
checkfile(patchname)
self.full_series.insert(0, patchname)
@@ -1369,7 +1389,7 @@
if filename == '-':
raise util.Abort(_('-e is incompatible with import from -'))
if not patchname:
- patchname = filename
+ patchname = normname(filename)
if not os.path.isfile(self.join(patchname)):
raise util.Abort(_("patch %s does not exist") % patchname)
else:
@@ -1383,7 +1403,7 @@
except IOError:
raise util.Abort(_("unable to read %s") % patchname)
if not patchname:
- patchname = os.path.basename(filename)
+ patchname = normname(os.path.basename(filename))
checkfile(patchname)
patchf = self.opener(patchname, "w")
patchf.write(text)
@@ -1474,13 +1494,16 @@
r = q.init(repo, create=opts['create_repo'])
q.save_dirty()
if r:
- fp = r.wopener('.hgignore', 'w')
- print >> fp, 'syntax: glob'
- print >> fp, 'status'
- print >> fp, 'guards'
- fp.close()
- r.wopener('series', 'w').close()
+ if not os.path.exists(r.wjoin('.hgignore')):
+ fp = r.wopener('.hgignore', 'w')
+ fp.write('syntax: glob\n')
+ fp.write('status\n')
+ fp.write('guards\n')
+ fp.close()
+ if not os.path.exists(r.wjoin('series')):
+ r.wopener('series', 'w').close()
r.add(['.hgignore', 'series'])
+ commands.add(ui, r)
return 0
def clone(ui, source, dest=None, **opts):
@@ -1595,6 +1618,9 @@
If any file patterns are provided, the refreshed patch will contain only
the modifications that match those patterns; the remaining modifications
will remain in the working directory.
+
+ hg add/remove/copy/rename work as usual, though you might want to use
+ git-style patches (--git or [diff] git=1) to track copies and renames.
"""
q = repo.mq
message = commands.logmessage(opts)
@@ -1766,7 +1792,8 @@
if opts['all']:
if not q.series:
- raise util.Abort(_('no patches in series'))
+ ui.warn(_('no patches in series\n'))
+ return 0
patch = q.series[-1]
if opts['merge']:
if opts['name']:
@@ -1792,9 +1819,10 @@
localupdate = False
else:
q = repo.mq
- q.pop(repo, patch, force=opts['force'], update=localupdate, all=opts['all'])
+ ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
+ all=opts['all'])
q.save_dirty()
- return 0
+ return ret
def rename(ui, repo, patch, name=None, **opts):
"""rename a patch
@@ -1817,7 +1845,7 @@
patch = q.lookup('qtip')
absdest = q.join(name)
if os.path.isdir(absdest):
- name = os.path.join(name, os.path.basename(patch))
+ name = normname(os.path.join(name, os.path.basename(patch)))
absdest = q.join(name)
if os.path.exists(absdest):
raise util.Abort(_('%s already exists') % absdest)
@@ -2022,7 +2050,7 @@
return super(mqrepo, self).commit(*args, **opts)
def push(self, remote, force=False, revs=None):
- if self.mq.applied and not force:
+ if self.mq.applied and not force and not revs:
raise util.Abort(_('source has mq patches applied'))
return super(mqrepo, self).push(remote, force, revs)
--- a/hgext/notify.py Mon Mar 05 19:48:21 2007 +0100
+++ b/hgext/notify.py Mon Mar 05 19:54:21 2007 +0100
@@ -65,11 +65,10 @@
# if you like, you can put notify config file in repo that users can
# push changes to, they can manage their own subscriptions.
-from mercurial.demandload import *
-from mercurial.i18n import gettext as _
+from mercurial.i18n import _
from mercurial.node import *
-demandload(globals(), 'mercurial:patch,cmdutil,templater,util,mail')
-demandload(globals(), 'email.Parser fnmatch socket time')
+from mercurial import patch, cmdutil, templater, util, mail
+import email.Parser, fnmatch, socket, time
# template for single changeset can include email headers.
single_template = '''
@@ -113,7 +112,7 @@
template = (self.ui.config('notify', hooktype) or
self.ui.config('notify', 'template'))
self.t = cmdutil.changeset_templater(self.ui, self.repo,
- False, None, mapfile, False)
+ False, mapfile, False)
if not mapfile and not template:
template = deftemplates.get(hooktype) or single_template
if template:
--- a/hgext/patchbomb.py Mon Mar 05 19:48:21 2007 +0100
+++ b/hgext/patchbomb.py Mon Mar 05 19:54:21 2007 +0100
@@ -63,11 +63,10 @@
#
# That should be all. Now your patchbomb is on its way out.
-from mercurial.demandload import *
-demandload(globals(), '''email.MIMEMultipart email.MIMEText email.Utils
- mercurial:cmdutil,commands,hg,mail,ui,patch,util
- os errno popen2 socket sys tempfile''')
-from mercurial.i18n import gettext as _
+import os, errno, socket
+import email.MIMEMultipart, email.MIMEText, email.Utils
+from mercurial import cmdutil, commands, hg, mail, ui, patch, util
+from mercurial.i18n import _
from mercurial.node import *
try:
@@ -217,8 +216,6 @@
bcc = [a.strip() for a in bcc if a.strip()]
if len(patches) > 1:
- ui.write(_('\nWrite the introductory message for the patch series.\n\n'))
-
tlen = len(str(len(patches)))
subj = '[PATCH %0*d of %d] %s' % (
@@ -228,21 +225,13 @@
prompt('Subject:', rest = ' [PATCH %0*d of %d] ' % (tlen, 0,
len(patches))))
- ui.write(_('Finish with ^D or a dot on a line by itself.\n\n'))
-
- body = []
-
- while True:
- try: l = raw_input()
- except EOFError: break
- if l == '.': break
- body.append(l)
-
+ body = ''
if opts['diffstat']:
d = cdiffstat(_('Final summary:\n'), jumbo)
- if d: body.append('\n' + d)
+ if d: body = '\n' + d
- body = '\n'.join(body) + '\n'
+ ui.write(_('\nWrite the introductory message for the patch series.\n\n'))
+ body = ui.edit(body, sender)
msg = email.MIMEText.MIMEText(body)
msg['Subject'] = subj
--- a/hgext/transplant.py Mon Mar 05 19:48:21 2007 +0100
+++ b/hgext/transplant.py Mon Mar 05 19:54:21 2007 +0100
@@ -5,11 +5,10 @@
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
-from mercurial.demandload import *
-from mercurial.i18n import gettext as _
-demandload(globals(), 'os tempfile')
-demandload(globals(), 'mercurial:bundlerepo,cmdutil,commands,hg,merge,patch')
-demandload(globals(), 'mercurial:revlog,util')
+from mercurial.i18n import _
+import os, tempfile
+from mercurial import bundlerepo, changegroup, cmdutil, commands, hg, merge
+from mercurial import patch, revlog, util
'''patch transplanting tool
@@ -120,7 +119,8 @@
if pulls:
if source != repo:
repo.pull(source, heads=pulls, lock=lock)
- merge.update(repo, pulls[-1], wlock=wlock)
+ merge.update(repo, pulls[-1], False, False, None,
+ wlock=wlock)
p1, p2 = repo.dirstate.parents()
pulls = []
@@ -162,7 +162,7 @@
os.unlink(patchfile)
if pulls:
repo.pull(source, heads=pulls, lock=lock)
- merge.update(repo, pulls[-1], wlock=wlock)
+ merge.update(repo, pulls[-1], False, False, None, wlock=wlock)
finally:
self.saveseries(revmap, merges)
self.transplants.write()
@@ -473,7 +473,7 @@
bundle = None
if not source.local():
cg = source.changegroup(incoming, 'incoming')
- bundle = commands.write_bundle(cg, compress=False)
+ bundle = changegroup.writebundle(cg, None, 'HG10UN')
source = bundlerepo.bundlerepository(ui, repo.root, bundle)
return (source, incoming, bundle)
@@ -575,6 +575,7 @@
tp.apply(repo, source, revmap, merges, opts)
finally:
if bundle:
+ source.close()
os.unlink(bundle)
cmdtable = {
@@ -588,5 +589,5 @@
('', 'log', None, _('append transplant info to log message')),
('c', 'continue', None, _('continue last transplant session after repair')),
('', 'filter', '', _('filter changesets through FILTER'))],
- _('hg transplant [-s REPOSITORY] [-b BRANCH] [-p REV] [-m REV] [-n] REV...'))
+ _('hg transplant [-s REPOSITORY] [-b BRANCH [-a]] [-p REV] [-m REV] [REV]...'))
}
--- a/mercurial/appendfile.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/appendfile.py Mon Mar 05 19:54:21 2007 +0100
@@ -5,8 +5,7 @@
# 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(globals(), "cStringIO changelog errno manifest os tempfile util")
+import cStringIO, changelog, errno, manifest, os, tempfile, util
# writes to metadata files are ordered. reads: changelog, manifest,
# normal files. writes: normal files, manifest, changelog.
--- a/mercurial/archival.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/archival.py Mon Mar 05 19:54:21 2007 +0100
@@ -5,10 +5,9 @@
# This software may be used and distributed according to the terms of
# the GNU General Public License, incorporated herein by reference.
-from demandload import *
-from i18n import gettext as _
+from i18n import _
from node import *
-demandload(globals(), 'cStringIO os stat tarfile time util zipfile')
+import cStringIO, os, stat, tarfile, time, util, zipfile
def tidyprefix(dest, prefix, suffixes):
'''choose prefix to use for names in archive. make sure prefix is
@@ -155,15 +154,12 @@
def write(name, mode, data):
if matchfn and not matchfn(name): return
if decode:
- fp = cStringIO.StringIO()
- repo.wwrite(name, data, fp)
- data = fp.getvalue()
+ data = repo.wwritedata(name, data)
archiver.addfile(name, mode, data)
- change = repo.changelog.read(node)
- mn = change[0]
- archiver = archivers[kind](dest, prefix, mtime or change[2][0])
- m = repo.manifest.read(mn)
+ ctx = repo.changectx(node)
+ archiver = archivers[kind](dest, prefix, mtime or ctx.date()[0])
+ m = ctx.manifest()
items = m.items()
items.sort()
write('.hg_archival.txt', 0644,
--- a/mercurial/bdiff.c Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/bdiff.c Mon Mar 05 19:54:21 2007 +0100
@@ -33,7 +33,11 @@
}
#else
#include <sys/types.h>
+#ifdef __BEOS__
+#include <ByteOrder.h>
+#else
#include <arpa/inet.h>
+#endif
#include <inttypes.h>
#endif
--- a/mercurial/bundlerepo.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/bundlerepo.py Mon Mar 05 19:54:21 2007 +0100
@@ -11,9 +11,8 @@
"""
from node import *
-from i18n import gettext as _
-from demandload import demandload
-demandload(globals(), "changegroup util os struct bz2 tempfile")
+from i18n import _
+import changegroup, util, os, struct, bz2, tempfile
import localrepo, changelog, manifest, filelog, revlog
@@ -50,7 +49,7 @@
continue
for p in (p1, p2):
if not p in self.nodemap:
- raise revlog.RevlogError(_("unknown parent %s") % short(p1))
+ raise revlog.LookupError(_("unknown parent %s") % short(p1))
if linkmapper is None:
link = n
else:
--- a/mercurial/changegroup.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/changegroup.py Mon Mar 05 19:54:21 2007 +0100
@@ -6,9 +6,9 @@
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
"""
-from i18n import gettext as _
-from demandload import *
-demandload(globals(), "struct os bz2 zlib util tempfile")
+
+from i18n import _
+import struct, os, bz2, zlib, util, tempfile
def getchunk(source):
"""get a chunk from a changegroup"""
@@ -67,8 +67,6 @@
cleanup = None
try:
if filename:
- if os.path.exists(filename):
- raise util.Abort(_("file '%s' already exists") % filename)
fh = open(filename, "wb")
else:
fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
--- a/mercurial/changelog.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/changelog.py Mon Mar 05 19:54:21 2007 +0100
@@ -6,9 +6,8 @@
# of the GNU General Public License, incorporated herein by reference.
from revlog import *
-from i18n import gettext as _
-from demandload import demandload
-demandload(globals(), "os time util")
+from i18n import _
+import os, time, util
def _string_escape(text):
"""
--- a/mercurial/cmdutil.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/cmdutil.py Mon Mar 05 19:54:21 2007 +0100
@@ -5,11 +5,9 @@
# 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(), 'os sys')
-demandload(globals(), 'mdiff util templater patch')
+from i18n import _
+import os, sys, mdiff, bdiff, util, templater, patch
revrangesep = ':'
@@ -148,21 +146,29 @@
yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
def findrenames(repo, added=None, removed=None, threshold=0.5):
+ '''find renamed files -- yields (before, after, score) tuples'''
if added is None or removed is None:
added, removed = repo.status()[1:3]
- changes = repo.changelog.read(repo.dirstate.parents()[0])
- mf = repo.manifest.read(changes[0])
+ ctx = repo.changectx()
for a in added:
aa = repo.wread(a)
- bestscore, bestname = None, None
+ bestname, bestscore = None, threshold
for r in removed:
- rr = repo.file(r).read(mf[r])
- delta = mdiff.textdiff(aa, rr)
- if len(delta) < len(aa):
- myscore = 1.0 - (float(len(delta)) / len(aa))
- if bestscore is None or myscore > bestscore:
- bestscore, bestname = myscore, r
- if bestname and bestscore >= threshold:
+ rr = ctx.filectx(r).data()
+
+ # bdiff.blocks() returns blocks of matching lines
+ # count the number of bytes in each
+ equal = 0
+ alines = mdiff.splitnewlines(aa)
+ matches = bdiff.blocks(aa, rr)
+ for x1,x2,y1,y2 in matches:
+ for line in alines[x1:x2]:
+ equal += len(line)
+
+ myscore = equal*2.0 / (len(aa)+len(rr))
+ if myscore >= bestscore:
+ bestname, bestscore = r, myscore
+ if bestname:
yield bestname, a, bestscore
def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
@@ -179,7 +185,8 @@
mapping[abs] = rel, exact
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):
+ islink = os.path.islink(rel)
+ if repo.dirstate.state(abs) != 'r' and not islink and not os.path.exists(rel):
remove.append(abs)
mapping[abs] = rel, exact
if repo.ui.verbose or not exact:
@@ -201,12 +208,11 @@
class changeset_printer(object):
'''show changeset information when templating not requested.'''
- def __init__(self, ui, repo, patch, brinfo, buffered):
+ def __init__(self, ui, repo, patch, buffered):
self.ui = ui
self.repo = repo
self.buffered = buffered
self.patch = patch
- self.brinfo = brinfo
self.header = {}
self.hunk = {}
self.lastheader = None
@@ -270,11 +276,6 @@
for parent in parents:
self.ui.write(_("parent: %d:%s\n") % parent)
- if self.brinfo:
- br = self.repo.branchlookup([changenode])
- if br:
- self.ui.write(_("branch: %s\n") % " ".join(br[changenode]))
-
if self.ui.debugflag:
self.ui.write(_("manifest: %d:%s\n") %
(self.repo.manifest.rev(changes[0]), hex(changes[0])))
@@ -322,8 +323,8 @@
class changeset_templater(changeset_printer):
'''format changeset information.'''
- def __init__(self, ui, repo, patch, brinfo, mapfile, buffered):
- changeset_printer.__init__(self, ui, repo, patch, brinfo, buffered)
+ def __init__(self, ui, repo, patch, mapfile, buffered):
+ changeset_printer.__init__(self, ui, repo, patch, buffered)
self.t = templater.templater(mapfile, templater.common_filters,
cache={'parent': '{rev}:{node|short} ',
'manifest': '{rev}:{node|short}',
@@ -409,12 +410,6 @@
if branch:
branch = util.tolocal(branch)
return showlist('branch', [branch], plural='branches', **args)
- # add old style branches if requested
- if self.brinfo:
- br = self.repo.branchlookup([changenode])
- if changenode in br:
- return showlist('branch', br[changenode],
- plural='branches', **args)
def showparents(**args):
parents = [[('rev', log.rev(p)), ('node', hex(p))]
@@ -528,11 +523,6 @@
if opts.get('patch'):
patch = matchfn or util.always
- br = None
- if opts.get('branches'):
- ui.warn(_("the --branches option is deprecated, "
- "please use 'hg branches' instead\n"))
- br = True
tmpl = opts.get('template')
mapfile = None
if tmpl:
@@ -554,12 +544,12 @@
or templater.templatepath(mapfile))
if mapname: mapfile = mapname
try:
- t = changeset_templater(ui, repo, patch, br, mapfile, buffered)
+ t = changeset_templater(ui, repo, patch, mapfile, buffered)
except SyntaxError, inst:
raise util.Abort(inst.args[0])
if tmpl: t.use_template(tmpl)
return t
- return changeset_printer(ui, repo, patch, br, buffered)
+ return changeset_printer(ui, repo, patch, buffered)
def finddate(ui, repo, date):
"""Find the tipmost changeset that matches the given date spec"""
--- a/mercurial/commands.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/commands.py Mon Mar 05 19:54:21 2007 +0100
@@ -5,14 +5,14 @@
# 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
+import demandimport; demandimport.enable()
from node import *
-from i18n import gettext as _
-demandload(globals(), "bisect os re sys signal imp urllib pdb shlex stat")
-demandload(globals(), "fancyopts ui hg util lock revlog bundlerepo")
-demandload(globals(), "difflib patch time help mdiff tempfile")
-demandload(globals(), "traceback errno version atexit socket")
-demandload(globals(), "archival changegroup cmdutil hgweb.server sshserver")
+from i18n import _
+import bisect, os, re, sys, signal, imp, urllib, pdb, shlex, stat
+import fancyopts, ui, hg, util, lock, revlog, bundlerepo
+import difflib, patch, time, help, mdiff, tempfile
+import traceback, errno, version, atexit, socket
+import archival, changegroup, cmdutil, hgweb.server, sshserver
class UnknownCommand(Exception):
"""Exception raised if command is not in the command table."""
@@ -240,8 +240,7 @@
if op1 != node:
if opts['merge']:
ui.status(_('merging with changeset %s\n') % nice(op1))
- n = _lookup(repo, hex(op1))
- hg.merge(repo, n)
+ hg.merge(repo, hex(op1))
else:
ui.status(_('the backout changeset is a new head - '
'do not forget to merge\n'))
@@ -685,15 +684,12 @@
clist.sort()
ui.write("%s\n" % "\n".join(clist))
-def debugrebuildstate(ui, repo, rev=None):
+def debugrebuildstate(ui, repo, rev=""):
"""rebuild the dirstate as it would look like for the given revision"""
- if not rev:
+ if rev == "":
rev = repo.changelog.tip()
- else:
- rev = repo.lookup(rev)
- change = repo.changelog.read(rev)
- n = change[0]
- files = repo.manifest.read(n)
+ ctx = repo.changectx(rev)
+ files = ctx.manifest()
wlock = repo.wlock()
repo.dirstate.rebuild(rev, files)
@@ -704,10 +700,8 @@
dc = repo.dirstate.map
keys = dc.keys()
keys.sort()
- m1n = repo.changelog.read(parent1)[0]
- m2n = repo.changelog.read(parent2)[0]
- m1 = repo.manifest.read(m1n)
- m2 = repo.manifest.read(m2n)
+ m1 = repo.changectx(parent1).manifest()
+ m2 = repo.changectx(parent2).manifest()
errors = 0
for f in dc:
state = repo.dirstate.state(f)
@@ -1156,13 +1150,14 @@
prev = {}
def display(fn, rev, states, prevstates):
- counts = {'-': 0, '+': 0}
+ found = False
filerevmatches = {}
- if incrementing or not opts['all']:
- a, b, r = prevstates, states, rev
+ r = prev.get(fn, -1)
+ if opts['all']:
+ iter = difflinestates(states, prevstates)
else:
- a, b, r = states, prevstates, prev.get(fn, -1)
- for change, l in difflinestates(a, b):
+ iter = [('', l) for l in prevstates]
+ for change, l in iter:
cols = [fn, str(r)]
if opts['line_number']:
cols.append(str(l.linenum))
@@ -1178,19 +1173,17 @@
else:
cols.append(l.line)
ui.write(sep.join(cols), eol)
- counts[change] += 1
- return counts['+'], counts['-']
+ found = True
+ return found
fstate = {}
skip = {}
get = util.cachefunc(lambda r: repo.changectx(r).changeset())
changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
- count = 0
- incrementing = False
+ found = False
follow = opts.get('follow')
for st, rev, fns in changeiter:
if st == 'window':
- incrementing = rev
matches.clear()
elif st == 'add':
mf = repo.changectx(rev).manifest()
@@ -1216,10 +1209,10 @@
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']:
+ if fn in prev or fstate[fn]:
+ r = display(fn, rev, m, fstate[fn])
+ found = found or r
+ if r and not opts['all']:
skip[fn] = True
if copy:
skip[copy] = True
@@ -1228,15 +1221,14 @@
fstate[copy] = m
prev[fn] = rev
- if not incrementing:
- fstate = fstate.items()
- fstate.sort()
- for fn, state in fstate:
- if fn in skip:
- continue
- if fn not in copies.get(prev[fn], {}):
- display(fn, rev, {}, state)
- return (count == 0 and 1) or 0
+ fstate = fstate.items()
+ fstate.sort()
+ for fn, state in fstate:
+ if fn in skip:
+ continue
+ if fn not in copies.get(prev[fn], {}):
+ found = display(fn, rev, {}, state) or found
+ return (not found and 1) or 0
def heads(ui, repo, **opts):
"""show current repository heads
@@ -1545,8 +1537,12 @@
other = hg.repository(ui, source)
incoming = repo.findincoming(other, force=opts["force"])
if not incoming:
+ try:
+ os.unlink(opts["bundle"])
+ except:
+ pass
ui.status(_("no changes found\n"))
- return
+ return 1
cleanup = None
try:
@@ -1711,7 +1707,6 @@
if opts["date"]:
df = util.matchdate(opts["date"])
-
displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
for st, rev, fns in changeiter:
if st == 'add':
@@ -1778,7 +1773,7 @@
ui.write("%3s " % (m.execf(f) and "755" or "644"))
ui.write("%s\n" % f)
-def merge(ui, repo, node=None, force=None, branch=None):
+def merge(ui, repo, node=None, force=None):
"""merge working directory with another revision
Merge the contents of the current working directory and the
@@ -1792,9 +1787,7 @@
revision to merge with must be provided.
"""
- if node or branch:
- node = _lookup(repo, node, branch)
- else:
+ if not node:
heads = repo.heads()
if len(heads) > 2:
raise util.Abort(_('repo has %d heads - '
@@ -1829,7 +1822,7 @@
o = repo.findoutgoing(other, force=opts['force'])
if not o:
ui.status(_("no changes found\n"))
- return
+ return 1
o = repo.changelog.nodesbetween(o, revs)[0]
if opts['newest_first']:
o.reverse()
@@ -2142,8 +2135,9 @@
if not opts['rev'] and p2 != nullid:
raise util.Abort(_('uncommitted merge - please provide a '
'specific revision'))
- node = repo.changectx(opts['rev']).node()
- mf = repo.manifest.read(repo.changelog.read(node)[0])
+ ctx = repo.changectx(opts['rev'])
+ node = ctx.node()
+ mf = ctx.manifest()
if node == parent:
pmf = mf
else:
@@ -2233,7 +2227,7 @@
if pmf is None:
# only need parent manifest in this unlikely case,
# so do not read by default
- pmf = repo.manifest.read(repo.changelog.read(parent)[0])
+ pmf = repo.changectx(parent).manifest()
if abs in pmf:
if mfentry:
# if version of file is same in parent and target
@@ -2467,9 +2461,10 @@
hexfunc = ui.debugflag and hex or short
for t, n in l:
try:
+ hn = hexfunc(n)
r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
- except KeyError:
- r = " ?:?"
+ except revlog.LookupError:
+ r = " ?:%s" % hn
if ui.quiet:
ui.write("%s\n" % t)
else:
@@ -2497,7 +2492,7 @@
modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
return postincoming(ui, repo, modheads, opts['update'])
-def update(ui, repo, node=None, clean=False, branch=None, date=None):
+def update(ui, repo, node=None, clean=False, date=None):
"""update working directory
Update the working directory to the specified revision.
@@ -2517,36 +2512,11 @@
raise util.Abort(_("you can't specify a revision and a date"))
node = cmdutil.finddate(ui, repo, date)
- node = _lookup(repo, node, branch)
if clean:
return hg.clean(repo, node)
else:
return hg.update(repo, node)
-def _lookup(repo, node, branch=None):
- if branch:
- repo.ui.warn(_("the --branch option is deprecated, "
- "please use 'hg branch' instead\n"))
- br = repo.branchlookup(branch=branch)
- found = []
- for x in br:
- if branch in br[x]:
- found.append(x)
- if len(found) > 1:
- repo.ui.warn(_("Found multiple heads for %s\n") % branch)
- for x in found:
- cmdutil.show_changeset(ui, repo, {}).show(changenode=x)
- raise util.Abort("")
- if len(found) == 1:
- node = found[0]
- repo.ui.warn(_("Using head %s for branch %s\n")
- % (short(node), branch))
- else:
- raise util.Abort(_("branch %s not found") % branch)
- else:
- node = node and repo.lookup(node) or repo.changelog.tip()
- return node
-
def verify(ui, repo):
"""verify the integrity of the repository
@@ -2752,8 +2722,7 @@
_('hg grep [OPTION]... PATTERN [FILE]...')),
"heads":
(heads,
- [('b', 'branches', None, _('show branches (DEPRECATED)')),
- ('', 'style', '', _('display using template map file')),
+ [('', 'style', '', _('display using template map file')),
('r', 'rev', '', _('show only heads which are descendants of rev')),
('', 'template', '', _('display with template'))],
_('hg heads [-r REV]')),
@@ -2764,7 +2733,7 @@
[('p', 'strip', 1,
_('directory strip option for patch. This has the same\n'
'meaning as the corresponding patch option')),
- ('b', 'base', '', _('base path (DEPRECATED)')),
+ ('b', 'base', '', _('base path')),
('f', 'force', None,
_('skip check for outstanding uncommitted changes'))] + commitopts,
_('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
@@ -2796,8 +2765,7 @@
_('hg locate [OPTION]... [PATTERN]...')),
"^log|history":
(log,
- [('b', 'branches', None, _('show branches (DEPRECATED)')),
- ('f', 'follow', None,
+ [('f', 'follow', None,
_('follow changeset history, or file history across copies and renames')),
('', 'follow-first', None,
_('only follow the first parent of merge changesets')),
@@ -2818,8 +2786,7 @@
"manifest": (manifest, [], _('hg manifest [REV]')),
"^merge":
(merge,
- [('b', 'branch', '', _('merge with head of a specific branch (DEPRECATED)')),
- ('f', 'force', None, _('force a merge with outstanding changes'))],
+ [('f', 'force', None, _('force a merge with outstanding changes'))],
_('hg merge [-f] [REV]')),
"outgoing|out": (outgoing,
[('M', 'no-merges', None, _('do not show merges')),
@@ -2834,8 +2801,7 @@
_('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
"^parents":
(parents,
- [('b', 'branches', None, _('show branches (DEPRECATED)')),
- ('r', 'rev', '', _('show parents from the specified rev')),
+ [('r', 'rev', '', _('show parents from the specified rev')),
('', 'style', '', _('display using template map file')),
('', 'template', '', _('display with template'))],
_('hg parents [-r REV] [FILE]')),
@@ -2938,8 +2904,7 @@
"tags": (tags, [], _('hg tags')),
"tip":
(tip,
- [('b', 'branches', None, _('show branches (DEPRECATED)')),
- ('', 'style', '', _('display using template map file')),
+ [('', 'style', '', _('display using template map file')),
('p', 'patch', None, _('show patch')),
('', 'template', '', _('display with template'))],
_('hg tip [-p]')),
@@ -2950,9 +2915,7 @@
_('hg unbundle [-u] FILE')),
"^update|up|checkout|co":
(update,
- [('b', 'branch', '',
- _('checkout the head of a specific branch (DEPRECATED)')),
- ('C', 'clean', None, _('overwrite locally modified files')),
+ [('C', 'clean', None, _('overwrite locally modified files')),
('d', 'date', '', _('tipmost revision matching date'))],
_('hg update [-C] [-d DATE] [REV]')),
"verify": (verify, [], _('hg verify')),
@@ -3109,9 +3072,10 @@
if reposetup:
hg.repo_setup_hooks.append(reposetup)
cmdtable = getattr(mod, 'cmdtable', {})
- for t in cmdtable:
- if t in table:
- ui.warn(_("module %s overrides %s\n") % (name, t))
+ overrides = [cmd for cmd in cmdtable if cmd in table]
+ if overrides:
+ ui.warn(_("extension '%s' overrides commands: %s\n")
+ % (name, " ".join(overrides)))
table.update(cmdtable)
def parseconfig(config):
--- a/mercurial/context.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/context.py Mon Mar 05 19:54:21 2007 +0100
@@ -6,9 +6,8 @@
# of the GNU General Public License, incorporated herein by reference.
from node import *
-from i18n import gettext as _
-from demandload import demandload
-demandload(globals(), "ancestor bdiff repo revlog util os")
+from i18n import _
+import ancestor, bdiff, repo, revlog, util, os, errno
class changectx(object):
"""A changecontext object makes access to data related to a particular
@@ -84,21 +83,22 @@
try:
return self._manifest[path]
except KeyError:
- raise repo.LookupError(_("'%s' not found in manifest") % path)
+ raise revlog.LookupError(_("'%s' not found in manifest") % path)
if '_manifestdelta' in self.__dict__ or path in self.files():
if path in self._manifestdelta:
return self._manifestdelta[path]
node, flag = self._repo.manifest.find(self._changeset[0], path)
if not node:
- raise repo.LookupError(_("'%s' not found in manifest") % path)
+ raise revlog.LookupError(_("'%s' not found in manifest") % path)
return node
- def filectx(self, path, fileid=None):
+ def filectx(self, path, fileid=None, filelog=None):
"""get a file context from this changeset"""
if fileid is None:
fileid = self.filenode(path)
- return filectx(self._repo, path, fileid=fileid, changectx=self)
+ return filectx(self._repo, path, fileid=fileid,
+ changectx=self, filelog=filelog)
def filectxs(self):
"""generate a file context for each file in this changeset's
@@ -126,16 +126,18 @@
self._repo = repo
self._path = path
- assert changeid is not None or fileid is not None
+ assert (changeid is not None
+ or fileid is not None
+ or changectx is not None)
if filelog:
self._filelog = filelog
- if changectx:
- self._changectx = changectx
- self._changeid = changectx.node()
if fileid is None:
- self._changeid = changeid
+ if changectx is None:
+ self._changeid = changeid
+ else:
+ self._changectx = changectx
else:
self._fileid = fileid
@@ -150,13 +152,10 @@
self._changeid = self._filelog.linkrev(self._filenode)
return self._changeid
elif name == '_filenode':
- try:
- if '_fileid' in self.__dict__:
- self._filenode = self._filelog.lookup(self._fileid)
- else:
- self._filenode = self._changectx.filenode(self._path)
- except revlog.RevlogError, inst:
- raise repo.LookupError(str(inst))
+ if '_fileid' in self.__dict__:
+ self._filenode = self._filelog.lookup(self._fileid)
+ else:
+ self._filenode = self._changectx.filenode(self._path)
return self._filenode
elif name == '_filerev':
self._filerev = self._filelog.rev(self._filenode)
@@ -168,7 +167,7 @@
try:
n = self._filenode
return True
- except repo.LookupError:
+ except revlog.LookupError:
# file is missing
return False
@@ -379,13 +378,15 @@
"""generate a manifest corresponding to the working directory"""
man = self._parents[0].manifest().copy()
+ is_exec = util.execfunc(self._repo.root, man.execf)
+ is_link = util.linkfunc(self._repo.root, man.linkf)
copied = self._repo.dirstate.copies()
modified, added, removed, deleted, unknown = self._status[:5]
for i, l in (("a", added), ("m", modified), ("u", unknown)):
for f in l:
man[f] = man.get(copied.get(f, f), nullid) + i
try:
- man.set(f, util.is_exec(self._repo.wjoin(f), man.execf(f)))
+ man.set(f, is_exec(f), is_link(f))
except OSError:
pass
@@ -424,9 +425,10 @@
def children(self):
return []
- def filectx(self, path):
+ def filectx(self, path, filelog=None):
"""get a file context from the working directory"""
- return workingfilectx(self._repo, path, workingctx=self)
+ return workingfilectx(self._repo, path, workingctx=self,
+ filelog=filelog)
def ancestor(self, c2):
"""return the ancestor context of self and c2"""
@@ -484,7 +486,7 @@
rp = self._repopath
if rp == self._path:
return None
- return rp, self._workingctx._parents._manifest.get(rp, nullid)
+ return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
def parents(self):
'''return parent filectxs, following copies if necessary'''
@@ -505,5 +507,12 @@
return []
def size(self): return os.stat(self._repo.wjoin(self._path)).st_size
+ def date(self):
+ t, tz = self._changectx.date()
+ try:
+ return (int(os.lstat(self._repo.wjoin(self._path)).st_mtime), tz)
+ except OSError, err:
+ if err.errno != errno.ENOENT: raise
+ return (t, tz)
def cmp(self, text): return self._repo.wread(self._path) == text
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/demandimport.py Mon Mar 05 19:54:21 2007 +0100
@@ -0,0 +1,115 @@
+# demandimport.py - global demand-loading of modules for Mercurial
+#
+# 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.
+
+'''
+demandimport - automatic demandloading of modules
+
+To enable this module, do:
+
+ import demandimport; demandimport.enable()
+
+Imports of the following forms will be demand-loaded:
+
+ import a, b.c
+ import a.b as c
+ from a import b,c # a will be loaded immediately
+
+These imports will not be delayed:
+
+ from a import *
+ b = __import__(a)
+'''
+
+_origimport = __import__
+
+class _demandmod(object):
+ """module demand-loader and proxy"""
+ def __init__(self, name, globals, locals):
+ if '.' in name:
+ head, rest = name.split('.', 1)
+ after = [rest]
+ else:
+ head = name
+ after = []
+ object.__setattr__(self, "_data", (head, globals, locals, after))
+ object.__setattr__(self, "_module", None)
+ def _extend(self, name):
+ """add to the list of submodules to load"""
+ self._data[3].append(name)
+ def _load(self):
+ if not self._module:
+ head, globals, locals, after = self._data
+ mod = _origimport(head, globals, locals)
+ # load submodules
+ def subload(mod, p):
+ h, t = p, None
+ if '.' in p:
+ h, t = p.split('.', 1)
+ if not hasattr(mod, h):
+ setattr(mod, h, _demandmod(p, mod.__dict__, mod.__dict__))
+ elif t:
+ subload(getattr(mod, h), t)
+
+ for x in after:
+ subload(mod, x)
+
+ # are we in the locals dictionary still?
+ if locals and locals.get(head) == self:
+ locals[head] = mod
+ object.__setattr__(self, "_module", mod)
+ def __repr__(self):
+ return "<unloaded module '%s'>" % self._data[0]
+ def __call__(self, *args, **kwargs):
+ raise TypeError("'unloaded module' object is not callable")
+ def __getattribute__(self, attr):
+ if attr in ('_data', '_extend', '_load', '_module'):
+ return object.__getattribute__(self, attr)
+ self._load()
+ return getattr(self._module, attr)
+ def __setattr__(self, attr, val):
+ self._load()
+ setattr(self._module, attr, val)
+
+def _demandimport(name, globals=None, locals=None, fromlist=None):
+ if not locals or name in ignore or fromlist == ('*',):
+ # these cases we can't really delay
+ return _origimport(name, globals, locals, fromlist)
+ elif not fromlist:
+ # import a [as b]
+ if '.' in name: # a.b
+ base, rest = name.split('.', 1)
+ # email.__init__ loading email.mime
+ if globals and globals.get('__name__', None) == base:
+ return _origimport(name, globals, locals, fromlist)
+ # if a is already demand-loaded, add b to its submodule list
+ if base in locals:
+ if isinstance(locals[base], _demandmod):
+ locals[base]._extend(rest)
+ return locals[base]
+ return _demandmod(name, globals, locals)
+ else:
+ # from a import b,c,d
+ mod = _origimport(name, globals, locals)
+ # recurse down the module chain
+ for comp in name.split('.')[1:]:
+ mod = getattr(mod, comp)
+ for x in fromlist:
+ # set requested submodules for demand load
+ if not(hasattr(mod, x)):
+ setattr(mod, x, _demandmod(x, mod.__dict__, mod.__dict__))
+ return mod
+
+ignore = ['_hashlib', '_xmlplus', 'fcntl', 'win32com.gen_py']
+
+def enable():
+ "enable global demand-loading of modules"
+ __builtins__["__import__"] = _demandimport
+
+def disable():
+ "disable global demand-loading of modules"
+ __builtins__["__import__"] = _origimport
+
--- a/mercurial/demandload.py Mon Mar 05 19:48:21 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,135 +0,0 @@
-'''Demand load modules when used, not when imported.'''
-
-__author__ = '''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.'''
-
-# this is based on matt's original demandload module. it is a
-# complete rewrite. some time, we may need to support syntax of
-# "import foo as bar".
-
-class _importer(object):
- '''import a module. it is not imported until needed, and is
- imported at most once per scope.'''
-
- def __init__(self, scope, modname, fromlist):
- '''scope is context (globals() or locals()) in which import
- should be made. modname is name of module to import.
- fromlist is list of modules for "from foo import ..."
- emulation.'''
-
- self.scope = scope
- self.modname = modname
- self.fromlist = fromlist
- self.mod = None
-
- def module(self):
- '''import the module if needed, and return.'''
- if self.mod is None:
- self.mod = __import__(self.modname, self.scope, self.scope,
- self.fromlist)
- del self.modname, self.fromlist
- return self.mod
-
-class _replacer(object):
- '''placeholder for a demand loaded module. demandload puts this in
- a target scope. when an attribute of this object is looked up,
- this object is replaced in the target scope with the actual
- module.
-
- we use __getattribute__ to avoid namespace clashes between
- placeholder object and real module.'''
-
- def __init__(self, importer, target):
- self.importer = importer
- self.target = target
- # consider case where we do this:
- # demandload(globals(), 'foo.bar foo.quux')
- # foo will already exist in target scope when we get to
- # foo.quux. so we remember that we will need to demandload
- # quux into foo's scope when we really load it.
- self.later = []
-
- def module(self):
- return object.__getattribute__(self, 'importer').module()
-
- def __getattribute__(self, key):
- '''look up an attribute in a module and return it. replace the
- name of the module in the caller\'s dict with the actual
- module.'''
-
- module = object.__getattribute__(self, 'module')()
- target = object.__getattribute__(self, 'target')
- importer = object.__getattribute__(self, 'importer')
- later = object.__getattribute__(self, 'later')
-
- if later:
- demandload(module.__dict__, ' '.join(later))
-
- importer.scope[target] = module
-
- return getattr(module, key)
-
-class _replacer_from(_replacer):
- '''placeholder for a demand loaded module. used for "from foo
- import ..." emulation. semantics of this are different than
- regular import, so different implementation needed.'''
-
- def module(self):
- importer = object.__getattribute__(self, 'importer')
- target = object.__getattribute__(self, 'target')
-
- return getattr(importer.module(), target)
-
- def __call__(self, *args, **kwargs):
- target = object.__getattribute__(self, 'module')()
- return target(*args, **kwargs)
-
-def demandload(scope, modules):
- '''import modules into scope when each is first used.
-
- scope should be the value of globals() in the module calling this
- function, or locals() in the calling function.
-
- modules is a string listing module names, separated by white
- space. names are handled like this:
-
- foo import foo
- foo bar import foo, bar
- foo@bar import foo as bar
- foo.bar import foo.bar
- foo:bar from foo import bar
- foo:bar,quux from foo import bar, quux
- foo.bar:quux from foo.bar import quux'''
-
- for mod in modules.split():
- col = mod.find(':')
- if col >= 0:
- fromlist = mod[col+1:].split(',')
- mod = mod[:col]
- else:
- fromlist = []
- as_ = None
- if '@' in mod:
- mod, as_ = mod.split("@")
- importer = _importer(scope, mod, fromlist)
- if fromlist:
- for name in fromlist:
- scope[name] = _replacer_from(importer, name)
- else:
- dot = mod.find('.')
- if dot >= 0:
- basemod = mod[:dot]
- val = scope.get(basemod)
- # if base module has already been demandload()ed,
- # remember to load this submodule into its namespace
- # when needed.
- if isinstance(val, _replacer):
- later = object.__getattribute__(val, 'later')
- later.append(mod[dot+1:])
- continue
- else:
- basemod = mod
- if not as_:
- as_ = basemod
- scope[as_] = _replacer(importer, as_)
--- a/mercurial/dirstate.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/dirstate.py Mon Mar 05 19:54:21 2007 +0100
@@ -8,9 +8,8 @@
"""
from node import *
-from i18n import gettext as _
-from demandload import *
-demandload(globals(), "struct os time bisect stat strutil util re errno")
+from i18n import _
+import struct, os, time, bisect, stat, strutil, util, re, errno
class dirstate(object):
format = ">cllll"
@@ -338,14 +337,13 @@
return ret
def supported_type(self, f, st, verbose=False):
- if stat.S_ISREG(st.st_mode):
+ if stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode):
return True
if verbose:
kind = 'unknown'
if stat.S_ISCHR(st.st_mode): kind = _('character device')
elif stat.S_ISBLK(st.st_mode): kind = _('block device')
elif stat.S_ISFIFO(st.st_mode): kind = _('fifo')
- elif stat.S_ISLNK(st.st_mode): kind = _('symbolic link')
elif stat.S_ISSOCK(st.st_mode): kind = _('socket')
elif stat.S_ISDIR(st.st_mode): kind = _('directory')
self.ui.warn(_('%s: unsupported file type (type is %s)\n') % (
--- a/mercurial/filelog.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/filelog.py Mon Mar 05 19:54:21 2007 +0100
@@ -6,8 +6,7 @@
# of the GNU General Public License, incorporated herein by reference.
from revlog import *
-from demandload import *
-demandload(globals(), "os")
+import os
class filelog(revlog):
def __init__(self, opener, path, defversion=REVLOG_DEFAULT_VERSION):
--- a/mercurial/hg.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/hg.py Mon Mar 05 19:54:21 2007 +0100
@@ -8,10 +8,11 @@
from node import *
from repo import *
-from demandload import *
-from i18n import gettext as _
-demandload(globals(), "localrepo bundlerepo httprepo sshrepo statichttprepo")
-demandload(globals(), "errno lock os shutil util merge@_merge verify@_verify")
+from i18n import _
+import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo
+import errno, lock, os, shutil, util
+import merge as _merge
+import verify as _verify
def _local(path):
return (os.path.isfile(util.drop_scheme('file', path)) and
--- a/mercurial/hgweb/__init__.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/hgweb/__init__.py Mon Mar 05 19:54:21 2007 +0100
@@ -6,6 +6,11 @@
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
-from mercurial.demandload import demandload
-demandload(globals(), "mercurial.hgweb.hgweb_mod:hgweb")
-demandload(globals(), "mercurial.hgweb.hgwebdir_mod:hgwebdir")
+import hgweb_mod, hgwebdir_mod
+
+def hgweb(*args, **kwargs):
+ return hgweb_mod.hgweb(*args, **kwargs)
+
+def hgwebdir(*args, **kwargs):
+ return hgwebdir_mod.hgwebdir(*args, **kwargs)
+
--- a/mercurial/hgweb/common.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/hgweb/common.py Mon Mar 05 19:54:21 2007 +0100
@@ -7,7 +7,6 @@
# of the GNU General Public License, incorporated herein by reference.
import os, mimetypes
-import os.path
def get_mtime(repo_path):
store_path = os.path.join(repo_path, ".hg")
@@ -39,7 +38,7 @@
os.stat(path)
ct = mimetypes.guess_type(path)[0] or "text/plain"
req.header([('Content-type', ct),
- ('Content-length', os.path.getsize(path))])
+ ('Content-length', str(os.path.getsize(path)))])
return file(path, 'rb').read()
except (TypeError, OSError):
# illegal fname or unreadable file
--- a/mercurial/hgweb/hgweb_mod.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/hgweb/hgweb_mod.py Mon Mar 05 19:54:21 2007 +0100
@@ -6,17 +6,13 @@
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
-import os
-import os.path
-import mimetypes
-from mercurial.demandload import demandload
-demandload(globals(), "re zlib ConfigParser mimetools cStringIO sys tempfile")
-demandload(globals(), 'urllib bz2')
-demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,streamclone,patch")
-demandload(globals(), "mercurial:revlog,templater")
-demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile,style_map")
+import os, mimetypes, re, zlib, mimetools, cStringIO, sys
+import tempfile, urllib, bz2
from mercurial.node import *
from mercurial.i18n import gettext as _
+from mercurial import mdiff, ui, hg, util, archival, streamclone, patch
+from mercurial import revlog, templater
+from common import get_mtime, staticfile, style_map
def _up(p):
if p[0] != "/":
@@ -172,14 +168,10 @@
yield self.t("diffline", line=l)
r = self.repo
- cl = r.changelog
- mf = r.manifest
- change1 = cl.read(node1)
- change2 = cl.read(node2)
- mmap1 = mf.read(change1[0])
- mmap2 = mf.read(change2[0])
- date1 = util.datestr(change1[2])
- date2 = util.datestr(change2[2])
+ c1 = r.changectx(node1)
+ c2 = r.changectx(node2)
+ date1 = util.datestr(c1.date())
+ date2 = util.datestr(c2.date())
modified, added, removed, deleted, unknown = r.status(node1, node2)[:5]
if files:
@@ -188,17 +180,17 @@
diffopts = patch.diffopts(self.repo.ui, untrusted=True)
for f in modified:
- to = r.file(f).read(mmap1[f])
- tn = r.file(f).read(mmap2[f])
+ to = c1.filectx(f).data()
+ tn = c2.filectx(f).data()
yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
opts=diffopts), f, tn)
for f in added:
to = None
- tn = r.file(f).read(mmap2[f])
+ tn = c2.filectx(f).data()
yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
opts=diffopts), f, tn)
for f in removed:
- to = r.file(f).read(mmap1[f])
+ to = c1.filectx(f).data()
tn = None
yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
opts=diffopts), f, tn)
@@ -497,8 +489,6 @@
archives=self.archivelist(hex(node)))
def tags(self):
- cl = self.repo.changelog
-
i = self.repo.tagslist()
i.reverse()
@@ -509,7 +499,7 @@
continue
yield {"parity": self.stripes(parity),
"tag": k,
- "date": cl.read(n)[2],
+ "date": self.repo.changectx(n).date(),
"node": hex(n)}
parity += 1
@@ -519,8 +509,6 @@
entriesnotip=lambda **x: entries(True, **x))
def summary(self):
- cl = self.repo.changelog
-
i = self.repo.tagslist()
i.reverse()
@@ -535,14 +523,11 @@
if count > 10: # limit to 10 tags
break;
- c = cl.read(n)
- t = c[2]
-
yield self.t("tagentry",
- parity = self.stripes(parity),
- tag = k,
- node = hex(n),
- date = t)
+ parity=self.stripes(parity),
+ tag=k,
+ node=hex(n),
+ date=self.repo.changectx(n).date())
parity += 1
def heads(**map):
@@ -564,40 +549,38 @@
def changelist(**map):
parity = 0
- cl = self.repo.changelog
l = [] # build a list in forward order for efficiency
for i in xrange(start, end):
- n = cl.node(i)
- changes = cl.read(n)
- hn = hex(n)
- t = changes[2]
+ ctx = self.repo.changectx(i)
+ hn = hex(ctx.node())
l.insert(0, self.t(
'shortlogentry',
- parity = parity,
- author = changes[1],
- desc = changes[4],
- date = t,
- rev = i,
- node = hn))
+ parity=parity,
+ author=ctx.user(),
+ desc=ctx.description(),
+ date=ctx.date(),
+ rev=i,
+ node=hn))
parity = 1 - parity
yield l
+ cl = self.repo.changelog
count = cl.count()
start = max(0, count - self.maxchanges)
end = min(count, start + self.maxchanges)
yield self.t("summary",
- desc = self.config("web", "description", "unknown"),
- owner = (self.config("ui", "username") or # preferred
- self.config("web", "contact") or # deprecated
- self.config("web", "author", "unknown")), # also
- lastchange = cl.read(cl.tip())[2],
- tags = tagentries,
- heads = heads,
- shortlog = changelist,
- node = hex(cl.tip()),
+ desc=self.config("web", "description", "unknown"),
+ owner=(self.config("ui", "username") or # preferred
+ self.config("web", "contact") or # deprecated
+ self.config("web", "author", "unknown")), # also
+ lastchange=cl.read(cl.tip())[2],
+ tags=tagentries,
+ heads=heads,
+ shortlog=changelist,
+ node=hex(cl.tip()),
archives=self.archivelist("tip"))
def filediff(self, fctx):
@@ -789,6 +772,9 @@
port = req.env["SERVER_PORT"]
port = port != "80" and (":" + port) or ""
urlbase = 'http://%s%s' % (req.env['SERVER_NAME'], port)
+ staticurl = self.config("web", "staticurl") or req.url + 'static/'
+ if not staticurl.endswith('/'):
+ staticurl += '/'
if not self.reponame:
self.reponame = (self.config("web", "name")
@@ -797,6 +783,7 @@
self.t = templater.templater(mapfile, templater.common_filters,
defaults={"url": req.url,
+ "staticurl": staticurl,
"urlbase": urlbase,
"repo": self.reponame,
"header": header,
@@ -873,7 +860,7 @@
try:
req.write(self.filerevision(self.filectx(req)))
return
- except hg.RepoError:
+ except revlog.LookupError:
pass
req.write(self.manifest(self.changectx(req), path))
--- a/mercurial/hgweb/hgwebdir_mod.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/hgweb/hgwebdir_mod.py Mon Mar 05 19:54:21 2007 +0100
@@ -6,13 +6,12 @@
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
-import os
-from mercurial.demandload import demandload
-demandload(globals(), "mimetools cStringIO")
-demandload(globals(), "mercurial:ui,hg,util,templater")
-demandload(globals(), "mercurial.hgweb.hgweb_mod:hgweb")
-demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile,style_map")
+from mercurial import demandimport; demandimport.enable()
+import os, mimetools, cStringIO
from mercurial.i18n import gettext as _
+from mercurial import ui, hg, util, templater
+from common import get_mtime, staticfile, style_map
+from hgweb_mod import hgweb
# This is a stopgap
class hgwebdir(object):
@@ -31,8 +30,11 @@
self.repos = cleannames(config.items())
self.repos.sort()
else:
- cp = util.configparser()
- cp.read(config)
+ if isinstance(config, util.configparser):
+ cp = config
+ else:
+ cp = util.configparser()
+ cp.read(config)
self.repos = []
if cp.has_section('web'):
if cp.has_option('web', 'motd'):
@@ -86,6 +88,10 @@
if not url.endswith('/'):
url += '/'
+ staticurl = config('web', 'staticurl') or url + 'static/'
+ if not staticurl.endswith('/'):
+ staticurl += '/'
+
style = self.style
if style is None:
style = config('web', 'style', '')
@@ -96,7 +102,8 @@
defaults={"header": header,
"footer": footer,
"motd": motd,
- "url": url})
+ "url": url,
+ "staticurl": staticurl})
def archivelist(ui, nodeid, url):
allowed = ui.configlist("web", "allow_archive", untrusted=True)
--- a/mercurial/hgweb/request.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/hgweb/request.py Mon Mar 05 19:54:21 2007 +0100
@@ -6,8 +6,7 @@
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
-from mercurial.demandload import demandload
-demandload(globals(), "socket sys cgi os errno")
+import socket, cgi, errno
from mercurial.i18n import gettext as _
class wsgiapplication(object):
--- a/mercurial/hgweb/server.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/hgweb/server.py Mon Mar 05 19:54:21 2007 +0100
@@ -6,11 +6,11 @@
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
-from mercurial.demandload import demandload
-import os, sys, errno
-demandload(globals(), "urllib BaseHTTPServer socket SocketServer traceback")
-demandload(globals(), "mercurial:ui,hg,util,templater")
-demandload(globals(), "hgweb_mod:hgweb hgwebdir_mod:hgwebdir request:wsgiapplication")
+import os, sys, errno, urllib, BaseHTTPServer, socket, SocketServer, traceback
+from mercurial import ui, hg, util, templater
+from hgweb_mod import hgweb
+from hgwebdir_mod import hgwebdir
+from request import wsgiapplication
from mercurial.i18n import gettext as _
def _splitURI(uri):
--- a/mercurial/httprepo.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/httprepo.py Mon Mar 05 19:54:21 2007 +0100
@@ -8,10 +8,9 @@
from node import *
from remoterepo import *
-from i18n import gettext as _
-from demandload import *
-demandload(globals(), "hg os urllib urllib2 urlparse zlib util httplib")
-demandload(globals(), "errno keepalive tempfile socket changegroup")
+from i18n import _
+import hg, os, urllib, urllib2, urlparse, zlib, util, httplib
+import errno, keepalive, tempfile, socket, changegroup
class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm):
def __init__(self, ui):
--- a/mercurial/i18n.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/i18n.py Mon Mar 05 19:54:21 2007 +0100
@@ -7,9 +7,7 @@
of the GNU General Public License, incorporated herein by reference.
"""
-# the import from gettext is _really_ slow
-# for now we use a dummy function
-gettext = lambda x: x
-#import gettext
-#t = gettext.translation('hg', '/usr/share/locale', fallback=1)
-#gettext = t.gettext
+import gettext
+t = gettext.translation('hg', fallback=1)
+gettext = t.gettext
+_ = gettext
--- a/mercurial/localrepo.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/localrepo.py Mon Mar 05 19:54:21 2007 +0100
@@ -6,13 +6,11 @@
# of the GNU General Public License, incorporated herein by reference.
from node import *
-from i18n import gettext as _
-from demandload import *
-import repo
-demandload(globals(), "appendfile changegroup")
-demandload(globals(), "changelog dirstate filelog manifest context")
-demandload(globals(), "re lock transaction tempfile stat mdiff errno ui")
-demandload(globals(), "os revlog time util")
+from i18n import _
+import repo, appendfile, changegroup
+import changelog, dirstate, filelog, manifest, context
+import re, lock, transaction, tempfile, stat, mdiff, errno, ui
+import os, revlog, time, util
class localrepository(repo.repository):
capabilities = ('lookup', 'changegroupsubset')
@@ -119,10 +117,14 @@
self.tagscache = None
self.branchcache = None
self.nodetagscache = None
- self.encodepats = None
- self.decodepats = None
+ self.filterpats = {}
self.transhandle = None
+ self._link = lambda x: False
+ if util.checklink(self.root):
+ r = self.root # avoid circular reference in lambda
+ self._link = lambda x: util.is_link(os.path.join(r, x))
+
self.dirstate = dirstate.dirstate(self.opener, self.ui, self.root)
def url(self):
@@ -140,32 +142,34 @@
be run as hooks without wrappers to convert return values.'''
self.ui.note(_("calling hook %s: %s\n") % (hname, funcname))
- d = funcname.rfind('.')
- if d == -1:
- raise util.Abort(_('%s hook is invalid ("%s" not in a module)')
- % (hname, funcname))
- modname = funcname[:d]
- try:
- obj = __import__(modname)
- except ImportError:
+ obj = funcname
+ if not callable(obj):
+ d = funcname.rfind('.')
+ if d == -1:
+ raise util.Abort(_('%s hook is invalid ("%s" not in '
+ 'a module)') % (hname, funcname))
+ modname = funcname[:d]
try:
- # extensions are loaded with hgext_ prefix
- obj = __import__("hgext_%s" % modname)
+ obj = __import__(modname)
except ImportError:
+ try:
+ # extensions are loaded with hgext_ prefix
+ obj = __import__("hgext_%s" % modname)
+ except ImportError:
+ raise util.Abort(_('%s hook is invalid '
+ '(import of "%s" failed)') %
+ (hname, modname))
+ try:
+ for p in funcname.split('.')[1:]:
+ obj = getattr(obj, p)
+ except AttributeError, err:
raise util.Abort(_('%s hook is invalid '
- '(import of "%s" failed)') %
- (hname, modname))
- try:
- for p in funcname.split('.')[1:]:
- obj = getattr(obj, p)
- except AttributeError, err:
- raise util.Abort(_('%s hook is invalid '
- '("%s" is not defined)') %
- (hname, funcname))
- if not callable(obj):
- raise util.Abort(_('%s hook is invalid '
- '("%s" is not callable)') %
- (hname, funcname))
+ '("%s" is not defined)') %
+ (hname, funcname))
+ if not callable(obj):
+ raise util.Abort(_('%s hook is invalid '
+ '("%s" is not callable)') %
+ (hname, funcname))
try:
r = obj(ui=self.ui, repo=self, hooktype=name, **args)
except (KeyboardInterrupt, util.SignalInterrupt):
@@ -203,7 +207,9 @@
if hname.split(".", 1)[0] == name and cmd]
hooks.sort()
for hname, cmd in hooks:
- if cmd.startswith('python:'):
+ if callable(cmd):
+ r = callhook(hname, cmd) or r
+ elif cmd.startswith('python:'):
r = callhook(hname, cmd[7:].strip()) or r
else:
r = runhook(hname, cmd) or r
@@ -211,6 +217,37 @@
tag_disallowed = ':\r\n'
+ def _tag(self, name, node, message, local, user, date, parent=None):
+ use_dirstate = parent is None
+
+ for c in self.tag_disallowed:
+ if c in name:
+ raise util.Abort(_('%r cannot be used in a tag name') % c)
+
+ self.hook('pretag', throw=True, node=hex(node), tag=name, local=local)
+
+ if local:
+ # local tags are stored in the current charset
+ self.opener('localtags', 'a').write('%s %s\n' % (hex(node), name))
+ self.hook('tag', node=hex(node), tag=name, local=local)
+ return
+
+ # committed tags are stored in UTF-8
+ line = '%s %s\n' % (hex(node), util.fromlocal(name))
+ if use_dirstate:
+ self.wfile('.hgtags', 'ab').write(line)
+ else:
+ ntags = self.filectx('.hgtags', parent).data()
+ self.wfile('.hgtags', 'ab').write(ntags + line)
+ if use_dirstate and self.dirstate.state('.hgtags') == '?':
+ self.add(['.hgtags'])
+
+ tagnode = self.commit(['.hgtags'], message, user, date, p1=parent)
+
+ self.hook('tag', node=hex(node), tag=name, local=local)
+
+ return tagnode
+
def tag(self, name, node, message, local, user, date):
'''tag a revision with a symbolic name.
@@ -229,31 +266,13 @@
date: date tuple to use if committing'''
- for c in self.tag_disallowed:
- if c in name:
- raise util.Abort(_('%r cannot be used in a tag name') % c)
-
- self.hook('pretag', throw=True, node=hex(node), tag=name, local=local)
-
- if local:
- # local tags are stored in the current charset
- self.opener('localtags', 'a').write('%s %s\n' % (hex(node), name))
- self.hook('tag', node=hex(node), tag=name, local=local)
- return
-
for x in self.status()[:5]:
if '.hgtags' in x:
raise util.Abort(_('working copy of .hgtags is changed '
'(please commit .hgtags manually)'))
- # committed tags are stored in UTF-8
- line = '%s %s\n' % (hex(node), util.fromlocal(name))
- self.wfile('.hgtags', 'ab').write(line)
- if self.dirstate.state('.hgtags') == '?':
- self.add(['.hgtags'])
- self.commit(['.hgtags'], message, user, date)
- self.hook('tag', node=hex(node), tag=name, local=local)
+ self._tag(name, node, message, local, user, date)
def tags(self):
'''return a mapping of tag to node'''
@@ -319,7 +338,7 @@
rev = c.rev()
try:
fnode = c.filenode('.hgtags')
- except repo.LookupError:
+ except revlog.LookupError:
continue
ret.append((rev, node, fnode))
if fnode in last:
@@ -480,17 +499,15 @@
def wfile(self, f, mode='r'):
return self.wopener(f, mode)
- def wread(self, filename):
- if self.encodepats == None:
+ def _filter(self, filter, filename, data):
+ if filter not in self.filterpats:
l = []
- for pat, cmd in self.ui.configitems("encode"):
+ for pat, cmd in self.ui.configitems(filter):
mf = util.matcher(self.root, "", [pat], [], [])[1]
l.append((mf, cmd))
- self.encodepats = l
+ self.filterpats[filter] = l
- data = self.wopener(filename, 'r').read()
-
- for mf, cmd in self.encodepats:
+ for mf, cmd in self.filterpats[filter]:
if mf(filename):
self.ui.debug(_("filtering %s through %s\n") % (filename, cmd))
data = util.filter(data, cmd)
@@ -498,23 +515,36 @@
return data
- def wwrite(self, filename, data, fd=None):
- if self.decodepats == None:
- l = []
- for pat, cmd in self.ui.configitems("decode"):
- mf = util.matcher(self.root, "", [pat], [], [])[1]
- l.append((mf, cmd))
- self.decodepats = l
+ def wread(self, filename):
+ if self._link(filename):
+ data = os.readlink(self.wjoin(filename))
+ else:
+ data = self.wopener(filename, 'r').read()
+ return self._filter("encode", filename, data)
- for mf, cmd in self.decodepats:
- if mf(filename):
- self.ui.debug(_("filtering %s through %s\n") % (filename, cmd))
- data = util.filter(data, cmd)
- break
+ def wwrite(self, filename, data, flags):
+ data = self._filter("decode", filename, data)
+ if "l" in flags:
+ f = self.wjoin(filename)
+ try:
+ os.unlink(f)
+ except OSError:
+ pass
+ d = os.path.dirname(f)
+ if not os.path.exists(d):
+ os.makedirs(d)
+ os.symlink(data, f)
+ else:
+ try:
+ if self._link(filename):
+ os.unlink(self.wjoin(filename))
+ except OSError:
+ pass
+ self.wopener(filename, 'w').write(data)
+ util.set_exec(self.wjoin(filename), "x" in flags)
- if fd:
- return fd.write(data)
- return self.wopener(filename, 'w').write(data)
+ def wwritedata(self, filename, data):
+ return self._filter("decode", filename, data)
def transaction(self):
tr = self.transhandle
@@ -654,11 +684,11 @@
changelist.append(fn)
return fl.add(t, meta, transaction, linkrev, fp1, fp2)
- def rawcommit(self, files, text, user, date, p1=None, p2=None, wlock=None):
+ def rawcommit(self, files, text, user, date, p1=None, p2=None, wlock=None, extra={}):
if p1 is None:
p1, p2 = self.dirstate.parents()
return self.commit(files=files, text=text, user=user, date=date,
- p1=p1, p2=p2, wlock=wlock)
+ p1=p1, p2=p2, wlock=wlock, extra=extra)
def commit(self, files=None, text="", user=None, date=None,
match=util.always, force=False, lock=None, wlock=None,
@@ -732,12 +762,14 @@
new = {}
linkrev = self.changelog.count()
commit.sort()
+ is_exec = util.execfunc(self.root, m1.execf)
+ is_link = util.linkfunc(self.root, m1.linkf)
for f in commit:
self.ui.note(f + "\n")
try:
new[f] = self.filecommit(f, m1, m2, linkrev, tr, changed)
- m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f)))
- except IOError:
+ m1.set(f, is_exec(f), is_link(f))
+ except (OSError, IOError):
if use_dirstate:
self.ui.warn(_("trouble committing %s!\n") % f)
raise
@@ -747,11 +779,13 @@
# update manifest
m1.update(new)
remove.sort()
+ removed = []
for f in remove:
if f in m1:
del m1[f]
- mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0], (new, remove))
+ removed.append(f)
+ mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0], (new, removed))
# add changeset
new = new.keys()
@@ -766,8 +800,10 @@
edittext.append("HG: user: %s" % user)
if p2 != nullid:
edittext.append("HG: branch merge")
+ if branchname:
+ edittext.append("HG: branch %s" % util.tolocal(branchname))
edittext.extend(["HG: changed %s" % f for f in changed])
- edittext.extend(["HG: removed %s" % f for f in remove])
+ edittext.extend(["HG: removed %s" % f for f in removed])
if not changed and not remove:
edittext.append("HG: no files changed")
edittext.append("")
@@ -785,17 +821,20 @@
text = '\n'.join(lines)
if branchname:
extra["branch"] = branchname
- n = self.changelog.add(mn, changed + remove, text, tr, p1, p2,
+ n = self.changelog.add(mn, changed + removed, text, tr, p1, p2,
user, date, extra)
self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
parent2=xp2)
tr.close()
+ if self.branchcache and "branch" in extra:
+ self.branchcache[util.tolocal(extra["branch"])] = n
+
if use_dirstate or update_dirstate:
self.dirstate.setparents(n)
if use_dirstate:
self.dirstate.update(new, "n")
- self.dirstate.forget(remove)
+ self.dirstate.forget(removed)
self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2)
return n
@@ -895,9 +934,11 @@
# generate a pseudo-manifest for the working dir
# XXX: create it in dirstate.py ?
mf2 = mfmatches(self.dirstate.parents()[0])
+ is_exec = util.execfunc(self.root, mf2.execf)
+ is_link = util.linkfunc(self.root, mf2.linkf)
for f in lookup + modified + added:
mf2[f] = ""
- mf2.set(f, execf=util.is_exec(self.wjoin(f), mf2.execf(f)))
+ mf2.set(f, is_exec(f), is_link(f))
for f in removed:
if f in mf2:
del mf2[f]
@@ -936,11 +977,12 @@
wlock = self.wlock()
for f in list:
p = self.wjoin(f)
- if not os.path.exists(p):
+ islink = os.path.islink(p)
+ if not islink and not os.path.exists(p):
self.ui.warn(_("%s does not exist!\n") % f)
- elif not os.path.isfile(p):
- self.ui.warn(_("%s not added: only files supported currently\n")
- % f)
+ elif not islink and not os.path.isfile(p):
+ self.ui.warn(_("%s not added: only files and symlinks "
+ "supported currently\n") % f)
elif self.dirstate.state(f) in 'an':
self.ui.warn(_("%s already tracked!\n") % f)
else:
@@ -987,8 +1029,7 @@
self.ui.warn("%s not removed!\n" % f)
else:
t = self.file(f).read(m[f])
- self.wwrite(f, t)
- util.set_exec(self.wjoin(f), m.execf(f))
+ self.wwrite(f, t, m.flags(f))
self.dirstate.update([f], "n")
def copy(self, source, dest, wlock=None):
@@ -1011,112 +1052,6 @@
heads.sort()
return [n for (r, n) in heads]
- # branchlookup returns a dict giving a list of branches for
- # each head. A branch is defined as the tag of a node or
- # the branch of the node's parents. If a node has multiple
- # branch tags, tags are eliminated if they are visible from other
- # branch tags.
- #
- # So, for this graph: a->b->c->d->e
- # \ /
- # aa -----/
- # a has tag 2.6.12
- # d has tag 2.6.13
- # e would have branch tags for 2.6.12 and 2.6.13. Because the node
- # for 2.6.12 can be reached from the node 2.6.13, that is eliminated
- # from the list.
- #
- # It is possible that more than one head will have the same branch tag.
- # callers need to check the result for multiple heads under the same
- # branch tag if that is a problem for them (ie checkout of a specific
- # branch).
- #
- # passing in a specific branch will limit the depth of the search
- # through the parents. It won't limit the branches returned in the
- # result though.
- def branchlookup(self, heads=None, branch=None):
- if not heads:
- heads = self.heads()
- headt = [ h for h in heads ]
- chlog = self.changelog
- branches = {}
- merges = []
- seenmerge = {}
-
- # traverse the tree once for each head, recording in the branches
- # dict which tags are visible from this head. The branches
- # dict also records which tags are visible from each tag
- # while we traverse.
- while headt or merges:
- if merges:
- n, found = merges.pop()
- visit = [n]
- else:
- h = headt.pop()
- visit = [h]
- found = [h]
- seen = {}
- while visit:
- n = visit.pop()
- if n in seen:
- continue
- pp = chlog.parents(n)
- tags = self.nodetags(n)
- if tags:
- for x in tags:
- if x == 'tip':
- continue
- for f in found:
- branches.setdefault(f, {})[n] = 1
- branches.setdefault(n, {})[n] = 1
- break
- if n not in found:
- found.append(n)
- if branch in tags:
- continue
- seen[n] = 1
- if pp[1] != nullid and n not in seenmerge:
- merges.append((pp[1], [x for x in found]))
- seenmerge[n] = 1
- if pp[0] != nullid:
- visit.append(pp[0])
- # traverse the branches dict, eliminating branch tags from each
- # head that are visible from another branch tag for that head.
- out = {}
- viscache = {}
- for h in heads:
- def visible(node):
- if node in viscache:
- return viscache[node]
- ret = {}
- visit = [node]
- while visit:
- x = visit.pop()
- if x in viscache:
- ret.update(viscache[x])
- elif x not in ret:
- ret[x] = 1
- if x in branches:
- visit[len(visit):] = branches[x].keys()
- viscache[node] = ret
- return ret
- if h not in branches:
- continue
- # O(n^2), but somewhat limited. This only searches the
- # tags visible from a specific head, not all the tags in the
- # whole repo.
- for b in branches[h]:
- vis = False
- for bb in branches[h].keys():
- if b != bb:
- if b in visible(bb):
- vis = True
- break
- if not vis:
- l = out.setdefault(h, [])
- l[len(l):] = self.nodetags(b)
- return out
-
def branches(self, nodes):
if not nodes:
nodes = [self.changelog.tip()]
--- a/mercurial/lock.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/lock.py Mon Mar 05 19:54:21 2007 +0100
@@ -5,8 +5,7 @@
# 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(globals(), 'errno os socket time util')
+import errno, os, socket, time, util
class LockException(IOError):
def __init__(self, errno, strerror, filename, desc):
--- a/mercurial/mail.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/mail.py Mon Mar 05 19:54:21 2007 +0100
@@ -5,9 +5,8 @@
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
-from i18n import gettext as _
-from demandload import *
-demandload(globals(), "os re smtplib templater util socket")
+from i18n import _
+import os, smtplib, templater, util, socket
def _smtp(ui):
'''send mail using smtp.'''
--- a/mercurial/manifest.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/manifest.py Mon Mar 05 19:54:21 2007 +0100
@@ -6,10 +6,8 @@
# of the GNU General Public License, incorporated herein by reference.
from revlog import *
-from i18n import gettext as _
-from demandload import *
-demandload(globals(), "array bisect struct")
-demandload(globals(), "mdiff")
+from i18n import _
+import array, bisect, struct, mdiff
class manifestdict(dict):
def __init__(self, mapping=None, flags=None):
--- a/mercurial/mdiff.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/mdiff.py Mon Mar 05 19:54:21 2007 +0100
@@ -5,9 +5,7 @@
# 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
-import bdiff, mpatch
-demandload(globals(), "re struct util md5")
+import bdiff, mpatch, re, struct, util, md5
def splitnewlines(text):
'''like str.splitlines, but only split on newlines.'''
--- a/mercurial/merge.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/merge.py Mon Mar 05 19:54:21 2007 +0100
@@ -6,9 +6,8 @@
# of the GNU General Public License, incorporated herein by reference.
from node import *
-from i18n import gettext as _
-from demandload import *
-demandload(globals(), "errno util os tempfile")
+from i18n import _
+import errno, util, os, tempfile
def filemerge(repo, fw, fo, wctx, mctx):
"""perform a 3-way merge in the working directory
@@ -21,8 +20,9 @@
def temp(prefix, ctx):
pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
(fd, name) = tempfile.mkstemp(prefix=pre)
+ data = repo.wwritedata(ctx.path(), ctx.data())
f = os.fdopen(fd, "wb")
- repo.wwrite(ctx.path(), ctx.data(), f)
+ f.write(data)
f.close()
return name
@@ -221,12 +221,17 @@
copy = {}
def fmerge(f, f2=None, fa=None):
- """merge executable flags"""
+ """merge flags"""
if not f2:
f2 = f
fa = f
a, b, c = ma.execf(fa), m1.execf(f), m2.execf(f2)
- return ((a^b) | (a^c)) ^ a
+ if ((a^b) | (a^c)) ^ a:
+ return 'x'
+ a, b, c = ma.linkf(fa), m1.linkf(f), m2.linkf(f2)
+ if ((a^b) | (a^c)) ^ a:
+ return 'l'
+ return ''
def act(msg, m, f, *args):
repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m))
@@ -251,21 +256,21 @@
# is remote's version newer?
# or are we going back in time and clean?
elif overwrite or m2[f] != a or (backwards and not n[20:]):
- act("remote is newer", "g", f, m2.execf(f))
+ act("remote is newer", "g", f, m2.flags(f))
# local is newer, not overwrite, check mode bits
- elif fmerge(f) != m1.execf(f):
- act("update permissions", "e", f, m2.execf(f))
+ elif fmerge(f) != m1.flags(f):
+ act("update permissions", "e", f, m2.flags(f))
# contents same, check mode bits
- elif m1.execf(f) != m2.execf(f):
- if overwrite or fmerge(f) != m1.execf(f):
- act("update permissions", "e", f, m2.execf(f))
+ elif m1.flags(f) != m2.flags(f):
+ if overwrite or fmerge(f) != m1.flags(f):
+ act("update permissions", "e", f, m2.flags(f))
elif f in copied:
continue
elif f in copy:
f2 = copy[f]
if f2 not in m2: # directory rename
act("remote renamed directory to " + f2, "d",
- f, None, f2, m1.execf(f))
+ f, None, f2, m1.flags(f))
elif f2 in m1: # case 2 A,B/B/B
act("local copied to " + f2, "m",
f, f2, f, fmerge(f, f2, f2), False)
@@ -296,7 +301,7 @@
f2 = copy[f]
if f2 not in m1: # directory rename
act("local renamed directory to " + f2, "d",
- None, f, f2, m2.execf(f))
+ None, f, f2, m2.flags(f))
elif f2 in m2: # rename case 1, A/A,B/A
act("remote copied to " + f, "m",
f2, f, f, fmerge(f2, f, f2), False)
@@ -305,14 +310,14 @@
f2, f, f, fmerge(f2, f, f2), True)
elif f in ma:
if overwrite or backwards:
- act("recreating", "g", f, m2.execf(f))
+ act("recreating", "g", f, m2.flags(f))
elif n != ma[f]:
if repo.ui.prompt(
(_("remote changed %s which local deleted\n") % f) +
_("(k)eep or (d)elete?"), _("[kd]"), _("k")) == _("k"):
- act("prompt recreating", "g", f, m2.execf(f))
+ act("prompt recreating", "g", f, m2.flags(f))
else:
- act("remote created", "g", f, m2.execf(f))
+ act("remote created", "g", f, m2.flags(f))
return action
@@ -336,7 +341,7 @@
(f, inst.strerror))
removed += 1
elif m == "m": # merge
- f2, fd, flag, move = a[2:]
+ f2, fd, flags, move = a[2:]
r = filemerge(repo, f, f2, wctx, mctx)
if r > 0:
unresolved += 1
@@ -347,35 +352,32 @@
merged += 1
if f != fd:
repo.ui.debug(_("copying %s to %s\n") % (f, fd))
- repo.wwrite(fd, repo.wread(f))
+ repo.wwrite(fd, repo.wread(f), flags)
if move:
repo.ui.debug(_("removing %s\n") % f)
os.unlink(repo.wjoin(f))
- util.set_exec(repo.wjoin(fd), flag)
+ util.set_exec(repo.wjoin(fd), "x" in flags)
elif m == "g": # get
- flag = a[2]
+ flags = a[2]
repo.ui.note(_("getting %s\n") % f)
t = mctx.filectx(f).data()
- repo.wwrite(f, t)
- util.set_exec(repo.wjoin(f), flag)
+ repo.wwrite(f, t, flags)
updated += 1
elif m == "d": # directory rename
- f2, fd, flag = a[2:]
+ f2, fd, flags = a[2:]
if f:
repo.ui.note(_("moving %s to %s\n") % (f, fd))
t = wctx.filectx(f).data()
- repo.wwrite(fd, t)
- util.set_exec(repo.wjoin(fd), flag)
+ repo.wwrite(fd, t, flags)
util.unlink(repo.wjoin(f))
if f2:
repo.ui.note(_("getting %s to %s\n") % (f2, fd))
t = mctx.filectx(f2).data()
- repo.wwrite(fd, t)
- util.set_exec(repo.wjoin(fd), flag)
+ repo.wwrite(fd, t, flags)
updated += 1
elif m == "e": # exec
- flag = a[2]
- util.set_exec(repo.wjoin(f), flag)
+ flags = a[2]
+ util.set_exec(repo.wjoin(f), flags)
return updated, merged, removed, unresolved
@@ -442,6 +444,9 @@
wlock = working dir lock, if already held
"""
+ if node is None:
+ node = "tip"
+
if not wlock:
wlock = repo.wlock()
--- a/mercurial/mpatch.c Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/mpatch.c Mon Mar 05 19:54:21 2007 +0100
@@ -42,7 +42,11 @@
#else
/* not windows */
# include <sys/types.h>
-# include <arpa/inet.h>
+# ifdef __BEOS__
+# include <ByteOrder.h>
+# else
+# include <arpa/inet.h>
+# endif
# include <inttypes.h>
#endif
--- a/mercurial/node.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/node.py Mon Mar 05 19:54:21 2007 +0100
@@ -7,8 +7,7 @@
of the GNU General Public License, incorporated herein by reference.
"""
-from demandload import demandload
-demandload(globals(), "binascii")
+import binascii
nullrev = -1
nullid = "\0" * 20
--- a/mercurial/packagescan.py Mon Mar 05 19:48:21 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-# packagescan.py - Helper module for identifing used modules.
-# Used for the py2exe distutil.
-# This module must be the first mercurial module imported in setup.py
-#
-# 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.
-import glob
-import os
-import sys
-import ihooks
-import types
-import string
-
-# Install this module as fake demandload module
-sys.modules['mercurial.demandload'] = sys.modules[__name__]
-
-# Requiredmodules contains the modules imported by demandload.
-# Please note that demandload can be invoked before the
-# mercurial.packagescan.scan method is invoked in case a mercurial
-# module is imported.
-requiredmodules = {}
-def demandload(scope, modules):
- """ fake demandload function that collects the required modules
- foo import foo
- foo bar import foo, bar
- foo.bar import foo.bar
- foo@bar import foo as bar
- foo:bar from foo import bar
- foo:bar,quux from foo import bar, quux
- foo.bar:quux from foo.bar import quux"""
-
- for m in modules.split():
- mod = None
- try:
- module, fromlist = m.split(':')
- fromlist = fromlist.split(',')
- except:
- module = m
- fromlist = []
- as_ = None
- if '@' in module:
- module, as_ = module.split('@')
- mod = __import__(module, scope, scope, fromlist)
- if fromlist == []:
- # mod is only the top package, but we need all packages
- comp = module.split('.')
- i = 1
- mn = comp[0]
- while True:
- # mn and mod.__name__ might not be the same
- if not as_:
- as_ = mn
- scope[as_] = mod
- requiredmodules[mod.__name__] = 1
- if len(comp) == i: break
- mod = getattr(mod, comp[i])
- mn = string.join(comp[:i+1],'.')
- i += 1
- else:
- # mod is the last package in the component list
- requiredmodules[mod.__name__] = 1
- for f in fromlist:
- scope[f] = getattr(mod, f)
- if type(scope[f]) == types.ModuleType:
- requiredmodules[scope[f].__name__] = 1
-
-class SkipPackage(Exception):
- def __init__(self, reason):
- self.reason = reason
-
-scan_in_progress = False
-
-def scan(libpath, packagename):
- """ helper for finding all required modules of package <packagename> """
- global scan_in_progress
- scan_in_progress = True
- # Use the package in the build directory
- libpath = os.path.abspath(libpath)
- sys.path.insert(0, libpath)
- packdir = os.path.join(libpath, packagename.replace('.', '/'))
- # A normal import would not find the package in
- # the build directory. ihook is used to force the import.
- # After the package is imported the import scope for
- # the following imports is settled.
- p = importfrom(packdir)
- globals()[packagename] = p
- sys.modules[packagename] = p
- # Fetch the python modules in the package
- cwd = os.getcwd()
- os.chdir(packdir)
- pymodulefiles = glob.glob('*.py')
- extmodulefiles = glob.glob('*.pyd')
- os.chdir(cwd)
- # Import all python modules and by that run the fake demandload
- for m in pymodulefiles:
- if m == '__init__.py': continue
- tmp = {}
- mname, ext = os.path.splitext(m)
- fullname = packagename+'.'+mname
- try:
- __import__(fullname, tmp, tmp)
- except SkipPackage, inst:
- print >> sys.stderr, 'skipping %s: %s' % (fullname, inst.reason)
- continue
- requiredmodules[fullname] = 1
- # Import all extension modules and by that run the fake demandload
- for m in extmodulefiles:
- tmp = {}
- mname, ext = os.path.splitext(m)
- fullname = packagename+'.'+mname
- __import__(fullname, tmp, tmp)
- requiredmodules[fullname] = 1
-
-def getmodules():
- return requiredmodules.keys()
-
-def importfrom(filename):
- """
- import module/package from a named file and returns the module.
- It does not check on sys.modules or includes the module in the scope.
- """
- loader = ihooks.BasicModuleLoader()
- path, file = os.path.split(filename)
- name, ext = os.path.splitext(file)
- m = loader.find_module_in_dir(name, path)
- if not m:
- raise ImportError, name
- m = loader.load_module(name, m)
- return m
--- a/mercurial/patch.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/patch.py Mon Mar 05 19:54:21 2007 +0100
@@ -5,12 +5,11 @@
# 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 i18n import _
from node import *
-demandload(globals(), "base85 cmdutil mdiff util")
-demandload(globals(), "cStringIO email.Parser errno os popen2 re shutil sha")
-demandload(globals(), "sys tempfile zlib")
+import base85, cmdutil, mdiff, util, context, revlog
+import cStringIO, email.Parser, os, popen2, re, sha
+import sys, tempfile, zlib
# helper functions
@@ -378,8 +377,9 @@
dst = os.path.join(repo.root, gp.path)
# patch won't create empty files
if ctype == 'ADD' and not os.path.exists(dst):
- repo.wwrite(gp.path, '')
- util.set_exec(dst, x)
+ repo.wwrite(gp.path, '', x and 'x' or '')
+ else:
+ util.set_exec(dst, x)
cmdutil.addremove(repo, cfiles, wlock=wlock)
files = patches.keys()
files.extend([r for r in removes if r not in files])
@@ -441,27 +441,25 @@
if not node1:
node1 = repo.dirstate.parents()[0]
- clcache = {}
- def getchangelog(n):
- if n not in clcache:
- clcache[n] = repo.changelog.read(n)
- return clcache[n]
- mcache = {}
- def getmanifest(n):
- if n not in mcache:
- mcache[n] = repo.manifest.read(n)
- return mcache[n]
- fcache = {}
- def getfile(f):
- if f not in fcache:
- fcache[f] = repo.file(f)
- return fcache[f]
+ ccache = {}
+ def getctx(r):
+ if r not in ccache:
+ ccache[r] = context.changectx(repo, r)
+ return ccache[r]
+
+ flcache = {}
+ def getfilectx(f, ctx):
+ flctx = ctx.filectx(f, filelog=flcache.get(f))
+ if f not in flcache:
+ flcache[f] = flctx._filelog
+ return flctx
# reading the data for node1 early allows it to play nicely
# with repo.status and the revlog cache.
- change = getchangelog(node1)
- mmap = getmanifest(change[0])
- date1 = util.datestr(change[2])
+ ctx1 = context.changectx(repo, node1)
+ # force manifest reading
+ man1 = ctx1.manifest()
+ date1 = util.datestr(ctx1.date())
if not changes:
changes = repo.status(node1, node2, files, match=match)[:5]
@@ -481,67 +479,38 @@
if not modified and not added and not removed:
return
- # returns False if there was no rename between n1 and n2
- # returns None if the file was created between n1 and n2
- # returns the (file, node) present in n1 that was renamed to f in n2
- def renamedbetween(f, n1, n2):
- r1, r2 = map(repo.changelog.rev, (n1, n2))
+ if node2:
+ ctx2 = context.changectx(repo, node2)
+ else:
+ ctx2 = context.workingctx(repo)
+ man2 = ctx2.manifest()
+
+ # returns False if there was no rename between ctx1 and ctx2
+ # returns None if the file was created between ctx1 and ctx2
+ # returns the (file, node) present in ctx1 that was renamed to f in ctx2
+ def renamed(f):
+ startrev = ctx1.rev()
+ c = ctx2
+ crev = c.rev()
+ if crev is None:
+ crev = repo.changelog.count()
orig = f
- src = None
- while r2 > r1:
- cl = getchangelog(n2)
- if f in cl[3]:
- m = getmanifest(cl[0])
+ while crev > startrev:
+ if f in c.files():
try:
- src = getfile(f).renamed(m[f])
- except KeyError:
+ src = getfilectx(f, c).renamed()
+ except revlog.LookupError:
return None
if src:
f = src[0]
- n2 = repo.changelog.parents(n2)[0]
- r2 = repo.changelog.rev(n2)
- cl = getchangelog(n1)
- m = getmanifest(cl[0])
- if f not in m:
+ crev = c.parents()[0].rev()
+ # try to reuse
+ c = getctx(crev)
+ if f not in man1:
return None
if f == orig:
return False
- return f, m[f]
-
- if node2:
- change = getchangelog(node2)
- mmap2 = getmanifest(change[0])
- _date2 = util.datestr(change[2])
- def date2(f):
- return _date2
- def read(f):
- return getfile(f).read(mmap2[f])
- def renamed(f):
- return renamedbetween(f, node1, node2)
- else:
- tz = util.makedate()[1]
- _date2 = util.datestr()
- def date2(f):
- try:
- return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz))
- except OSError, err:
- if err.errno != errno.ENOENT: raise
- return _date2
- def read(f):
- return repo.wread(f)
- def renamed(f):
- src = repo.dirstate.copied(f)
- parent = repo.dirstate.parents()[0]
- if src:
- f = src
- of = renamedbetween(f, node1, parent)
- if of or of is None:
- return of
- elif src:
- cl = getchangelog(parent)[0]
- return (src, getmanifest(cl)[src])
- else:
- return None
+ return f
if repo.ui.quiet:
r = None
@@ -555,20 +524,21 @@
src = renamed(f)
if src:
copied[f] = src
- srcs = [x[1][0] for x in copied.items()]
+ srcs = [x[1] for x in copied.items()]
all = modified + added + removed
all.sort()
gone = {}
+
for f in all:
to = None
tn = None
dodiff = True
header = []
- if f in mmap:
- to = getfile(f).read(mmap[f])
+ if f in man1:
+ to = getfilectx(f, ctx1).data()
if f not in removed:
- tn = read(f)
+ tn = getfilectx(f, ctx2).data()
if opts.git:
def gitmode(x):
return x and '100755' or '100644'
@@ -579,13 +549,10 @@
a, b = f, f
if f in added:
- if node2:
- mode = gitmode(mmap2.execf(f))
- else:
- mode = gitmode(util.is_exec(repo.wjoin(f), None))
+ mode = gitmode(man2.execf(f))
if f in copied:
- a, arev = copied[f]
- omode = gitmode(mmap.execf(a))
+ a = copied[f]
+ omode = gitmode(man1.execf(a))
addmodehdr(header, omode, mode)
if a in removed and a not in gone:
op = 'rename'
@@ -594,7 +561,7 @@
op = 'copy'
header.append('%s from %s\n' % (op, a))
header.append('%s to %s\n' % (op, f))
- to = getfile(a).read(arev)
+ to = getfilectx(a, ctx1).data()
else:
header.append('new file mode %s\n' % mode)
if util.binary(tn):
@@ -603,14 +570,11 @@
if f in srcs:
dodiff = False
else:
- mode = gitmode(mmap.execf(f))
+ mode = gitmode(man1.execf(f))
header.append('deleted file mode %s\n' % mode)
else:
- omode = gitmode(mmap.execf(f))
- if node2:
- nmode = gitmode(mmap2.execf(f))
- else:
- nmode = gitmode(util.is_exec(repo.wjoin(f), mmap.execf(f)))
+ omode = gitmode(man1.execf(f))
+ nmode = gitmode(man2.execf(f))
addmodehdr(header, omode, nmode)
if util.binary(to) or util.binary(tn):
dodiff = 'binary'
@@ -620,7 +584,10 @@
if dodiff == 'binary':
text = b85diff(fp, to, tn)
else:
- text = mdiff.unidiff(to, date1, tn, date2(f), f, r, opts=opts)
+ text = mdiff.unidiff(to, date1,
+ # ctx2 date may be dynamic
+ tn, util.datestr(ctx2.date()),
+ f, r, opts=opts)
if text or len(header) > 1:
fp.write(''.join(header))
fp.write(text)
@@ -632,27 +599,28 @@
total = len(revs)
revwidth = max([len(str(rev)) for rev in revs])
- def single(node, seqno, fp):
- parents = [p for p in repo.changelog.parents(node) if p != nullid]
+ def single(rev, seqno, fp):
+ ctx = repo.changectx(rev)
+ node = ctx.node()
+ parents = [p.node() for p in ctx.parents() if p]
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):
+ if fp != sys.stdout and hasattr(fp, 'name'):
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("# User %s\n" % ctx.user())
+ fp.write("# Date %d %d\n" % ctx.date())
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(ctx.description().rstrip())
fp.write("\n\n")
diff(repo, prev, node, fp=fp, opts=opts)
@@ -660,7 +628,7 @@
fp.close()
for seqno, rev in enumerate(revs):
- single(repo.lookup(rev), seqno+1, fp)
+ single(rev, seqno+1, fp)
def diffstat(patchlines):
fd, name = tempfile.mkstemp(prefix="hg-patchbomb-", suffix=".txt")
--- a/mercurial/repo.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/repo.py Mon Mar 05 19:54:21 2007 +0100
@@ -9,9 +9,6 @@
class RepoError(Exception):
pass
-class LookupError(RepoError):
- pass
-
class repository(object):
def capable(self, name):
'''tell whether repo supports named capability.
--- a/mercurial/revlog.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/revlog.py Mon Mar 05 19:54:21 2007 +0100
@@ -11,10 +11,9 @@
"""
from node import *
-from i18n import gettext as _
-from demandload import demandload
-demandload(globals(), "binascii changegroup errno ancestor mdiff os")
-demandload(globals(), "sha struct util zlib")
+from i18n import _
+import binascii, changegroup, errno, ancestor, mdiff, os
+import sha, struct, util, zlib
# revlog version strings
REVLOGV0 = 0
@@ -147,6 +146,9 @@
lend = len(data) / self.s
i = blockstart / self.s
off = 0
+ # lazyindex supports __delitem__
+ if lend > len(self.index) - i:
+ lend = len(self.index) - i
for x in xrange(lend):
if self.index[i + x] == None:
b = data[off : off + self.s]
@@ -282,6 +284,7 @@
del self.p.map[key]
class RevlogError(Exception): pass
+class LookupError(RevlogError): pass
class revlog(object):
"""
@@ -472,7 +475,7 @@
try:
return self.nodemap[node]
except KeyError:
- raise RevlogError(_('%s: no node %s') % (self.indexfile, hex(node)))
+ raise LookupError(_('%s: no node %s') % (self.indexfile, hex(node)))
def linkrev(self, node):
return (node == nullid) and nullrev or self.index[self.rev(node)][-4]
def parents(self, node):
@@ -767,7 +770,7 @@
node = id
r = self.rev(node) # quick search the index
return node
- except RevlogError:
+ except LookupError:
pass # may be partial hex id
try:
# str(rev)
@@ -796,7 +799,7 @@
for n in self.nodemap:
if n.startswith(bin_id) and hex(n).startswith(id):
if node is not None:
- raise RevlogError(_("Ambiguous identifier"))
+ raise LookupError(_("Ambiguous identifier"))
node = n
if node is not None:
return node
@@ -816,7 +819,7 @@
if n:
return n
- raise RevlogError(_("No match found"))
+ raise LookupError(_("No match found"))
def cmp(self, node, text):
"""compare text with a given file revision"""
@@ -1156,13 +1159,13 @@
for p in (p1, p2):
if not p in self.nodemap:
- raise RevlogError(_("unknown parent %s") % short(p))
+ raise LookupError(_("unknown parent %s") % short(p))
if not chain:
# retrieve the parent revision of the delta chain
chain = p1
if not chain in self.nodemap:
- raise RevlogError(_("unknown base %s") % short(chain[:4]))
+ raise LookupError(_("unknown base %s") % short(chain[:4]))
# full versions are inserted when the needed deltas become
# comparable to the uncompressed text or when the previous
--- a/mercurial/sshrepo.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/sshrepo.py Mon Mar 05 19:54:21 2007 +0100
@@ -7,9 +7,8 @@
from node import *
from remoterepo import *
-from i18n import gettext as _
-from demandload import *
-demandload(globals(), "hg os re stat util")
+from i18n import _
+import hg, os, re, stat, util
class sshrepository(remoterepository):
def __init__(self, ui, path, create=0):
--- a/mercurial/sshserver.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/sshserver.py Mon Mar 05 19:54:21 2007 +0100
@@ -6,10 +6,9 @@
# 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 i18n import _
from node import *
-demandload(globals(), "os streamclone sys tempfile util")
+import os, streamclone, sys, tempfile, util
class sshserver(object):
def __init__(self, ui, repo):
--- a/mercurial/statichttprepo.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/statichttprepo.py Mon Mar 05 19:54:21 2007 +0100
@@ -7,10 +7,9 @@
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
-from demandload import *
-from i18n import gettext as _
-demandload(globals(), "changelog filelog httprangereader")
-demandload(globals(), "repo localrepo manifest os urllib urllib2 util")
+from i18n import _
+import changelog, filelog, httprangereader
+import repo, localrepo, manifest, os, urllib, urllib2, util
class rangereader(httprangereader.httprangereader):
def read(self, size=None):
--- a/mercurial/streamclone.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/streamclone.py Mon Mar 05 19:54:21 2007 +0100
@@ -5,9 +5,8 @@
# 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 _
-demandload(globals(), "os stat util lock")
+from i18n import _
+import os, stat, util, lock
# if server supports streaming clone, it advertises "stream"
# capability with value that is version+flags of repo it is serving.
--- a/mercurial/templater.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/templater.py Mon Mar 05 19:54:21 2007 +0100
@@ -5,10 +5,9 @@
# 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 i18n import _
from node import *
-demandload(globals(), "cgi re sys os time urllib util textwrap")
+import cgi, re, sys, os, time, urllib, util, textwrap
def parsestring(s, quoted=True):
'''parse a string using simple c-like syntax.
--- a/mercurial/transaction.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/transaction.py Mon Mar 05 19:54:21 2007 +0100
@@ -11,9 +11,8 @@
# 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 _
-demandload(globals(), 'os')
+from i18n import _
+import os
class transaction(object):
def __init__(self, report, opener, journal, after=None):
--- a/mercurial/ui.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/ui.py Mon Mar 05 19:54:21 2007 +0100
@@ -5,10 +5,9 @@
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
-from i18n import gettext as _
-from demandload import *
-demandload(globals(), "errno getpass os re socket sys tempfile")
-demandload(globals(), "ConfigParser traceback util")
+from i18n import _
+import errno, getpass, os, re, socket, sys, tempfile
+import ConfigParser, traceback, util
def dupconfig(orig):
new = util.configparser(orig.defaults())
@@ -310,7 +309,7 @@
sections.sort()
for section in sections:
for name, value in self.configitems(section, untrusted):
- yield section, name, value.replace('\n', '\\n')
+ yield section, name, str(value).replace('\n', '\\n')
def extensions(self):
result = self.configitems("extensions")
@@ -388,6 +387,9 @@
if not sys.stdout.closed: sys.stdout.flush()
for a in args:
sys.stderr.write(str(a))
+ # stderr may be buffered under win32 when redirected to files,
+ # including stdout.
+ if not sys.stderr.closed: sys.stderr.flush()
except IOError, inst:
if inst.errno != errno.EPIPE:
raise
--- a/mercurial/util.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/util.py Mon Mar 05 19:54:21 2007 +0100
@@ -12,10 +12,9 @@
platform-specific details from the core.
"""
-from i18n import gettext as _
-from demandload import *
-demandload(globals(), "cStringIO errno getpass popen2 re shutil sys tempfile")
-demandload(globals(), "os threading time calendar ConfigParser locale glob")
+from i18n import _
+import cStringIO, errno, getpass, popen2, re, shutil, sys, tempfile
+import os, threading, time, calendar, ConfigParser, locale, glob
try:
_encoding = os.environ.get("HGENCODING") or locale.getpreferredencoding() \
@@ -117,11 +116,23 @@
class SignalInterrupt(Exception):
"""Exception raised on SIGTERM and SIGHUP."""
-# like SafeConfigParser but with case-sensitive keys
+# differences from SafeConfigParser:
+# - case-sensitive keys
+# - allows values that are not strings (this means that you may not
+# be able to save the configuration to a file)
class configparser(ConfigParser.SafeConfigParser):
def optionxform(self, optionstr):
return optionstr
+ def set(self, section, option, value):
+ return ConfigParser.ConfigParser.set(self, section, option, value)
+
+ def _interpolate(self, section, option, rawval, vars):
+ if not isinstance(rawval, basestring):
+ return rawval
+ return ConfigParser.SafeConfigParser._interpolate(self, section,
+ option, rawval, vars)
+
def cachefunc(func):
'''cache the result of function calls'''
# XXX doesn't handle keywords args
@@ -715,9 +726,47 @@
except:
return True
+def checkexec(path):
+ """
+ Check whether the given path is on a filesystem with UNIX-like exec flags
+
+ Requires a directory (like /foo/.hg)
+ """
+ fh, fn = tempfile.mkstemp("", "", path)
+ os.close(fh)
+ m = os.stat(fn).st_mode
+ os.chmod(fn, m ^ 0111)
+ r = (os.stat(fn).st_mode != m)
+ os.unlink(fn)
+ return r
+
+def execfunc(path, fallback):
+ '''return an is_exec() function with default to fallback'''
+ if checkexec(path):
+ return lambda x: is_exec(os.path.join(path, x))
+ return fallback
+
+def checklink(path):
+ """check whether the given path is on a symlink-capable filesystem"""
+ # mktemp is not racy because symlink creation will fail if the
+ # file already exists
+ name = tempfile.mktemp(dir=path)
+ try:
+ os.symlink(".", name)
+ os.unlink(name)
+ return True
+ except (OSError, AttributeError):
+ return False
+
+def linkfunc(path, fallback):
+ '''return an is_link() function with default to fallback'''
+ if checklink(path):
+ return lambda x: is_link(os.path.join(path, x))
+ return fallback
+
# Platform specific variants
if os.name == 'nt':
- demandload(globals(), "msvcrt")
+ import msvcrt
nulldev = 'NUL:'
class winstdout:
@@ -758,19 +807,18 @@
except:
return [r'c:\mercurial\mercurial.ini']
- def os_rcpath():
- '''return default os-specific hgrc search path'''
- path = system_rcpath()
- path.append(user_rcpath())
+ def user_rcpath():
+ '''return os-specific hgrc search path to the user dir'''
+ try:
+ userrc = user_rcpath_win32()
+ except:
+ userrc = os.path.join(os.path.expanduser('~'), 'mercurial.ini')
+ path = [userrc]
userprofile = os.environ.get('USERPROFILE')
if userprofile:
path.append(os.path.join(userprofile, 'mercurial.ini'))
return path
- def user_rcpath():
- '''return os-specific hgrc search path to the user dir'''
- return os.path.join(os.path.expanduser('~'), 'mercurial.ini')
-
def parse_patch_output(output_line):
"""parses the output produced by patch and returns the file name"""
pf = output_line[14:]
@@ -782,10 +830,10 @@
'''return False if pid dead, True if running or not known'''
return True
- def is_exec(f, last):
- return last
+ def set_exec(f, mode):
+ pass
- def set_exec(f, mode):
+ def set_link(f, mode):
pass
def set_binary(fd):
@@ -842,6 +890,8 @@
else:
nulldev = '/dev/null'
+ _umask = os.umask(0)
+ os.umask(_umask)
def rcfiles(path):
rcs = [os.path.join(path, 'hgrc')]
@@ -853,18 +903,18 @@
pass
return rcs
- def os_rcpath():
- '''return default os-specific hgrc search path'''
+ def system_rcpath():
path = []
# old mod_python does not set sys.argv
if len(getattr(sys, 'argv', [])) > 0:
path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
'/../etc/mercurial'))
path.extend(rcfiles('/etc/mercurial'))
- path.append(os.path.expanduser('~/.hgrc'))
- path = [os.path.normpath(f) for f in path]
return path
+ def user_rcpath():
+ return [os.path.expanduser('~/.hgrc')]
+
def parse_patch_output(output_line):
"""parses the output produced by patch and returns the file name"""
pf = output_line[14:]
@@ -872,7 +922,7 @@
pf = pf[1:-1] # Remove the quotes
return pf
- def is_exec(f, last):
+ def is_exec(f):
"""check whether a file is executable"""
return (os.lstat(f).st_mode & 0100 != 0)
@@ -883,12 +933,34 @@
if mode:
# Turn on +x for every +r bit when making a file executable
# and obey umask.
- umask = os.umask(0)
- os.umask(umask)
- os.chmod(f, s | (s & 0444) >> 2 & ~umask)
+ os.chmod(f, s | (s & 0444) >> 2 & ~_umask)
else:
os.chmod(f, s & 0666)
+ def is_link(f):
+ """check whether a file is a symlink"""
+ return (os.lstat(f).st_mode & 0120000 == 0120000)
+
+ def set_link(f, mode):
+ """make a file a symbolic link/regular file
+
+ if a file is changed to a link, its contents become the link data
+ if a link is changed to a file, its link data become its contents
+ """
+
+ m = is_link(f)
+ if m == bool(mode):
+ return
+
+ if mode: # switch file to link
+ data = file(f).read()
+ os.unlink(f)
+ os.symlink(data, f)
+ else:
+ data = os.readlink(f)
+ os.unlink(f)
+ file(f, "w").write(data)
+
def set_binary(fd):
pass
@@ -1317,6 +1389,13 @@
_rcpath = None
+def os_rcpath():
+ '''return default os-specific hgrc search path'''
+ path = system_rcpath()
+ path.extend(user_rcpath())
+ path = [os.path.normpath(f) for f in path]
+ return path
+
def rcpath():
'''return hgrc search path. if env var HGRCPATH is set, use it.
for each item in path, if directory, use files ending in .rc,
--- a/mercurial/util_win32.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/util_win32.py Mon Mar 05 19:54:21 2007 +0100
@@ -13,10 +13,10 @@
import win32api
-from demandload import *
-from i18n import gettext as _
-demandload(globals(), 'errno os pywintypes win32con win32file win32process')
-demandload(globals(), 'cStringIO win32com.shell:shell,shellcon winerror')
+from i18n import _
+import errno, os, pywintypes, win32con, win32file, win32process
+import cStringIO, winerror
+from win32com.shell import shell,shellcon
class WinError:
winerror_map = {
@@ -187,7 +187,7 @@
filename = win32api.GetModuleFileName(0)
return [os.path.join(os.path.dirname(filename), 'mercurial.ini')]
-def user_rcpath():
+def user_rcpath_win32():
'''return os-specific hgrc search path to the user dir'''
userdir = os.path.expanduser('~')
if userdir == '~':
--- a/mercurial/verify.py Mon Mar 05 19:48:21 2007 +0100
+++ b/mercurial/verify.py Mon Mar 05 19:54:21 2007 +0100
@@ -6,7 +6,7 @@
# of the GNU General Public License, incorporated herein by reference.
from node import *
-from i18n import gettext as _
+from i18n import _
import revlog, mdiff
def verify(repo):
--- a/setup.py Mon Mar 05 19:48:21 2007 +0100
+++ b/setup.py Mon Mar 05 19:54:21 2007 +0100
@@ -13,9 +13,11 @@
from distutils.core import setup, Extension
from distutils.command.install_data import install_data
-# mercurial.packagescan must be the first mercurial module imported
-import mercurial.packagescan
import mercurial.version
+import mercurial.demandimport
+mercurial.demandimport.enable = lambda: None
+
+extra = {}
# py2exe needs to be installed to work
try:
@@ -35,34 +37,10 @@
except ImportError:
pass
- # Due to the use of demandload py2exe is not finding the modules.
- # packagescan.getmodules creates a list of modules included in
- # the mercurial package plus dependant modules.
- from py2exe.build_exe import py2exe as build_exe
+ extra['console'] = ['hg']
- class py2exe_for_demandload(build_exe):
- """ overwrites the py2exe command class for getting the build
- directory and for setting the 'includes' option."""
- def initialize_options(self):
- self.build_lib = None
- build_exe.initialize_options(self)
- def finalize_options(self):
- # Get the build directory, ie. where to search for modules.
- self.set_undefined_options('build',
- ('build_lib', 'build_lib'))
- # Sets the 'includes' option with the list of needed modules
- if not self.includes:
- self.includes = []
- else:
- self.includes = self.includes.split(',')
- mercurial.packagescan.scan(self.build_lib, 'mercurial')
- mercurial.packagescan.scan(self.build_lib, 'mercurial.hgweb')
- mercurial.packagescan.scan(self.build_lib, 'hgext')
- self.includes += mercurial.packagescan.getmodules()
- build_exe.finalize_options(self)
except ImportError:
- py2exe_for_demandload = None
-
+ pass
# specify version string, otherwise 'hg identify' will be used:
version = ''
@@ -75,10 +53,6 @@
mercurial.version.remember_version(version)
cmdclass = {'install_data': install_package_data}
-py2exe_opts = {}
-if py2exe_for_demandload is not None:
- cmdclass['py2exe'] = py2exe_for_demandload
- py2exe_opts['console'] = ['hg']
setup(name='mercurial',
version=mercurial.version.get_version(),
@@ -100,4 +74,4 @@
license='COPYING',
readme='contrib/macosx/Readme.html',
welcome='contrib/macosx/Welcome.html')),
- **py2exe_opts)
+ **extra)
--- a/templates/gitweb/header.tmpl Mon Mar 05 19:48:21 2007 +0100
+++ b/templates/gitweb/header.tmpl Mon Mar 05 19:54:21 2007 +0100
@@ -4,7 +4,7 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
<head>
-<link rel="icon" href="{url}static/hgicon.png" type="image/png">
+<link rel="icon" href="{staticurl}hgicon.png" type="image/png">
<meta name="robots" content="index, nofollow"/>
-<link rel="stylesheet" href="{url}static/style-gitweb.css" type="text/css" />
+<link rel="stylesheet" href="{staticurl}style-gitweb.css" type="text/css" />
--- a/templates/gitweb/map Mon Mar 05 19:48:21 2007 +0100
+++ b/templates/gitweb/map Mon Mar 05 19:54:21 2007 +0100
@@ -48,7 +48,7 @@
filediffchild = '<tr><th class="child">child {rev}:</th><td class="child"><a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
filelogchild = '<tr><td align="right">child #rev#: </td><td><a href="{url}file{node|short}/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
shortlog = shortlog.tmpl
-shortlogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><i>#author#</i></td><td><a class="list" href="{url}rev/#node|short#{sessionvars%urlparameter}"><b>#desc|strip|firstline|escape#</b></a></td><td class="link"><a href="{url}rev/#node|short#{sessionvars%urlparameter}">changeset</a> | <a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a></td></tr>'
+shortlogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><i>#author#</i></td><td><a class="list" href="{url}rev/#node|short#{sessionvars%urlparameter}"><b>#desc|strip|firstline|escape#</b></a></td><td class="link" nowrap><a href="{url}rev/#node|short#{sessionvars%urlparameter}">changeset</a> | <a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a></td></tr>'
filelogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><a class="list" href="{url}rev/#node|short#{sessionvars%urlparameter}"><b>#desc|strip|firstline|escape#</b></a></td><td class="link"><a href="{url}file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a> | <a href="{url}diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">diff</a> | <a href="{url}annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a> #rename%filelogrename#</td></tr>'
archiveentry = ' | <a href="{url}archive/{node|short}{extension}">#type|escape#</a> '
indexentry = '<tr class="parity#parity#"><td><a class="list" href="#url#{sessionvars%urlparameter}"><b>#name|escape#</b></a></td><td>#description#</td><td>#contact|obfuscate#</td><td class="age">#lastchange|age# ago</td><td class="indexlinks"><a class="rss_logo" href="#url#rss-log">RSS</a> #archives%archiveentry#</td></tr>'
--- a/templates/header.tmpl Mon Mar 05 19:48:21 2007 +0100
+++ b/templates/header.tmpl Mon Mar 05 19:54:21 2007 +0100
@@ -3,6 +3,6 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
-<link rel="icon" href="#url#static/hgicon.png" type="image/png">
+<link rel="icon" href="#staticurl#hgicon.png" type="image/png">
<meta name="robots" content="index, nofollow" />
-<link rel="stylesheet" href="#url#static/style.css" type="text/css" />
+<link rel="stylesheet" href="#staticurl#style.css" type="text/css" />
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/raw/index.tmpl Mon Mar 05 19:54:21 2007 +0100
@@ -0,0 +1,2 @@
+#header#
+#entries%indexentry#
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/raw/manifest.tmpl Mon Mar 05 19:54:21 2007 +0100
@@ -0,0 +1,3 @@
+{header}
+{dentries%manifestdirentry}{fentries%manifestfileentry}
+{footer}
--- a/templates/raw/map Mon Mar 05 19:48:21 2007 +0100
+++ b/templates/raw/map Mon Mar 05 19:54:21 2007 +0100
@@ -14,3 +14,8 @@
filediff = filediff.tmpl
fileannotate = fileannotate.tmpl
annotateline = '#author#@#rev#: #line#'
+manifest = manifest.tmpl
+manifestdirentry = 'drwxr-xr-x {basename}\n'
+manifestfileentry = '{permissions|permissions} {size} {basename}\n'
+index = index.tmpl
+indexentry = '#url#\n'
--- a/tests/README Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/README Mon Mar 05 19:54:21 2007 +0100
@@ -1,93 +1,7 @@
-A simple testing framework
-
To run the tests, do:
cd tests/
python run-tests.py
-This finds all scripts in the test directory named test-* and executes
-them. The scripts can be either shell scripts or Python. Each test is
-run in a temporary directory that is removed when the test is complete.
-
-A test-<x> succeeds if the script returns success and its output
-matches test-<x>.out. If the new output doesn't match, it is stored in
-test-<x>.err.
-
-There are some tricky points here that you should be aware of when
-writing tests:
-
-- hg commit and hg merge want user interaction
-
- for commit use -m "text"
- for hg merge, set HGMERGE to something noninteractive (like true or merge)
-
-- changeset hashes will change based on user and date which make
- things like hg history output change
-
- use commit -m "test" -u test -d "1000000 0"
-
-- diff and export may show the current time
-
- use -D/--nodates to strip the dates
-
-- You can append your own hgrc settings to the file that the environment
- variable HGRCPATH points to. This file is cleared before running a test.
-
-You also need to be careful that the tests are portable from one platform
-to another. You're probably working on Linux, where the GNU toolchain has
-more (or different) functionality than on MacOS, *BSD, Solaris, AIX, etc.
-While testing on all platforms is the only sure-fire way to make sure that
-you've written portable code, here's a list of problems that have been
-found and fixed in the tests. Another, more comprehensive list may be
-found in the GNU Autoconf manual, online here:
-
- http://www.gnu.org/software/autoconf/manual/html_node/Portable-Shell.html
-
-sh:
-
-The Bourne shell is a very basic shell. /bin/sh on Linux is typically
-bash, which even in Bourne-shell mode has many features that Bourne shells
-on other Unix systems don't have (and even on Linux /bin/sh isn't
-guaranteed to be bash). You'll need to be careful about constructs that
-seem ubiquitous, but are actually not available in the least common
-denominator. While using another shell (ksh, bash explicitly, posix shell,
-etc.) explicitly may seem like another option, these may not exist in a
-portable location, and so are generally probably not a good idea. You may
-find that rewriting the test in python will be easier.
-
-- don't use pushd/popd; save the output of "pwd" and use "cd" in place of
- the pushd, and cd back to the saved pwd instead of popd.
-
-- don't use math expressions like let, (( ... )), or $(( ... )); use "expr"
- instead.
-
-grep:
-
-- don't use the -q option; redirect stdout to /dev/null instead.
-
-- don't use extended regular expressions with grep; use egrep instead, and
- don't escape any regex operators.
-
-sed:
-
-- make sure that the beginning-of-line matcher ("^") is at the very
- beginning of the expression -- it may not be supported inside parens.
-
-echo:
-
-- echo may interpret "\n" and print a newline; use printf instead if you
- want a literal "\n" (backslash + n).
-
-false:
-
-- false is guaranteed only to return a non-zero value; you cannot depend on
- it being 1. On Solaris in particular, /bin/false returns 255. Rewrite
- your test to not depend on a particular return value, or create a
- temporary "false" executable, and call that instead.
-
-diff:
-
-- don't use the -N option. There's no particularly good workaround short
- of writing a reasonably complicated replacement script, but substituting
- gdiff for diff if you can't rewrite the test not to need -N will probably
- do.
+See http://www.selenic.com/mercurial/wiki/index.cgi/WritingTests for
+more information on writing tests.
--- a/tests/test-abort-checkin Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/test-abort-checkin Mon Mar 05 19:54:21 2007 +0100
@@ -1,12 +1,19 @@
#!/bin/sh
+cat > abortcommit.py <<EOF
+from mercurial import util
+
+def hook(**args):
+ raise util.Abort("no commits allowed")
+
+def reposetup(ui, repo):
+ repo.ui.setconfig("hooks", "pretxncommit.nocommits", hook)
+EOF
+abspath=`pwd`/abortcommit.py
+
echo "[extensions]" >> $HGRCPATH
echo "mq=" >> $HGRCPATH
-cat > $HGTMP/false <<EOF
-#!/bin/sh
-exit 1
-EOF
-chmod +x $HGTMP/false
+echo "abortcommit = $abspath" >> $HGRCPATH
hg init foo
cd foo
@@ -15,7 +22,7 @@
# mq may keep a reference to the repository so __del__ will not be called
# and .hg/journal.dirstate will not be deleted:
-HGEDITOR=$HGTMP/false hg ci
-HGEDITOR=$HGTMP/false hg ci
+hg ci -m foo
+hg ci -m foo
exit 0
--- a/tests/test-abort-checkin.out Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/test-abort-checkin.out Mon Mar 05 19:54:21 2007 +0100
@@ -1,6 +1,8 @@
-abort: edit failed: false exited with status 1
+error: pretxncommit.nocommits hook failed: no commits allowed
+abort: no commits allowed
transaction abort!
rollback completed
-abort: edit failed: false exited with status 1
+error: pretxncommit.nocommits hook failed: no commits allowed
+abort: no commits allowed
transaction abort!
rollback completed
--- a/tests/test-acl Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/test-acl Mon Mar 05 19:54:21 2007 +0100
@@ -26,7 +26,7 @@
echo 'in foo' > foo/file.txt
echo 'in foo/Bar' > foo/Bar/file.txt
echo 'in quux' > quux/file.py
-hg add
+hg add -q
hg ci -m 'add files' -d '1000000 0'
echo >> foo/file.txt
hg ci -m 'change foo/file' -d '1000001 0'
--- a/tests/test-acl.out Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/test-acl.out Mon Mar 05 19:54:21 2007 +0100
@@ -1,6 +1,3 @@
-adding foo/Bar/file.txt
-adding foo/file.txt
-adding quux/file.py
3:911600dab2ae
requesting all changes
adding changesets
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-addremove-similar Mon Mar 05 19:54:21 2007 +0100
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+hg init rep; cd rep
+
+touch empty-file
+python -c 'for x in range(10000): print x' > large-file
+
+hg addremove
+
+hg commit -m A
+
+rm large-file empty-file
+python -c 'for x in range(10,10000): print x' > another-file
+
+hg addremove -s50
+
+hg commit -m B
+
+cd ..
+
+hg init rep2; cd rep2
+
+python -c 'for x in range(10000): print x' > large-file
+python -c 'for x in range(50): print x' > tiny-file
+
+hg addremove
+
+hg commit -m A
+
+python -c 'for x in range(70): print x' > small-file
+rm tiny-file
+rm large-file
+
+hg addremove -s50
+
+hg commit -m B
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-addremove-similar.out Mon Mar 05 19:54:21 2007 +0100
@@ -0,0 +1,12 @@
+adding empty-file
+adding large-file
+adding another-file
+removing empty-file
+removing large-file
+recording removal of large-file as rename to another-file (99% similar)
+adding large-file
+adding tiny-file
+adding small-file
+removing large-file
+removing tiny-file
+recording removal of tiny-file as rename to small-file (82% similar)
--- a/tests/test-bad-extension Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/test-bad-extension Mon Mar 05 19:54:21 2007 +0100
@@ -1,9 +1,11 @@
#!/bin/sh
-echo 'syntax error' > badext.py
+echo 'raise Exception("bit bucket overflow")' > badext.py
abspath=`pwd`/badext.py
echo '[extensions]' >> $HGRCPATH
+echo "gpg =" >> $HGRCPATH
+echo "hgext.gpg =" >> $HGRCPATH
echo "badext = $abspath" >> $HGRCPATH
hg -q help help
--- a/tests/test-bad-extension.out Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/test-bad-extension.out Mon Mar 05 19:54:21 2007 +0100
@@ -1,4 +1,5 @@
-*** failed to import extension badext: invalid syntax (badext.py, line 1)
+*** failed to import extension badext: bit bucket overflow
+extension 'hgext.gpg' overrides commands: sigs sigcheck sign
hg help [COMMAND]
show help for a command, extension, or list of commands
--- a/tests/test-branch Mon Mar 05 19:48:21 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-#!/bin/sh
-#
-# test for branch handling
-#
-# XXX: need more tests
-
-hg init
-echo a > a
-echo b > b
-hg ci -A -m 0 -d "1000000 0"
-echo aa > a
-echo bb > b
-hg ci -m 1 -d "1000000 0"
-hg tag -l foo
-hg update 0
-hg parents -b
-
-# test update
-hg update -b foo
-hg parents
-
-# test merge
-hg update 0
-echo c > c
-hg ci -A -m 0.0 -d "1000000 0"
-hg merge -b foo
-hg parents -b
-
-# re-test with more branches
-hg update -C 0
-echo d > d
-hg ci -A -m 0.0 -d "1000000 0"
-hg merge -b foo
-hg parents -b
--- a/tests/test-branch.out Mon Mar 05 19:48:21 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-adding a
-adding b
-2 files updated, 0 files merged, 0 files removed, 0 files unresolved
-the --branches option is deprecated, please use 'hg branches' instead
-changeset: 0:b544c4ac4389
-user: test
-date: Mon Jan 12 13:46:40 1970 +0000
-summary: 0
-
-the --branch option is deprecated, please use 'hg branch' instead
-Using head f4ac749470f2 for branch foo
-2 files updated, 0 files merged, 0 files removed, 0 files unresolved
-changeset: 1:f4ac749470f2
-tag: foo
-tag: tip
-user: test
-date: Mon Jan 12 13:46:40 1970 +0000
-summary: 1
-
-2 files updated, 0 files merged, 0 files removed, 0 files unresolved
-adding c
-the --branch option is deprecated, please use 'hg branch' instead
-Using head f4ac749470f2 for branch foo
-2 files updated, 0 files merged, 0 files removed, 0 files unresolved
-(branch merge, don't forget to commit)
-the --branches option is deprecated, please use 'hg branches' instead
-changeset: 2:1505d56ee00e
-tag: tip
-parent: 0:b544c4ac4389
-user: test
-date: Mon Jan 12 13:46:40 1970 +0000
-summary: 0.0
-
-changeset: 1:f4ac749470f2
-tag: foo
-branch: foo
-user: test
-date: Mon Jan 12 13:46:40 1970 +0000
-summary: 1
-
-2 files updated, 0 files merged, 1 files removed, 0 files unresolved
-adding d
-the --branch option is deprecated, please use 'hg branch' instead
-Using head f4ac749470f2 for branch foo
-2 files updated, 0 files merged, 0 files removed, 0 files unresolved
-(branch merge, don't forget to commit)
-the --branches option is deprecated, please use 'hg branches' instead
-changeset: 3:53b72df12ae5
-tag: tip
-parent: 0:b544c4ac4389
-user: test
-date: Mon Jan 12 13:46:40 1970 +0000
-summary: 0.0
-
-changeset: 1:f4ac749470f2
-tag: foo
-branch: foo
-user: test
-date: Mon Jan 12 13:46:40 1970 +0000
-summary: 1
-
--- a/tests/test-commit.out Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/test-commit.out Mon Mar 05 19:54:21 2007 +0100
@@ -21,8 +21,7 @@
dir/file
does-not-exist: No such file or directory
abort: file .../test/does-not-exist not found!
-baz: unsupported file type (type is symbolic link)
-abort: can't commit .../test/baz: unsupported file type!
+abort: file .../test/baz not tracked!
abort: file .../test/quux not tracked!
dir/file
% partial subdir commit test
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-context.py Mon Mar 05 19:54:21 2007 +0100
@@ -0,0 +1,20 @@
+import os
+from mercurial import hg, ui, commands
+
+u = ui.ui()
+
+repo = hg.repository(u, 'test1', create=1)
+os.chdir('test1')
+repo = hg.repository(u, '.') # FIXME: can't lock repo without doing this
+
+# create 'foo' with fixed time stamp
+f = file('foo', 'w')
+f.write('foo\n')
+f.close()
+os.utime('foo', (1000, 1000))
+
+# add+commit 'foo'
+repo.add(['foo'])
+repo.commit(text='commit1', date="0 0")
+
+print "workingfilectx.date =", repo.workingctx().filectx('foo').date()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-context.py.out Mon Mar 05 19:54:21 2007 +0100
@@ -0,0 +1,1 @@
+workingfilectx.date = (1000, 0)
--- a/tests/test-grep Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/test-grep Mon Mar 05 19:54:21 2007 +0100
@@ -17,8 +17,11 @@
head -n 3 port > port1
mv port1 port
hg commit -m 4 -u spam -d '4 0'
+echo % simple
hg grep port port
+echo % all
hg grep --all -nu port port
+echo % other
hg grep import port
hg cp port port2
@@ -28,3 +31,22 @@
echo deport >> port2
hg commit -m 5 -u eggs -d '6 0'
hg grep -f --all -nu port port2
+
+cd ..
+hg init t2
+cd t2
+hg grep foobar foo
+hg grep foobar
+echo blue >> color
+echo black >> color
+hg add color
+hg ci -m 0 -d '0 0'
+echo orange >> color
+hg ci -m 1 -d '0 0'
+echo black > color
+hg ci -m 2 -d '0 0'
+echo orange >> color
+echo blue >> color
+hg ci -m 3 -d '0 0'
+hg grep orange
+hg grep --all orange
--- a/tests/test-grep.out Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/test-grep.out Mon Mar 05 19:54:21 2007 +0100
@@ -1,6 +1,8 @@
+% simple
port:4:export
port:4:vaportight
port:4:import/export
+% all
port:4:4:-:spam:import/export
port:3:4:+:eggs:import/export
port:2:1:-:spam:import
@@ -10,6 +12,7 @@
port:2:3:+:spam:import/export
port:1:2:+:eggs:export
port:0:1:+:spam:import
+% other
port:4:import/export
% follow
port:0:import
@@ -23,3 +26,7 @@
port:2:3:+:spam:import/export
port:1:2:+:eggs:export
port:0:1:+:spam:import
+color:3:orange
+color:3:+:orange
+color:2:-:orange
+color:1:+:orange
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-hgweb Mon Mar 05 19:54:21 2007 +0100
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+hg init test
+cd test
+mkdir da
+echo foo > da/foo
+echo foo > foo
+hg ci -Ambase -d '0 0'
+hg serve -p 20060 -d --pid-file=hg.pid
+echo % manifest
+("$TESTDIR/get-with-headers.py" localhost:20060 '/file/tip/?style=raw')
+("$TESTDIR/get-with-headers.py" localhost:20060 '/file/tip/da?style=raw')
+kill `cat hg.pid`
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-hgweb.out Mon Mar 05 19:54:21 2007 +0100
@@ -0,0 +1,16 @@
+adding da/foo
+adding foo
+% manifest
+200 Script output follows
+
+
+drwxr-xr-x da
+-rw-r--r-- 4 foo
+
+
+200 Script output follows
+
+
+-rw-r--r-- 4 foo
+
+
--- a/tests/test-hook Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/test-hook Mon Mar 05 19:54:21 2007 +0100
@@ -183,4 +183,26 @@
echo a >> a
hg --traceback commit -A -m a 2>&1 | grep '^Traceback'
+cd ..
+hg init c
+cd c
+
+cat > hookext.py <<EOF
+def autohook(**args):
+ print "Automatically installed hook"
+
+def reposetup(ui, repo):
+ repo.ui.setconfig("hooks", "commit.auto", autohook)
+EOF
+echo '[extensions]' >> .hg/hgrc
+echo 'hookext = hookext.py' >> .hg/hgrc
+
+touch foo
+hg add foo
+hg ci -m 'add foo'
+echo >> foo
+hg ci --debug -m 'change foo' | sed -e 's/ at .*>/>/'
+
+hg showconfig hooks | sed -e 's/ at .*>/>/'
+
exit 0
--- a/tests/test-hook.out Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/test-hook.out Mon Mar 05 19:54:21 2007 +0100
@@ -138,3 +138,8 @@
(run 'hg update' to get a working copy)
# make sure --traceback works
Traceback (most recent call last):
+Automatically installed hook
+foo
+calling hook commit.auto: <function autohook>
+Automatically installed hook
+hooks.commit.auto=<function autohook>
--- a/tests/test-mq Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/test-mq Mon Mar 05 19:54:21 2007 +0100
@@ -40,6 +40,40 @@
hg -R c qnew test.patch
hg -R c/.hg/patches st
+echo '% qinit; qinit -c'
+hg init d
+cd d
+hg qinit
+hg qinit -c
+# qinit -c should create both files if they don't exist
+echo ' .hgignore:'
+cat .hg/patches/.hgignore
+echo ' series:'
+cat .hg/patches/series
+hg qinit -c 2>&1 | sed -e 's/repository.*already/repository already/'
+cd ..
+
+echo '% qinit; <stuff>; qinit -c'
+hg init e
+cd e
+hg qnew A
+echo foo > foo
+hg add foo
+hg qrefresh
+hg qnew B
+echo >> foo
+hg qrefresh
+echo status >> .hg/patches/.hgignore
+echo bleh >> .hg/patches/.hgignore
+hg qinit -c
+hg -R .hg/patches status
+# qinit -c shouldn't touch these files if they already exist
+echo ' .hgignore:'
+cat .hg/patches/.hgignore
+echo ' series:'
+cat .hg/patches/series
+cd ..
+
cd a
echo % qnew -m
@@ -135,6 +169,46 @@
hg qpop -a
hg push ../../k
+echo % qpush/qpop error codes
+errorcode()
+{
+ hg "$@" && echo " $@ succeeds" || echo " $@ fails"
+}
+
+# we want to start with some patches applied
+hg qpush -a
+echo " % pops all patches and succeeds"
+errorcode qpop -a
+echo " % does nothing and succeeds"
+errorcode qpop -a
+echo " % fails - nothing else to pop"
+errorcode qpop
+echo " % pushes a patch and succeeds"
+errorcode qpush
+echo " % pops a patch and succeeds"
+errorcode qpop
+echo " % pushes up to test1b.patch and succeeds"
+errorcode qpush test1b.patch
+echo " % does nothing and succeeds"
+errorcode qpush test1b.patch
+echo " % does nothing and succeeds"
+errorcode qpop test1b.patch
+echo " % fails - can't push to this patch"
+errorcode qpush test.patch
+echo " % fails - can't pop to this patch"
+errorcode qpop test2.patch
+echo " % pops up to test.patch and succeeds"
+errorcode qpop test.patch
+echo " % pushes all patches and succeeds"
+errorcode qpush -a
+echo " % does nothing and succeeds"
+errorcode qpush -a
+echo " % fails - nothing else to push"
+errorcode qpush
+echo " % does nothing and succeeds"
+errorcode qpush test2.patch
+
+
echo % strip
cd ../../b
echo x>x
--- a/tests/test-mq.out Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/test-mq.out Mon Mar 05 19:54:21 2007 +0100
@@ -60,6 +60,26 @@
A .hgignore
A series
A test.patch
+% qinit; qinit -c
+ .hgignore:
+syntax: glob
+status
+guards
+ series:
+abort: repository already exists!
+% qinit; <stuff>; qinit -c
+adding A
+adding B
+A .hgignore
+A A
+A B
+A series
+ .hgignore:
+status
+bleh
+ series:
+A
+B
% qnew -m
foo bar
% qrefresh
@@ -136,6 +156,61 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
+% qpush/qpop error codes
+applying test.patch
+applying test1b.patch
+applying test2.patch
+Now at: test2.patch
+ % pops all patches and succeeds
+Patch queue now empty
+ qpop -a succeeds
+ % does nothing and succeeds
+no patches applied
+ qpop -a succeeds
+ % fails - nothing else to pop
+no patches applied
+ qpop fails
+ % pushes a patch and succeeds
+applying test.patch
+Now at: test.patch
+ qpush succeeds
+ % pops a patch and succeeds
+Patch queue now empty
+ qpop succeeds
+ % pushes up to test1b.patch and succeeds
+applying test.patch
+applying test1b.patch
+Now at: test1b.patch
+ qpush test1b.patch succeeds
+ % does nothing and succeeds
+qpush: test1b.patch is already at the top
+ qpush test1b.patch succeeds
+ % does nothing and succeeds
+qpop: test1b.patch is already at the top
+ qpop test1b.patch succeeds
+ % fails - can't push to this patch
+abort: cannot push to a previous patch: test.patch
+ qpush test.patch fails
+ % fails - can't pop to this patch
+abort: patch test2.patch is not applied
+ qpop test2.patch fails
+ % pops up to test.patch and succeeds
+Now at: test.patch
+ qpop test.patch succeeds
+ % pushes all patches and succeeds
+applying test1b.patch
+applying test2.patch
+Now at: test2.patch
+ qpush -a succeeds
+ % does nothing and succeeds
+all patches are currently applied
+ qpush -a succeeds
+ % fails - nothing else to push
+patch series already fully applied
+ qpush fails
+ % does nothing and succeeds
+all patches are currently applied
+ qpush test2.patch succeeds
% strip
adding x
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
--- a/tests/test-symlinks Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/test-symlinks Mon Mar 05 19:54:21 2007 +0100
@@ -55,3 +55,18 @@
ln -s x/f ../z
# this should fail
hg status ../z && { echo hg mistakenly exited with status 0; exit 1; } || :
+
+cd .. ; rm -r test
+hg init test; cd test;
+
+echo '# try cloning symlink in a subdir'
+echo '1. commit a symlink'
+mkdir -p a/b/c
+cd a/b/c
+ln -s /path/to/symlink/source demo
+cd ../../..
+hg stat
+hg commit -A -m 'add symlink in a/b/c subdir'
+echo '2. clone it'
+cd ..
+hg clone test testclone
--- a/tests/test-symlinks.out Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/test-symlinks.out Mon Mar 05 19:54:21 2007 +0100
@@ -1,11 +1,12 @@
+adding bar
adding foo
adding bomb
adding a.c
adding dir/a.o
adding dir/b.o
+M dir/b.o
! a.c
! dir/a.o
-! dir/b.o
? .hgignore
a.c: unsupported file type (type is fifo)
! a.c
@@ -13,3 +14,9 @@
A f
# try symlink outside repo to file inside
abort: ../z not under root
+# try cloning symlink in a subdir
+1. commit a symlink
+? a/b/c/demo
+adding a/b/c/demo
+2. clone it
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- a/tests/test-transplant Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/test-transplant Mon Mar 05 19:54:21 2007 +0100
@@ -22,28 +22,25 @@
hg log --template '{rev} {parents} {desc}\n'
-cd ..
-hg clone t rebase
-cd rebase
+hg clone . ../rebase
+cd ../rebase
hg up -C 1
echo '% rebase b onto r1'
hg transplant -a -b tip
hg log --template '{rev} {parents} {desc}\n'
-cd ..
-hg clone t prune
-cd prune
+hg clone ../t ../prune
+cd ../prune
hg up -C 1
echo '% rebase b onto r1, skipping b2'
hg transplant -a -b tip -p 3
hg log --template '{rev} {parents} {desc}\n'
-cd ..
echo '% remote transplant'
-hg clone -r 1 t remote
-cd remote
+hg clone -r 1 ../t ../remote
+cd ../remote
hg transplant --log -s ../t 2 4
hg log --template '{rev} {parents} {desc}\n'
@@ -54,11 +51,19 @@
echo '% skip local changes transplanted to the source'
echo b4 > b4
hg ci -Amb4 -d '3 0'
-cd ..
-hg clone t pullback
-cd pullback
+hg clone ../t ../pullback
+cd ../pullback
hg transplant -s ../remote -a -b tip
+echo '% remote transplant with pull'
+hg -R ../t serve -p 20062 -d --pid-file=../t.pid
+cat ../t.pid >> $DAEMON_PIDS
+
+hg clone -r 0 ../t ../rp
+cd ../rp
+hg transplant -s http://localhost:20062/ 2 4
+hg log --template '{rev} {parents} {desc}\n'
+
echo '% transplant --continue'
hg init ../tc
cd ../tc
--- a/tests/test-transplant.out Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/test-transplant.out Mon Mar 05 19:54:21 2007 +0100
@@ -75,6 +75,24 @@
searching for changes
applying 4333daefcb15
4333daefcb15 transplanted to 5f42c04e07cc
+% remote transplant with pull
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+searching for changes
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
+applying a53251cdf717
+a53251cdf717 transplanted to 8d9279348abb
+2 b3
+1 b1
+0 r1
% transplant --continue
adding foo
adding toremove
--- a/tests/test-ui-config Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/test-ui-config Mon Mar 05 19:54:21 2007 +0100
@@ -1,5 +1,6 @@
#!/usr/bin/env python
+import ConfigParser
from mercurial import ui, util, commands
testui = ui.ui()
@@ -70,3 +71,21 @@
except util.Abort, inst:
print inst
print "---"
+
+cp = util.configparser()
+cp.add_section('foo')
+cp.set('foo', 'bar', 'baz')
+try:
+ # should fail - keys are case-sensitive
+ cp.get('foo', 'Bar')
+except ConfigParser.NoOptionError, inst:
+ print inst
+
+def function():
+ pass
+
+cp.add_section('hook')
+# values that aren't strings should work
+cp.set('hook', 'commit', function)
+f = cp.get('hook', 'commit')
+print "f %s= function" % (f == function and '=' or '!')
--- a/tests/test-ui-config.out Mon Mar 05 19:48:21 2007 +0100
+++ b/tests/test-ui-config.out Mon Mar 05 19:54:21 2007 +0100
@@ -43,3 +43,5 @@
Error in configuration section [interpolation] parameter 'value5':
'%' must be followed by '%' or '(', found: '%bad2'
---
+No option 'Bar' in section: 'foo'
+f == function