From 1d8afd83c1d83ee497bf4f5b05c976add5e2ed1a Mon Sep 17 00:00:00 2001 From: Thomas Arendsen Hein Date: Fri, 19 May 2006 06:10:59 +0200 Subject: [PATCH 01/13] Fixed typo (qshell instead of shell) in win98 code (see issue244). --- mercurial/util_win32.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mercurial/util_win32.py b/mercurial/util_win32.py index 64f377a32b..fd5e3d6a60 100644 --- a/mercurial/util_win32.py +++ b/mercurial/util_win32.py @@ -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') From 138d9f83fca5ccf73a00371b6ec66fa96bd18d7d Mon Sep 17 00:00:00 2001 From: Volker Kleinfeld Date: Thu, 18 May 2006 22:35:41 -0700 Subject: [PATCH 02/13] Remove quotes from patch command. When the gpatch fix for solaris was introduced in b67447b909f3 the patch command was "". For some strange reason windows 2000 is not happy with those quotes when given in os.popen. --- mercurial/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mercurial/util.py b/mercurial/util.py index a32bbd4040..1751f5683f 100644 --- a/mercurial/util.py +++ b/mercurial/util.py @@ -94,7 +94,7 @@ def patch(strip, patchname, ui): """apply the patch 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() From b1ae07c169813f68fe90ed0bfd0eead64e038c6d Mon Sep 17 00:00:00 2001 From: FUJIWARA Katsunori Date: Thu, 18 May 2006 22:43:09 -0700 Subject: [PATCH 03/13] Emacs: adapt read-file-name invocation for (non-X)Emacs 21.4. this patch deters hg-read-file-name from passing hg-file-history to read-file-name as 6th parameter in non-X Emacs environment. --- contrib/mercurial.el | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/contrib/mercurial.el b/contrib/mercurial.el index 8976206915..c90a7bc28c 100644 --- a/contrib/mercurial.el +++ b/contrib/mercurial.el @@ -382,14 +382,17 @@ 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-config () "Return an alist of (key . value) pairs of Mercurial config data. From db4f956aa033f814683753237ad6c901b945c2d8 Mon Sep 17 00:00:00 2001 From: FUJIWARA Katsunori Date: Thu, 18 May 2006 22:44:36 -0700 Subject: [PATCH 04/13] Emacs: separate limitations of revision range and shown changesets. For revision range limitation, use "-r" opt with range notation at "hg log" invocation, and use hg-rev-completion-limit as default value. For shown changesets limitation, use "-l" opt at "hg log" invocation, and use hg-log-limit as default value. --- contrib/mercurial.el | 73 +++++++++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 22 deletions(-) diff --git a/contrib/mercurial.el b/contrib/mercurial.el index 8976206915..55c8a1d2ca 100644 --- a/contrib/mercurial.el +++ b/contrib/mercurial.el @@ -391,6 +391,16 @@ Handle frickin' frackin' gratuitous event-related incompatibilities." 'hg-file-history)) 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. Each key is of the form (section . name)." @@ -950,36 +960,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." From 421983dd067db34471bf683d2e0d84495d13677c Mon Sep 17 00:00:00 2001 From: FUJIWARA Katsunori Date: Thu, 18 May 2006 22:52:19 -0700 Subject: [PATCH 05/13] If HOME is defined on Windows, Mercurial uses it. Document this. --- doc/hgrc.5.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/hgrc.5.txt b/doc/hgrc.5.txt index c2917bb10a..f6fe90319b 100644 --- a/doc/hgrc.5.txt +++ b/doc/hgrc.5.txt @@ -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) /.hg/hgrc:: Per-repository configuration options that only apply in a From 89a3f5af782b4214255df2880aba22646785c5d1 Mon Sep 17 00:00:00 2001 From: Vadim Gelfer Date: Thu, 18 May 2006 23:02:24 -0700 Subject: [PATCH 06/13] test-globalopts: make sed expression better. --- tests/test-globalopts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-globalopts b/tests/test-globalopts index 994ecf0add..6d66f72044 100755 --- a/tests/test-globalopts +++ b/tests/test-globalopts @@ -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 From 5eb540c338a25dba2ec1415769752c5c09c2148d Mon Sep 17 00:00:00 2001 From: Vadim Gelfer Date: Thu, 18 May 2006 23:31:12 -0700 Subject: [PATCH 07/13] fix parsing of tags. make parse errors useful. add new tag tests. old code read every head of .hgtags. delete and recreate of .hgtags gave new head, but if error in deleted rev, .hgtags had error messages every time it was parsed. this was very hard to fix, because deleted revs hard to get back and update, needed merges too. new code reads .hgtags on every head. advantage is if parse error happens with new code, is possible to fix them by editing .hgtags on a head and committing. NOTE: new code uses binary search of manifest of each head to be fast, but still much slower than old code. best thing would be to have delete record stored in filelog so we never touch manifest. could find live heads directly from filelog. this is more work than i want now. new tests check for parse of tags on different heads, and inaccessible heads created by delete and recreate of .hgtags. --- mercurial/localrepo.py | 31 ++++++++------ mercurial/manifest.py | 95 ++++++++++++++++++++++++------------------ tests/test-tags | 19 +++++++++ tests/test-tags.out | 27 ++++++++---- 4 files changed, 110 insertions(+), 62 deletions(-) diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py index d8ed135654..c8c04c0f31 100644 --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -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 diff --git a/mercurial/manifest.py b/mercurial/manifest.py index a2b097db06..23e32ec417 100644 --- a/mercurial/manifest.py +++ b/mercurial/manifest.py @@ -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 '') diff --git a/tests/test-tags b/tests/test-tags index 35672133e6..6c283bfd42 100755 --- a/tests/test-tags +++ b/tests/test-tags @@ -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 diff --git a/tests/test-tags.out b/tests/test-tags.out index 7b7d68f1fa..c635da6b19 100644 --- a/tests/test-tags.out +++ b/tests/test-tags.out @@ -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 From a743462e0da8db5e1157d5069258a6bd81f05e56 Mon Sep 17 00:00:00 2001 From: Lee Cantey Date: Thu, 18 May 2006 11:48:03 -0700 Subject: [PATCH 08/13] Update configuration note with mercurial.ini change from Thomas --- contrib/win32/ReadMe.html | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/contrib/win32/ReadMe.html b/contrib/win32/ReadMe.html index a497b12e7a..077f717858 100644 --- a/contrib/win32/ReadMe.html +++ b/contrib/win32/ReadMe.html @@ -90,8 +90,14 @@ hg other Mercurial commands should work fine for you.

