deleted file mode 100644
--- a/PKG-INFO
+++ /dev/null
@@ -1,10 +0,0 @@
-Metadata-Version: 1.0
-Name: mercurial
-Version: 0.7
-Summary: scalable distributed SCM
-Home-page: http://selenic.com/mercurial
-Author: Matt Mackall
-Author-email: mpm@selenic.com
-License: GNU GPL
-Description: UNKNOWN
-Platform: UNKNOWN
--- a/contrib/bash_completion
+++ b/contrib/bash_completion
@@ -1,30 +1,5 @@
shopt -s extglob
-_hg_command_list()
-{
- "$hg" --debug help 2>/dev/null | \
- awk -F', ' '/^list of commands:/ {commands=1}
- commands==1 && /^ [^ ]/ {
- line = substr($0, 2)
- colon = index(line, ":")
- if (colon > 0)
- line = substr(line, 1, colon-1)
- n = split(line, aliases)
- command = aliases[1]
- if (index(command, "debug") == 1) {
- for (i=1; i<=n; i++)
- debug[j++] = aliases[i]
- next
- }
- print command
- for (i=2; i<=n; i++)
- if (index(command, aliases[i]) != 1)
- print aliases[i]
- }
- /^global options:/ {exit 0}
- END {for (i in debug) print debug[i]}'
-}
-
_hg_option_list()
{
"$hg" -v help $1 2>/dev/null | \
@@ -40,21 +15,9 @@ shopt -s extglob
_hg_commands()
{
- local all commands result
-
- all=$(_hg_command_list)
- commands=${all%%$'\n'debug*}
- result=$(compgen -W '$commands' -- "$cur")
-
- # hide debug commands from users, but complete them if
- # there is no other possible command
- if [ "$result" = "" ]; then
- local debug
- debug=debug${all#*$'\n'debug}
- result=$(compgen -W '$debug' -- "$cur")
- fi
-
- COMPREPLY=(${COMPREPLY[@]:-} $result)
+ local commands
+ commands="$("$hg" debugcomplete "$cur" 2>/dev/null)" || commands=""
+ COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$commands' -- "$cur"))
}
_hg_paths()
--- a/contrib/mercurial.spec
+++ b/contrib/mercurial.spec
@@ -1,7 +1,7 @@
Summary: Mercurial -- a distributed SCM
Name: mercurial
-Version: 0.7
-Release: 1
+Version: 0.8
+Release: 0
License: GPL
Group: Development/Tools
Source: http://www.selenic.com/mercurial/release/%{name}-%{version}.tar.gz
@@ -10,6 +10,7 @@ BuildRoot: /tmp/build.%{name}-%{version}
%define pythonver %(python -c 'import sys;print ".".join(map(str, sys.version_info[:2]))')
%define pythonlib %{_libdir}/python%{pythonver}/site-packages/%{name}
+%define hgext %{_libdir}/python%{pythonver}/site-packages/hgext
%description
Mercurial is a fast, lightweight source control management system designed
@@ -30,10 +31,12 @@ rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root,-)
-%doc doc/* contrib/patchbomb *.cgi
+%doc doc/* *.cgi
%dir %{pythonlib}
+%dir %{hgext}
%{_bindir}/hgmerge
%{_bindir}/hg
%{pythonlib}/templates
%{pythonlib}/*.py*
%{pythonlib}/*.so
+%{hgext}/*.py*
--- a/contrib/win32/mercurial.iss
+++ b/contrib/win32/mercurial.iss
@@ -28,23 +28,22 @@ AllowNoIcons=true
DefaultGroupName=Mercurial
[Files]
-Source: templates\*.*; DestDir: {app}\Templates; Flags: recursesubdirs createallsubdirs
+Source: ..\..\msys\1.0\bin\patch.exe; DestDir: {app}
Source: contrib\mercurial.el; DestDir: {app}/Contrib
-Source: contrib\patchbomb; DestDir: {app}/Contrib
-Source: dist\w9xpopen.exe; DestDir: {app}
+Source: contrib\win32\ReadMe.html; DestDir: {app}; Flags: isreadme
+Source: contrib\win32\mercurial.ini; DestDir: {app}; DestName: Mercurial.ini; Flags: confirmoverwrite
+Source: contrib\win32\postinstall.txt; DestDir: {app}; DestName: ReleaseNotes.txt
Source: dist\hg.exe; DestDir: {app}
+Source: dist\library.zip; DestDir: {app}
+Source: dist\mfc71.dll; DestDir: {sys}; Flags: sharedfile uninsnosharedfileprompt
Source: dist\msvcr71.dll; DestDir: {sys}; Flags: sharedfile uninsnosharedfileprompt
-Source: dist\library.zip; DestDir: {app}
+Source: dist\w9xpopen.exe; DestDir: {app}
Source: doc\*.txt; DestDir: {app}\Docs
-Source: dist\mfc71.dll; DestDir: {sys}; Flags: sharedfile uninsnosharedfileprompt
+Source: templates\*.*; DestDir: {app}\Templates; Flags: recursesubdirs createallsubdirs
+Source: CONTRIBUTORS; DestDir: {app}; DestName: Contributors.txt
Source: COPYING; DestDir: {app}; DestName: Copying.txt
Source: comparison.txt; DestDir: {app}\Docs; DestName: Comparison.txt
Source: notes.txt; DestDir: {app}\Docs; DestName: DesignNotes.txt
-Source: CONTRIBUTORS; DestDir: {app}; DestName: Contributors.txt
-Source: contrib\win32\ReadMe.html; DestDir: {app}; Flags: isreadme
-Source: ..\..\msys\1.0\bin\patch.exe; DestDir: {app}
-Source: contrib\win32\mercurial.ini; DestDir: {app}; DestName: Mercurial.ini; Flags: confirmoverwrite
-Source: contrib\win32\postinstall.txt; DestDir: {app}; DestName: ReleaseNotes.txt
[INI]
Filename: {app}\Mercurial.url; Section: InternetShortcut; Key: URL; String: http://www.selenic.com/mercurial/
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -24,4 +24,4 @@ hg.1.gendoc.txt: ../mercurial/commands.p
asciidoc -b html4 $*.txt || asciidoc -b html $*.txt
clean:
- $(RM) $(MAN) $(MAN:%=%.xml) $(MAN:%=%.html)
+ $(RM) $(MAN) $(MAN:%=%.xml) $(MAN:%=%.html) *.[0-9].gendoc.txt
rename from contrib/hbisect.py
rename to hgext/hbisect.py
--- a/contrib/hbisect.py
+++ b/hgext/hbisect.py
@@ -1,11 +1,13 @@
-#!/usr/bin/env python
+# bisect extension for mercurial
+#
+# Copyright 2005, 2006 Benoit Boissinot <benoit.boissinot@ens-lyon.org>
+# Inspired by git bisect, extension skeleton taken from mq.py.
#
# 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(), "os sys sets")
-from mercurial import hg
+demandload(globals(), "os sys sets mercurial:hg,util")
versionstr = "0.0.3"
@@ -30,33 +32,32 @@ class bisect(object):
"""dichotomic search in the DAG of changesets"""
def __init__(self, ui, repo):
self.repo = repo
- self.path = os.path.join(repo.join(""), "bisect")
+ self.path = repo.join("bisect")
+ self.opener = util.opener(self.path)
self.ui = ui
self.goodrevs = []
self.badrev = None
self.good_dirty = 0
self.bad_dirty = 0
- self.good_path = os.path.join(self.path, "good")
- self.bad_path = os.path.join(self.path, "bad")
+ self.good_path = "good"
+ self.bad_path = "bad"
- s = self.good_path
- if os.path.exists(s):
- self.goodrevs = self.repo.opener(s).read().splitlines()
+ if os.path.exists(os.path.join(self.path, self.good_path)):
+ self.goodrevs = self.opener(self.good_path).read().splitlines()
self.goodrevs = [hg.bin(x) for x in self.goodrevs]
- s = self.bad_path
- if os.path.exists(s):
- r = self.repo.opener(s).read().splitlines()
+ if os.path.exists(os.path.join(self.path, self.bad_path)):
+ r = self.opener(self.bad_path).read().splitlines()
if r:
self.badrev = hg.bin(r.pop(0))
def __del__(self):
if not os.path.isdir(self.path):
return
- f = self.repo.opener(self.good_path, "w")
+ f = self.opener(self.good_path, "w")
f.write("\n".join([hg.hex(r) for r in self.goodrevs]))
if len(self.goodrevs) > 0:
f.write("\n")
- f = self.repo.opener(self.bad_path, "w")
+ f = self.opener(self.bad_path, "w")
if self.badrev:
f.write(hg.hex(self.badrev) + "\n")
@@ -72,7 +73,8 @@ class bisect(object):
def reset(self):
"""finish a bisection"""
if os.path.isdir(self.path):
- sl = [self.bad_path, self.good_path]
+ sl = [os.path.join(self.path, p)
+ for p in [self.bad_path, self.good_path]]
for s in sl:
if os.path.exists(s):
os.unlink(s)
@@ -92,7 +94,7 @@ class bisect(object):
if head is None:
head = self.badrev
return self.__ancestors_and_nb_ancestors(head, stop)[1]
-
+
def ancestors(self, head=None, stop=None):
"""
returns the set of the ancestors of head (self included)
@@ -101,7 +103,7 @@ class bisect(object):
if head is None:
head = self.badrev
return self.__ancestors_and_nb_ancestors(head, stop)[0]
-
+
def __ancestors_and_nb_ancestors(self, head, stop=None):
"""
if stop is None then ancestors of goodrevs are used as
@@ -114,7 +116,8 @@ class bisect(object):
cl = self.repo.changelog
if not stop:
stop = sets.Set([])
- for g in reversed(self.goodrevs):
+ for i in xrange(len(self.goodrevs)-1, -1, -1):
+ g = self.goodrevs[i]
if g in stop:
continue
stop.update(cl.reachable(g))
@@ -132,7 +135,7 @@ class bisect(object):
for p in parents:
d[p][0] += 1
return d
-
+
if head in stop:
self.ui.warn("Unconsistent state, %s is good and bad\n"
% hg.hex(head))
@@ -162,7 +165,8 @@ class bisect(object):
if not self.goodrevs:
self.ui.warn("No good revision given\n")
self.ui.warn("Assuming the first revision is good\n")
- ancestors, num_ancestors = self.__ancestors_and_nb_ancestors(self.badrev)
+ ancestors, num_ancestors = self.__ancestors_and_nb_ancestors(
+ self.badrev)
tot = len(ancestors)
if tot == 1:
if ancestors.pop() != self.badrev:
@@ -261,7 +265,7 @@ for subcommands see "hg bisect help\"
for cmd in cmds:
doc = cmdtable[cmd][0].__doc__.splitlines(0)[0].rstrip()
ui.write(" %-*s %s\n" % (m, cmd, doc))
-
+
b = bisect(ui, repo)
bisectcmdtable = {
"init": (b.init, 0, "hg bisect init"),
@@ -271,7 +275,7 @@ for subcommands see "hg bisect help\"
"reset": (b.reset, 0, "hg bisect reset"),
"help": (help_, 1, "hg bisect help [<subcommand>]"),
}
-
+
if not bisectcmdtable.has_key(cmd):
ui.warn("bisect: Unknown sub-command\n")
return help_()
@@ -281,7 +285,6 @@ for subcommands see "hg bisect help\"
return bisectcmdtable[cmd][0](*args)
cmdtable = {
- "bisect": (bisect_run, [],
- "hg bisect [help|init|reset|next|good|bad]"),
+ "bisect": (bisect_run, [], "hg bisect [help|init|reset|next|good|bad]"),
#"bisect-test": (test, [], "hg bisect-test rev"),
}
--- a/hgext/mq.py
+++ b/hgext/mq.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# queue.py - patch queues for mercurial
#
# Copyright 2005 Chris Mason <mason@suse.com>
@@ -17,28 +16,26 @@ repomap = {}
class queue:
def __init__(self, ui, path, patchdir=None):
- self.opener = util.opener(path)
self.basepath = path
if patchdir:
self.path = patchdir
else:
self.path = os.path.join(path, "patches")
+ self.opener = util.opener(self.path)
self.ui = ui
self.applied = []
self.full_series = []
self.applied_dirty = 0
self.series_dirty = 0
- self.series_path = os.path.join(self.path, "series")
- self.status_path = os.path.join(self.path, "status")
+ self.series_path = "series"
+ self.status_path = "status"
- s = self.series_path
- if os.path.exists(s):
- self.full_series = self.opener(s).read().splitlines()
+ if os.path.exists(os.path.join(self.path, self.series_path)):
+ self.full_series = self.opener(self.series_path).read().splitlines()
self.read_series(self.full_series)
- s = self.status_path
- if os.path.exists(s):
- self.applied = self.opener(s).read().splitlines()
+ if os.path.exists(os.path.join(self.path, self.status_path)):
+ self.applied = self.opener(self.status_path).read().splitlines()
def find_series(self, patch):
pre = re.compile("(\s*)([^#]+)")
@@ -186,7 +183,7 @@ class queue:
self.ui.warn("Unable to read %s\n" % patch)
sys.exit(1)
- patchf = self.opener(os.path.join(self.path, patch), "w")
+ patchf = self.opener(patch, "w")
if comments:
comments = "\n".join(comments) + '\n\n'
patchf.write(comments)
@@ -402,7 +399,7 @@ class queue:
self.read_series(self.full_series)
self.series_dirty = 1
self.applied_dirty = 1
- p = self.opener(os.path.join(self.path, patch), "w")
+ p = self.opener(patch, "w")
if msg:
msg = msg + "\n"
p.write(msg)
@@ -716,7 +713,7 @@ class queue:
patchparent = self.qparents(repo, top)
message, comments, user, patchfound = self.readheaders(patch)
- patchf = self.opener(os.path.join(self.path, patch), "w")
+ patchf = self.opener(patch, "w")
if comments:
comments = "\n".join(comments) + '\n\n'
patchf.write(comments)
@@ -835,8 +832,9 @@ class queue:
d = root[len(self.path) + 1:]
for f in files:
fl = os.path.join(d, f)
- if (fl not in self.series and fl != "status" and
- fl != "series" and not fl.startswith('.')):
+ if (fl not in self.series and
+ fl not in (self.status_path, self.series_path)
+ and not fl.startswith('.')):
list.append(fl)
list.sort()
if list:
@@ -1012,7 +1010,7 @@ class queue:
if not force and os.path.isfile(os.path.join(self.path, patch)):
self.ui.warn("patch %s already exists\n" % patch)
sys.exit(1)
- patchf = self.opener(os.path.join(self.path, patch), "w")
+ patchf = self.opener(patch, "w")
patchf.write(text)
if patch in self.series:
self.ui.warn("patch %s is already in the series file\n" % patch)
@@ -1205,7 +1203,7 @@ def save(ui, repo, **opts):
util.copyfiles(path, newpath)
if opts['empty']:
try:
- os.unlink(q.status_path)
+ os.unlink(os.path.join(q.path, q.status_path))
except:
pass
return 0
--- a/hgext/patchbomb.py
+++ b/hgext/patchbomb.py
@@ -52,7 +52,7 @@
from mercurial.demandload import *
demandload(globals(), '''email.MIMEMultipart email.MIMEText email.Utils
mercurial:commands,hg,ui
- os popen2 smtplib socket sys tempfile time''')
+ os errno popen2 smtplib socket sys tempfile time''')
from mercurial.i18n import gettext as _
try:
@@ -141,7 +141,10 @@ def patchbomb(ui, repo, *revs, **opts):
body += cdiffstat('\n'.join(desc), patch) + '\n\n'
body += '\n'.join(patch)
msg = email.MIMEText.MIMEText(body)
- subj = '[PATCH %d of %d] %s' % (idx, total, desc[0].strip())
+ if total == 1:
+ subj = '[PATCH] ' + desc[0].strip()
+ else:
+ subj = '[PATCH %d of %d] %s' % (idx, total, desc[0].strip())
if subj.endswith('.'): subj = subj[:-1]
msg['Subject'] = subj
msg['X-Mercurial-Node'] = node
@@ -180,17 +183,9 @@ def patchbomb(ui, repo, *revs, **opts):
jumbo.extend(p)
msgs.append(makepatch(p, i + 1, len(patches)))
- ui.write(_('\nWrite the introductory message for the patch series.\n\n'))
-
sender = (opts['from'] or ui.config('patchbomb', 'from') or
prompt('From', ui.username()))
- msg = email.MIMEMultipart.MIMEMultipart()
- msg['Subject'] = '[PATCH 0 of %d] %s' % (
- len(patches),
- opts['subject'] or
- prompt('Subject:', rest = ' [PATCH 0 of %d] ' % len(patches)))
-
def getaddrs(opt, prpt, default = None):
addrs = opts[opt] or (ui.config('patchbomb', opt) or
prompt(prpt, default = default)).split(',')
@@ -198,26 +193,35 @@ def patchbomb(ui, repo, *revs, **opts):
to = getaddrs('to', 'To')
cc = getaddrs('cc', 'Cc', '')
- ui.write(_('Finish with ^D or a dot on a line by itself.\n\n'))
+ if len(patches) > 1:
+ ui.write(_('\nWrite the introductory message for the patch series.\n\n'))
- body = []
+ msg = email.MIMEMultipart.MIMEMultipart()
+ msg['Subject'] = '[PATCH 0 of %d] %s' % (
+ len(patches),
+ opts['subject'] or
+ prompt('Subject:', rest = ' [PATCH 0 of %d] ' % 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)
+ while True:
+ try: l = raw_input()
+ except EOFError: break
+ if l == '.': break
+ body.append(l)
- msg.attach(email.MIMEText.MIMEText('\n'.join(body) + '\n'))
+ msg.attach(email.MIMEText.MIMEText('\n'.join(body) + '\n'))
+
+ if opts['diffstat']:
+ d = cdiffstat(_('Final summary:\n'), jumbo)
+ if d: msg.attach(email.MIMEText.MIMEText(d))
+
+ msgs.insert(0, msg)
ui.write('\n')
- if opts['diffstat']:
- d = cdiffstat(_('Final summary:\n'), jumbo)
- if d: msg.attach(email.MIMEText.MIMEText(d))
-
- msgs.insert(0, msg)
-
if not opts['test'] and not opts['mbox']:
s = smtplib.SMTP()
s.connect(host = ui.config('smtp', 'host', 'mail'),
@@ -250,8 +254,12 @@ def patchbomb(ui, repo, *revs, **opts):
if opts['test']:
ui.status('Displaying ', m['Subject'], ' ...\n')
fp = os.popen(os.getenv('PAGER', 'more'), 'w')
- fp.write(m.as_string(0))
- fp.write('\n')
+ try:
+ fp.write(m.as_string(0))
+ fp.write('\n')
+ except IOError, inst:
+ if inst.errno != errno.EPIPE:
+ raise
fp.close()
elif opts['mbox']:
ui.status('Writing ', m['Subject'], ' ...\n')
--- a/hgmerge
+++ b/hgmerge
@@ -3,7 +3,13 @@
# hgmerge - default merge helper for Mercurial
#
# This tries to find a way to do three-way merge on the current system.
-# The result ought to end up in $1.
+# The result ought to end up in $1. Script is run in root directory of
+# repository.
+#
+# Environment variables set by Mercurial:
+# HG_FILE name of file within repo
+# HG_MY_NODE revision being merged
+# HG_OTHER_NODE revision being merged
set -e # bail out quickly on failure
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -593,12 +593,7 @@ def annotate(ui, repo, *pats, **opts):
change = repo.changelog.read(node)
mmap = repo.manifest.read(change[0])
- for src, abs, rel, exact in walk(repo, pats, opts):
- if abs not in mmap:
- ui.warn(_("warning: %s is not in the repository!\n") %
- ((pats and rel) or abs))
- continue
-
+ for src, abs, rel, exact in walk(repo, pats, opts, node=node):
f = repo.file(abs)
if not opts['text'] and util.binary(f.read(mmap[abs])):
ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
@@ -634,7 +629,7 @@ def bundle(ui, repo, fname, dest="defaul
contents including permissions, rename data, and revision history.
"""
f = open(fname, "wb")
- dest = ui.expandpath(dest, repo.root)
+ dest = ui.expandpath(dest)
other = hg.repository(ui, dest)
o = repo.findoutgoing(other)
cg = repo.changegroup(o, 'bundle')
@@ -723,8 +718,7 @@ def clone(ui, source, dest=None, **opts)
if opts['remotecmd']:
ui.setconfig("ui", "remotecmd", opts['remotecmd'])
- if not os.path.exists(source):
- source = ui.expandpath(source)
+ source = ui.expandpath(source)
d = Dircleanup(dest)
abspath = source
@@ -1018,6 +1012,12 @@ def debugancestor(ui, index, rev1, rev2)
a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
ui.write("%d:%s\n" % (r.rev(a), hex(a)))
+def debugcomplete(ui, cmd):
+ """returns the completion list associated with the given command"""
+ clist = findpossible(cmd).keys()
+ clist.sort()
+ ui.write("%s\n" % " ".join(clist))
+
def debugrebuildstate(ui, repo, rev=None):
"""rebuild the dirstate as it would look like for the given revision"""
if not rev:
@@ -1063,13 +1063,8 @@ def debugcheckstate(ui, repo):
error = _(".hg/dirstate inconsistent with current parent's manifest")
raise util.Abort(error)
-def debugconfig(ui):
+def debugconfig(ui, repo):
"""show combined config settings from all hgrc files"""
- try:
- repo = hg.repository(ui)
- ui = repo.ui
- except hg.RepoError:
- pass
for section, name, value in ui.walkconfig():
ui.write('%s.%s=%s\n' % (section, name, value))
@@ -1548,7 +1543,7 @@ def incoming(ui, repo, source="default",
Currently only local repositories are supported.
"""
- source = ui.expandpath(source, repo.root)
+ source = ui.expandpath(source)
other = hg.repository(ui, source)
if not other.local():
raise util.Abort(_("incoming doesn't work for remote repositories yet"))
@@ -1735,7 +1730,7 @@ def outgoing(ui, repo, dest="default-pus
See pull for valid source format details.
"""
- dest = ui.expandpath(dest, repo.root)
+ dest = ui.expandpath(dest)
other = hg.repository(ui, dest)
o = repo.findoutgoing(other)
o = repo.changelog.nodesbetween(o)[0]
@@ -1768,7 +1763,7 @@ def parents(ui, repo, rev=None, branches
if n != nullid:
show_changeset(ui, repo, changenode=n, brinfo=br)
-def paths(ui, search=None):
+def paths(ui, repo, search=None):
"""show definition of symbolic path names
Show definition of symbolic path name NAME. If no name is given, show
@@ -1777,12 +1772,6 @@ def paths(ui, search=None):
Path names are defined in the [paths] section of /etc/mercurial/hgrc
and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
"""
- try:
- repo = hg.repository(ui)
- ui = repo.ui
- except hg.RepoError:
- pass
-
if search:
for name, path in ui.configitems("paths"):
if name == search:
@@ -1815,7 +1804,7 @@ def pull(ui, repo, source="default", **o
to the remote user's home directory by default; use two slashes at
the start of a path to specify it as relative to the filesystem root.
"""
- source = ui.expandpath(source, repo.root)
+ source = ui.expandpath(source)
ui.status(_('pulling from %s\n') % (source))
if opts['ssh']:
@@ -1860,7 +1849,7 @@ def push(ui, repo, dest="default-push",
SSH requires an accessible shell account on the destination
machine and a copy of hg in the remote path.
"""
- dest = ui.expandpath(dest, repo.root)
+ dest = ui.expandpath(dest)
ui.status('pushing to %s\n' % (dest))
if opts['ssh']:
@@ -1936,7 +1925,7 @@ def remove(ui, repo, pat, *pats, **opts)
def okaytoremove(abs, rel, exact):
modified, added, removed, deleted, unknown = repo.changes(files=[abs])
reason = None
- if modified:
+ if modified and not opts['force']:
reason = _('is modified')
elif added:
reason = _('has been marked for add')
@@ -2443,6 +2432,7 @@ table = {
('X', 'exclude', [], _('exclude names matching the given patterns'))],
_('hg copy [OPTION]... [SOURCE]... DEST')),
"debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
+ "debugcomplete": (debugcomplete, [], _('debugcomplete CMD')),
"debugrebuildstate":
(debugrebuildstate,
[('r', 'rev', '', _('revision to rebuild to'))],
@@ -2579,7 +2569,8 @@ table = {
"recover": (recover, [], _('hg recover')),
"^remove|rm":
(remove,
- [('I', 'include', [], _('include names matching the given patterns')),
+ [('f', 'force', None, _('remove file even if modified')),
+ ('I', 'include', [], _('include names matching the given patterns')),
('X', 'exclude', [], _('exclude names matching the given patterns'))],
_('hg remove [OPTION]... FILE...')),
"rename|mv":
@@ -2589,7 +2580,7 @@ table = {
_('forcibly copy over an existing managed file')),
('I', 'include', [], _('include names matching the given patterns')),
('X', 'exclude', [], _('exclude names matching the given patterns'))],
- _('hg rename [OPTION]... [SOURCE]... DEST')),
+ _('hg rename [OPTION]... SOURCE... DEST')),
"^revert":
(revert,
[('r', 'rev', '', _('revision to revert to')),
@@ -2658,7 +2649,8 @@ table = {
}
globalopts = [
- ('R', 'repository', '', _('repository root directory')),
+ ('R', 'repository', '',
+ _('repository root directory or symbolic path name')),
('', 'cwd', '', _('change working directory')),
('y', 'noninteractive', None,
_('do not prompt, assume \'yes\' for any required answers')),
@@ -2673,28 +2665,49 @@ globalopts = [
('h', 'help', None, _('display help and exit')),
]
-norepo = ("clone init version help debugancestor debugconfig debugdata"
- " debugindex debugindexdot paths")
-
-def find(cmd):
- """Return (aliases, command table entry) for command string."""
- choice = None
- count = 0
+norepo = ("clone init version help debugancestor debugcomplete debugdata"
+ " debugindex debugindexdot")
+optionalrepo = ("paths debugconfig")
+
+def findpossible(cmd):
+ """
+ Return cmd -> (aliases, command table entry)
+ for each matching command
+ """
+ choice = {}
+ debugchoice = {}
for e in table.keys():
aliases = e.lstrip("^").split("|")
if cmd in aliases:
- return aliases, table[e]
+ choice[cmd] = (aliases, table[e])
+ continue
for a in aliases:
if a.startswith(cmd):
- count += 1
- choice = aliases, table[e]
+ if aliases[0].startswith("debug"):
+ debugchoice[a] = (aliases, table[e])
+ else:
+ choice[a] = (aliases, table[e])
break
- if count > 1:
- raise AmbiguousCommand(cmd)
+ if not choice and debugchoice:
+ choice = debugchoice
+
+ return choice
+
+def find(cmd):
+ """Return (aliases, command table entry) for command string."""
+ choice = findpossible(cmd)
+
+ if choice.has_key(cmd):
+ return choice[cmd]
+
+ if len(choice) > 1:
+ clist = choice.keys()
+ clist.sort()
+ raise AmbiguousCommand(cmd, clist)
if choice:
- return choice
+ return choice.values()[0]
raise UnknownCommand(cmd)
@@ -2782,7 +2795,10 @@ def dispatch(args):
mod = getattr(mod, comp)
return mod
try:
- mod = importh(x[0])
+ try:
+ mod = importh("hgext." + x[0])
+ except ImportError:
+ mod = importh(x[0])
except Exception, inst:
on_exception(Exception, inst)
continue
@@ -2797,44 +2813,37 @@ def dispatch(args):
try:
cmd, func, args, options, cmdoptions = parse(u, args)
- except ParseError, inst:
- if inst.args[0]:
- u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
- help_(u, inst.args[0])
- else:
- u.warn(_("hg: %s\n") % inst.args[1])
- help_(u, 'shortlist')
- sys.exit(-1)
- except AmbiguousCommand, inst:
- u.warn(_("hg: command '%s' is ambiguous.\n") % inst.args[0])
- sys.exit(1)
- except UnknownCommand, inst:
- u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
- help_(u, 'shortlist')
- sys.exit(1)
-
- if options["time"]:
- def get_times():
- t = os.times()
- if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
- t = (t[0], t[1], t[2], t[3], time.clock())
- return t
- s = get_times()
- def print_time():
- t = get_times()
- u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
- (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
- atexit.register(print_time)
-
- u.updateopts(options["verbose"], options["debug"], options["quiet"],
- not options["noninteractive"])
-
- # enter the debugger before command execution
- if options['debugger']:
- pdb.set_trace()
-
- try:
+ if options["time"]:
+ def get_times():
+ t = os.times()
+ if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
+ t = (t[0], t[1], t[2], t[3], time.clock())
+ return t
+ s = get_times()
+ def print_time():
+ t = get_times()
+ u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
+ (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
+ atexit.register(print_time)
+
+ u.updateopts(options["verbose"], options["debug"], options["quiet"],
+ not options["noninteractive"])
+
+ # enter the debugger before command execution
+ if options['debugger']:
+ pdb.set_trace()
+
try:
+ if options['cwd']:
+ try:
+ os.chdir(options['cwd'])
+ except OSError, inst:
+ raise util.Abort('%s: %s' %
+ (options['cwd'], inst.strerror))
+
+ path = u.expandpath(options["repository"]) or ""
+ repo = path and hg.repository(u, path=path) or None
+
if options['help']:
help_(u, cmd, options['version'])
sys.exit(0)
@@ -2845,20 +2854,17 @@ def dispatch(args):
help_(u, 'shortlist')
sys.exit(0)
- if options['cwd']:
+ if cmd not in norepo.split():
try:
- os.chdir(options['cwd'])
- except OSError, inst:
- raise util.Abort('%s: %s' %
- (options['cwd'], inst.strerror))
-
- if cmd not in norepo.split():
- path = options["repository"] or ""
- repo = hg.repository(u, path=path)
- u = repo.ui
- for x in external:
- if hasattr(x, 'reposetup'):
- x.reposetup(u, repo)
+ if not repo:
+ repo = hg.repository(u, path=path)
+ u = repo.ui
+ for x in external:
+ if hasattr(x, 'reposetup'):
+ x.reposetup(u, repo)
+ except hg.RepoError:
+ if cmd not in optionalrepo.split():
+ raise
d = lambda: func(u, repo, *args, **cmdoptions)
else:
d = lambda: func(u, *args, **cmdoptions)
@@ -2894,6 +2900,22 @@ def dispatch(args):
if options['traceback']:
traceback.print_exc()
raise
+ except ParseError, inst:
+ if inst.args[0]:
+ u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
+ help_(u, inst.args[0])
+ else:
+ u.warn(_("hg: %s\n") % inst.args[1])
+ help_(u, 'shortlist')
+ sys.exit(-1)
+ except AmbiguousCommand, inst:
+ u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
+ (inst.args[0], " ".join(inst.args[1])))
+ sys.exit(1)
+ except UnknownCommand, inst:
+ u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
+ help_(u, 'shortlist')
+ sys.exit(1)
except hg.RepoError, inst:
u.warn(_("abort: "), inst, "!\n")
except revlog.RevlogError, inst:
@@ -2940,12 +2962,6 @@ def dispatch(args):
u.debug(inst, "\n")
u.warn(_("%s: invalid arguments\n") % cmd)
help_(u, cmd)
- except AmbiguousCommand, inst:
- u.warn(_("hg: command '%s' is ambiguous.\n") % inst.args[0])
- help_(u, 'shortlist')
- except UnknownCommand, inst:
- u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
- help_(u, 'shortlist')
except SystemExit:
# don't catch this in the catch-all below
raise
--- a/mercurial/hgweb.py
+++ b/mercurial/hgweb.py
@@ -851,7 +851,7 @@ class hgweb(object):
def run(self, req=hgrequest()):
def clean(path):
- p = os.path.normpath(path)
+ p = util.normpath(path)
if p[:2] == "..":
raise "suspicious path"
return p
--- a/mercurial/httprepo.py
+++ b/mercurial/httprepo.py
@@ -67,6 +67,9 @@ class httprepository(remoterepository):
def dev(self):
return -1
+ def lock(self):
+ raise util.Abort(_('operation not supported over http'))
+
def do_cmd(self, cmd, **args):
self.ui.debug(_("sending %s command\n") % cmd)
q = {"cmd": cmd}
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -47,35 +47,15 @@ class localrepository(object):
self.dirstate = dirstate.dirstate(self.opener, self.ui, self.root)
try:
- self.ui.readconfig(self.join("hgrc"))
+ self.ui.readconfig(self.join("hgrc"), self.root)
except IOError:
pass
def hook(self, name, throw=False, **args):
def runhook(name, cmd):
self.ui.note(_("running hook %s: %s\n") % (name, cmd))
- old = {}
- for k, v in args.items():
- k = k.upper()
- old['HG_' + k] = os.environ.get(k, None)
- old[k] = os.environ.get(k, None)
- os.environ['HG_' + k] = str(v)
- os.environ[k] = str(v)
-
- try:
- # Hooks run in the repository root
- olddir = os.getcwd()
- os.chdir(self.root)
- r = os.system(cmd)
- finally:
- for k, v in old.items():
- if v is not None:
- os.environ[k] = v
- else:
- del os.environ[k]
-
- os.chdir(olddir)
-
+ env = dict([('HG_' + k.upper(), v) for k, v in args.iteritems()])
+ r = util.system(cmd, environ=env, cwd=self.root)
if r:
desc, r = util.explain_exit(r)
if throw:
@@ -231,7 +211,7 @@ class localrepository(object):
self.opener("journal.dirstate", "w").write(ds)
tr = transaction.transaction(self.ui.warn, self.opener,
- self.join("journal"),
+ self.join("journal"),
aftertrans(self.path))
self.transhandle = tr
return tr
@@ -1654,14 +1634,18 @@ class localrepository(object):
self.dirstate.update([f], 'n')
# merge the tricky bits
+ failedmerge = []
files = merge.keys()
files.sort()
+ xp1 = hex(p1)
+ xp2 = hex(p2)
for f in files:
self.ui.status(_("merging %s\n") % f)
my, other, flag = merge[f]
- ret = self.merge3(f, my, other)
+ ret = self.merge3(f, my, other, xp1, xp2)
if ret:
err = True
+ failedmerge.append(f)
util.set_exec(self.wjoin(f), flag)
if moddirstate:
if branch_merge:
@@ -1695,9 +1679,19 @@ class localrepository(object):
if moddirstate:
self.dirstate.setparents(p1, p2)
+
+ stat = ((len(get), _("updated")),
+ (len(merge) - len(failedmerge), _("merged")),
+ (len(remove), _("removed")),
+ (len(failedmerge), _("unresolved")))
+ note = ", ".join([_("%d files %s") % s for s in stat])
+ self.ui.note("%s\n" % note)
+ if moddirstate and branch_merge:
+ self.ui.note(_("(branch merge, don't forget to commit)\n"))
+
return err
- def merge3(self, fn, my, other):
+ def merge3(self, fn, my, other, p1, p2):
"""perform a 3-way merge in the working directory"""
def temp(prefix, node):
@@ -1720,7 +1714,13 @@ class localrepository(object):
cmd = (os.environ.get("HGMERGE") or self.ui.config("ui", "merge")
or "hgmerge")
- r = os.system('%s "%s" "%s" "%s"' % (cmd, a, b, c))
+ r = util.system('%s "%s" "%s" "%s"' % (cmd, a, b, c), cwd=self.root,
+ environ={'HG_FILE': fn,
+ 'HG_MY_NODE': p1,
+ 'HG_OTHER_NODE': p2,
+ 'HG_FILE_MY_NODE': hex(my),
+ 'HG_FILE_OTHER_NODE': hex(other),
+ 'HG_FILE_BASE_NODE': hex(base)})
if r:
self.ui.warn(_("merging %s failed!\n") % fn)
@@ -1771,6 +1771,7 @@ class localrepository(object):
raise
except Exception, inst:
err(_("unpacking changeset %s: %s") % (short(n), inst))
+ continue
neededmanifests[changes[0]] = n
@@ -1808,10 +1809,14 @@ class localrepository(object):
raise
except Exception, inst:
err(_("unpacking manifest %s: %s") % (short(n), inst))
+ continue
- ff = [ l.split('\0') for l in delta.splitlines() ]
- for f, fn in ff:
- filenodes.setdefault(f, {})[bin(fn[:40])] = 1
+ try:
+ ff = [ l.split('\0') for l in delta.splitlines() ]
+ for f, fn in ff:
+ filenodes.setdefault(f, {})[bin(fn[:40])] = 1
+ except (ValueError, TypeError), inst:
+ err(_("broken delta in manifest %s: %s") % (short(n), inst))
self.ui.status(_("crosschecking files in changesets and manifests\n"))
@@ -1835,6 +1840,9 @@ class localrepository(object):
if f == "/dev/null":
continue
files += 1
+ if not f:
+ err(_("file without name in manifest %s") % short(n))
+ continue
fl = self.file(f)
checksize(fl, f)
@@ -1852,7 +1860,7 @@ class localrepository(object):
del filenodes[f][n]
flr = fl.linkrev(n)
- if flr not in filelinkrevs[f]:
+ if flr not in filelinkrevs.get(f, []):
err(_("%s:%s points to unexpected changeset %d")
% (f, short(n), flr))
else:
--- a/mercurial/lock.py
+++ b/mercurial/lock.py
@@ -6,7 +6,7 @@
# of the GNU General Public License, incorporated herein by reference.
from demandload import *
-demandload(globals(), 'errno os time util')
+demandload(globals(), 'errno os socket time util')
class LockException(Exception):
pass
@@ -16,11 +16,22 @@ class LockUnavailable(LockException):
pass
class lock(object):
+ # lock is symlink on platforms that support it, file on others.
+
+ # symlink is used because create of directory entry and contents
+ # are atomic even over nfs.
+
+ # old-style lock: symlink to pid
+ # new-style lock: symlink to hostname:pid
+
def __init__(self, file, timeout=-1, releasefn=None):
self.f = file
self.held = 0
self.timeout = timeout
self.releasefn = releasefn
+ self.id = None
+ self.host = None
+ self.pid = None
self.lock()
def __del__(self):
@@ -41,15 +52,50 @@ class lock(object):
raise inst
def trylock(self):
- pid = os.getpid()
+ if self.id is None:
+ self.host = socket.gethostname()
+ self.pid = os.getpid()
+ self.id = '%s:%s' % (self.host, self.pid)
+ while not self.held:
+ try:
+ util.makelock(self.id, self.f)
+ self.held = 1
+ except (OSError, IOError), why:
+ if why.errno == errno.EEXIST:
+ locker = self.testlock()
+ if locker:
+ raise LockHeld(locker)
+ else:
+ raise LockUnavailable(why)
+
+ def testlock(self):
+ '''return id of locker if lock is valid, else None.'''
+ # if old-style lock, we cannot tell what machine locker is on.
+ # with new-style lock, if locker is on this machine, we can
+ # see if locker is alive. if locker is on this machine but
+ # not alive, we can safely break lock.
+ locker = util.readlock(self.f)
+ c = locker.find(':')
+ if c == -1:
+ return locker
+ host = locker[:c]
+ if host != self.host:
+ return locker
try:
- util.makelock(str(pid), self.f)
- self.held = 1
- except (OSError, IOError), why:
- if why.errno == errno.EEXIST:
- raise LockHeld(util.readlock(self.f))
- else:
- raise LockUnavailable(why)
+ pid = int(locker[c+1:])
+ except:
+ return locker
+ if util.testpid(pid):
+ return locker
+ # if locker dead, break lock. must do this with another lock
+ # held, or can race and break valid lock.
+ try:
+ l = lock(self.f + '.break')
+ l.trylock()
+ os.unlink(self.f)
+ l.release()
+ except (LockHeld, LockUnavailable):
+ return locker
def release(self):
if self.held:
--- a/mercurial/packagescan.py
+++ b/mercurial/packagescan.py
@@ -16,8 +16,14 @@ def demandload(scope, modules):
""" fake demandload function that collects the required modules """
for m in modules.split():
mod = None
- mod = __import__(m,scope,scope)
- scope[m] = mod
+ try:
+ module, submodules = m.split(':')
+ submodules = submodules.split(',')
+ except:
+ module = m
+ submodules = []
+ mod = __import__(module, scope, scope, submodules)
+ scope[module] = mod
requiredmodules[mod.__name__] = 1
def getmodules(libpath,packagename):
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -48,7 +48,7 @@ def decompress(bin):
if t == '\0': return bin
if t == 'x': return zlib.decompress(bin)
if t == 'u': return bin[1:]
- raise RevlogError(_("unknown compression type %s") % t)
+ raise RevlogError(_("unknown compression type %r") % t)
indexformat = ">4l20s20s20s"
--- a/mercurial/ui.py
+++ b/mercurial/ui.py
@@ -5,18 +5,19 @@
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
-import os, ConfigParser
+import ConfigParser
from i18n import gettext as _
from demandload import *
-demandload(globals(), "re socket sys util")
+demandload(globals(), "os re socket sys util")
class ui(object):
def __init__(self, verbose=False, debug=False, quiet=False,
interactive=True, parentui=None):
self.overlay = {}
- self.cdata = ConfigParser.SafeConfigParser()
- self.parentui = parentui and parentui.parentui or parentui
if parentui is None:
+ # this is the parent of all ui children
+ self.parentui = None
+ self.cdata = ConfigParser.SafeConfigParser()
self.readconfig(util.rcpath)
self.quiet = self.configbool("ui", "quiet")
@@ -26,6 +27,16 @@ class ui(object):
self.updateopts(verbose, debug, quiet, interactive)
self.diffcache = None
+ else:
+ # parentui may point to an ui object which is already a child
+ self.parentui = parentui.parentui or parentui
+ parent_cdata = self.parentui.cdata
+ self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults())
+ # make interpolation work
+ for section in parent_cdata.sections():
+ self.cdata.add_section(section)
+ for name, value in parent_cdata.items(section, raw=True):
+ self.cdata.set(section, name, value)
def __getattr__(self, key):
return getattr(self.parentui, key)
@@ -37,7 +48,7 @@ class ui(object):
self.debugflag = (self.debugflag or debug)
self.interactive = (self.interactive and interactive)
- def readconfig(self, fn):
+ def readconfig(self, fn, root=None):
if isinstance(fn, basestring):
fn = [fn]
for f in fn:
@@ -45,6 +56,12 @@ class ui(object):
self.cdata.read(f)
except ConfigParser.ParsingError, inst:
raise util.Abort(_("Failed to parse %s\n%s") % (f, inst))
+ # translate paths relative to root (or home) into absolute paths
+ if root is None:
+ root = os.path.expanduser('~')
+ for name, path in self.configitems("paths"):
+ if path and path.find("://") == -1 and not os.path.isabs(path):
+ self.cdata.set("paths", name, os.path.join(root, path))
def setconfig(self, section, name, val):
self.overlay[(section, name)] = val
@@ -53,7 +70,10 @@ class ui(object):
if self.overlay.has_key((section, name)):
return self.overlay[(section, name)]
if self.cdata.has_option(section, name):
- return self.cdata.get(section, name)
+ try:
+ return self.cdata.get(section, name)
+ except ConfigParser.InterpolationError, inst:
+ raise util.Abort(_("Error in configuration:\n%s") % inst)
if self.parentui is None:
return default
else:
@@ -63,7 +83,10 @@ class ui(object):
if self.overlay.has_key((section, name)):
return self.overlay[(section, name)]
if self.cdata.has_option(section, name):
- return self.cdata.getboolean(section, name)
+ try:
+ return self.cdata.getboolean(section, name)
+ except ConfigParser.InterpolationError, inst:
+ raise util.Abort(_("Error in configuration:\n%s") % inst)
if self.parentui is None:
return default
else:
@@ -74,7 +97,10 @@ class ui(object):
if self.parentui is not None:
items = dict(self.parentui.configitems(section))
if self.cdata.has_section(section):
- items.update(dict(self.cdata.items(section)))
+ try:
+ items.update(dict(self.cdata.items(section)))
+ except ConfigParser.InterpolationError, inst:
+ raise util.Abort(_("Error in configuration:\n%s") % inst)
x = items.items()
x.sort()
return x
@@ -133,15 +159,12 @@ class ui(object):
user = user[f+1:]
return user
- def expandpath(self, loc, root=""):
- paths = {}
- for name, path in self.configitems("paths"):
- m = path.find("://")
- if m == -1:
- path = os.path.join(root, path)
- paths[name] = path
+ def expandpath(self, loc):
+ """Return repository location relative to cwd or from [paths]"""
+ if loc.find("://") != -1 or os.path.exists(loc):
+ return loc
- return paths.get(loc, loc)
+ return self.config("paths", loc, loc)
def write(self, *args):
for a in args:
@@ -189,7 +212,9 @@ class ui(object):
os.environ.get("EDITOR", "vi"))
os.environ["HGUSER"] = self.username()
- util.system("%s \"%s\"" % (editor, name), errprefix=_("edit failed"))
+ util.system("%s \"%s\"" % (editor, name),
+ environ={'HGUSER': self.username()},
+ onerr=util.Abort, errprefix=_("edit failed"))
t = open(name).read()
t = re.sub("(?m)^HG:.*\n", "", t)
@@ -197,4 +222,3 @@ class ui(object):
os.unlink(name)
return t
-
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -315,15 +315,42 @@ def _matcher(canonroot, cwd, names, inc,
(files and filematch(fn)))),
(inc or exc or (pats and pats != [('glob', '**')])) and True)
-def system(cmd, errprefix=None):
- """execute a shell command that must succeed"""
- rc = os.system(cmd)
- if rc:
- errmsg = "%s %s" % (os.path.basename(cmd.split(None, 1)[0]),
- explain_exit(rc)[0])
- if errprefix:
- errmsg = "%s: %s" % (errprefix, errmsg)
- raise Abort(errmsg)
+def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None):
+ '''enhanced shell command execution.
+ run with environment maybe modified, maybe in different dir.
+
+ if command fails and onerr is None, return status. if ui object,
+ print error message and return status, else raise onerr object as
+ exception.'''
+ oldenv = {}
+ for k in environ:
+ oldenv[k] = os.environ.get(k)
+ if cwd is not None:
+ oldcwd = os.getcwd()
+ try:
+ for k, v in environ.iteritems():
+ os.environ[k] = str(v)
+ if cwd is not None and oldcwd != cwd:
+ os.chdir(cwd)
+ rc = os.system(cmd)
+ if rc and onerr:
+ errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
+ explain_exit(rc)[0])
+ if errprefix:
+ errmsg = '%s: %s' % (errprefix, errmsg)
+ try:
+ onerr.warn(errmsg + '\n')
+ except AttributeError:
+ raise onerr(errmsg)
+ return rc
+ finally:
+ for k, v in oldenv.iteritems():
+ if v is None:
+ del os.environ[k]
+ else:
+ os.environ[k] = v
+ if cwd is not None and oldcwd != cwd:
+ os.chdir(oldcwd)
def rename(src, dst):
"""forcibly rename a file"""
@@ -499,7 +526,7 @@ if os.name == 'nt':
return pf
try: # ActivePython can create hard links using win32file module
- import win32file
+ import win32api, win32con, win32file
def os_link(src, dst): # NB will only succeed on NTFS
win32file.CreateHardLink(dst, src)
@@ -516,8 +543,18 @@ if os.name == 'nt':
except:
return os.stat(pathname).st_nlink
+ def testpid(pid):
+ '''return False if pid is dead, True if running or not known'''
+ try:
+ win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION,
+ False, pid)
+ except:
+ return True
+
except ImportError:
- pass
+ def testpid(pid):
+ '''return False if pid dead, True if running or not known'''
+ return True
def is_exec(f, last):
return last
@@ -614,6 +651,14 @@ else:
else:
raise
+ def testpid(pid):
+ '''return False if pid dead, True if running or not sure'''
+ try:
+ os.kill(pid, 0)
+ return True
+ except OSError, inst:
+ return inst.errno != errno.ESRCH
+
def explain_exit(code):
"""return a 2-tuple (desc, code) describing a process's status"""
if os.WIFEXITED(code):
--- a/setup.py
+++ b/setup.py
@@ -5,8 +5,11 @@
# './setup.py install', or
# './setup.py --help' for more options
+import sys
+if not hasattr(sys, 'version_info') or sys.version_info < (2, 3):
+ raise SystemExit, "Mercurial requires python 2.3 or later."
+
import glob
-import sys
from distutils.core import setup, Extension
from distutils.command.install_data import install_data
--- a/tests/run-tests
+++ b/tests/run-tests
@@ -57,7 +57,16 @@ else
fi
cd "$TESTDIR"
-PATH="$INST/bin:$PATH"; export PATH
+BINDIR="$INST/bin"
+PATH="$BINDIR:$PATH"; export PATH
+if [ -n "$PYTHON" ]; then
+ {
+ echo "#!/bin/sh"
+ echo "exec \"$PYTHON"'" "$@"'
+ } > "$BINDIR/python"
+ chmod 755 "$BINDIR/python"
+fi
+
PYTHONPATH="$PYTHONDIR"; export PYTHONPATH
run_one() {
--- a/tests/test-clone-r
+++ b/tests/test-clone-r
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
hg init test
cd test
--- a/tests/test-filebranch.out
+++ b/tests/test-filebranch.out
@@ -19,6 +19,8 @@ resolving manifests
getting bar
merging foo
resolving foo
+1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
we shouldn't have anything but foo in merge state here
m 644 3 foo
main: we should have a merge here
--- a/tests/test-flags.out
+++ b/tests/test-flags.out
@@ -44,5 +44,7 @@ summary: added a b
resolving manifests
merging a
resolving a
+0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
-rwxr-x---
-rwxr-x---
--- a/tests/test-merge7.out
+++ b/tests/test-merge7.out
@@ -24,6 +24,8 @@ merging test.txt
resolving test.txt
file test.txt: my fc3148072371 other d40249267ae3 ancestor 8fe46a3eb557
merging test.txt failed!
+0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+(branch merge, don't forget to commit)
one
<<<<<<<
two-point-five
--- a/tests/test-push-r
+++ b/tests/test-push-r
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
hg init test
cd test
--- a/tests/test-up-local-change.out
+++ b/tests/test-up-local-change.out
@@ -21,6 +21,7 @@ getting b
merging a
resolving a
file a: my b789fdd96dc2 other d730145abbf9 ancestor b789fdd96dc2
+1 files updated, 1 files merged, 0 files removed, 0 files unresolved
changeset: 1:1e71731e6fbb
tag: tip
user: test
@@ -32,6 +33,7 @@ resolving manifests
ancestor a0c8bcbbb45c local 1165e8bd193e remote a0c8bcbbb45c
remote deleted b
removing b
+0 files updated, 0 files merged, 1 files removed, 0 files unresolved
changeset: 0:c19d34741b0a
user: test
date: Thu Jan 1 00:00:00 1970 +0000
@@ -53,6 +55,7 @@ getting b
merging a
resolving a
file a: my b789fdd96dc2 other d730145abbf9 ancestor b789fdd96dc2
+1 files updated, 1 files merged, 0 files removed, 0 files unresolved
changeset: 1:1e71731e6fbb
tag: tip
user: test
@@ -113,6 +116,8 @@ file a: my d730145abbf9 other 13e0d5f949
merging b
resolving b
file b: my 1e88685f5dde other 61de8c7723ca ancestor 000000000000
+0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
changeset: 1:1e71731e6fbb
user: test
date: Thu Jan 1 00:00:00 1970 +0000
--- a/tests/test-update-reverse.out
+++ b/tests/test-update-reverse.out
@@ -47,6 +47,7 @@ remote created main
getting main
removing side1
removing side2
+1 files updated, 0 files merged, 2 files removed, 0 files unresolved
Should only show a main
a
main