merge with crew.

This commit is contained in:
Vadim Gelfer 2006-05-21 23:39:25 -07:00
commit 34b7a0d83b
14 changed files with 254 additions and 123 deletions

View File

@ -382,14 +382,27 @@ Handle frickin' frackin' gratuitous event-related incompatibilities."
(set-buffer hg-prev-buffer))
(let ((path (or default (buffer-file-name))))
(if (or (not path) current-prefix-arg)
(expand-file-name
(read-file-name (format "File, directory or pattern%s: "
(or prompt ""))
(and path (file-name-directory path))
nil nil
(and path (file-name-nondirectory path))
'hg-file-history))
path))))
(expand-file-name
(eval (list* 'read-file-name
(format "File, directory or pattern%s: "
(or prompt ""))
(and path (file-name-directory path))
nil nil
(and path (file-name-nondirectory path))
(if hg-running-xemacs
(cons (quote 'hg-file-history) nil)
nil))))
path))))
(defun hg-read-number (&optional prompt default)
"Read a integer value."
(save-excursion
(if (or (not default) current-prefix-arg)
(string-to-number
(eval (list* 'read-string
(or prompt "")
(if default (cons (format "%d" default) nil) nil))))
default)))
(defun hg-read-config ()
"Return an alist of (key . value) pairs of Mercurial config data.
@ -950,36 +963,55 @@ With a prefix argument, prompt for the path to forget."
(kill-entire-line))
(run-hooks 'hg-log-mode-hook))
(defun hg-log (path &optional rev1 rev2)
"Display the revision history of PATH, between REV1 and REV2.
REV1 defaults to hg-log-limit changes from the tip revision, while
REV2 defaults to the tip.
(defun hg-log (path &optional rev1 rev2 log-limit)
"Display the revision history of PATH.
History is displayed between REV1 and REV2.
Number of displayed changesets is limited to LOG-LIMIT.
REV1 defaults to the tip, while
REV2 defaults to `hg-rev-completion-limit' changes from the tip revision.
LOG-LIMIT defaults to `hg-log-limit'.
With a prefix argument, prompt for each parameter."
(interactive (list (hg-read-file-name " to log")
(hg-read-rev " to start with" "-1")
(hg-read-rev " to end with" (format "-%d" hg-log-limit))))
(hg-read-rev " to start with"
"tip")
(hg-read-rev " to end with"
(format "%d" (- hg-rev-completion-limit)))
(hg-read-number "Output limited to: "
hg-log-limit)))
(let ((a-path (hg-abbrev-file-name path))
(r1 (or rev1 (format "-%d" hg-log-limit)))
(r2 (or rev2 rev1 "-1")))
(r1 (or rev1 (format "-%d" hg-rev-completion-limit)))
(r2 (or rev2 rev1 "tip"))
(limit (format "%d" (or log-limit hg-log-limit))))
(hg-view-output ((if (equal r1 r2)
(format "Mercurial: Log of rev %s of %s" rev1 a-path)
(format "Mercurial: Log from rev %s to %s of %s"
r1 r2 a-path)))
(let ((revs (format "%s:%s" r1 r2)))
(if (> (length path) (length (hg-root path)))
(call-process (hg-binary) nil t nil "log" "-r" revs path)
(call-process (hg-binary) nil t nil "log" "-r" revs)))
(format "Mercurial: Log of rev %s of %s" rev1 a-path)
(format
"Mercurial: at most %s log(s) from rev %s to %s of %s"
limit r1 r2 a-path)))
(eval (list* 'call-process (hg-binary) nil t nil
"log"
"-r" (format "%s:%s" r1 r2)
"-l" limit
(if (> (length path) (length (hg-root path)))
(cons path nil)
nil)))
(hg-log-mode))))
(defun hg-log-repo (path &optional rev1 rev2)
(defun hg-log-repo (path &optional rev1 rev2 log-limit)
"Display the revision history of the repository containing PATH.
History is displayed between REV1, which defaults to the tip, and
REV2, which defaults to the initial revision.
Variable hg-log-limit controls the number of log entries displayed."
History is displayed between REV1 and REV2.
Number of displayed changesets is limited to LOG-LIMIT,
REV1 defaults to the tip, while
REV2 defaults to `hg-rev-completion-limit' changes from the tip revision.
LOG-LIMIT defaults to `hg-log-limit'.
With a prefix argument, prompt for each parameter."
(interactive (list (hg-read-file-name " to log")
(hg-read-rev " to start with" "tip")
(hg-read-rev " to end with" (format "-%d" hg-log-limit))))
(hg-log (hg-root path) rev1 rev2))
(hg-read-rev " to start with"
"tip")
(hg-read-rev " to end with"
(format "%d" (- hg-rev-completion-limit)))
(hg-read-number "Output limited to: "
hg-log-limit)))
(hg-log (hg-root path) rev1 rev2 log-limit))
(defun hg-outgoing (&optional repo)
"Display changesets present locally that are not present in REPO."

View File

@ -90,8 +90,14 @@ hg
other Mercurial commands should work fine for you.</p>
<h1>Configuration notes</h1>
<p>The default editor is 'vi'. You can set the EDITOR environment variable
(or HGEDITOR) to specify your preference. </p>
<p>The default editor for commit messages is 'vi'. You can set the EDITOR
(or HGEDITOR) environment variable to specify your preference or set it in
mercurial.ini:</p>
<pre>
[ui]
editor = whatever
</pre>
<h1>Reporting problems</h1>

View File

@ -36,11 +36,14 @@ installed.
files override per-installation options.
(Unix) $HOME/.hgrc::
(Windows) C:\Documents and Settings\USERNAME\Mercurial.ini
(Windows) C:\Documents and Settings\USERNAME\Mercurial.ini::
(Windows) $HOME\Mercurial.ini::
Per-user configuration file, for the user running Mercurial.
Options in this file apply to all Mercurial commands executed by
any user in any directory. Options in this file override
per-installation and per-system options.
On Windows system, one of these is chosen exclusively according
to definition of HOME environment variable.
(Unix, Windows) <repo>/.hg/hgrc::
Per-repository configuration options that only apply in a

View File

@ -99,7 +99,9 @@ class notifier(object):
def __init__(self, ui, repo, hooktype):
self.ui = ui
self.ui.readconfig(self.ui.config('notify', 'config'))
cfg = self.ui.config('notify', 'config')
if cfg:
self.ui.readconfig(cfg)
self.repo = repo
self.stripcount = int(self.ui.config('notify', 'strip', 0))
self.root = self.strip(self.repo.root)
@ -123,7 +125,7 @@ class notifier(object):
path = util.pconvert(path)
count = self.stripcount
while path and count >= 0:
while count > 0:
c = path.find('/')
if c == -1:
break
@ -225,6 +227,8 @@ class notifier(object):
if not msgtext.endswith('\n'):
self.ui.write('\n')
else:
self.ui.status(_('notify: sending %d subscribers %d changes\n') %
(len(self.subs), count))
mail = self.ui.sendmail()
mail.sendmail(templater.email(msg['From']), self.subs, msgtext)
@ -250,7 +254,12 @@ def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
if used as changegroup hook, send one email for all changesets in
changegroup. else send one email per changeset.'''
n = notifier(ui, repo, hooktype)
if not n.subs or n.skipsource(source):
if not n.subs:
ui.debug(_('notify: no subscribers to this repo\n'))
return
if n.skipsource(source):
ui.debug(_('notify: changes have source "%s" - skipping\n') %
source)
return
node = bin(node)
if hooktype == 'changegroup':

View File

@ -519,7 +519,8 @@ class hgweb(object):
mnode = hex(mn)
mf = man.read(mn)
rev = man.rev(mn)
node = self.repo.changelog.node(rev)
changerev = man.linkrev(mn)
node = self.repo.changelog.node(changerev)
mff = man.readflags(mn)
files = {}

View File

@ -166,37 +166,44 @@ class localrepository(object):
return
s = l.split(" ", 1)
if len(s) != 2:
self.ui.warn(_("%s: ignoring invalid tag\n") % context)
self.ui.warn(_("%s: cannot parse entry\n") % context)
return
node, key = s
key = key.strip()
try:
bin_n = bin(node)
except TypeError:
self.ui.warn(_("%s: ignoring invalid tag\n") % context)
self.ui.warn(_("%s: node '%s' is not well formed\n") %
(context, node))
return
if bin_n not in self.changelog.nodemap:
self.ui.warn(_("%s: ignoring invalid tag\n") % context)
self.ui.warn(_("%s: tag '%s' refers to unknown node\n") %
(context, key))
return
self.tagscache[key.strip()] = bin_n
self.tagscache[key] = bin_n
# read each head of the tags file, ending with the tip
# read the tags file from each head, ending with the tip,
# and add each tag found to the map, with "newer" ones
# taking precedence
heads = self.heads()
heads.reverse()
fl = self.file(".hgtags")
h = fl.heads()
h.reverse()
for r in h:
for node in heads:
change = self.changelog.read(node)
rev = self.changelog.rev(node)
fn, ff = self.manifest.find(change[0], '.hgtags')
if fn is None: continue
count = 0
for l in fl.read(r).splitlines():
for l in fl.read(fn).splitlines():
count += 1
parsetag(l, ".hgtags:%d" % count)
parsetag(l, _(".hgtags (rev %d:%s), line %d") %
(rev, short(node), count))
try:
f = self.opener("localtags")
count = 0
for l in f:
count += 1
parsetag(l, "localtags:%d" % count)
parsetag(l, _("localtags, line %d") % count)
except IOError:
pass

View File

@ -43,48 +43,61 @@ class manifest(revlog):
def diff(self, a, b):
return mdiff.textdiff(str(a), str(b))
def _search(self, m, s, lo=0, hi=None):
'''return a tuple (start, end) that says where to find s within m.
If the string is found m[start:end] are the line containing
that string. If start == end the string was not found and
they indicate the proper sorted insertion point. This was
taken from bisect_left, and modified to find line start/end as
it goes along.
m should be a buffer or a string
s is a string'''
def advance(i, c):
while i < lenm and m[i] != c:
i += 1
return i
lenm = len(m)
if not hi:
hi = lenm
while lo < hi:
mid = (lo + hi) // 2
start = mid
while start > 0 and m[start-1] != '\n':
start -= 1
end = advance(start, '\0')
if m[start:end] < s:
# we know that after the null there are 40 bytes of sha1
# this translates to the bisect lo = mid + 1
lo = advance(end + 40, '\n') + 1
else:
# this translates to the bisect hi = mid
hi = start
end = advance(lo, '\0')
found = m[lo:end]
if cmp(s, found) == 0:
# we know that after the null there are 40 bytes of sha1
end = advance(end + 40, '\n')
return (lo, end+1)
else:
return (lo, lo)
def find(self, node, f):
'''look up entry for a single file efficiently.
return (node, flag) pair if found, (None, None) if not.'''
if self.mapcache and node == self.mapcache[0]:
return self.mapcache[1].get(f), self.mapcache[2].get(f)
text = self.revision(node)
start, end = self._search(text, f)
if start == end:
return None, None
l = text[start:end]
f, n = l.split('\0')
return bin(n[:40]), n[40:-1] == 'x'
def add(self, map, flags, transaction, link, p1=None, p2=None,
changed=None):
# returns a tuple (start, end). If the string is found
# m[start:end] are the line containing that string. If start == end
# the string was not found and they indicate the proper sorted
# insertion point. This was taken from bisect_left, and modified
# to find line start/end as it goes along.
#
# m should be a buffer or a string
# s is a string
#
def manifestsearch(m, s, lo=0, hi=None):
def advance(i, c):
while i < lenm and m[i] != c:
i += 1
return i
lenm = len(m)
if not hi:
hi = lenm
while lo < hi:
mid = (lo + hi) // 2
start = mid
while start > 0 and m[start-1] != '\n':
start -= 1
end = advance(start, '\0')
if m[start:end] < s:
# we know that after the null there are 40 bytes of sha1
# this translates to the bisect lo = mid + 1
lo = advance(end + 40, '\n') + 1
else:
# this translates to the bisect hi = mid
hi = start
end = advance(lo, '\0')
found = m[lo:end]
if cmp(s, found) == 0:
# we know that after the null there are 40 bytes of sha1
end = advance(end + 40, '\n')
return (lo, end+1)
else:
return (lo, lo)
# apply the changes collected during the bisect loop to our addlist
# return a delta suitable for addrevision
def addlistdelta(addlist, x):
@ -137,7 +150,7 @@ class manifest(revlog):
for w in work:
f = w[0]
# bs will either be the index of the item or the insert point
start, end = manifestsearch(addbuf, f, start)
start, end = self._search(addbuf, f, start)
if w[1] == 0:
l = "%s\000%s%s\n" % (f, hex(map[f]),
flags[f] and "x" or '')

View File

@ -1,5 +1,6 @@
# 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 Volker Kleinfeld <Volker.Kleinfeld@gmx.de>
#
@ -8,25 +9,58 @@
import glob
import os
import sys
import demandload
import ihooks
import types
import string
requiredmodules = {} # Will contain the modules imported by demandload
# 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 """
""" fake demandload function that collects the required modules
foo import foo
foo bar import foo, 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 m in modules.split():
mod = None
try:
module, submodules = m.split(':')
submodules = submodules.split(',')
module, fromlist = m.split(':')
fromlist = fromlist.split(',')
except:
module = m
submodules = []
mod = __import__(module, scope, scope, submodules)
scope[module] = mod
requiredmodules[mod.__name__] = 1
fromlist = []
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
scope[mn] = 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
def getmodules(libpath,packagename):
def scan(libpath,packagename):
""" helper for finding all required modules of package <packagename> """
# Use the package in the build directory
libpath = os.path.abspath(libpath)
@ -45,8 +79,6 @@ def getmodules(libpath,packagename):
pymodulefiles = glob.glob('*.py')
extmodulefiles = glob.glob('*.pyd')
os.chdir(cwd)
# Install a fake demandload module
sys.modules['mercurial.demandload'] = sys.modules['mercurial.packagescan']
# Import all python modules and by that run the fake demandload
for m in pymodulefiles:
if m == '__init__.py': continue
@ -62,8 +94,9 @@ def getmodules(libpath,packagename):
fullname = packagename+'.'+mname
__import__(fullname,tmp,tmp)
requiredmodules[fullname] = 1
includes = requiredmodules.keys()
return includes
def getmodules():
return requiredmodules.keys()
def importfrom(filename):
"""

View File

@ -94,7 +94,7 @@ def patch(strip, patchname, ui):
"""apply the patch <patchname> to the working directory.
a list of patched files is returned"""
patcher = find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
fp = os.popen('"%s" -p%d < "%s"' % (patcher, strip, patchname))
fp = os.popen('%s -p%d < "%s"' % (patcher, strip, patchname))
files = {}
for line in fp:
line = line.rstrip()

View File

@ -194,7 +194,7 @@ def user_rcpath():
# We are on win < nt: fetch the APPDATA directory location and use
# the parent directory as the user home dir.
appdir = shell.SHGetPathFromIDList(
qshell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
userdir = os.path.dirname(appdir)
return os.path.join(userdir, 'mercurial.ini')

View File

@ -13,6 +13,8 @@ import glob
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
# py2exe needs to be installed to work
@ -36,7 +38,6 @@ try:
# 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 depdent modules.
import mercurial.packagescan
from py2exe.build_exe import py2exe as build_exe
class py2exe_for_demandload(build_exe):
@ -54,12 +55,10 @@ try:
self.includes = []
else:
self.includes = self.includes.split(',')
self.includes += mercurial.packagescan.getmodules(self.build_lib,
'mercurial')
self.includes += mercurial.packagescan.getmodules(self.build_lib,
'mercurial/hgweb')
self.includes += mercurial.packagescan.getmodules(self.build_lib,
'hgext')
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

View File

@ -62,7 +62,7 @@ echo %% --time
hg --cwd a --time tip 2>&1 | grep '^Time:' | sed 's/[0-9][0-9]*/x/g'
echo %% --version
hg --version -q | sed 's/version [a-f0-9+]*/version xxx/'
hg --version -q | sed 's/version \([a-f0-9+]*\|unknown\)/version xxx/'
echo %% -h/--help
hg -h

View File

@ -32,12 +32,31 @@ hg id
hg status
hg commit -m "merge" -d "1000000 0"
# create fake head, make sure tag not visible afterwards
cp .hgtags tags
hg tag -d "1000000 0" last
hg rm .hgtags
hg commit -m "remove" -d "1000000 0"
mv tags .hgtags
hg add .hgtags
hg commit -m "readd" -d "1000000 0"
hg tags
# invalid tags
echo "spam" >> .hgtags
echo >> .hgtags
echo "foo bar" >> .hgtags
echo "$T invalid" | sed "s/..../a5a5/" >> .hg/localtags
hg commit -m "tags" -d "1000000 0"
# report tag parse error on other head
hg up 3
echo 'x y' >> .hgtags
hg commit -m "head" -d "1000000 0"
hg tags
hg tip

View File

@ -16,17 +16,26 @@ M a
(branch merge, don't forget to commit)
8216907a933d+8a3ca90d111d+ tip
M .hgtags
.hgtags:2: ignoring invalid tag
.hgtags:4: ignoring invalid tag
localtags:1: ignoring invalid tag
tip 4:fd868a874787a7b5af31e1675666ce691c803035
tip 6:c6af9d771a81bb9c7f267ec03491224a9f8ba1cd
first 0:0acdaf8983679e0aac16e811534eb49d7ee1f2b4
changeset: 4:fd868a874787
.hgtags:2: ignoring invalid tag
.hgtags:4: ignoring invalid tag
localtags:1: ignoring invalid tag
.hgtags (rev 7:39bba1bbbc4c), line 2: cannot parse entry
.hgtags (rev 7:39bba1bbbc4c), line 4: node 'foo' is not well formed
localtags, line 1: tag 'invalid' refers to unknown node
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
.hgtags (rev 7:39bba1bbbc4c), line 2: cannot parse entry
.hgtags (rev 7:39bba1bbbc4c), line 4: node 'foo' is not well formed
.hgtags (rev 8:4ca6f1b1a68c), line 2: node 'x' is not well formed
localtags, line 1: tag 'invalid' refers to unknown node
tip 8:4ca6f1b1a68c77be687a03aaeb1614671ba59b20
first 0:0acdaf8983679e0aac16e811534eb49d7ee1f2b4
changeset: 8:4ca6f1b1a68c
.hgtags (rev 7:39bba1bbbc4c), line 2: cannot parse entry
.hgtags (rev 7:39bba1bbbc4c), line 4: node 'foo' is not well formed
.hgtags (rev 8:4ca6f1b1a68c), line 2: node 'x' is not well formed
localtags, line 1: tag 'invalid' refers to unknown node
tag: tip
parent: 3:b2ef3841386b
user: test
date: Mon Jan 12 13:46:40 1970 +0000
summary: tags
summary: head