Configuration notes

-

The default editor is 'vi'. You can set the EDITOR environment variable - (or HGEDITOR) to specify your preference.

+

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:

+
+[ui]
+editor = whatever
+
+

Reporting problems

From cbdd4c99a6c93aa073a4131fdeb6f788a4b3c0b7 Mon Sep 17 00:00:00 2001 From: Volker Kleinfeld Date: Fri, 19 May 2006 08:51:58 -0700 Subject: [PATCH 09/13] packagescan: handle demandload module naming changes. --- mercurial/packagescan.py | 41 +++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/mercurial/packagescan.py b/mercurial/packagescan.py index 881c9f9174..d00abc76fd 100644 --- a/mercurial/packagescan.py +++ b/mercurial/packagescan.py @@ -10,21 +10,48 @@ import os import sys import demandload import ihooks +import types +import string requiredmodules = {} # Will contain the modules imported by demandload 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): """ helper for finding all required modules of package """ From 271afc71fc0a17d8f361dea89d7ba0ec62d6c0b4 Mon Sep 17 00:00:00 2001 From: Volker Kleinfeld Date: Fri, 19 May 2006 08:54:28 -0700 Subject: [PATCH 10/13] setup.py: install packagescan before any mercurial modules is imported Further the installation of packagescan over demandload is moved to the packagescan module. I added as well few more comments in the packagescan module to avoid the wrong use of package scan in the future. Reason: mercurial.packagescan acts as fake mercurial.demandload during a py2exe run. Unfortunatly the import of mercurial.version in setup.py is done before mercurial.packagescan is installed. This results in few imports without mercurial.packagescan in charge and therefore not all dependend modules are detected when running mercurial.packagescan.getmodules later e.g. winerror is missed. --- mercurial/packagescan.py | 20 +++++++++++++------- setup.py | 10 +++++----- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/mercurial/packagescan.py b/mercurial/packagescan.py index 881c9f9174..ee308a204f 100644 --- a/mercurial/packagescan.py +++ b/mercurial/packagescan.py @@ -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 # @@ -8,10 +9,16 @@ import glob import os import sys -import demandload import ihooks -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 """ for m in modules.split(): @@ -26,7 +33,7 @@ def demandload(scope, modules): scope[module] = mod requiredmodules[mod.__name__] = 1 -def getmodules(libpath,packagename): +def scan(libpath,packagename): """ helper for finding all required modules of package """ # Use the package in the build directory libpath = os.path.abspath(libpath) @@ -45,8 +52,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 +67,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): """ diff --git a/setup.py b/setup.py index b96a74d3c1..827352cc1b 100644 --- a/setup.py +++ b/setup.py @@ -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,10 +55,9 @@ 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, - 'hgext') + mercurial.packagescan.scan(self.build_lib,'mercurial') + mercurial.packagescan.scan(self.build_lib,'hgext') + self.includes += mercurial.packagescan.getmodules() build_exe.finalize_options(self) except ImportError: py2exe_for_demandload = None From be9056ad56ea7f5221777e0bc997d0f787de3cc6 Mon Sep 17 00:00:00 2001 From: Vadim Gelfer Date: Fri, 19 May 2006 14:57:45 -0700 Subject: [PATCH 11/13] notify: fix off by one error. --- hgext/notify.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hgext/notify.py b/hgext/notify.py index 4fe084f1bd..0c567addb6 100644 --- a/hgext/notify.py +++ b/hgext/notify.py @@ -123,7 +123,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 From 8b1ff2c942fdce9f9bdbd6dfaeb6ac82b39af209 Mon Sep 17 00:00:00 2001 From: "Alexis S. L. Carvalho" Date: Sat, 20 May 2006 15:34:19 -0300 Subject: [PATCH 12/13] hgweb.manifest: revno of manifest and changelog aren't always the same In the v4l-dvb repo, the manifest revno and the changelog revno are not in sync. This happened because the same patch was applied to the same revision in two different branches, resulting in the same manifest text, with the same parents and so the first revision was reused. Since hgweb.manifest was assuming the revnos of the manifest and of the changelog were always the same, clicking on manifest -> bz2 in the v4l-dvb site would download the wrong revision. Use the linkrev to go from manifest revision to changelog revision. This still won't be perfect since the page will still talk about "manifest for changeset XYZ", where XYZ was the first changeset to have this manifest, which is not necessarily the same changeset that the user clicked to get to this page - but at least the contents will be the same. --- mercurial/hgweb/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mercurial/hgweb/__init__.py b/mercurial/hgweb/__init__.py index 83c2bdfe84..c504cd4d12 100644 --- a/mercurial/hgweb/__init__.py +++ b/mercurial/hgweb/__init__.py @@ -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 = {} From 10c73bbd93093e2b3f7e009bac0256736827739b Mon Sep 17 00:00:00 2001 From: Vadim Gelfer Date: Sat, 20 May 2006 12:52:02 -0700 Subject: [PATCH 13/13] notify: add debug output. do not fail if no config file. use --debug to see debug output. --- hgext/notify.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/hgext/notify.py b/hgext/notify.py index 0c567addb6..f669b79563 100644 --- a/hgext/notify.py +++ b/hgext/notify.py @@ -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) @@ -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':