##// END OF EJS Templates
merge with -stable
Benoit Boissinot -
r4029:9210fba0 merge default
parent child Browse files
Show More
@@ -0,0 +1,115 b''
1 # demandimport.py - global demand-loading of modules for Mercurial
2 #
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 #
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7
8 '''
9 demandimport - automatic demandloading of modules
10
11 To enable this module, do:
12
13 import demandimport; demandimport.enable()
14
15 Imports of the following forms will be demand-loaded:
16
17 import a, b.c
18 import a.b as c
19 from a import b,c # a will be loaded immediately
20
21 These imports will not be delayed:
22
23 from a import *
24 b = __import__(a)
25 '''
26
27 _origimport = __import__
28
29 class _demandmod(object):
30 """module demand-loader and proxy"""
31 def __init__(self, name, globals, locals):
32 if '.' in name:
33 head, rest = name.split('.', 1)
34 after = [rest]
35 else:
36 head = name
37 after = []
38 object.__setattr__(self, "_data", (head, globals, locals, after))
39 object.__setattr__(self, "_module", None)
40 def _extend(self, name):
41 """add to the list of submodules to load"""
42 self._data[3].append(name)
43 def _load(self):
44 if not self._module:
45 head, globals, locals, after = self._data
46 mod = _origimport(head, globals, locals)
47 # load submodules
48 def subload(mod, p):
49 h, t = p, None
50 if '.' in p:
51 h, t = p.split('.', 1)
52 if not hasattr(mod, h):
53 setattr(mod, h, _demandmod(p, mod.__dict__, mod.__dict__))
54 elif t:
55 subload(getattr(mod, h), t)
56
57 for x in after:
58 subload(mod, x)
59
60 # are we in the locals dictionary still?
61 if locals and locals.get(head) == self:
62 locals[head] = mod
63 object.__setattr__(self, "_module", mod)
64 def __repr__(self):
65 return "<unloaded module '%s'>" % self._data[0]
66 def __call__(self, *args, **kwargs):
67 raise TypeError("'unloaded module' object is not callable")
68 def __getattribute__(self, attr):
69 if attr in ('_data', '_extend', '_load', '_module'):
70 return object.__getattribute__(self, attr)
71 self._load()
72 return getattr(self._module, attr)
73 def __setattr__(self, attr, val):
74 self._load()
75 setattr(self._module, attr, val)
76
77 def _demandimport(name, globals=None, locals=None, fromlist=None):
78 if not locals or name in ignore or fromlist == ('*',):
79 # these cases we can't really delay
80 return _origimport(name, globals, locals, fromlist)
81 elif not fromlist:
82 # import a [as b]
83 if '.' in name: # a.b
84 base, rest = name.split('.', 1)
85 # email.__init__ loading email.mime
86 if globals and globals.get('__name__', None) == base:
87 return _origimport(name, globals, locals, fromlist)
88 # if a is already demand-loaded, add b to its submodule list
89 if base in locals:
90 if isinstance(locals[base], _demandmod):
91 locals[base]._extend(rest)
92 return locals[base]
93 return _demandmod(name, globals, locals)
94 else:
95 # from a import b,c,d
96 mod = _origimport(name, globals, locals)
97 # recurse down the module chain
98 for comp in name.split('.')[1:]:
99 mod = getattr(mod, comp)
100 for x in fromlist:
101 # set requested submodules for demand load
102 if not(hasattr(mod, x)):
103 setattr(mod, x, _demandmod(x, mod.__dict__, mod.__dict__))
104 return mod
105
106 ignore = ['_hashlib', 'fcntl', 'win32com.gen_py']
107
108 def enable():
109 "enable global demand-loading of modules"
110 __builtins__["__import__"] = _demandimport
111
112 def disable():
113 "disable global demand-loading of modules"
114 __builtins__["__import__"] = _origimport
115
@@ -0,0 +1,2 b''
1 #header#
2 #entries%indexentry#
@@ -0,0 +1,3 b''
1 {header}
2 {dentries%manifestdirentry}{fentries%manifestfileentry}
3 {footer}
@@ -0,0 +1,13 b''
1 #!/bin/sh
2
3 hg init test
4 cd test
5 mkdir da
6 echo foo > da/foo
7 echo foo > foo
8 hg ci -Ambase -d '0 0'
9 hg serve -p 20060 -d --pid-file=hg.pid
10 echo % manifest
11 ("$TESTDIR/get-with-headers.py" localhost:20060 '/file/tip/?style=raw')
12 ("$TESTDIR/get-with-headers.py" localhost:20060 '/file/tip/da?style=raw')
13 kill `cat hg.pid`
@@ -0,0 +1,16 b''
1 adding da/foo
2 adding foo
3 % manifest
4 200 Script output follows
5
6
7 drwxr-xr-x da
8 -rw-r--r-- 4 foo
9
10
11 200 Script output follows
12
13
14 -rw-r--r-- 4 foo
15
16
@@ -67,10 +67,10 b' dist-notests:\tdoc MANIFEST'
67 TAR_OPTIONS="--owner=root --group=root --mode=u+w,go-w,a+rX-s" $(PYTHON) setup.py -q sdist
67 TAR_OPTIONS="--owner=root --group=root --mode=u+w,go-w,a+rX-s" $(PYTHON) setup.py -q sdist
68
68
69 tests:
69 tests:
70 cd tests && $(PYTHON) run-tests.py
70 cd tests && $(PYTHON) run-tests.py $(TESTFLAGS)
71
71
72 test-%:
72 test-%:
73 cd tests && $(PYTHON) run-tests.py $@
73 cd tests && $(PYTHON) run-tests.py $(TESTFLAGS) $@
74
74
75
75
76 .PHONY: help all local build doc clean install install-bin install-doc \
76 .PHONY: help all local build doc clean install install-bin install-doc \
@@ -1,99 +1,10 b''
1 MERCURIAL QUICK-START
1 Basic install:
2
3 Setting up Mercurial:
4
5 Note: some distributions fails to include bits of distutils by
6 default, you'll need python-dev to install. You'll also need a C
7 compiler and a 3-way merge tool like merge, tkdiff, or kdiff3.
8
9 First, unpack the source:
10
11 $ tar xvzf mercurial-<ver>.tar.gz
12 $ cd mercurial-<ver>
13
14 When installing, change python to python2.3 or python2.4 if 2.2 is the
15 default on your system.
16
17 To install system-wide:
18
19 $ python setup.py install --force
20
21 To install in your home directory (~/bin and ~/lib, actually), run:
22
23 $ python setup.py install --home=${HOME} --force
24 $ export PYTHONPATH=${HOME}/lib/python # (or lib64/ on some systems)
25 $ export PATH=${HOME}/bin:$PATH # add these to your .bashrc
26
27 And finally:
28
29 $ hg debuginstall # run some basic tests
30 $ hg # show help
31
32 If you get complaints about missing modules, you probably haven't set
33 PYTHONPATH correctly.
34
35 Setting up a Mercurial project:
36
37 $ hg init project # creates project directory
38 $ cd project
39 # copy files in, edit them
40 $ hg add # add all unknown files
41 $ hg commit # commit all changes, edit changelog entry
42
43 Mercurial will look for a file named .hgignore in the root of your
44 repository which contains a set of regular expressions to ignore in
45 file paths.
46
47 Branching and merging:
48
2
49 $ hg clone project project-work # create a new branch
3 $ make # see install targets
50 $ cd project-work
4 $ make install # do a system-wide install
51 $ <make changes>
5 $ hg debuginstall # sanity-check setup
52 $ hg commit
6 $ hg # see help
53 $ cd ../project
54 $ hg pull ../project-work # pull changesets from project-work
55 $ hg merge # merge the new tip from project-work into
56 # our working directory
57 $ hg commit # commit the result of the merge
58
59 Importing patches:
60
61 Simple:
62 $ patch < ../p/foo.patch
63 $ hg commit -A
64
65 Fast:
66 $ cat ../p/patchlist | xargs hg import -p1 -b ../p
67
68 Exporting a patch:
69
70 (make changes)
71 $ hg commit
72 $ hg export tip > foo.patch # export latest change
73
7
74 Network support:
8 See http://www.selenic.com/mercurial/ for detailed installation
75
9 instructions, platform-specific notes, and Mercurial user information.
76 # pull from the primary Mercurial repo
77 foo$ hg clone http://selenic.com/hg/
78 foo$ cd hg
79
80 # make your current repo available via http://server:8000/
81 foo$ hg serve
82
83 # pushing and pulling changes to/from a remote repo with SSH
84 foo$ hg push ssh://user@example.com/my/repository
85 foo$ hg pull ssh://user@example.com//home/somebody/his/repository
86
10
87 # merge changes from a remote machine (e.g. running 'hg serve')
88 bar$ hg pull http://foo:8000/
89 bar$ hg merge # merge changes into your working directory
90 bar$ hg commit # commit merge in to your local repository
91
92 # Set up a CGI server on your webserver
93 foo$ cp hgweb.cgi ~/public_html/hg/index.cgi
94 foo$ emacs ~/public_html/hg/index.cgi # adjust the defaults
95
96 For more info:
97
98 Documentation in doc/
99 Mercurial website at http://selenic.com/mercurial
@@ -145,6 +145,7 b' shopt -s extglob'
145 # global options
145 # global options
146 case "$prev" in
146 case "$prev" in
147 -R|--repository)
147 -R|--repository)
148 _hg_paths
148 _hg_repos
149 _hg_repos
149 return
150 return
150 ;;
151 ;;
@@ -477,3 +478,25 b' complete -o bashdefault -o default -F _h'
477 {
478 {
478 _hg_tags
479 _hg_tags
479 }
480 }
481
482
483 # transplant
484 _hg_cmd_transplant()
485 {
486 case "$prev" in
487 -s|--source)
488 _hg_paths
489 _hg_repos
490 return
491 ;;
492 --filter)
493 # standard filename completion
494 return
495 ;;
496 esac
497
498 # all other transplant options values and command parameters are revisions
499 _hg_tags
500 return
501 }
502
@@ -11,10 +11,9 b''
11 #
11 #
12 # <alias email> <actual email>
12 # <alias email> <actual email>
13
13
14 from mercurial.demandload import *
14 import sys
15 from mercurial.i18n import gettext as _
15 from mercurial.i18n import gettext as _
16 demandload(globals(), 'time sys signal os')
16 from mercurial import hg, mdiff, cmdutil, ui, util, templater, node
17 demandload(globals(), 'mercurial:hg,mdiff,fancyopts,cmdutil,ui,util,templater,node')
18
17
19 def __gather(ui, repo, node1, node2):
18 def __gather(ui, repo, node1, node2):
20 def dirtywork(f, mmap1, mmap2):
19 def dirtywork(f, mmap1, mmap2):
@@ -3,29 +3,49 b''
3 # This is a generalized framework for converting between SCM
3 # This is a generalized framework for converting between SCM
4 # repository formats.
4 # repository formats.
5 #
5 #
6 # In its current form, it's hardcoded to convert incrementally between
7 # git and Mercurial.
8 #
9 # To use, run:
6 # To use, run:
10 #
7 #
11 # convert-repo <git-dir> <hg-dir> <mapfile>
8 # convert-repo <source> [<dest> [<mapfile>]]
12 #
9 #
13 # (don't forget to create the <hg-dir> repository beforehand)
10 # Currently accepted source formats: git, cvs
11 # Currently accepted destination formats: hg
14 #
12 #
15 # The <mapfile> is a simple text file that maps a git commit hash to
13 # If destination isn't given, a new Mercurial repo named <src>-hg will
16 # the hash in Mercurial for that version, like so:
14 # be created. If <mapfile> isn't given, it will be put in a default
15 # location (<dest>/.hg/shamap by default)
17 #
16 #
18 # <git hash> <mercurial hash>
17 # The <mapfile> is a simple text file that maps each source commit ID to
18 # the destination ID for that revision, like so:
19 #
20 # <source ID> <destination ID>
19 #
21 #
20 # If the file doesn't exist, it's automatically created. It's updated
22 # If the file doesn't exist, it's automatically created. It's updated
21 # on each commit copied, so convert-repo can be interrupted and can
23 # on each commit copied, so convert-repo can be interrupted and can
22 # be run repeatedly to copy new commits.
24 # be run repeatedly to copy new commits.
23
25
24 import sys, os, zlib, sha, time
26 import sys, os, zlib, sha, time, re, locale
25
26 os.environ["HGENCODING"] = "utf-8"
27 os.environ["HGENCODING"] = "utf-8"
28 from mercurial import hg, ui, util, fancyopts
27
29
28 from mercurial import hg, ui, util
30 class Abort(Exception): pass
31 class NoRepo(Exception): pass
32
33 class commit:
34 def __init__(self, **parts):
35 for x in "author date desc parents".split():
36 if not x in parts:
37 abort("commit missing field %s\n" % x)
38 self.__dict__.update(parts)
39
40 quiet = 0
41 def status(msg):
42 if not quiet: sys.stdout.write(str(msg))
43
44 def warn(msg):
45 sys.stderr.write(str(msg))
46
47 def abort(msg):
48 raise Abort(msg)
29
49
30 def recode(s):
50 def recode(s):
31 try:
51 try:
@@ -36,9 +56,210 b' def recode(s):'
36 except:
56 except:
37 return s.decode("utf-8", "replace").encode("utf-8")
57 return s.decode("utf-8", "replace").encode("utf-8")
38
58
59 # CVS conversion code inspired by hg-cvs-import and git-cvsimport
60 class convert_cvs:
61 def __init__(self, path):
62 self.path = path
63 cvs = os.path.join(path, "CVS")
64 if not os.path.exists(cvs):
65 raise NoRepo("couldn't open CVS repo %s" % path)
66
67 self.changeset = {}
68 self.files = {}
69 self.tags = {}
70 self.lastbranch = {}
71 self.parent = {}
72 self.socket = None
73 self.cvsroot = file(os.path.join(cvs, "Root")).read()[:-1]
74 self.cvsrepo = file(os.path.join(cvs, "Repository")).read()[:-1]
75 self.encoding = locale.getpreferredencoding()
76 self._parse()
77 self._connect()
78
79 def _parse(self):
80 if self.changeset:
81 return
82
83 d = os.getcwd()
84 try:
85 os.chdir(self.path)
86 id = None
87 state = 0
88 for l in os.popen("cvsps -A"):
89 if state == 0: # header
90 if l.startswith("PatchSet"):
91 id = l[9:-2]
92 elif l.startswith("Date"):
93 date = util.parsedate(l[6:-1], ["%Y/%m/%d %H:%M:%S"])
94 date = util.datestr(date)
95 elif l.startswith("Branch"):
96 branch = l[8:-1]
97 self.parent[id] = self.lastbranch.get(branch,'bad')
98 self.lastbranch[branch] = id
99 elif l.startswith("Ancestor branch"):
100 ancestor = l[17:-1]
101 self.parent[id] = self.lastbranch[ancestor]
102 elif l.startswith("Author"):
103 author = self.recode(l[8:-1])
104 elif l.startswith("Tag: "):
105 t = l[5:-1]
106 if t != "(none) ":
107 self.tags[t] = id
108 elif l.startswith("Log:"):
109 state = 1
110 log = ""
111 elif state == 1: # log
112 if l == "Members: \n":
113 files = {}
114 log = self.recode(log[:-1])
115 if log.isspace():
116 log = "*** empty log message ***\n"
117 state = 2
118 else:
119 log += l
120 elif state == 2:
121 if l == "\n": #
122 state = 0
123 p = [self.parent[id]]
124 if id == "1":
125 p = []
126 c = commit(author=author, date=date, parents=p,
127 desc=log, branch=branch)
128 self.changeset[id] = c
129 self.files[id] = files
130 else:
131 file,rev = l[1:-2].rsplit(':',1)
132 rev = rev.split("->")[1]
133 files[file] = rev
134
135 self.heads = self.lastbranch.values()
136 finally:
137 os.chdir(d)
138
139 def _connect(self):
140 root = self.cvsroot
141 local = False
142 user, host = None, None
143 cmd = ['cvs', 'server']
144
145 status("connecting to %s\n" % root)
146
147 # only non-pserver for now
148 if root.startswith(":pserver"):
149 abort("can't handle pserver mode yet: %s\n" % root)
150
151 if root.startswith(":local:"):
152 local = True
153 root = root[7:]
154 else:
155 # :ext:user@host/home/user/path/to/cvsroot
156 if root.startswith(":ext:"):
157 root = root[5:]
158 m = re.match(r'(?:([^@:/]+)@)?([^:/]+):?(.*)', root)
159 if not m:
160 local = True
161 else:
162 local = False
163 user, host, root = m.group(1), m.group(2), m.group(3)
164
165 if not local:
166 rsh = os.environ.get("CVS_RSH" or "rsh")
167 if user:
168 cmd = [rsh, '-l', user, host] + cmd
169 else:
170 cmd = [rsh, host] + cmd
171
172 self.writep, self.readp = os.popen2(cmd)
173 self.realroot = root
174
175 self.writep.write("Root %s\n" % root)
176 self.writep.write("Valid-responses ok error Valid-requests Mode"
177 " M Mbinary E Checked-in Created Updated"
178 " Merged Removed\n")
179 self.writep.write("valid-requests\n")
180 self.writep.flush()
181 r = self.readp.readline()
182 if not r.startswith("Valid-requests"):
183 abort("server sucks\n")
184 if "UseUnchanged" in r:
185 self.writep.write("UseUnchanged\n")
186 self.writep.flush()
187 r = self.readp.readline()
188
189 def getheads(self):
190 return self.heads
191
192 def _getfile(self, name, rev):
193 if rev.endswith("(DEAD)"):
194 raise IOError
195
196 args = ("-N -P -kk -r %s --" % rev).split()
197 args.append(os.path.join(self.cvsrepo, name))
198 for x in args:
199 self.writep.write("Argument %s\n" % x)
200 self.writep.write("Directory .\n%s\nco\n" % self.realroot)
201 self.writep.flush()
202
203 data = ""
204 while 1:
205 line = self.readp.readline()
206 if line.startswith("Created ") or line.startswith("Updated "):
207 self.readp.readline() # path
208 self.readp.readline() # entries
209 mode = self.readp.readline()[:-1]
210 count = int(self.readp.readline()[:-1])
211 data = self.readp.read(count)
212 elif line.startswith(" "):
213 data += line[1:]
214 elif line.startswith("M "):
215 pass
216 elif line.startswith("Mbinary "):
217 count = int(self.readp.readline()[:-1])
218 data = self.readp.read(count)
219 else:
220 if line == "ok\n":
221 return (data, "x" in mode)
222 elif line.startswith("E "):
223 warn("cvs server: %s\n" % line[2:])
224 elif line.startswith("Remove"):
225 l = self.readp.readline()
226 l = self.readp.readline()
227 if l != "ok\n":
228 abort("unknown CVS response: %s\n" % l)
229 else:
230 abort("unknown CVS response: %s\n" % line)
231
232 def getfile(self, file, rev):
233 data, mode = self._getfile(file, rev)
234 self.modecache[(file, rev)] = mode
235 return data
236
237 def getmode(self, file, rev):
238 return self.modecache[(file, rev)]
239
240 def getchanges(self, rev):
241 self.modecache = {}
242 files = self.files[rev]
243 cl = files.items()
244 cl.sort()
245 return cl
246
247 def recode(self, text):
248 return text.decode(self.encoding, "replace").encode("utf-8")
249
250 def getcommit(self, rev):
251 return self.changeset[rev]
252
253 def gettags(self):
254 return self.tags
255
39 class convert_git:
256 class convert_git:
40 def __init__(self, path):
257 def __init__(self, path):
258 if os.path.isdir(path + "/.git"):
259 path += "/.git"
41 self.path = path
260 self.path = path
261 if not os.path.exists(path + "/HEAD"):
262 raise NoRepo("couldn't open GIT repo %s" % path)
42
263
43 def getheads(self):
264 def getheads(self):
44 fh = os.popen("GIT_DIR=%s git-rev-parse --verify HEAD" % self.path)
265 fh = os.popen("GIT_DIR=%s git-rev-parse --verify HEAD" % self.path)
@@ -52,7 +273,11 b' class convert_git:'
52 def getfile(self, name, rev):
273 def getfile(self, name, rev):
53 return self.catfile(rev, "blob")
274 return self.catfile(rev, "blob")
54
275
276 def getmode(self, name, rev):
277 return self.modecache[(name, rev)]
278
55 def getchanges(self, version):
279 def getchanges(self, version):
280 self.modecache = {}
56 fh = os.popen("GIT_DIR=%s git-diff-tree --root -m -r %s" % (self.path, version))
281 fh = os.popen("GIT_DIR=%s git-diff-tree --root -m -r %s" % (self.path, version))
57 changes = []
282 changes = []
58 for l in fh:
283 for l in fh:
@@ -61,7 +286,8 b' class convert_git:'
61 m = m.split()
286 m = m.split()
62 h = m[3]
287 h = m[3]
63 p = (m[1] == "100755")
288 p = (m[1] == "100755")
64 changes.append((f, h, p))
289 self.modecache[(f, h)] = p
290 changes.append((f, h))
65 return changes
291 return changes
66
292
67 def getcommit(self, version):
293 def getcommit(self, version):
@@ -92,7 +318,9 b' class convert_git:'
92 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
318 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
93 tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
319 tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
94 date = tm + " " + str(tz)
320 date = tm + " " + str(tz)
95 return (parents, author, date, message)
321
322 c = commit(parents=parents, date=date, author=author, desc=message)
323 return c
96
324
97 def gettags(self):
325 def gettags(self):
98 tags = {}
326 tags = {}
@@ -110,19 +338,23 b' class convert_mercurial:'
110 def __init__(self, path):
338 def __init__(self, path):
111 self.path = path
339 self.path = path
112 u = ui.ui()
340 u = ui.ui()
113 self.repo = hg.repository(u, path)
341 try:
342 self.repo = hg.repository(u, path)
343 except:
344 raise NoRepo("could open hg repo %s" % path)
345
346 def mapfile(self):
347 return os.path.join(self.path, ".hg", "shamap")
114
348
115 def getheads(self):
349 def getheads(self):
116 h = self.repo.changelog.heads()
350 h = self.repo.changelog.heads()
117 return [ hg.hex(x) for x in h ]
351 return [ hg.hex(x) for x in h ]
118
352
119 def putfile(self, f, e, data):
353 def putfile(self, f, e, data):
120 self.repo.wfile(f, "w").write(data)
354 self.repo.wwrite(f, data, e and 'x' or '')
121 if self.repo.dirstate.state(f) == '?':
355 if self.repo.dirstate.state(f) == '?':
122 self.repo.dirstate.update([f], "a")
356 self.repo.dirstate.update([f], "a")
123
357
124 util.set_exec(self.repo.wjoin(f), e)
125
126 def delfile(self, f):
358 def delfile(self, f):
127 try:
359 try:
128 os.unlink(self.repo.wjoin(f))
360 os.unlink(self.repo.wjoin(f))
@@ -130,7 +362,7 b' class convert_mercurial:'
130 except:
362 except:
131 pass
363 pass
132
364
133 def putcommit(self, files, parents, author, dest, text):
365 def putcommit(self, files, parents, commit):
134 seen = {}
366 seen = {}
135 pl = []
367 pl = []
136 for p in parents:
368 for p in parents:
@@ -143,11 +375,18 b' class convert_mercurial:'
143 if len(parents) < 2: parents.append("0" * 40)
375 if len(parents) < 2: parents.append("0" * 40)
144 p2 = parents.pop(0)
376 p2 = parents.pop(0)
145
377
378 text = commit.desc
379 extra = {}
380 try:
381 extra["branch"] = commit.branch
382 except AttributeError:
383 pass
384
146 while parents:
385 while parents:
147 p1 = p2
386 p1 = p2
148 p2 = parents.pop(0)
387 p2 = parents.pop(0)
149 self.repo.rawcommit(files, text, author, dest,
388 a = self.repo.rawcommit(files, text, commit.author, commit.date,
150 hg.bin(p1), hg.bin(p2))
389 hg.bin(p1), hg.bin(p2), extra=extra)
151 text = "(octopus merge fixup)\n"
390 text = "(octopus merge fixup)\n"
152 p2 = hg.hex(self.repo.changelog.tip())
391 p2 = hg.hex(self.repo.changelog.tip())
153
392
@@ -170,7 +409,7 b' class convert_mercurial:'
170 newlines.sort()
409 newlines.sort()
171
410
172 if newlines != oldlines:
411 if newlines != oldlines:
173 #print "updating tags"
412 status("updating tags\n")
174 f = self.repo.wfile(".hgtags", "w")
413 f = self.repo.wfile(".hgtags", "w")
175 f.write("".join(newlines))
414 f.write("".join(newlines))
176 f.close()
415 f.close()
@@ -180,11 +419,25 b' class convert_mercurial:'
180 date, self.repo.changelog.tip(), hg.nullid)
419 date, self.repo.changelog.tip(), hg.nullid)
181 return hg.hex(self.repo.changelog.tip())
420 return hg.hex(self.repo.changelog.tip())
182
421
422 converters = [convert_cvs, convert_git, convert_mercurial]
423
424 def converter(path):
425 if not os.path.isdir(path):
426 abort("%s: not a directory\n" % path)
427 for c in converters:
428 try:
429 return c(path)
430 except NoRepo:
431 pass
432 abort("%s: unknown repository type\n" % path)
433
183 class convert:
434 class convert:
184 def __init__(self, source, dest, mapfile):
435 def __init__(self, source, dest, mapfile, opts):
436
185 self.source = source
437 self.source = source
186 self.dest = dest
438 self.dest = dest
187 self.mapfile = mapfile
439 self.mapfile = mapfile
440 self.opts = opts
188 self.commitcache = {}
441 self.commitcache = {}
189
442
190 self.map = {}
443 self.map = {}
@@ -204,7 +457,7 b' class convert:'
204 if n in known or n in self.map: continue
457 if n in known or n in self.map: continue
205 known[n] = 1
458 known[n] = 1
206 self.commitcache[n] = self.source.getcommit(n)
459 self.commitcache[n] = self.source.getcommit(n)
207 cp = self.commitcache[n][0]
460 cp = self.commitcache[n].parents
208 for p in cp:
461 for p in cp:
209 parents.setdefault(n, []).append(p)
462 parents.setdefault(n, []).append(p)
210 visit.append(p)
463 visit.append(p)
@@ -247,42 +500,60 b' class convert:'
247 if not dep:
500 if not dep:
248 # all n's parents are in the list
501 # all n's parents are in the list
249 removed[n] = 1
502 removed[n] = 1
250 s.append(n)
503 if n not in self.map:
504 s.append(n)
251 if n in children:
505 if n in children:
252 for c in children[n]:
506 for c in children[n]:
253 visit.insert(0, c)
507 visit.insert(0, c)
254
508
509 if opts.get('datesort'):
510 depth = {}
511 for n in s:
512 depth[n] = 0
513 pl = [p for p in self.commitcache[n].parents if p not in self.map]
514 if pl:
515 depth[n] = max([depth[p] for p in pl]) + 1
516
517 s = [(depth[n], self.commitcache[n].date, n) for n in s]
518 s.sort()
519 s = [e[2] for e in s]
520
255 return s
521 return s
256
522
257 def copy(self, rev):
523 def copy(self, rev):
258 p, a, d, t = self.commitcache[rev]
524 c = self.commitcache[rev]
259 files = self.source.getchanges(rev)
525 files = self.source.getchanges(rev)
260
526
261 for f,v,e in files:
527 for f,v in files:
262 try:
528 try:
263 data = self.source.getfile(f, v)
529 data = self.source.getfile(f, v)
264 except IOError, inst:
530 except IOError, inst:
265 self.dest.delfile(f)
531 self.dest.delfile(f)
266 else:
532 else:
533 e = self.source.getmode(f, v)
267 self.dest.putfile(f, e, data)
534 self.dest.putfile(f, e, data)
268
535
269 r = [self.map[v] for v in p]
536 r = [self.map[v] for v in c.parents]
270 f = [f for f,v,e in files]
537 f = [f for f,v in files]
271 self.map[rev] = self.dest.putcommit(f, r, a, d, t)
538 self.map[rev] = self.dest.putcommit(f, r, c)
272 file(self.mapfile, "a").write("%s %s\n" % (rev, self.map[rev]))
539 file(self.mapfile, "a").write("%s %s\n" % (rev, self.map[rev]))
273
540
274 def convert(self):
541 def convert(self):
542 status("scanning source...\n")
275 heads = self.source.getheads()
543 heads = self.source.getheads()
276 parents = self.walktree(heads)
544 parents = self.walktree(heads)
545 status("sorting...\n")
277 t = self.toposort(parents)
546 t = self.toposort(parents)
278 t = [n for n in t if n not in self.map]
279 num = len(t)
547 num = len(t)
280 c = None
548 c = None
281
549
550 status("converting...\n")
282 for c in t:
551 for c in t:
283 num -= 1
552 num -= 1
284 desc = self.commitcache[c][3].splitlines()[0]
553 desc = self.commitcache[c].desc
285 #print num, desc
554 if "\n" in desc:
555 desc = desc.splitlines()[0]
556 status("%d %s\n" % (num, desc))
286 self.copy(c)
557 self.copy(c)
287
558
288 tags = self.source.gettags()
559 tags = self.source.gettags()
@@ -299,9 +570,41 b' class convert:'
299 if nrev:
570 if nrev:
300 file(self.mapfile, "a").write("%s %s\n" % (c, nrev))
571 file(self.mapfile, "a").write("%s %s\n" % (c, nrev))
301
572
302 gitpath, hgpath, mapfile = sys.argv[1:]
573 def command(src, dest=None, mapfile=None, **opts):
303 if os.path.isdir(gitpath + "/.git"):
574 srcc = converter(src)
304 gitpath += "/.git"
575 if not hasattr(srcc, "getcommit"):
576 abort("%s: can't read from this repo type\n" % src)
577
578 if not dest:
579 dest = src + "-hg"
580 status("assuming destination %s\n" % dest)
581 if not os.path.isdir(dest):
582 status("creating repository %s\n" % dest)
583 os.system("hg init " + dest)
584 destc = converter(dest)
585 if not hasattr(destc, "putcommit"):
586 abort("%s: can't write to this repo type\n" % src)
305
587
306 c = convert(convert_git(gitpath), convert_mercurial(hgpath), mapfile)
588 if not mapfile:
307 c.convert()
589 try:
590 mapfile = destc.mapfile()
591 except:
592 mapfile = os.path.join(destc, "map")
593
594 c = convert(srcc, destc, mapfile, opts)
595 c.convert()
596
597 options = [('q', 'quiet', None, 'suppress output'),
598 ('', 'datesort', None, 'try to sort changesets by date')]
599 opts = {}
600 args = fancyopts.fancyopts(sys.argv[1:], options, opts)
601
602 if opts['quiet']:
603 quiet = 1
604
605 try:
606 command(*args, **opts)
607 except Abort, inst:
608 warn(inst)
609 except KeyboardInterrupt:
610 status("interrupted\n")
@@ -43,7 +43,9 b' proc getcommits {rargs} {'
43 }
43 }
44 if [catch {
44 if [catch {
45 set parse_args [concat --default HEAD $revargs]
45 set parse_args [concat --default HEAD $revargs]
46 set parsed_args [split [eval exec hg debug-rev-parse $parse_args] "\n"]
46 set parse_temp [eval exec hg debug-rev-parse $parse_args]
47 regsub -all "\r\n" $parse_temp "\n" parse_temp
48 set parsed_args [split $parse_temp "\n"]
47 } err] {
49 } err] {
48 # if git-rev-parse failed for some reason...
50 # if git-rev-parse failed for some reason...
49 if {$rargs == {}} {
51 if {$rargs == {}} {
@@ -108,6 +110,7 b' to allow selection of commits to be disp'
108 set leftover {}
110 set leftover {}
109 }
111 }
110 set start [expr {$i + 1}]
112 set start [expr {$i + 1}]
113 regsub -all "\r\n" $cmit "\n" cmit
111 set j [string first "\n" $cmit]
114 set j [string first "\n" $cmit]
112 set ok 0
115 set ok 0
113 if {$j >= 0} {
116 if {$j >= 0} {
@@ -209,6 +212,7 b' proc parsecommit {id contents listed old'
209 incr ncleft($p)
212 incr ncleft($p)
210 }
213 }
211 }
214 }
215 regsub -all "\r\n" $contents "\n" contents
212 foreach line [split $contents "\n"] {
216 foreach line [split $contents "\n"] {
213 if {$inhdr} {
217 if {$inhdr} {
214 set line [split $line]
218 set line [split $line]
@@ -257,7 +261,8 b' proc readrefs {} {'
257 global tagids idtags headids idheads tagcontents
261 global tagids idtags headids idheads tagcontents
258
262
259 set tags [exec hg tags]
263 set tags [exec hg tags]
260 set lines [split $tags '\n']
264 regsub -all "\r\n" $tags "\n" tags
265 set lines [split $tags "\n"]
261 foreach f $lines {
266 foreach f $lines {
262 set f [regexp -all -inline {\S+} $f]
267 set f [regexp -all -inline {\S+} $f]
263 set direct [lindex $f 0]
268 set direct [lindex $f 0]
@@ -2856,6 +2861,7 b' proc getblobdiffline {bdf ids} {'
2856 if {$ids != $diffids || $bdf != $blobdifffd($ids)} {
2861 if {$ids != $diffids || $bdf != $blobdifffd($ids)} {
2857 return
2862 return
2858 }
2863 }
2864 regsub -all "\r" $line "" line
2859 $ctext conf -state normal
2865 $ctext conf -state normal
2860 if {[regexp {^diff --git a/(.*) b/(.*)} $line match fname newname]} {
2866 if {[regexp {^diff --git a/(.*) b/(.*)} $line match fname newname]} {
2861 # start of a new file
2867 # start of a new file
@@ -2914,7 +2920,7 b' proc getblobdiffline {bdf ids} {'
2914 } elseif {$diffinhdr || $x == "\\"} {
2920 } elseif {$diffinhdr || $x == "\\"} {
2915 # e.g. "\ No newline at end of file"
2921 # e.g. "\ No newline at end of file"
2916 $ctext insert end "$line\n" filesep
2922 $ctext insert end "$line\n" filesep
2917 } else {
2923 } elseif {$line != ""} {
2918 # Something else we don't recognize
2924 # Something else we don't recognize
2919 if {$curdifftag != "Comments"} {
2925 if {$curdifftag != "Comments"} {
2920 $ctext insert end "\n"
2926 $ctext insert end "\n"
@@ -7,6 +7,5 b''
7 # This software may be used and distributed according to the terms
7 # This software may be used and distributed according to the terms
8 # of the GNU General Public License, incorporated herein by reference.
8 # of the GNU General Public License, incorporated herein by reference.
9
9
10 from mercurial import commands
10 import mercurial.commands
11
11 mercurial.commands.run()
12 commands.run()
@@ -45,10 +45,10 b''
45 # glob pattern = user4, user5
45 # glob pattern = user4, user5
46 # ** = user6
46 # ** = user6
47
47
48 from mercurial.demandload import *
48 from mercurial.i18n import _
49 from mercurial.i18n import gettext as _
50 from mercurial.node import *
49 from mercurial.node import *
51 demandload(globals(), 'getpass mercurial:util')
50 from mercurial import util
51 import getpass
52
52
53 class checker(object):
53 class checker(object):
54 '''acl checker.'''
54 '''acl checker.'''
@@ -91,7 +91,7 b' class checker(object):'
91
91
92 def check(self, node):
92 def check(self, node):
93 '''return if access allowed, raise exception if not.'''
93 '''return if access allowed, raise exception if not.'''
94 files = self.repo.changelog.read(node)[3]
94 files = self.repo.changectx(node).files()
95 if self.deniable:
95 if self.deniable:
96 for f in files:
96 for f in files:
97 if self.deny(f):
97 if self.deny(f):
@@ -52,10 +52,10 b''
52 # [usermap]
52 # [usermap]
53 # committer_email = bugzilla_user_name
53 # committer_email = bugzilla_user_name
54
54
55 from mercurial.demandload import *
55 from mercurial.i18n import _
56 from mercurial.i18n import gettext as _
57 from mercurial.node import *
56 from mercurial.node import *
58 demandload(globals(), 'mercurial:cmdutil,templater,util os re time')
57 from mercurial import cmdutil, templater, util
58 import os, re, time
59
59
60 MySQLdb = None
60 MySQLdb = None
61
61
@@ -222,7 +222,7 b' class bugzilla(object):'
222 _bug_re = None
222 _bug_re = None
223 _split_re = None
223 _split_re = None
224
224
225 def find_bug_ids(self, node, desc):
225 def find_bug_ids(self, ctx):
226 '''find valid bug ids that are referred to in changeset
226 '''find valid bug ids that are referred to in changeset
227 comments and that do not already have references to this
227 comments and that do not already have references to this
228 changeset.'''
228 changeset.'''
@@ -235,7 +235,7 b' class bugzilla(object):'
235 start = 0
235 start = 0
236 ids = {}
236 ids = {}
237 while True:
237 while True:
238 m = bugzilla._bug_re.search(desc, start)
238 m = bugzilla._bug_re.search(ctx.description(), start)
239 if not m:
239 if not m:
240 break
240 break
241 start = m.end()
241 start = m.end()
@@ -246,10 +246,10 b' class bugzilla(object):'
246 if ids:
246 if ids:
247 ids = self.filter_real_bug_ids(ids)
247 ids = self.filter_real_bug_ids(ids)
248 if ids:
248 if ids:
249 ids = self.filter_unknown_bug_ids(node, ids)
249 ids = self.filter_unknown_bug_ids(ctx.node(), ids)
250 return ids
250 return ids
251
251
252 def update(self, bugid, node, changes):
252 def update(self, bugid, ctx):
253 '''update bugzilla bug with reference to changeset.'''
253 '''update bugzilla bug with reference to changeset.'''
254
254
255 def webroot(root):
255 def webroot(root):
@@ -268,7 +268,7 b' class bugzilla(object):'
268 mapfile = self.ui.config('bugzilla', 'style')
268 mapfile = self.ui.config('bugzilla', 'style')
269 tmpl = self.ui.config('bugzilla', 'template')
269 tmpl = self.ui.config('bugzilla', 'template')
270 t = cmdutil.changeset_templater(self.ui, self.repo,
270 t = cmdutil.changeset_templater(self.ui, self.repo,
271 False, None, mapfile, False)
271 False, mapfile, False)
272 if not mapfile and not tmpl:
272 if not mapfile and not tmpl:
273 tmpl = _('changeset {node|short} in repo {root} refers '
273 tmpl = _('changeset {node|short} in repo {root} refers '
274 'to bug {bug}.\ndetails:\n\t{desc|tabindent}')
274 'to bug {bug}.\ndetails:\n\t{desc|tabindent}')
@@ -276,13 +276,13 b' class bugzilla(object):'
276 tmpl = templater.parsestring(tmpl, quoted=False)
276 tmpl = templater.parsestring(tmpl, quoted=False)
277 t.use_template(tmpl)
277 t.use_template(tmpl)
278 self.ui.pushbuffer()
278 self.ui.pushbuffer()
279 t.show(changenode=node, changes=changes,
279 t.show(changenode=ctx.node(), changes=ctx.changeset(),
280 bug=str(bugid),
280 bug=str(bugid),
281 hgweb=self.ui.config('web', 'baseurl'),
281 hgweb=self.ui.config('web', 'baseurl'),
282 root=self.repo.root,
282 root=self.repo.root,
283 webroot=webroot(self.repo.root))
283 webroot=webroot(self.repo.root))
284 data = self.ui.popbuffer()
284 data = self.ui.popbuffer()
285 self.add_comment(bugid, data, templater.email(changes[1]))
285 self.add_comment(bugid, data, templater.email(ctx.user()))
286
286
287 def hook(ui, repo, hooktype, node=None, **kwargs):
287 def hook(ui, repo, hooktype, node=None, **kwargs):
288 '''add comment to bugzilla for each changeset that refers to a
288 '''add comment to bugzilla for each changeset that refers to a
@@ -300,12 +300,11 b' def hook(ui, repo, hooktype, node=None, '
300 hooktype)
300 hooktype)
301 try:
301 try:
302 bz = bugzilla(ui, repo)
302 bz = bugzilla(ui, repo)
303 bin_node = bin(node)
303 ctx = repo.changctx(node)
304 changes = repo.changelog.read(bin_node)
304 ids = bz.find_bug_ids(ctx)
305 ids = bz.find_bug_ids(bin_node, changes[4])
306 if ids:
305 if ids:
307 for id in ids:
306 for id in ids:
308 bz.update(id, bin_node, changes)
307 bz.update(id, ctx)
309 bz.notify(ids)
308 bz.notify(ids)
310 except MySQLdb.MySQLError, err:
309 except MySQLdb.MySQLError, err:
311 raise util.Abort(_('database error: %s') % err[1])
310 raise util.Abort(_('database error: %s') % err[1])
@@ -48,16 +48,15 b''
48 # needed files, so running the external diff program will actually be
48 # needed files, so running the external diff program will actually be
49 # pretty fast (at least faster than having to compare the entire tree).
49 # pretty fast (at least faster than having to compare the entire tree).
50
50
51 from mercurial.demandload import demandload
51 from mercurial.i18n import _
52 from mercurial.i18n import gettext as _
53 from mercurial.node import *
52 from mercurial.node import *
54 demandload(globals(), 'mercurial:cmdutil,util os shutil tempfile')
53 from mercurial import cmdutil, util
54 import os, shutil, tempfile
55
55
56 def dodiff(ui, repo, diffcmd, diffopts, pats, opts):
56 def dodiff(ui, repo, diffcmd, diffopts, pats, opts):
57 def snapshot_node(files, node):
57 def snapshot_node(files, node):
58 '''snapshot files as of some revision'''
58 '''snapshot files as of some revision'''
59 changes = repo.changelog.read(node)
59 mf = repo.changectx(node).manifest()
60 mf = repo.manifest.read(changes[0])
61 dirname = '%s.%s' % (os.path.basename(repo.root), short(node))
60 dirname = '%s.%s' % (os.path.basename(repo.root), short(node))
62 base = os.path.join(tmproot, dirname)
61 base = os.path.join(tmproot, dirname)
63 os.mkdir(base)
62 os.mkdir(base)
@@ -74,7 +73,8 b' def dodiff(ui, repo, diffcmd, diffopts, '
74 destdir = os.path.dirname(dest)
73 destdir = os.path.dirname(dest)
75 if not os.path.isdir(destdir):
74 if not os.path.isdir(destdir):
76 os.makedirs(destdir)
75 os.makedirs(destdir)
77 repo.wwrite(wfn, repo.file(fn).read(mf[fn]), open(dest, 'w'))
76 data = repo.wwritedata(wfn, repo.file(wfn).read(mf[wfn]))
77 open(dest, 'w').write(data)
78 return dirname
78 return dirname
79
79
80 def snapshot_wdir(files):
80 def snapshot_wdir(files):
@@ -5,10 +5,9 b''
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from mercurial.demandload import *
8 from mercurial.i18n import _
9 from mercurial.i18n import gettext as _
10 from mercurial.node import *
9 from mercurial.node import *
11 demandload(globals(), 'mercurial:commands,hg,node,util')
10 from mercurial import commands, hg, node, util
12
11
13 def fetch(ui, repo, source='default', **opts):
12 def fetch(ui, repo, source='default', **opts):
14 '''Pull changes from a remote repository, merge new changes if needed.
13 '''Pull changes from a remote repository, merge new changes if needed.
@@ -8,7 +8,7 b''
8 import os, tempfile, binascii
8 import os, tempfile, binascii
9 from mercurial import util
9 from mercurial import util
10 from mercurial import node as hgnode
10 from mercurial import node as hgnode
11 from mercurial.i18n import gettext as _
11 from mercurial.i18n import _
12
12
13 class gpg:
13 class gpg:
14 def __init__(self, path, key=None):
14 def __init__(self, path, key=None):
@@ -6,9 +6,9 b''
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8
8
9 from mercurial.i18n import gettext as _
9 from mercurial.i18n import _
10 from mercurial.demandload import demandload
10 from mercurial import hg, util, commands, cmdutil
11 demandload(globals(), "os sys sets mercurial:hg,util,commands,cmdutil")
11 import os, sys, sets
12
12
13 versionstr = "0.0.3"
13 versionstr = "0.0.3"
14
14
@@ -5,26 +5,18 b''
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from mercurial.demandload import *
8 import sys, os
9 demandload(globals(), 'time sys signal os')
9 from mercurial import hg, fancyopts, commands, ui, util, patch, revlog
10 demandload(globals(), 'mercurial:hg,fancyopts,commands,ui,util,patch,revlog')
11
10
12 def difftree(ui, repo, node1=None, node2=None, *files, **opts):
11 def difftree(ui, repo, node1=None, node2=None, *files, **opts):
13 """diff trees from two commits"""
12 """diff trees from two commits"""
14 def __difftree(repo, node1, node2, files=[]):
13 def __difftree(repo, node1, node2, files=[]):
15 if node2:
14 assert node2 is not None
16 change = repo.changelog.read(node2)
15 mmap = repo.changectx(node1).manifest()
17 mmap2 = repo.manifest.read(change[0])
16 mmap2 = repo.changectx(node2).manifest()
18 status = repo.status(node1, node2, files=files)[:5]
17 status = repo.status(node1, node2, files=files)[:5]
19 modified, added, removed, deleted, unknown = status
18 modified, added, removed, deleted, unknown = status
20 else:
21 status = repo.status(node1, files=files)[:5]
22 modified, added, removed, deleted, unknown = status
23 if not node1:
24 node1 = repo.dirstate.parents()[0]
25
19
26 change = repo.changelog.read(node1)
27 mmap = repo.manifest.read(change[0])
28 empty = hg.short(hg.nullid)
20 empty = hg.short(hg.nullid)
29
21
30 for f in modified:
22 for f in modified:
@@ -70,32 +62,30 b' def difftree(ui, repo, node1=None, node2'
70 if not opts['stdin']:
62 if not opts['stdin']:
71 break
63 break
72
64
73 def catcommit(repo, n, prefix, changes=None):
65 def catcommit(repo, n, prefix, ctx=None):
74 nlprefix = '\n' + prefix;
66 nlprefix = '\n' + prefix;
75 (p1, p2) = repo.changelog.parents(n)
67 if ctx is None:
76 (h, h1, h2) = map(hg.short, (n, p1, p2))
68 ctx = repo.changectx(n)
77 (i1, i2) = map(repo.changelog.rev, (p1, p2))
69 (p1, p2) = ctx.parents()
78 if not changes:
70 print "tree %s" % (hg.short(ctx.changeset()[0])) # use ctx.node() instead ??
79 changes = repo.changelog.read(n)
71 if p1: print "parent %s" % (hg.short(p1.node()))
80 print "tree %s" % (hg.short(changes[0]))
72 if p2: print "parent %s" % (hg.short(p2.node()))
81 if i1 != hg.nullrev: print "parent %s" % (h1)
73 date = ctx.date()
82 if i2 != hg.nullrev: print "parent %s" % (h2)
74 description = ctx.description()
83 date_ar = changes[2]
75 lines = description.splitlines()
84 date = int(float(date_ar[0]))
85 lines = changes[4].splitlines()
86 if lines and lines[-1].startswith('committer:'):
76 if lines and lines[-1].startswith('committer:'):
87 committer = lines[-1].split(': ')[1].rstrip()
77 committer = lines[-1].split(': ')[1].rstrip()
88 else:
78 else:
89 committer = changes[1]
79 committer = ctx.user()
90
80
91 print "author %s %s %s" % (changes[1], date, date_ar[1])
81 print "author %s %s %s" % (ctx.user(), int(date[0]), date[1])
92 print "committer %s %s %s" % (committer, date, date_ar[1])
82 print "committer %s %s %s" % (committer, int(date[0]), date[1])
93 print "revision %d" % repo.changelog.rev(n)
83 print "revision %d" % ctx.rev()
94 print ""
84 print ""
95 if prefix != "":
85 if prefix != "":
96 print "%s%s" % (prefix, changes[4].replace('\n', nlprefix).strip())
86 print "%s%s" % (prefix, description.replace('\n', nlprefix).strip())
97 else:
87 else:
98 print changes[4]
88 print description
99 if prefix:
89 if prefix:
100 sys.stdout.write('\0')
90 sys.stdout.write('\0')
101
91
@@ -146,8 +136,7 b' def catfile(ui, repo, type=None, r=None,'
146 # you can specify a commit to stop at by starting the sha1 with ^
136 # you can specify a commit to stop at by starting the sha1 with ^
147 def revtree(args, repo, full="tree", maxnr=0, parents=False):
137 def revtree(args, repo, full="tree", maxnr=0, parents=False):
148 def chlogwalk():
138 def chlogwalk():
149 ch = repo.changelog
139 count = repo.changelog.count()
150 count = ch.count()
151 i = count
140 i = count
152 l = [0] * 100
141 l = [0] * 100
153 chunk = 100
142 chunk = 100
@@ -163,7 +152,8 b' def revtree(args, repo, full="tree", max'
163 l[chunk - x:] = [0] * (chunk - x)
152 l[chunk - x:] = [0] * (chunk - x)
164 break
153 break
165 if full != None:
154 if full != None:
166 l[x] = ch.read(ch.node(i + x))
155 l[x] = repo.changectx(i + x)
156 l[x].changeset() # force reading
167 else:
157 else:
168 l[x] = 1
158 l[x] = 1
169 for x in xrange(chunk-1, -1, -1):
159 for x in xrange(chunk-1, -1, -1):
@@ -217,7 +207,7 b' def revtree(args, repo, full="tree", max'
217
207
218 # walk the repository looking for commits that are in our
208 # walk the repository looking for commits that are in our
219 # reachability graph
209 # reachability graph
220 for i, changes in chlogwalk():
210 for i, ctx in chlogwalk():
221 n = repo.changelog.node(i)
211 n = repo.changelog.node(i)
222 mask = is_reachable(want_sha1, reachable, n)
212 mask = is_reachable(want_sha1, reachable, n)
223 if mask:
213 if mask:
@@ -232,13 +222,13 b' def revtree(args, repo, full="tree", max'
232 print hg.short(n) + parentstr
222 print hg.short(n) + parentstr
233 elif full == "commit":
223 elif full == "commit":
234 print hg.short(n) + parentstr
224 print hg.short(n) + parentstr
235 catcommit(repo, n, ' ', changes)
225 catcommit(repo, n, ' ', ctx)
236 else:
226 else:
237 (p1, p2) = repo.changelog.parents(n)
227 (p1, p2) = repo.changelog.parents(n)
238 (h, h1, h2) = map(hg.short, (n, p1, p2))
228 (h, h1, h2) = map(hg.short, (n, p1, p2))
239 (i1, i2) = map(repo.changelog.rev, (p1, p2))
229 (i1, i2) = map(repo.changelog.rev, (p1, p2))
240
230
241 date = changes[2][0]
231 date = ctx.date()[0]
242 print "%s %s:%s" % (date, h, mask),
232 print "%s %s:%s" % (date, h, mask),
243 mask = is_reachable(want_sha1, reachable, p1)
233 mask = is_reachable(want_sha1, reachable, p1)
244 if i1 != hg.nullrev and mask > 0:
234 if i1 != hg.nullrev and mask > 0:
@@ -29,11 +29,9 b' remove patch from applied stack '
29 refresh contents of top applied patch qrefresh
29 refresh contents of top applied patch qrefresh
30 '''
30 '''
31
31
32 from mercurial.demandload import *
32 from mercurial.i18n import _
33 from mercurial.i18n import gettext as _
33 from mercurial import commands, cmdutil, hg, patch, revlog, util, changegroup
34 from mercurial import commands
34 import os, sys, re, errno
35 demandload(globals(), "os sys re struct traceback errno bz2")
36 demandload(globals(), "mercurial:cmdutil,hg,patch,revlog,util,changegroup")
37
35
38 commands.norepo += " qclone qversion"
36 commands.norepo += " qclone qversion"
39
37
@@ -328,11 +326,12 b' class queue:'
328 hg.clean(repo, head, wlock=wlock)
326 hg.clean(repo, head, wlock=wlock)
329 self.strip(repo, n, update=False, backup='strip', wlock=wlock)
327 self.strip(repo, n, update=False, backup='strip', wlock=wlock)
330
328
331 c = repo.changelog.read(rev)
329 ctx = repo.changectx(rev)
332 ret = hg.merge(repo, rev, wlock=wlock)
330 ret = hg.merge(repo, rev, wlock=wlock)
333 if ret:
331 if ret:
334 raise util.Abort(_("update returned %d") % ret)
332 raise util.Abort(_("update returned %d") % ret)
335 n = repo.commit(None, c[4], c[1], force=1, wlock=wlock)
333 n = repo.commit(None, ctx.description(), ctx.user(),
334 force=1, wlock=wlock)
336 if n == None:
335 if n == None:
337 raise util.Abort(_("repo commit failed"))
336 raise util.Abort(_("repo commit failed"))
338 try:
337 try:
@@ -614,15 +613,12 b' class queue:'
614 self.ui.warn("saving bundle to %s\n" % name)
613 self.ui.warn("saving bundle to %s\n" % name)
615 return changegroup.writebundle(cg, name, "HG10BZ")
614 return changegroup.writebundle(cg, name, "HG10BZ")
616
615
617 def stripall(rev, revnum):
616 def stripall(revnum):
618 cl = repo.changelog
617 mm = repo.changectx(rev).manifest()
619 c = cl.read(rev)
620 mm = repo.manifest.read(c[0])
621 seen = {}
618 seen = {}
622
619
623 for x in xrange(revnum, cl.count()):
620 for x in xrange(revnum, repo.changelog.count()):
624 c = cl.read(cl.node(x))
621 for f in repo.changectx(x).files():
625 for f in c[3]:
626 if f in seen:
622 if f in seen:
627 continue
623 continue
628 seen[f] = 1
624 seen[f] = 1
@@ -703,7 +699,7 b' class queue:'
703 backupch = repo.changegroupsubset(savebases.keys(), saveheads, 'strip')
699 backupch = repo.changegroupsubset(savebases.keys(), saveheads, 'strip')
704 chgrpfile = bundle(backupch)
700 chgrpfile = bundle(backupch)
705
701
706 stripall(rev, revnum)
702 stripall(revnum)
707
703
708 change = chlog.read(rev)
704 change = chlog.read(rev)
709 chlog.strip(revnum, revnum)
705 chlog.strip(revnum, revnum)
@@ -834,14 +830,7 b' class queue:'
834 wlock=None):
830 wlock=None):
835 def getfile(f, rev):
831 def getfile(f, rev):
836 t = repo.file(f).read(rev)
832 t = repo.file(f).read(rev)
837 try:
833 repo.wfile(f, "w").write(t)
838 repo.wfile(f, "w").write(t)
839 except IOError:
840 try:
841 os.makedirs(os.path.dirname(repo.wjoin(f)))
842 except OSError, err:
843 if err.errno != errno.EEXIST: raise
844 repo.wfile(f, "w").write(t)
845
834
846 if not wlock:
835 if not wlock:
847 wlock = repo.wlock()
836 wlock = repo.wlock()
@@ -65,11 +65,10 b''
65 # if you like, you can put notify config file in repo that users can
65 # if you like, you can put notify config file in repo that users can
66 # push changes to, they can manage their own subscriptions.
66 # push changes to, they can manage their own subscriptions.
67
67
68 from mercurial.demandload import *
68 from mercurial.i18n import _
69 from mercurial.i18n import gettext as _
70 from mercurial.node import *
69 from mercurial.node import *
71 demandload(globals(), 'mercurial:patch,cmdutil,templater,util,mail')
70 from mercurial import patch, cmdutil, templater, util, mail
72 demandload(globals(), 'email.Parser fnmatch socket time')
71 import email.Parser, fnmatch, socket, time
73
72
74 # template for single changeset can include email headers.
73 # template for single changeset can include email headers.
75 single_template = '''
74 single_template = '''
@@ -113,7 +112,7 b' class notifier(object):'
113 template = (self.ui.config('notify', hooktype) or
112 template = (self.ui.config('notify', hooktype) or
114 self.ui.config('notify', 'template'))
113 self.ui.config('notify', 'template'))
115 self.t = cmdutil.changeset_templater(self.ui, self.repo,
114 self.t = cmdutil.changeset_templater(self.ui, self.repo,
116 False, None, mapfile, False)
115 False, mapfile, False)
117 if not mapfile and not template:
116 if not mapfile and not template:
118 template = deftemplates.get(hooktype) or single_template
117 template = deftemplates.get(hooktype) or single_template
119 if template:
118 if template:
@@ -63,11 +63,10 b''
63 #
63 #
64 # That should be all. Now your patchbomb is on its way out.
64 # That should be all. Now your patchbomb is on its way out.
65
65
66 from mercurial.demandload import *
66 import os, errno, socket
67 demandload(globals(), '''email.MIMEMultipart email.MIMEText email.Utils
67 import email.MIMEMultipart, email.MIMEText, email.Utils
68 mercurial:cmdutil,commands,hg,mail,ui,patch,util
68 from mercurial import cmdutil, commands, hg, mail, ui, patch, util
69 os errno popen2 socket sys tempfile''')
69 from mercurial.i18n import _
70 from mercurial.i18n import gettext as _
71 from mercurial.node import *
70 from mercurial.node import *
72
71
73 try:
72 try:
@@ -216,8 +215,6 b' def patchbomb(ui, repo, *revs, **opts):'
216 bcc = [a.strip() for a in bcc if a.strip()]
215 bcc = [a.strip() for a in bcc if a.strip()]
217
216
218 if len(patches) > 1:
217 if len(patches) > 1:
219 ui.write(_('\nWrite the introductory message for the patch series.\n\n'))
220
221 tlen = len(str(len(patches)))
218 tlen = len(str(len(patches)))
222
219
223 subj = '[PATCH %0*d of %d] %s' % (
220 subj = '[PATCH %0*d of %d] %s' % (
@@ -227,21 +224,13 b' def patchbomb(ui, repo, *revs, **opts):'
227 prompt('Subject:', rest = ' [PATCH %0*d of %d] ' % (tlen, 0,
224 prompt('Subject:', rest = ' [PATCH %0*d of %d] ' % (tlen, 0,
228 len(patches))))
225 len(patches))))
229
226
230 ui.write(_('Finish with ^D or a dot on a line by itself.\n\n'))
227 body = ''
231
232 body = []
233
234 while True:
235 try: l = raw_input()
236 except EOFError: break
237 if l == '.': break
238 body.append(l)
239
240 if opts['diffstat']:
228 if opts['diffstat']:
241 d = cdiffstat(_('Final summary:\n'), jumbo)
229 d = cdiffstat(_('Final summary:\n'), jumbo)
242 if d: body.append('\n' + d)
230 if d: body = '\n' + d
243
231
244 body = '\n'.join(body) + '\n'
232 ui.write(_('\nWrite the introductory message for the patch series.\n\n'))
233 body = ui.edit(body, sender)
245
234
246 msg = email.MIMEText.MIMEText(body)
235 msg = email.MIMEText.MIMEText(body)
247 msg['Subject'] = subj
236 msg['Subject'] = subj
@@ -5,11 +5,10 b''
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from mercurial.demandload import *
8 from mercurial.i18n import _
9 from mercurial.i18n import gettext as _
9 import os, tempfile
10 demandload(globals(), 'os tempfile')
10 from mercurial import bundlerepo, cmdutil, commands, hg, merge, patch, revlog
11 demandload(globals(), 'mercurial:bundlerepo,cmdutil,commands,hg,merge,patch')
11 from mercurial import util
12 demandload(globals(), 'mercurial:revlog,util')
13
12
14 '''patch transplanting tool
13 '''patch transplanting tool
15
14
@@ -588,5 +587,5 b' cmdtable = {'
588 ('', 'log', None, _('append transplant info to log message')),
587 ('', 'log', None, _('append transplant info to log message')),
589 ('c', 'continue', None, _('continue last transplant session after repair')),
588 ('c', 'continue', None, _('continue last transplant session after repair')),
590 ('', 'filter', '', _('filter changesets through FILTER'))],
589 ('', 'filter', '', _('filter changesets through FILTER'))],
591 _('hg transplant [-s REPOSITORY] [-b BRANCH] [-p REV] [-m REV] [-n] REV...'))
590 _('hg transplant [-s REPOSITORY] [-b BRANCH [-a]] [-p REV] [-m REV] [REV]...'))
592 }
591 }
@@ -5,8 +5,7 b''
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import *
8 import cStringIO, changelog, errno, manifest, os, tempfile, util
9 demandload(globals(), "cStringIO changelog errno manifest os tempfile util")
10
9
11 # writes to metadata files are ordered. reads: changelog, manifest,
10 # writes to metadata files are ordered. reads: changelog, manifest,
12 # normal files. writes: normal files, manifest, changelog.
11 # normal files. writes: normal files, manifest, changelog.
@@ -5,10 +5,9 b''
5 # This software may be used and distributed according to the terms of
5 # This software may be used and distributed according to the terms of
6 # the GNU General Public License, incorporated herein by reference.
6 # the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import *
8 from i18n import _
9 from i18n import gettext as _
10 from node import *
9 from node import *
11 demandload(globals(), 'cStringIO os stat tarfile time util zipfile')
10 import cStringIO, os, stat, tarfile, time, util, zipfile
12
11
13 def tidyprefix(dest, prefix, suffixes):
12 def tidyprefix(dest, prefix, suffixes):
14 '''choose prefix to use for names in archive. make sure prefix is
13 '''choose prefix to use for names in archive. make sure prefix is
@@ -155,15 +154,12 b' def archive(repo, dest, node, kind, deco'
155 def write(name, mode, data):
154 def write(name, mode, data):
156 if matchfn and not matchfn(name): return
155 if matchfn and not matchfn(name): return
157 if decode:
156 if decode:
158 fp = cStringIO.StringIO()
157 data = repo.wwritedata(name, data)
159 repo.wwrite(name, data, fp)
160 data = fp.getvalue()
161 archiver.addfile(name, mode, data)
158 archiver.addfile(name, mode, data)
162
159
163 change = repo.changelog.read(node)
160 ctx = repo.changectx(node)
164 mn = change[0]
161 archiver = archivers[kind](dest, prefix, mtime or ctx.date()[0])
165 archiver = archivers[kind](dest, prefix, mtime or change[2][0])
162 m = ctx.manifest()
166 m = repo.manifest.read(mn)
167 items = m.items()
163 items = m.items()
168 items.sort()
164 items.sort()
169 write('.hg_archival.txt', 0644,
165 write('.hg_archival.txt', 0644,
@@ -11,9 +11,8 b' of the GNU General Public License, incor'
11 """
11 """
12
12
13 from node import *
13 from node import *
14 from i18n import gettext as _
14 from i18n import _
15 from demandload import demandload
15 import changegroup, util, os, struct, bz2, tempfile
16 demandload(globals(), "changegroup util os struct bz2 tempfile")
17
16
18 import localrepo, changelog, manifest, filelog, revlog
17 import localrepo, changelog, manifest, filelog, revlog
19
18
@@ -50,7 +49,7 b' class bundlerevlog(revlog.revlog):'
50 continue
49 continue
51 for p in (p1, p2):
50 for p in (p1, p2):
52 if not p in self.nodemap:
51 if not p in self.nodemap:
53 raise revlog.RevlogError(_("unknown parent %s") % short(p1))
52 raise revlog.LookupError(_("unknown parent %s") % short(p1))
54 if linkmapper is None:
53 if linkmapper is None:
55 link = n
54 link = n
56 else:
55 else:
@@ -6,9 +6,9 b' changegroup.py - Mercurial changegroup m'
6 This software may be used and distributed according to the terms
6 This software may be used and distributed according to the terms
7 of the GNU General Public License, incorporated herein by reference.
7 of the GNU General Public License, incorporated herein by reference.
8 """
8 """
9 from i18n import gettext as _
9
10 from demandload import *
10 from i18n import _
11 demandload(globals(), "struct os bz2 zlib util tempfile")
11 import struct, os, bz2, zlib, util, tempfile
12
12
13 def getchunk(source):
13 def getchunk(source):
14 """get a chunk from a changegroup"""
14 """get a chunk from a changegroup"""
@@ -67,8 +67,6 b' def writebundle(cg, filename, bundletype'
67 cleanup = None
67 cleanup = None
68 try:
68 try:
69 if filename:
69 if filename:
70 if os.path.exists(filename):
71 raise util.Abort(_("file '%s' already exists") % filename)
72 fh = open(filename, "wb")
70 fh = open(filename, "wb")
73 else:
71 else:
74 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
72 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
@@ -6,9 +6,8 b''
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from revlog import *
8 from revlog import *
9 from i18n import gettext as _
9 from i18n import _
10 from demandload import demandload
10 import os, time, util
11 demandload(globals(), "os time util")
12
11
13 def _string_escape(text):
12 def _string_escape(text):
14 """
13 """
@@ -5,11 +5,9 b''
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import demandload
9 from node import *
8 from node import *
10 from i18n import gettext as _
9 from i18n import _
11 demandload(globals(), 'os sys')
10 import os, sys, mdiff, util, templater, patch
12 demandload(globals(), 'mdiff util templater patch')
13
11
14 revrangesep = ':'
12 revrangesep = ':'
15
13
@@ -148,13 +146,12 b' def walk(repo, pats=[], opts={}, node=No'
148 def findrenames(repo, added=None, removed=None, threshold=0.5):
146 def findrenames(repo, added=None, removed=None, threshold=0.5):
149 if added is None or removed is None:
147 if added is None or removed is None:
150 added, removed = repo.status()[1:3]
148 added, removed = repo.status()[1:3]
151 changes = repo.changelog.read(repo.dirstate.parents()[0])
149 ctx = repo.changectx()
152 mf = repo.manifest.read(changes[0])
153 for a in added:
150 for a in added:
154 aa = repo.wread(a)
151 aa = repo.wread(a)
155 bestscore, bestname = None, None
152 bestscore, bestname = None, None
156 for r in removed:
153 for r in removed:
157 rr = repo.file(r).read(mf[r])
154 rr = ctx.filectx(r).data()
158 delta = mdiff.textdiff(aa, rr)
155 delta = mdiff.textdiff(aa, rr)
159 if len(delta) < len(aa):
156 if len(delta) < len(aa):
160 myscore = 1.0 - (float(len(delta)) / len(aa))
157 myscore = 1.0 - (float(len(delta)) / len(aa))
@@ -199,12 +196,11 b' def addremove(repo, pats=[], opts={}, wl'
199 class changeset_printer(object):
196 class changeset_printer(object):
200 '''show changeset information when templating not requested.'''
197 '''show changeset information when templating not requested.'''
201
198
202 def __init__(self, ui, repo, patch, brinfo, buffered):
199 def __init__(self, ui, repo, patch, buffered):
203 self.ui = ui
200 self.ui = ui
204 self.repo = repo
201 self.repo = repo
205 self.buffered = buffered
202 self.buffered = buffered
206 self.patch = patch
203 self.patch = patch
207 self.brinfo = brinfo
208 self.header = {}
204 self.header = {}
209 self.hunk = {}
205 self.hunk = {}
210 self.lastheader = None
206 self.lastheader = None
@@ -268,11 +264,6 b' class changeset_printer(object):'
268 for parent in parents:
264 for parent in parents:
269 self.ui.write(_("parent: %d:%s\n") % parent)
265 self.ui.write(_("parent: %d:%s\n") % parent)
270
266
271 if self.brinfo:
272 br = self.repo.branchlookup([changenode])
273 if br:
274 self.ui.write(_("branch: %s\n") % " ".join(br[changenode]))
275
276 if self.ui.debugflag:
267 if self.ui.debugflag:
277 self.ui.write(_("manifest: %d:%s\n") %
268 self.ui.write(_("manifest: %d:%s\n") %
278 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
269 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
@@ -320,8 +311,8 b' class changeset_printer(object):'
320 class changeset_templater(changeset_printer):
311 class changeset_templater(changeset_printer):
321 '''format changeset information.'''
312 '''format changeset information.'''
322
313
323 def __init__(self, ui, repo, patch, brinfo, mapfile, buffered):
314 def __init__(self, ui, repo, patch, mapfile, buffered):
324 changeset_printer.__init__(self, ui, repo, patch, brinfo, buffered)
315 changeset_printer.__init__(self, ui, repo, patch, buffered)
325 self.t = templater.templater(mapfile, templater.common_filters,
316 self.t = templater.templater(mapfile, templater.common_filters,
326 cache={'parent': '{rev}:{node|short} ',
317 cache={'parent': '{rev}:{node|short} ',
327 'manifest': '{rev}:{node|short}',
318 'manifest': '{rev}:{node|short}',
@@ -407,12 +398,6 b' class changeset_templater(changeset_prin'
407 if branch:
398 if branch:
408 branch = util.tolocal(branch)
399 branch = util.tolocal(branch)
409 return showlist('branch', [branch], plural='branches', **args)
400 return showlist('branch', [branch], plural='branches', **args)
410 # add old style branches if requested
411 if self.brinfo:
412 br = self.repo.branchlookup([changenode])
413 if changenode in br:
414 return showlist('branch', br[changenode],
415 plural='branches', **args)
416
401
417 def showparents(**args):
402 def showparents(**args):
418 parents = [[('rev', log.rev(p)), ('node', hex(p))]
403 parents = [[('rev', log.rev(p)), ('node', hex(p))]
@@ -526,11 +511,6 b' def show_changeset(ui, repo, opts, buffe'
526 if opts.get('patch'):
511 if opts.get('patch'):
527 patch = matchfn or util.always
512 patch = matchfn or util.always
528
513
529 br = None
530 if opts.get('branches'):
531 ui.warn(_("the --branches option is deprecated, "
532 "please use 'hg branches' instead\n"))
533 br = True
534 tmpl = opts.get('template')
514 tmpl = opts.get('template')
535 mapfile = None
515 mapfile = None
536 if tmpl:
516 if tmpl:
@@ -552,12 +532,12 b' def show_changeset(ui, repo, opts, buffe'
552 or templater.templatepath(mapfile))
532 or templater.templatepath(mapfile))
553 if mapname: mapfile = mapname
533 if mapname: mapfile = mapname
554 try:
534 try:
555 t = changeset_templater(ui, repo, patch, br, mapfile, buffered)
535 t = changeset_templater(ui, repo, patch, mapfile, buffered)
556 except SyntaxError, inst:
536 except SyntaxError, inst:
557 raise util.Abort(inst.args[0])
537 raise util.Abort(inst.args[0])
558 if tmpl: t.use_template(tmpl)
538 if tmpl: t.use_template(tmpl)
559 return t
539 return t
560 return changeset_printer(ui, repo, patch, br, buffered)
540 return changeset_printer(ui, repo, patch, buffered)
561
541
562 def finddate(ui, repo, date):
542 def finddate(ui, repo, date):
563 """Find the tipmost changeset that matches the given date spec"""
543 """Find the tipmost changeset that matches the given date spec"""
@@ -5,14 +5,14 b''
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import demandload
8 import demandimport; demandimport.enable()
9 from node import *
9 from node import *
10 from i18n import gettext as _
10 from i18n import _
11 demandload(globals(), "bisect os re sys signal imp urllib pdb shlex stat")
11 import bisect, os, re, sys, signal, imp, urllib, pdb, shlex, stat
12 demandload(globals(), "fancyopts ui hg util lock revlog bundlerepo")
12 import fancyopts, ui, hg, util, lock, revlog, bundlerepo
13 demandload(globals(), "difflib patch time help mdiff tempfile")
13 import difflib, patch, time, help, mdiff, tempfile
14 demandload(globals(), "traceback errno version atexit socket")
14 import traceback, errno, version, atexit, socket
15 demandload(globals(), "archival changegroup cmdutil hgweb.server sshserver")
15 import archival, changegroup, cmdutil, hgweb.server, sshserver
16
16
17 class UnknownCommand(Exception):
17 class UnknownCommand(Exception):
18 """Exception raised if command is not in the command table."""
18 """Exception raised if command is not in the command table."""
@@ -240,8 +240,7 b' def backout(ui, repo, rev, **opts):'
240 if op1 != node:
240 if op1 != node:
241 if opts['merge']:
241 if opts['merge']:
242 ui.status(_('merging with changeset %s\n') % nice(op1))
242 ui.status(_('merging with changeset %s\n') % nice(op1))
243 n = _lookup(repo, hex(op1))
243 hg.merge(repo, hex(op1))
244 hg.merge(repo, n)
245 else:
244 else:
246 ui.status(_('the backout changeset is a new head - '
245 ui.status(_('the backout changeset is a new head - '
247 'do not forget to merge\n'))
246 'do not forget to merge\n'))
@@ -685,15 +684,12 b" def debugcomplete(ui, cmd='', **opts):"
685 clist.sort()
684 clist.sort()
686 ui.write("%s\n" % "\n".join(clist))
685 ui.write("%s\n" % "\n".join(clist))
687
686
688 def debugrebuildstate(ui, repo, rev=None):
687 def debugrebuildstate(ui, repo, rev=""):
689 """rebuild the dirstate as it would look like for the given revision"""
688 """rebuild the dirstate as it would look like for the given revision"""
690 if not rev:
689 if rev == "":
691 rev = repo.changelog.tip()
690 rev = repo.changelog.tip()
692 else:
691 ctx = repo.changectx(rev)
693 rev = repo.lookup(rev)
692 files = ctx.manifest()
694 change = repo.changelog.read(rev)
695 n = change[0]
696 files = repo.manifest.read(n)
697 wlock = repo.wlock()
693 wlock = repo.wlock()
698 repo.dirstate.rebuild(rev, files)
694 repo.dirstate.rebuild(rev, files)
699
695
@@ -704,10 +700,8 b' def debugcheckstate(ui, repo):'
704 dc = repo.dirstate.map
700 dc = repo.dirstate.map
705 keys = dc.keys()
701 keys = dc.keys()
706 keys.sort()
702 keys.sort()
707 m1n = repo.changelog.read(parent1)[0]
703 m1 = repo.changectx(parent1).manifest()
708 m2n = repo.changelog.read(parent2)[0]
704 m2 = repo.changectx(parent2).manifest()
709 m1 = repo.manifest.read(m1n)
710 m2 = repo.manifest.read(m2n)
711 errors = 0
705 errors = 0
712 for f in dc:
706 for f in dc:
713 state = repo.dirstate.state(f)
707 state = repo.dirstate.state(f)
@@ -1150,13 +1144,14 b' def grep(ui, repo, pattern, *pats, **opt'
1150
1144
1151 prev = {}
1145 prev = {}
1152 def display(fn, rev, states, prevstates):
1146 def display(fn, rev, states, prevstates):
1153 counts = {'-': 0, '+': 0}
1147 found = False
1154 filerevmatches = {}
1148 filerevmatches = {}
1155 if incrementing or not opts['all']:
1149 r = prev.get(fn, -1)
1156 a, b, r = prevstates, states, rev
1150 if opts['all']:
1151 iter = difflinestates(states, prevstates)
1157 else:
1152 else:
1158 a, b, r = states, prevstates, prev.get(fn, -1)
1153 iter = [('', l) for l in prevstates]
1159 for change, l in difflinestates(a, b):
1154 for change, l in iter:
1160 cols = [fn, str(r)]
1155 cols = [fn, str(r)]
1161 if opts['line_number']:
1156 if opts['line_number']:
1162 cols.append(str(l.linenum))
1157 cols.append(str(l.linenum))
@@ -1172,19 +1167,17 b' def grep(ui, repo, pattern, *pats, **opt'
1172 else:
1167 else:
1173 cols.append(l.line)
1168 cols.append(l.line)
1174 ui.write(sep.join(cols), eol)
1169 ui.write(sep.join(cols), eol)
1175 counts[change] += 1
1170 found = True
1176 return counts['+'], counts['-']
1171 return found
1177
1172
1178 fstate = {}
1173 fstate = {}
1179 skip = {}
1174 skip = {}
1180 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1175 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1181 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1176 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1182 count = 0
1177 found = False
1183 incrementing = False
1184 follow = opts.get('follow')
1178 follow = opts.get('follow')
1185 for st, rev, fns in changeiter:
1179 for st, rev, fns in changeiter:
1186 if st == 'window':
1180 if st == 'window':
1187 incrementing = rev
1188 matches.clear()
1181 matches.clear()
1189 elif st == 'add':
1182 elif st == 'add':
1190 mf = repo.changectx(rev).manifest()
1183 mf = repo.changectx(rev).manifest()
@@ -1210,10 +1203,10 b' def grep(ui, repo, pattern, *pats, **opt'
1210 if copy:
1203 if copy:
1211 skip[copy] = True
1204 skip[copy] = True
1212 continue
1205 continue
1213 if incrementing or not opts['all'] or fstate[fn]:
1206 if fn in prev or fstate[fn]:
1214 pos, neg = display(fn, rev, m, fstate[fn])
1207 r = display(fn, rev, m, fstate[fn])
1215 count += pos + neg
1208 found = found or r
1216 if pos and not opts['all']:
1209 if r and not opts['all']:
1217 skip[fn] = True
1210 skip[fn] = True
1218 if copy:
1211 if copy:
1219 skip[copy] = True
1212 skip[copy] = True
@@ -1222,15 +1215,14 b' def grep(ui, repo, pattern, *pats, **opt'
1222 fstate[copy] = m
1215 fstate[copy] = m
1223 prev[fn] = rev
1216 prev[fn] = rev
1224
1217
1225 if not incrementing:
1218 fstate = fstate.items()
1226 fstate = fstate.items()
1219 fstate.sort()
1227 fstate.sort()
1220 for fn, state in fstate:
1228 for fn, state in fstate:
1221 if fn in skip:
1229 if fn in skip:
1222 continue
1230 continue
1223 if fn not in copies.get(prev[fn], {}):
1231 if fn not in copies.get(prev[fn], {}):
1224 found = display(fn, rev, {}, state) or found
1232 display(fn, rev, {}, state)
1225 return (not found and 1) or 0
1233 return (count == 0 and 1) or 0
1234
1226
1235 def heads(ui, repo, **opts):
1227 def heads(ui, repo, **opts):
1236 """show current repository heads
1228 """show current repository heads
@@ -1539,8 +1531,12 b' def incoming(ui, repo, source="default",'
1539 other = hg.repository(ui, source)
1531 other = hg.repository(ui, source)
1540 incoming = repo.findincoming(other, force=opts["force"])
1532 incoming = repo.findincoming(other, force=opts["force"])
1541 if not incoming:
1533 if not incoming:
1534 try:
1535 os.unlink(opts["bundle"])
1536 except:
1537 pass
1542 ui.status(_("no changes found\n"))
1538 ui.status(_("no changes found\n"))
1543 return
1539 return 1
1544
1540
1545 cleanup = None
1541 cleanup = None
1546 try:
1542 try:
@@ -1705,7 +1701,6 b' def log(ui, repo, *pats, **opts):'
1705 if opts["date"]:
1701 if opts["date"]:
1706 df = util.matchdate(opts["date"])
1702 df = util.matchdate(opts["date"])
1707
1703
1708
1709 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1704 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1710 for st, rev, fns in changeiter:
1705 for st, rev, fns in changeiter:
1711 if st == 'add':
1706 if st == 'add':
@@ -1772,7 +1767,7 b' def manifest(ui, repo, rev=None):'
1772 ui.write("%3s " % (m.execf(f) and "755" or "644"))
1767 ui.write("%3s " % (m.execf(f) and "755" or "644"))
1773 ui.write("%s\n" % f)
1768 ui.write("%s\n" % f)
1774
1769
1775 def merge(ui, repo, node=None, force=None, branch=None):
1770 def merge(ui, repo, node=None, force=None):
1776 """merge working directory with another revision
1771 """merge working directory with another revision
1777
1772
1778 Merge the contents of the current working directory and the
1773 Merge the contents of the current working directory and the
@@ -1786,9 +1781,7 b' def merge(ui, repo, node=None, force=Non'
1786 revision to merge with must be provided.
1781 revision to merge with must be provided.
1787 """
1782 """
1788
1783
1789 if node or branch:
1784 if not node:
1790 node = _lookup(repo, node, branch)
1791 else:
1792 heads = repo.heads()
1785 heads = repo.heads()
1793 if len(heads) > 2:
1786 if len(heads) > 2:
1794 raise util.Abort(_('repo has %d heads - '
1787 raise util.Abort(_('repo has %d heads - '
@@ -1823,7 +1816,7 b' def outgoing(ui, repo, dest=None, **opts'
1823 o = repo.findoutgoing(other, force=opts['force'])
1816 o = repo.findoutgoing(other, force=opts['force'])
1824 if not o:
1817 if not o:
1825 ui.status(_("no changes found\n"))
1818 ui.status(_("no changes found\n"))
1826 return
1819 return 1
1827 o = repo.changelog.nodesbetween(o, revs)[0]
1820 o = repo.changelog.nodesbetween(o, revs)[0]
1828 if opts['newest_first']:
1821 if opts['newest_first']:
1829 o.reverse()
1822 o.reverse()
@@ -2136,8 +2129,9 b' def revert(ui, repo, *pats, **opts):'
2136 if not opts['rev'] and p2 != nullid:
2129 if not opts['rev'] and p2 != nullid:
2137 raise util.Abort(_('uncommitted merge - please provide a '
2130 raise util.Abort(_('uncommitted merge - please provide a '
2138 'specific revision'))
2131 'specific revision'))
2139 node = repo.changectx(opts['rev']).node()
2132 ctx = repo.changectx(opts['rev'])
2140 mf = repo.manifest.read(repo.changelog.read(node)[0])
2133 node = ctx.node()
2134 mf = ctx.manifest()
2141 if node == parent:
2135 if node == parent:
2142 pmf = mf
2136 pmf = mf
2143 else:
2137 else:
@@ -2227,7 +2221,7 b' def revert(ui, repo, *pats, **opts):'
2227 if pmf is None:
2221 if pmf is None:
2228 # only need parent manifest in this unlikely case,
2222 # only need parent manifest in this unlikely case,
2229 # so do not read by default
2223 # so do not read by default
2230 pmf = repo.manifest.read(repo.changelog.read(parent)[0])
2224 pmf = repo.changectx(parent).manifest()
2231 if abs in pmf:
2225 if abs in pmf:
2232 if mfentry:
2226 if mfentry:
2233 # if version of file is same in parent and target
2227 # if version of file is same in parent and target
@@ -2461,9 +2455,10 b' def tags(ui, repo):'
2461 hexfunc = ui.debugflag and hex or short
2455 hexfunc = ui.debugflag and hex or short
2462 for t, n in l:
2456 for t, n in l:
2463 try:
2457 try:
2458 hn = hexfunc(n)
2464 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2459 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2465 except KeyError:
2460 except revlog.LookupError:
2466 r = " ?:?"
2461 r = " ?:%s" % hn
2467 if ui.quiet:
2462 if ui.quiet:
2468 ui.write("%s\n" % t)
2463 ui.write("%s\n" % t)
2469 else:
2464 else:
@@ -2488,7 +2483,7 b' def unbundle(ui, repo, fname, **opts):'
2488 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2483 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2489 return postincoming(ui, repo, modheads, opts['update'])
2484 return postincoming(ui, repo, modheads, opts['update'])
2490
2485
2491 def update(ui, repo, node=None, clean=False, branch=None, date=None):
2486 def update(ui, repo, node=None, clean=False, date=None):
2492 """update working directory
2487 """update working directory
2493
2488
2494 Update the working directory to the specified revision.
2489 Update the working directory to the specified revision.
@@ -2508,36 +2503,11 b' def update(ui, repo, node=None, clean=Fa'
2508 raise util.Abort(_("you can't specify a revision and a date"))
2503 raise util.Abort(_("you can't specify a revision and a date"))
2509 node = cmdutil.finddate(ui, repo, date)
2504 node = cmdutil.finddate(ui, repo, date)
2510
2505
2511 node = _lookup(repo, node, branch)
2512 if clean:
2506 if clean:
2513 return hg.clean(repo, node)
2507 return hg.clean(repo, node)
2514 else:
2508 else:
2515 return hg.update(repo, node)
2509 return hg.update(repo, node)
2516
2510
2517 def _lookup(repo, node, branch=None):
2518 if branch:
2519 repo.ui.warn(_("the --branch option is deprecated, "
2520 "please use 'hg branch' instead\n"))
2521 br = repo.branchlookup(branch=branch)
2522 found = []
2523 for x in br:
2524 if branch in br[x]:
2525 found.append(x)
2526 if len(found) > 1:
2527 repo.ui.warn(_("Found multiple heads for %s\n") % branch)
2528 for x in found:
2529 cmdutil.show_changeset(ui, repo, {}).show(changenode=x)
2530 raise util.Abort("")
2531 if len(found) == 1:
2532 node = found[0]
2533 repo.ui.warn(_("Using head %s for branch %s\n")
2534 % (short(node), branch))
2535 else:
2536 raise util.Abort(_("branch %s not found") % branch)
2537 else:
2538 node = node and repo.lookup(node) or repo.changelog.tip()
2539 return node
2540
2541 def verify(ui, repo):
2511 def verify(ui, repo):
2542 """verify the integrity of the repository
2512 """verify the integrity of the repository
2543
2513
@@ -2743,8 +2713,7 b' table = {'
2743 _('hg grep [OPTION]... PATTERN [FILE]...')),
2713 _('hg grep [OPTION]... PATTERN [FILE]...')),
2744 "heads":
2714 "heads":
2745 (heads,
2715 (heads,
2746 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2716 [('', 'style', '', _('display using template map file')),
2747 ('', 'style', '', _('display using template map file')),
2748 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2717 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2749 ('', 'template', '', _('display with template'))],
2718 ('', 'template', '', _('display with template'))],
2750 _('hg heads [-r REV]')),
2719 _('hg heads [-r REV]')),
@@ -2755,7 +2724,7 b' table = {'
2755 [('p', 'strip', 1,
2724 [('p', 'strip', 1,
2756 _('directory strip option for patch. This has the same\n'
2725 _('directory strip option for patch. This has the same\n'
2757 'meaning as the corresponding patch option')),
2726 'meaning as the corresponding patch option')),
2758 ('b', 'base', '', _('base path (DEPRECATED)')),
2727 ('b', 'base', '', _('base path')),
2759 ('f', 'force', None,
2728 ('f', 'force', None,
2760 _('skip check for outstanding uncommitted changes'))] + commitopts,
2729 _('skip check for outstanding uncommitted changes'))] + commitopts,
2761 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2730 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
@@ -2787,8 +2756,7 b' table = {'
2787 _('hg locate [OPTION]... [PATTERN]...')),
2756 _('hg locate [OPTION]... [PATTERN]...')),
2788 "^log|history":
2757 "^log|history":
2789 (log,
2758 (log,
2790 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2759 [('f', 'follow', None,
2791 ('f', 'follow', None,
2792 _('follow changeset history, or file history across copies and renames')),
2760 _('follow changeset history, or file history across copies and renames')),
2793 ('', 'follow-first', None,
2761 ('', 'follow-first', None,
2794 _('only follow the first parent of merge changesets')),
2762 _('only follow the first parent of merge changesets')),
@@ -2809,8 +2777,7 b' table = {'
2809 "manifest": (manifest, [], _('hg manifest [REV]')),
2777 "manifest": (manifest, [], _('hg manifest [REV]')),
2810 "^merge":
2778 "^merge":
2811 (merge,
2779 (merge,
2812 [('b', 'branch', '', _('merge with head of a specific branch (DEPRECATED)')),
2780 [('f', 'force', None, _('force a merge with outstanding changes'))],
2813 ('f', 'force', None, _('force a merge with outstanding changes'))],
2814 _('hg merge [-f] [REV]')),
2781 _('hg merge [-f] [REV]')),
2815 "outgoing|out": (outgoing,
2782 "outgoing|out": (outgoing,
2816 [('M', 'no-merges', None, _('do not show merges')),
2783 [('M', 'no-merges', None, _('do not show merges')),
@@ -2825,8 +2792,7 b' table = {'
2825 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
2792 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
2826 "^parents":
2793 "^parents":
2827 (parents,
2794 (parents,
2828 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2795 [('r', 'rev', '', _('show parents from the specified rev')),
2829 ('r', 'rev', '', _('show parents from the specified rev')),
2830 ('', 'style', '', _('display using template map file')),
2796 ('', 'style', '', _('display using template map file')),
2831 ('', 'template', '', _('display with template'))],
2797 ('', 'template', '', _('display with template'))],
2832 _('hg parents [-r REV] [FILE]')),
2798 _('hg parents [-r REV] [FILE]')),
@@ -2929,8 +2895,7 b' table = {'
2929 "tags": (tags, [], _('hg tags')),
2895 "tags": (tags, [], _('hg tags')),
2930 "tip":
2896 "tip":
2931 (tip,
2897 (tip,
2932 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2898 [('', 'style', '', _('display using template map file')),
2933 ('', 'style', '', _('display using template map file')),
2934 ('p', 'patch', None, _('show patch')),
2899 ('p', 'patch', None, _('show patch')),
2935 ('', 'template', '', _('display with template'))],
2900 ('', 'template', '', _('display with template'))],
2936 _('hg tip [-p]')),
2901 _('hg tip [-p]')),
@@ -2941,9 +2906,7 b' table = {'
2941 _('hg unbundle [-u] FILE')),
2906 _('hg unbundle [-u] FILE')),
2942 "^update|up|checkout|co":
2907 "^update|up|checkout|co":
2943 (update,
2908 (update,
2944 [('b', 'branch', '',
2909 [('C', 'clean', None, _('overwrite locally modified files')),
2945 _('checkout the head of a specific branch (DEPRECATED)')),
2946 ('C', 'clean', None, _('overwrite locally modified files')),
2947 ('d', 'date', '', _('tipmost revision matching date'))],
2910 ('d', 'date', '', _('tipmost revision matching date'))],
2948 _('hg update [-C] [-d DATE] [REV]')),
2911 _('hg update [-C] [-d DATE] [REV]')),
2949 "verify": (verify, [], _('hg verify')),
2912 "verify": (verify, [], _('hg verify')),
@@ -3097,9 +3060,10 b' def load_extensions(ui):'
3097 if uisetup:
3060 if uisetup:
3098 uisetup(ui)
3061 uisetup(ui)
3099 cmdtable = getattr(mod, 'cmdtable', {})
3062 cmdtable = getattr(mod, 'cmdtable', {})
3100 for t in cmdtable:
3063 overrides = [cmd for cmd in cmdtable if cmd in table]
3101 if t in table:
3064 if overrides:
3102 ui.warn(_("module %s overrides %s\n") % (name, t))
3065 ui.warn(_("extension '%s' overrides commands: %s\n")
3066 % (name, " ".join(overrides)))
3103 table.update(cmdtable)
3067 table.update(cmdtable)
3104
3068
3105 def parseconfig(config):
3069 def parseconfig(config):
@@ -6,9 +6,8 b''
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from node import *
8 from node import *
9 from i18n import gettext as _
9 from i18n import _
10 from demandload import demandload
10 import ancestor, bdiff, repo, revlog, util, os, errno
11 demandload(globals(), "ancestor bdiff repo revlog util os")
12
11
13 class changectx(object):
12 class changectx(object):
14 """A changecontext object makes access to data related to a particular
13 """A changecontext object makes access to data related to a particular
@@ -84,21 +83,22 b' class changectx(object):'
84 try:
83 try:
85 return self._manifest[path]
84 return self._manifest[path]
86 except KeyError:
85 except KeyError:
87 raise repo.LookupError(_("'%s' not found in manifest") % path)
86 raise revlog.LookupError(_("'%s' not found in manifest") % path)
88 if '_manifestdelta' in self.__dict__ or path in self.files():
87 if '_manifestdelta' in self.__dict__ or path in self.files():
89 if path in self._manifestdelta:
88 if path in self._manifestdelta:
90 return self._manifestdelta[path]
89 return self._manifestdelta[path]
91 node, flag = self._repo.manifest.find(self._changeset[0], path)
90 node, flag = self._repo.manifest.find(self._changeset[0], path)
92 if not node:
91 if not node:
93 raise repo.LookupError(_("'%s' not found in manifest") % path)
92 raise revlog.LookupError(_("'%s' not found in manifest") % path)
94
93
95 return node
94 return node
96
95
97 def filectx(self, path, fileid=None):
96 def filectx(self, path, fileid=None, filelog=None):
98 """get a file context from this changeset"""
97 """get a file context from this changeset"""
99 if fileid is None:
98 if fileid is None:
100 fileid = self.filenode(path)
99 fileid = self.filenode(path)
101 return filectx(self._repo, path, fileid=fileid, changectx=self)
100 return filectx(self._repo, path, fileid=fileid,
101 changectx=self, filelog=filelog)
102
102
103 def filectxs(self):
103 def filectxs(self):
104 """generate a file context for each file in this changeset's
104 """generate a file context for each file in this changeset's
@@ -126,16 +126,18 b' class filectx(object):'
126 self._repo = repo
126 self._repo = repo
127 self._path = path
127 self._path = path
128
128
129 assert changeid is not None or fileid is not None
129 assert (changeid is not None
130 or fileid is not None
131 or changectx is not None)
130
132
131 if filelog:
133 if filelog:
132 self._filelog = filelog
134 self._filelog = filelog
133 if changectx:
134 self._changectx = changectx
135 self._changeid = changectx.node()
136
135
137 if fileid is None:
136 if fileid is None:
138 self._changeid = changeid
137 if changectx is None:
138 self._changeid = changeid
139 else:
140 self._changectx = changectx
139 else:
141 else:
140 self._fileid = fileid
142 self._fileid = fileid
141
143
@@ -150,13 +152,10 b' class filectx(object):'
150 self._changeid = self._filelog.linkrev(self._filenode)
152 self._changeid = self._filelog.linkrev(self._filenode)
151 return self._changeid
153 return self._changeid
152 elif name == '_filenode':
154 elif name == '_filenode':
153 try:
155 if '_fileid' in self.__dict__:
154 if '_fileid' in self.__dict__:
156 self._filenode = self._filelog.lookup(self._fileid)
155 self._filenode = self._filelog.lookup(self._fileid)
157 else:
156 else:
158 self._filenode = self._changectx.filenode(self._path)
157 self._filenode = self._changectx.filenode(self._path)
158 except revlog.RevlogError, inst:
159 raise repo.LookupError(str(inst))
160 return self._filenode
159 return self._filenode
161 elif name == '_filerev':
160 elif name == '_filerev':
162 self._filerev = self._filelog.rev(self._filenode)
161 self._filerev = self._filelog.rev(self._filenode)
@@ -168,7 +167,7 b' class filectx(object):'
168 try:
167 try:
169 n = self._filenode
168 n = self._filenode
170 return True
169 return True
171 except repo.LookupError:
170 except revlog.LookupError:
172 # file is missing
171 # file is missing
173 return False
172 return False
174
173
@@ -379,13 +378,15 b' class workingctx(changectx):'
379 """generate a manifest corresponding to the working directory"""
378 """generate a manifest corresponding to the working directory"""
380
379
381 man = self._parents[0].manifest().copy()
380 man = self._parents[0].manifest().copy()
381 is_exec = util.execfunc(self._repo.root, man.execf)
382 is_link = util.linkfunc(self._repo.root, man.linkf)
382 copied = self._repo.dirstate.copies()
383 copied = self._repo.dirstate.copies()
383 modified, added, removed, deleted, unknown = self._status[:5]
384 modified, added, removed, deleted, unknown = self._status[:5]
384 for i, l in (("a", added), ("m", modified), ("u", unknown)):
385 for i, l in (("a", added), ("m", modified), ("u", unknown)):
385 for f in l:
386 for f in l:
386 man[f] = man.get(copied.get(f, f), nullid) + i
387 man[f] = man.get(copied.get(f, f), nullid) + i
387 try:
388 try:
388 man.set(f, util.is_exec(self._repo.wjoin(f), man.execf(f)))
389 man.set(f, is_exec(f), is_link(f))
389 except OSError:
390 except OSError:
390 pass
391 pass
391
392
@@ -424,9 +425,10 b' class workingctx(changectx):'
424 def children(self):
425 def children(self):
425 return []
426 return []
426
427
427 def filectx(self, path):
428 def filectx(self, path, filelog=None):
428 """get a file context from the working directory"""
429 """get a file context from the working directory"""
429 return workingfilectx(self._repo, path, workingctx=self)
430 return workingfilectx(self._repo, path, workingctx=self,
431 filelog=filelog)
430
432
431 def ancestor(self, c2):
433 def ancestor(self, c2):
432 """return the ancestor context of self and c2"""
434 """return the ancestor context of self and c2"""
@@ -484,7 +486,7 b' class workingfilectx(filectx):'
484 rp = self._repopath
486 rp = self._repopath
485 if rp == self._path:
487 if rp == self._path:
486 return None
488 return None
487 return rp, self._workingctx._parents._manifest.get(rp, nullid)
489 return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
488
490
489 def parents(self):
491 def parents(self):
490 '''return parent filectxs, following copies if necessary'''
492 '''return parent filectxs, following copies if necessary'''
@@ -505,5 +507,12 b' class workingfilectx(filectx):'
505 return []
507 return []
506
508
507 def size(self): return os.stat(self._repo.wjoin(self._path)).st_size
509 def size(self): return os.stat(self._repo.wjoin(self._path)).st_size
510 def date(self):
511 t, tz = self._changectx.date()
512 try:
513 return (os.lstat(repo.wjoin(self._path)).st_mtime, tz)
514 except OSError, err:
515 if err.errno != errno.ENOENT: raise
516 return (t, tz)
508
517
509 def cmp(self, text): return self._repo.wread(self._path) == text
518 def cmp(self, text): return self._repo.wread(self._path) == text
@@ -8,9 +8,8 b' of the GNU General Public License, incor'
8 """
8 """
9
9
10 from node import *
10 from node import *
11 from i18n import gettext as _
11 from i18n import _
12 from demandload import *
12 import struct, os, time, bisect, stat, strutil, util, re, errno
13 demandload(globals(), "struct os time bisect stat strutil util re errno")
14
13
15 class dirstate(object):
14 class dirstate(object):
16 format = ">cllll"
15 format = ">cllll"
@@ -338,14 +337,13 b' class dirstate(object):'
338 return ret
337 return ret
339
338
340 def supported_type(self, f, st, verbose=False):
339 def supported_type(self, f, st, verbose=False):
341 if stat.S_ISREG(st.st_mode):
340 if stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode):
342 return True
341 return True
343 if verbose:
342 if verbose:
344 kind = 'unknown'
343 kind = 'unknown'
345 if stat.S_ISCHR(st.st_mode): kind = _('character device')
344 if stat.S_ISCHR(st.st_mode): kind = _('character device')
346 elif stat.S_ISBLK(st.st_mode): kind = _('block device')
345 elif stat.S_ISBLK(st.st_mode): kind = _('block device')
347 elif stat.S_ISFIFO(st.st_mode): kind = _('fifo')
346 elif stat.S_ISFIFO(st.st_mode): kind = _('fifo')
348 elif stat.S_ISLNK(st.st_mode): kind = _('symbolic link')
349 elif stat.S_ISSOCK(st.st_mode): kind = _('socket')
347 elif stat.S_ISSOCK(st.st_mode): kind = _('socket')
350 elif stat.S_ISDIR(st.st_mode): kind = _('directory')
348 elif stat.S_ISDIR(st.st_mode): kind = _('directory')
351 self.ui.warn(_('%s: unsupported file type (type is %s)\n') % (
349 self.ui.warn(_('%s: unsupported file type (type is %s)\n') % (
@@ -6,8 +6,7 b''
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from revlog import *
8 from revlog import *
9 from demandload import *
9 import os
10 demandload(globals(), "os")
11
10
12 class filelog(revlog):
11 class filelog(revlog):
13 def __init__(self, opener, path, defversion=REVLOG_DEFAULT_VERSION):
12 def __init__(self, opener, path, defversion=REVLOG_DEFAULT_VERSION):
@@ -8,10 +8,11 b''
8
8
9 from node import *
9 from node import *
10 from repo import *
10 from repo import *
11 from demandload import *
11 from i18n import _
12 from i18n import gettext as _
12 import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo
13 demandload(globals(), "localrepo bundlerepo httprepo sshrepo statichttprepo")
13 import errno, lock, os, shutil, util
14 demandload(globals(), "errno lock os shutil util merge@_merge verify@_verify")
14 import merge as _merge
15 import verify as _verify
15
16
16 def _local(path):
17 def _local(path):
17 return (os.path.isfile(util.drop_scheme('file', path)) and
18 return (os.path.isfile(util.drop_scheme('file', path)) and
@@ -6,6 +6,11 b''
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8
8
9 from mercurial.demandload import demandload
9 import hgweb_mod, hgwebdir_mod
10 demandload(globals(), "mercurial.hgweb.hgweb_mod:hgweb")
10
11 demandload(globals(), "mercurial.hgweb.hgwebdir_mod:hgwebdir")
11 def hgweb(*args, **kwargs):
12 return hgweb_mod.hgweb(*args, **kwargs)
13
14 def hgwebdir(*args, **kwargs):
15 return hgwebdir_mod.hgwebdir(*args, **kwargs)
16
@@ -7,7 +7,6 b''
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8
8
9 import os, mimetypes
9 import os, mimetypes
10 import os.path
11
10
12 def get_mtime(repo_path):
11 def get_mtime(repo_path):
13 store_path = os.path.join(repo_path, ".hg")
12 store_path = os.path.join(repo_path, ".hg")
@@ -6,17 +6,13 b''
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8
8
9 import os
9 import os, mimetypes, re, zlib, mimetools, cStringIO, sys
10 import os.path
10 import tempfile, urllib, bz2
11 import mimetypes
12 from mercurial.demandload import demandload
13 demandload(globals(), "re zlib ConfigParser mimetools cStringIO sys tempfile")
14 demandload(globals(), 'urllib bz2')
15 demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,streamclone,patch")
16 demandload(globals(), "mercurial:revlog,templater")
17 demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile,style_map")
18 from mercurial.node import *
11 from mercurial.node import *
19 from mercurial.i18n import gettext as _
12 from mercurial.i18n import gettext as _
13 from mercurial import mdiff, ui, hg, util, archival, streamclone, patch
14 from mercurial import revlog, templater
15 from common import get_mtime, staticfile, style_map
20
16
21 def _up(p):
17 def _up(p):
22 if p[0] != "/":
18 if p[0] != "/":
@@ -172,14 +168,10 b' class hgweb(object):'
172 yield self.t("diffline", line=l)
168 yield self.t("diffline", line=l)
173
169
174 r = self.repo
170 r = self.repo
175 cl = r.changelog
171 c1 = r.changectx(node1)
176 mf = r.manifest
172 c2 = r.changectx(node2)
177 change1 = cl.read(node1)
173 date1 = util.datestr(c1.date())
178 change2 = cl.read(node2)
174 date2 = util.datestr(c2.date())
179 mmap1 = mf.read(change1[0])
180 mmap2 = mf.read(change2[0])
181 date1 = util.datestr(change1[2])
182 date2 = util.datestr(change2[2])
183
175
184 modified, added, removed, deleted, unknown = r.status(node1, node2)[:5]
176 modified, added, removed, deleted, unknown = r.status(node1, node2)[:5]
185 if files:
177 if files:
@@ -188,17 +180,17 b' class hgweb(object):'
188
180
189 diffopts = patch.diffopts(self.repo.ui, untrusted=True)
181 diffopts = patch.diffopts(self.repo.ui, untrusted=True)
190 for f in modified:
182 for f in modified:
191 to = r.file(f).read(mmap1[f])
183 to = c1.filectx(f).data()
192 tn = r.file(f).read(mmap2[f])
184 tn = c2.filectx(f).data()
193 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
185 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
194 opts=diffopts), f, tn)
186 opts=diffopts), f, tn)
195 for f in added:
187 for f in added:
196 to = None
188 to = None
197 tn = r.file(f).read(mmap2[f])
189 tn = c2.filectx(f).data()
198 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
190 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
199 opts=diffopts), f, tn)
191 opts=diffopts), f, tn)
200 for f in removed:
192 for f in removed:
201 to = r.file(f).read(mmap1[f])
193 to = c1.filectx(f).data()
202 tn = None
194 tn = None
203 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
195 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
204 opts=diffopts), f, tn)
196 opts=diffopts), f, tn)
@@ -497,8 +489,6 b' class hgweb(object):'
497 archives=self.archivelist(hex(node)))
489 archives=self.archivelist(hex(node)))
498
490
499 def tags(self):
491 def tags(self):
500 cl = self.repo.changelog
501
502 i = self.repo.tagslist()
492 i = self.repo.tagslist()
503 i.reverse()
493 i.reverse()
504
494
@@ -509,7 +499,7 b' class hgweb(object):'
509 continue
499 continue
510 yield {"parity": self.stripes(parity),
500 yield {"parity": self.stripes(parity),
511 "tag": k,
501 "tag": k,
512 "date": cl.read(n)[2],
502 "date": self.repo.changectx(n).date(),
513 "node": hex(n)}
503 "node": hex(n)}
514 parity += 1
504 parity += 1
515
505
@@ -519,8 +509,6 b' class hgweb(object):'
519 entriesnotip=lambda **x: entries(True, **x))
509 entriesnotip=lambda **x: entries(True, **x))
520
510
521 def summary(self):
511 def summary(self):
522 cl = self.repo.changelog
523
524 i = self.repo.tagslist()
512 i = self.repo.tagslist()
525 i.reverse()
513 i.reverse()
526
514
@@ -535,14 +523,11 b' class hgweb(object):'
535 if count > 10: # limit to 10 tags
523 if count > 10: # limit to 10 tags
536 break;
524 break;
537
525
538 c = cl.read(n)
539 t = c[2]
540
541 yield self.t("tagentry",
526 yield self.t("tagentry",
542 parity = self.stripes(parity),
527 parity=self.stripes(parity),
543 tag = k,
528 tag=k,
544 node = hex(n),
529 node=hex(n),
545 date = t)
530 date=self.repo.changectx(n).date())
546 parity += 1
531 parity += 1
547
532
548 def heads(**map):
533 def heads(**map):
@@ -564,40 +549,38 b' class hgweb(object):'
564
549
565 def changelist(**map):
550 def changelist(**map):
566 parity = 0
551 parity = 0
567 cl = self.repo.changelog
568 l = [] # build a list in forward order for efficiency
552 l = [] # build a list in forward order for efficiency
569 for i in xrange(start, end):
553 for i in xrange(start, end):
570 n = cl.node(i)
554 ctx = self.repo.changectx(i)
571 changes = cl.read(n)
555 hn = hex(ctx.node())
572 hn = hex(n)
573 t = changes[2]
574
556
575 l.insert(0, self.t(
557 l.insert(0, self.t(
576 'shortlogentry',
558 'shortlogentry',
577 parity = parity,
559 parity=parity,
578 author = changes[1],
560 author=ctx.user(),
579 desc = changes[4],
561 desc=ctx.description(),
580 date = t,
562 date=ctx.date(),
581 rev = i,
563 rev=i,
582 node = hn))
564 node=hn))
583 parity = 1 - parity
565 parity = 1 - parity
584
566
585 yield l
567 yield l
586
568
569 cl = self.repo.changelog
587 count = cl.count()
570 count = cl.count()
588 start = max(0, count - self.maxchanges)
571 start = max(0, count - self.maxchanges)
589 end = min(count, start + self.maxchanges)
572 end = min(count, start + self.maxchanges)
590
573
591 yield self.t("summary",
574 yield self.t("summary",
592 desc = self.config("web", "description", "unknown"),
575 desc=self.config("web", "description", "unknown"),
593 owner = (self.config("ui", "username") or # preferred
576 owner=(self.config("ui", "username") or # preferred
594 self.config("web", "contact") or # deprecated
577 self.config("web", "contact") or # deprecated
595 self.config("web", "author", "unknown")), # also
578 self.config("web", "author", "unknown")), # also
596 lastchange = cl.read(cl.tip())[2],
579 lastchange=cl.read(cl.tip())[2],
597 tags = tagentries,
580 tags=tagentries,
598 heads = heads,
581 heads=heads,
599 shortlog = changelist,
582 shortlog=changelist,
600 node = hex(cl.tip()),
583 node=hex(cl.tip()),
601 archives=self.archivelist("tip"))
584 archives=self.archivelist("tip"))
602
585
603 def filediff(self, fctx):
586 def filediff(self, fctx):
@@ -873,7 +856,7 b' class hgweb(object):'
873 try:
856 try:
874 req.write(self.filerevision(self.filectx(req)))
857 req.write(self.filerevision(self.filectx(req)))
875 return
858 return
876 except hg.RepoError:
859 except revlog.LookupError:
877 pass
860 pass
878
861
879 req.write(self.manifest(self.changectx(req), path))
862 req.write(self.manifest(self.changectx(req), path))
@@ -6,13 +6,12 b''
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8
8
9 import os
9 from mercurial import demandimport; demandimport.enable()
10 from mercurial.demandload import demandload
10 import os, mimetools, cStringIO
11 demandload(globals(), "mimetools cStringIO")
12 demandload(globals(), "mercurial:ui,hg,util,templater")
13 demandload(globals(), "mercurial.hgweb.hgweb_mod:hgweb")
14 demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile,style_map")
15 from mercurial.i18n import gettext as _
11 from mercurial.i18n import gettext as _
12 from mercurial import ui, hg, util, templater
13 from common import get_mtime, staticfile, style_map
14 from hgweb_mod import hgweb
16
15
17 # This is a stopgap
16 # This is a stopgap
18 class hgwebdir(object):
17 class hgwebdir(object):
@@ -6,8 +6,7 b''
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8
8
9 from mercurial.demandload import demandload
9 import socket, cgi, errno
10 demandload(globals(), "socket sys cgi os errno")
11 from mercurial.i18n import gettext as _
10 from mercurial.i18n import gettext as _
12
11
13 class wsgiapplication(object):
12 class wsgiapplication(object):
@@ -6,11 +6,11 b''
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8
8
9 from mercurial.demandload import demandload
9 import os, sys, errno, urllib, BaseHTTPServer, socket, SocketServer, traceback
10 import os, sys, errno
10 from mercurial import ui, hg, util, templater
11 demandload(globals(), "urllib BaseHTTPServer socket SocketServer traceback")
11 from hgweb_mod import hgweb
12 demandload(globals(), "mercurial:ui,hg,util,templater")
12 from hgwebdir_mod import hgwebdir
13 demandload(globals(), "hgweb_mod:hgweb hgwebdir_mod:hgwebdir request:wsgiapplication")
13 from request import wsgiapplication
14 from mercurial.i18n import gettext as _
14 from mercurial.i18n import gettext as _
15
15
16 def _splitURI(uri):
16 def _splitURI(uri):
@@ -8,10 +8,9 b''
8
8
9 from node import *
9 from node import *
10 from remoterepo import *
10 from remoterepo import *
11 from i18n import gettext as _
11 from i18n import _
12 from demandload import *
12 import hg, os, urllib, urllib2, urlparse, zlib, util, httplib
13 demandload(globals(), "hg os urllib urllib2 urlparse zlib util httplib")
13 import errno, keepalive, tempfile, socket, changegroup
14 demandload(globals(), "errno keepalive tempfile socket changegroup")
15
14
16 class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm):
15 class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm):
17 def __init__(self, ui):
16 def __init__(self, ui):
@@ -7,9 +7,7 b' This software may be used and distribute'
7 of the GNU General Public License, incorporated herein by reference.
7 of the GNU General Public License, incorporated herein by reference.
8 """
8 """
9
9
10 # the import from gettext is _really_ slow
10 import gettext
11 # for now we use a dummy function
11 t = gettext.translation('hg', fallback=1)
12 gettext = lambda x: x
12 gettext = t.gettext
13 #import gettext
13 _ = gettext
14 #t = gettext.translation('hg', '/usr/share/locale', fallback=1)
15 #gettext = t.gettext
@@ -6,13 +6,11 b''
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from node import *
8 from node import *
9 from i18n import gettext as _
9 from i18n import _
10 from demandload import *
10 import repo, appendfile, changegroup
11 import repo
11 import changelog, dirstate, filelog, manifest, context
12 demandload(globals(), "appendfile changegroup")
12 import re, lock, transaction, tempfile, stat, mdiff, errno, ui
13 demandload(globals(), "changelog dirstate filelog manifest context")
13 import os, revlog, time, util
14 demandload(globals(), "re lock transaction tempfile stat mdiff errno ui")
15 demandload(globals(), "os revlog time util")
16
14
17 class localrepository(repo.repository):
15 class localrepository(repo.repository):
18 capabilities = ('lookup', 'changegroupsubset')
16 capabilities = ('lookup', 'changegroupsubset')
@@ -119,10 +117,14 b' class localrepository(repo.repository):'
119 self.tagscache = None
117 self.tagscache = None
120 self.branchcache = None
118 self.branchcache = None
121 self.nodetagscache = None
119 self.nodetagscache = None
122 self.encodepats = None
120 self.filterpats = {}
123 self.decodepats = None
124 self.transhandle = None
121 self.transhandle = None
125
122
123 self._link = lambda x: False
124 if util.checklink(self.root):
125 r = self.root # avoid circular reference in lambda
126 self._link = lambda x: util.is_link(os.path.join(r, x))
127
126 self.dirstate = dirstate.dirstate(self.opener, self.ui, self.root)
128 self.dirstate = dirstate.dirstate(self.opener, self.ui, self.root)
127
129
128 def url(self):
130 def url(self):
@@ -319,7 +321,7 b' class localrepository(repo.repository):'
319 rev = c.rev()
321 rev = c.rev()
320 try:
322 try:
321 fnode = c.filenode('.hgtags')
323 fnode = c.filenode('.hgtags')
322 except repo.LookupError:
324 except revlog.LookupError:
323 continue
325 continue
324 ret.append((rev, node, fnode))
326 ret.append((rev, node, fnode))
325 if fnode in last:
327 if fnode in last:
@@ -480,17 +482,15 b' class localrepository(repo.repository):'
480 def wfile(self, f, mode='r'):
482 def wfile(self, f, mode='r'):
481 return self.wopener(f, mode)
483 return self.wopener(f, mode)
482
484
483 def wread(self, filename):
485 def _filter(self, filter, filename, data):
484 if self.encodepats == None:
486 if filter not in self.filterpats:
485 l = []
487 l = []
486 for pat, cmd in self.ui.configitems("encode"):
488 for pat, cmd in self.ui.configitems(filter):
487 mf = util.matcher(self.root, "", [pat], [], [])[1]
489 mf = util.matcher(self.root, "", [pat], [], [])[1]
488 l.append((mf, cmd))
490 l.append((mf, cmd))
489 self.encodepats = l
491 self.filterpats[filter] = l
490
492
491 data = self.wopener(filename, 'r').read()
493 for mf, cmd in self.filterpats[filter]:
492
493 for mf, cmd in self.encodepats:
494 if mf(filename):
494 if mf(filename):
495 self.ui.debug(_("filtering %s through %s\n") % (filename, cmd))
495 self.ui.debug(_("filtering %s through %s\n") % (filename, cmd))
496 data = util.filter(data, cmd)
496 data = util.filter(data, cmd)
@@ -498,23 +498,32 b' class localrepository(repo.repository):'
498
498
499 return data
499 return data
500
500
501 def wwrite(self, filename, data, fd=None):
501 def wread(self, filename):
502 if self.decodepats == None:
502 if self._link(filename):
503 l = []
503 data = os.readlink(self.wjoin(filename))
504 for pat, cmd in self.ui.configitems("decode"):
504 else:
505 mf = util.matcher(self.root, "", [pat], [], [])[1]
505 data = self.wopener(filename, 'r').read()
506 l.append((mf, cmd))
506 return self._filter("encode", filename, data)
507 self.decodepats = l
508
507
509 for mf, cmd in self.decodepats:
508 def wwrite(self, filename, data, flags):
510 if mf(filename):
509 data = self._filter("decode", filename, data)
511 self.ui.debug(_("filtering %s through %s\n") % (filename, cmd))
510 if "l" in flags:
512 data = util.filter(data, cmd)
511 try:
513 break
512 os.unlink(self.wjoin(filename))
513 except OSError:
514 pass
515 os.symlink(data, self.wjoin(filename))
516 else:
517 try:
518 if self._link(filename):
519 os.unlink(self.wjoin(filename))
520 except OSError:
521 pass
522 self.wopener(filename, 'w').write(data)
523 util.set_exec(self.wjoin(filename), "x" in flags)
514
524
515 if fd:
525 def wwritedata(self, filename, data):
516 return fd.write(data)
526 return self._filter("decode", filename, data)
517 return self.wopener(filename, 'w').write(data)
518
527
519 def transaction(self):
528 def transaction(self):
520 tr = self.transhandle
529 tr = self.transhandle
@@ -636,11 +645,11 b' class localrepository(repo.repository):'
636 changelist.append(fn)
645 changelist.append(fn)
637 return fl.add(t, meta, transaction, linkrev, fp1, fp2)
646 return fl.add(t, meta, transaction, linkrev, fp1, fp2)
638
647
639 def rawcommit(self, files, text, user, date, p1=None, p2=None, wlock=None):
648 def rawcommit(self, files, text, user, date, p1=None, p2=None, wlock=None, extra={}):
640 if p1 is None:
649 if p1 is None:
641 p1, p2 = self.dirstate.parents()
650 p1, p2 = self.dirstate.parents()
642 return self.commit(files=files, text=text, user=user, date=date,
651 return self.commit(files=files, text=text, user=user, date=date,
643 p1=p1, p2=p2, wlock=wlock)
652 p1=p1, p2=p2, wlock=wlock, extra=extra)
644
653
645 def commit(self, files=None, text="", user=None, date=None,
654 def commit(self, files=None, text="", user=None, date=None,
646 match=util.always, force=False, lock=None, wlock=None,
655 match=util.always, force=False, lock=None, wlock=None,
@@ -714,12 +723,14 b' class localrepository(repo.repository):'
714 new = {}
723 new = {}
715 linkrev = self.changelog.count()
724 linkrev = self.changelog.count()
716 commit.sort()
725 commit.sort()
726 is_exec = util.execfunc(self.root, m1.execf)
727 is_link = util.linkfunc(self.root, m1.linkf)
717 for f in commit:
728 for f in commit:
718 self.ui.note(f + "\n")
729 self.ui.note(f + "\n")
719 try:
730 try:
720 new[f] = self.filecommit(f, m1, m2, linkrev, tr, changed)
731 new[f] = self.filecommit(f, m1, m2, linkrev, tr, changed)
721 m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f)))
732 m1.set(f, is_exec(f), is_link(f))
722 except IOError:
733 except OSError:
723 if use_dirstate:
734 if use_dirstate:
724 self.ui.warn(_("trouble committing %s!\n") % f)
735 self.ui.warn(_("trouble committing %s!\n") % f)
725 raise
736 raise
@@ -729,11 +740,13 b' class localrepository(repo.repository):'
729 # update manifest
740 # update manifest
730 m1.update(new)
741 m1.update(new)
731 remove.sort()
742 remove.sort()
743 removed = []
732
744
733 for f in remove:
745 for f in remove:
734 if f in m1:
746 if f in m1:
735 del m1[f]
747 del m1[f]
736 mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0], (new, remove))
748 removed.append(f)
749 mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0], (new, removed))
737
750
738 # add changeset
751 # add changeset
739 new = new.keys()
752 new = new.keys()
@@ -748,8 +761,10 b' class localrepository(repo.repository):'
748 edittext.append("HG: user: %s" % user)
761 edittext.append("HG: user: %s" % user)
749 if p2 != nullid:
762 if p2 != nullid:
750 edittext.append("HG: branch merge")
763 edittext.append("HG: branch merge")
764 if branchname:
765 edittext.append("HG: branch %s" % util.tolocal(branchname))
751 edittext.extend(["HG: changed %s" % f for f in changed])
766 edittext.extend(["HG: changed %s" % f for f in changed])
752 edittext.extend(["HG: removed %s" % f for f in remove])
767 edittext.extend(["HG: removed %s" % f for f in removed])
753 if not changed and not remove:
768 if not changed and not remove:
754 edittext.append("HG: no files changed")
769 edittext.append("HG: no files changed")
755 edittext.append("")
770 edittext.append("")
@@ -767,17 +782,20 b' class localrepository(repo.repository):'
767 text = '\n'.join(lines)
782 text = '\n'.join(lines)
768 if branchname:
783 if branchname:
769 extra["branch"] = branchname
784 extra["branch"] = branchname
770 n = self.changelog.add(mn, changed + remove, text, tr, p1, p2,
785 n = self.changelog.add(mn, changed + removed, text, tr, p1, p2,
771 user, date, extra)
786 user, date, extra)
772 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
787 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
773 parent2=xp2)
788 parent2=xp2)
774 tr.close()
789 tr.close()
775
790
791 if self.branchcache and "branch" in extra:
792 self.branchcache[util.tolocal(extra["branch"])] = n
793
776 if use_dirstate or update_dirstate:
794 if use_dirstate or update_dirstate:
777 self.dirstate.setparents(n)
795 self.dirstate.setparents(n)
778 if use_dirstate:
796 if use_dirstate:
779 self.dirstate.update(new, "n")
797 self.dirstate.update(new, "n")
780 self.dirstate.forget(remove)
798 self.dirstate.forget(removed)
781
799
782 self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2)
800 self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2)
783 return n
801 return n
@@ -877,9 +895,11 b' class localrepository(repo.repository):'
877 # generate a pseudo-manifest for the working dir
895 # generate a pseudo-manifest for the working dir
878 # XXX: create it in dirstate.py ?
896 # XXX: create it in dirstate.py ?
879 mf2 = mfmatches(self.dirstate.parents()[0])
897 mf2 = mfmatches(self.dirstate.parents()[0])
898 is_exec = util.execfunc(self.root, mf2.execf)
899 is_link = util.linkfunc(self.root, mf2.linkf)
880 for f in lookup + modified + added:
900 for f in lookup + modified + added:
881 mf2[f] = ""
901 mf2[f] = ""
882 mf2.set(f, execf=util.is_exec(self.wjoin(f), mf2.execf(f)))
902 mf2.set(f, is_exec(f), is_link(f))
883 for f in removed:
903 for f in removed:
884 if f in mf2:
904 if f in mf2:
885 del mf2[f]
905 del mf2[f]
@@ -918,11 +938,12 b' class localrepository(repo.repository):'
918 wlock = self.wlock()
938 wlock = self.wlock()
919 for f in list:
939 for f in list:
920 p = self.wjoin(f)
940 p = self.wjoin(f)
921 if not os.path.exists(p):
941 islink = os.path.islink(p)
942 if not islink and not os.path.exists(p):
922 self.ui.warn(_("%s does not exist!\n") % f)
943 self.ui.warn(_("%s does not exist!\n") % f)
923 elif not os.path.isfile(p):
944 elif not islink and not os.path.isfile(p):
924 self.ui.warn(_("%s not added: only files supported currently\n")
945 self.ui.warn(_("%s not added: only files and symlinks "
925 % f)
946 "supported currently\n") % f)
926 elif self.dirstate.state(f) in 'an':
947 elif self.dirstate.state(f) in 'an':
927 self.ui.warn(_("%s already tracked!\n") % f)
948 self.ui.warn(_("%s already tracked!\n") % f)
928 else:
949 else:
@@ -969,8 +990,7 b' class localrepository(repo.repository):'
969 self.ui.warn("%s not removed!\n" % f)
990 self.ui.warn("%s not removed!\n" % f)
970 else:
991 else:
971 t = self.file(f).read(m[f])
992 t = self.file(f).read(m[f])
972 self.wwrite(f, t)
993 self.wwrite(f, t, m.flags(f))
973 util.set_exec(self.wjoin(f), m.execf(f))
974 self.dirstate.update([f], "n")
994 self.dirstate.update([f], "n")
975
995
976 def copy(self, source, dest, wlock=None):
996 def copy(self, source, dest, wlock=None):
@@ -993,112 +1013,6 b' class localrepository(repo.repository):'
993 heads.sort()
1013 heads.sort()
994 return [n for (r, n) in heads]
1014 return [n for (r, n) in heads]
995
1015
996 # branchlookup returns a dict giving a list of branches for
997 # each head. A branch is defined as the tag of a node or
998 # the branch of the node's parents. If a node has multiple
999 # branch tags, tags are eliminated if they are visible from other
1000 # branch tags.
1001 #
1002 # So, for this graph: a->b->c->d->e
1003 # \ /
1004 # aa -----/
1005 # a has tag 2.6.12
1006 # d has tag 2.6.13
1007 # e would have branch tags for 2.6.12 and 2.6.13. Because the node
1008 # for 2.6.12 can be reached from the node 2.6.13, that is eliminated
1009 # from the list.
1010 #
1011 # It is possible that more than one head will have the same branch tag.
1012 # callers need to check the result for multiple heads under the same
1013 # branch tag if that is a problem for them (ie checkout of a specific
1014 # branch).
1015 #
1016 # passing in a specific branch will limit the depth of the search
1017 # through the parents. It won't limit the branches returned in the
1018 # result though.
1019 def branchlookup(self, heads=None, branch=None):
1020 if not heads:
1021 heads = self.heads()
1022 headt = [ h for h in heads ]
1023 chlog = self.changelog
1024 branches = {}
1025 merges = []
1026 seenmerge = {}
1027
1028 # traverse the tree once for each head, recording in the branches
1029 # dict which tags are visible from this head. The branches
1030 # dict also records which tags are visible from each tag
1031 # while we traverse.
1032 while headt or merges:
1033 if merges:
1034 n, found = merges.pop()
1035 visit = [n]
1036 else:
1037 h = headt.pop()
1038 visit = [h]
1039 found = [h]
1040 seen = {}
1041 while visit:
1042 n = visit.pop()
1043 if n in seen:
1044 continue
1045 pp = chlog.parents(n)
1046 tags = self.nodetags(n)
1047 if tags:
1048 for x in tags:
1049 if x == 'tip':
1050 continue
1051 for f in found:
1052 branches.setdefault(f, {})[n] = 1
1053 branches.setdefault(n, {})[n] = 1
1054 break
1055 if n not in found:
1056 found.append(n)
1057 if branch in tags:
1058 continue
1059 seen[n] = 1
1060 if pp[1] != nullid and n not in seenmerge:
1061 merges.append((pp[1], [x for x in found]))
1062 seenmerge[n] = 1
1063 if pp[0] != nullid:
1064 visit.append(pp[0])
1065 # traverse the branches dict, eliminating branch tags from each
1066 # head that are visible from another branch tag for that head.
1067 out = {}
1068 viscache = {}
1069 for h in heads:
1070 def visible(node):
1071 if node in viscache:
1072 return viscache[node]
1073 ret = {}
1074 visit = [node]
1075 while visit:
1076 x = visit.pop()
1077 if x in viscache:
1078 ret.update(viscache[x])
1079 elif x not in ret:
1080 ret[x] = 1
1081 if x in branches:
1082 visit[len(visit):] = branches[x].keys()
1083 viscache[node] = ret
1084 return ret
1085 if h not in branches:
1086 continue
1087 # O(n^2), but somewhat limited. This only searches the
1088 # tags visible from a specific head, not all the tags in the
1089 # whole repo.
1090 for b in branches[h]:
1091 vis = False
1092 for bb in branches[h].keys():
1093 if b != bb:
1094 if b in visible(bb):
1095 vis = True
1096 break
1097 if not vis:
1098 l = out.setdefault(h, [])
1099 l[len(l):] = self.nodetags(b)
1100 return out
1101
1102 def branches(self, nodes):
1016 def branches(self, nodes):
1103 if not nodes:
1017 if not nodes:
1104 nodes = [self.changelog.tip()]
1018 nodes = [self.changelog.tip()]
@@ -5,8 +5,7 b''
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import *
8 import errno, os, socket, time, util
9 demandload(globals(), 'errno os socket time util')
10
9
11 class LockException(IOError):
10 class LockException(IOError):
12 def __init__(self, errno, strerror, filename, desc):
11 def __init__(self, errno, strerror, filename, desc):
@@ -5,9 +5,8 b''
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from i18n import gettext as _
8 from i18n import _
9 from demandload import *
9 import os, smtplib, templater, util
10 demandload(globals(), "os re smtplib templater util")
11
10
12 def _smtp(ui):
11 def _smtp(ui):
13 '''send mail using smtp.'''
12 '''send mail using smtp.'''
@@ -6,10 +6,8 b''
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from revlog import *
8 from revlog import *
9 from i18n import gettext as _
9 from i18n import _
10 from demandload import *
10 import array, bisect, struct, mdiff
11 demandload(globals(), "array bisect struct")
12 demandload(globals(), "mdiff")
13
11
14 class manifestdict(dict):
12 class manifestdict(dict):
15 def __init__(self, mapping=None, flags=None):
13 def __init__(self, mapping=None, flags=None):
@@ -5,9 +5,7 b''
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import demandload
8 import bdiff, mpatch, re, struct, util
9 import bdiff, mpatch
10 demandload(globals(), "re struct util")
11
9
12 def splitnewlines(text):
10 def splitnewlines(text):
13 '''like str.splitlines, but only split on newlines.'''
11 '''like str.splitlines, but only split on newlines.'''
@@ -6,9 +6,8 b''
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from node import *
8 from node import *
9 from i18n import gettext as _
9 from i18n import _
10 from demandload import *
10 import errno, util, os, tempfile
11 demandload(globals(), "errno util os tempfile")
12
11
13 def filemerge(repo, fw, fo, wctx, mctx):
12 def filemerge(repo, fw, fo, wctx, mctx):
14 """perform a 3-way merge in the working directory
13 """perform a 3-way merge in the working directory
@@ -21,8 +20,9 b' def filemerge(repo, fw, fo, wctx, mctx):'
21 def temp(prefix, ctx):
20 def temp(prefix, ctx):
22 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
21 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
23 (fd, name) = tempfile.mkstemp(prefix=pre)
22 (fd, name) = tempfile.mkstemp(prefix=pre)
23 data = repo.wwritedata(ctx.path(), ctx.data())
24 f = os.fdopen(fd, "wb")
24 f = os.fdopen(fd, "wb")
25 repo.wwrite(ctx.path(), ctx.data(), f)
25 f.write(data)
26 f.close()
26 f.close()
27 return name
27 return name
28
28
@@ -220,12 +220,17 b' def manifestmerge(repo, p1, p2, pa, over'
220 copy = {}
220 copy = {}
221
221
222 def fmerge(f, f2=None, fa=None):
222 def fmerge(f, f2=None, fa=None):
223 """merge executable flags"""
223 """merge flags"""
224 if not f2:
224 if not f2:
225 f2 = f
225 f2 = f
226 fa = f
226 fa = f
227 a, b, c = ma.execf(fa), m1.execf(f), m2.execf(f2)
227 a, b, c = ma.execf(fa), m1.execf(f), m2.execf(f2)
228 return ((a^b) | (a^c)) ^ a
228 if ((a^b) | (a^c)) ^ a:
229 return 'x'
230 a, b, c = ma.linkf(fa), m1.linkf(f), m2.linkf(f2)
231 if ((a^b) | (a^c)) ^ a:
232 return 'l'
233 return ''
229
234
230 def act(msg, m, f, *args):
235 def act(msg, m, f, *args):
231 repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m))
236 repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m))
@@ -250,21 +255,21 b' def manifestmerge(repo, p1, p2, pa, over'
250 # is remote's version newer?
255 # is remote's version newer?
251 # or are we going back in time and clean?
256 # or are we going back in time and clean?
252 elif overwrite or m2[f] != a or (backwards and not n[20:]):
257 elif overwrite or m2[f] != a or (backwards and not n[20:]):
253 act("remote is newer", "g", f, m2.execf(f))
258 act("remote is newer", "g", f, m2.flags(f))
254 # local is newer, not overwrite, check mode bits
259 # local is newer, not overwrite, check mode bits
255 elif fmerge(f) != m1.execf(f):
260 elif fmerge(f) != m1.flags(f):
256 act("update permissions", "e", f, m2.execf(f))
261 act("update permissions", "e", f, m2.flags(f))
257 # contents same, check mode bits
262 # contents same, check mode bits
258 elif m1.execf(f) != m2.execf(f):
263 elif m1.flags(f) != m2.flags(f):
259 if overwrite or fmerge(f) != m1.execf(f):
264 if overwrite or fmerge(f) != m1.flags(f):
260 act("update permissions", "e", f, m2.execf(f))
265 act("update permissions", "e", f, m2.flags(f))
261 elif f in copied:
266 elif f in copied:
262 continue
267 continue
263 elif f in copy:
268 elif f in copy:
264 f2 = copy[f]
269 f2 = copy[f]
265 if f2 not in m2: # directory rename
270 if f2 not in m2: # directory rename
266 act("remote renamed directory to " + f2, "d",
271 act("remote renamed directory to " + f2, "d",
267 f, None, f2, m1.execf(f))
272 f, None, f2, m1.flags(f))
268 elif f2 in m1: # case 2 A,B/B/B
273 elif f2 in m1: # case 2 A,B/B/B
269 act("local copied to " + f2, "m",
274 act("local copied to " + f2, "m",
270 f, f2, f, fmerge(f, f2, f2), False)
275 f, f2, f, fmerge(f, f2, f2), False)
@@ -295,7 +300,7 b' def manifestmerge(repo, p1, p2, pa, over'
295 f2 = copy[f]
300 f2 = copy[f]
296 if f2 not in m1: # directory rename
301 if f2 not in m1: # directory rename
297 act("local renamed directory to " + f2, "d",
302 act("local renamed directory to " + f2, "d",
298 None, f, f2, m2.execf(f))
303 None, f, f2, m2.flags(f))
299 elif f2 in m2: # rename case 1, A/A,B/A
304 elif f2 in m2: # rename case 1, A/A,B/A
300 act("remote copied to " + f, "m",
305 act("remote copied to " + f, "m",
301 f2, f, f, fmerge(f2, f, f2), False)
306 f2, f, f, fmerge(f2, f, f2), False)
@@ -304,14 +309,14 b' def manifestmerge(repo, p1, p2, pa, over'
304 f2, f, f, fmerge(f2, f, f2), True)
309 f2, f, f, fmerge(f2, f, f2), True)
305 elif f in ma:
310 elif f in ma:
306 if overwrite or backwards:
311 if overwrite or backwards:
307 act("recreating", "g", f, m2.execf(f))
312 act("recreating", "g", f, m2.flags(f))
308 elif n != ma[f]:
313 elif n != ma[f]:
309 if repo.ui.prompt(
314 if repo.ui.prompt(
310 (_("remote changed %s which local deleted\n") % f) +
315 (_("remote changed %s which local deleted\n") % f) +
311 _("(k)eep or (d)elete?"), _("[kd]"), _("k")) == _("k"):
316 _("(k)eep or (d)elete?"), _("[kd]"), _("k")) == _("k"):
312 act("prompt recreating", "g", f, m2.execf(f))
317 act("prompt recreating", "g", f, m2.flags(f))
313 else:
318 else:
314 act("remote created", "g", f, m2.execf(f))
319 act("remote created", "g", f, m2.flags(f))
315
320
316 return action
321 return action
317
322
@@ -335,7 +340,7 b' def applyupdates(repo, action, wctx, mct'
335 (f, inst.strerror))
340 (f, inst.strerror))
336 removed += 1
341 removed += 1
337 elif m == "m": # merge
342 elif m == "m": # merge
338 f2, fd, flag, move = a[2:]
343 f2, fd, flags, move = a[2:]
339 r = filemerge(repo, f, f2, wctx, mctx)
344 r = filemerge(repo, f, f2, wctx, mctx)
340 if r > 0:
345 if r > 0:
341 unresolved += 1
346 unresolved += 1
@@ -346,35 +351,32 b' def applyupdates(repo, action, wctx, mct'
346 merged += 1
351 merged += 1
347 if f != fd:
352 if f != fd:
348 repo.ui.debug(_("copying %s to %s\n") % (f, fd))
353 repo.ui.debug(_("copying %s to %s\n") % (f, fd))
349 repo.wwrite(fd, repo.wread(f))
354 repo.wwrite(fd, repo.wread(f), flags)
350 if move:
355 if move:
351 repo.ui.debug(_("removing %s\n") % f)
356 repo.ui.debug(_("removing %s\n") % f)
352 os.unlink(repo.wjoin(f))
357 os.unlink(repo.wjoin(f))
353 util.set_exec(repo.wjoin(fd), flag)
358 util.set_exec(repo.wjoin(fd), "x" in flags)
354 elif m == "g": # get
359 elif m == "g": # get
355 flag = a[2]
360 flags = a[2]
356 repo.ui.note(_("getting %s\n") % f)
361 repo.ui.note(_("getting %s\n") % f)
357 t = mctx.filectx(f).data()
362 t = mctx.filectx(f).data()
358 repo.wwrite(f, t)
363 repo.wwrite(f, t, flags)
359 util.set_exec(repo.wjoin(f), flag)
360 updated += 1
364 updated += 1
361 elif m == "d": # directory rename
365 elif m == "d": # directory rename
362 f2, fd, flag = a[2:]
366 f2, fd, flags = a[2:]
363 if f:
367 if f:
364 repo.ui.note(_("moving %s to %s\n") % (f, fd))
368 repo.ui.note(_("moving %s to %s\n") % (f, fd))
365 t = wctx.filectx(f).data()
369 t = wctx.filectx(f).data()
366 repo.wwrite(fd, t)
370 repo.wwrite(fd, t, flags)
367 util.set_exec(repo.wjoin(fd), flag)
368 util.unlink(repo.wjoin(f))
371 util.unlink(repo.wjoin(f))
369 if f2:
372 if f2:
370 repo.ui.note(_("getting %s to %s\n") % (f2, fd))
373 repo.ui.note(_("getting %s to %s\n") % (f2, fd))
371 t = mctx.filectx(f2).data()
374 t = mctx.filectx(f2).data()
372 repo.wwrite(fd, t)
375 repo.wwrite(fd, t, flags)
373 util.set_exec(repo.wjoin(fd), flag)
374 updated += 1
376 updated += 1
375 elif m == "e": # exec
377 elif m == "e": # exec
376 flag = a[2]
378 flags = a[2]
377 util.set_exec(repo.wjoin(f), flag)
379 util.set_exec(repo.wjoin(f), flags)
378
380
379 return updated, merged, removed, unresolved
381 return updated, merged, removed, unresolved
380
382
@@ -441,6 +443,9 b' def update(repo, node, branchmerge, forc'
441 wlock = working dir lock, if already held
443 wlock = working dir lock, if already held
442 """
444 """
443
445
446 if node is None:
447 node = "tip"
448
444 if not wlock:
449 if not wlock:
445 wlock = repo.wlock()
450 wlock = repo.wlock()
446
451
@@ -7,8 +7,7 b' This software may be used and distribute'
7 of the GNU General Public License, incorporated herein by reference.
7 of the GNU General Public License, incorporated herein by reference.
8 """
8 """
9
9
10 from demandload import demandload
10 import binascii
11 demandload(globals(), "binascii")
12
11
13 nullrev = -1
12 nullrev = -1
14 nullid = "\0" * 20
13 nullid = "\0" * 20
@@ -5,12 +5,11 b''
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import demandload
8 from i18n import _
9 from i18n import gettext as _
10 from node import *
9 from node import *
11 demandload(globals(), "base85 cmdutil mdiff util")
10 import base85, cmdutil, mdiff, util, context, revlog
12 demandload(globals(), "cStringIO email.Parser errno os popen2 re shutil sha")
11 import cStringIO, email.Parser, os, popen2, re, sha
13 demandload(globals(), "sys tempfile zlib")
12 import sys, tempfile, zlib
14
13
15 # helper functions
14 # helper functions
16
15
@@ -378,8 +377,9 b' def updatedir(ui, repo, patches, wlock=N'
378 dst = os.path.join(repo.root, gp.path)
377 dst = os.path.join(repo.root, gp.path)
379 # patch won't create empty files
378 # patch won't create empty files
380 if ctype == 'ADD' and not os.path.exists(dst):
379 if ctype == 'ADD' and not os.path.exists(dst):
381 repo.wwrite(gp.path, '')
380 repo.wwrite(gp.path, '', x and 'x' or '')
382 util.set_exec(dst, x)
381 else:
382 util.set_exec(dst, x)
383 cmdutil.addremove(repo, cfiles, wlock=wlock)
383 cmdutil.addremove(repo, cfiles, wlock=wlock)
384 files = patches.keys()
384 files = patches.keys()
385 files.extend([r for r in removes if r not in files])
385 files.extend([r for r in removes if r not in files])
@@ -437,27 +437,25 b' def diff(repo, node1=None, node2=None, f'
437 if not node1:
437 if not node1:
438 node1 = repo.dirstate.parents()[0]
438 node1 = repo.dirstate.parents()[0]
439
439
440 clcache = {}
440 ccache = {}
441 def getchangelog(n):
441 def getctx(r):
442 if n not in clcache:
442 if r not in ccache:
443 clcache[n] = repo.changelog.read(n)
443 ccache[r] = context.changectx(repo, r)
444 return clcache[n]
444 return ccache[r]
445 mcache = {}
445
446 def getmanifest(n):
446 flcache = {}
447 if n not in mcache:
447 def getfilectx(f, ctx):
448 mcache[n] = repo.manifest.read(n)
448 flctx = ctx.filectx(f, filelog=flcache.get(f))
449 return mcache[n]
449 if f not in flcache:
450 fcache = {}
450 flcache[f] = flctx._filelog
451 def getfile(f):
451 return flctx
452 if f not in fcache:
453 fcache[f] = repo.file(f)
454 return fcache[f]
455
452
456 # reading the data for node1 early allows it to play nicely
453 # reading the data for node1 early allows it to play nicely
457 # with repo.status and the revlog cache.
454 # with repo.status and the revlog cache.
458 change = getchangelog(node1)
455 ctx1 = context.changectx(repo, node1)
459 mmap = getmanifest(change[0])
456 # force manifest reading
460 date1 = util.datestr(change[2])
457 man1 = ctx1.manifest()
458 date1 = util.datestr(ctx1.date())
461
459
462 if not changes:
460 if not changes:
463 changes = repo.status(node1, node2, files, match=match)[:5]
461 changes = repo.status(node1, node2, files, match=match)[:5]
@@ -477,67 +475,38 b' def diff(repo, node1=None, node2=None, f'
477 if not modified and not added and not removed:
475 if not modified and not added and not removed:
478 return
476 return
479
477
480 # returns False if there was no rename between n1 and n2
478 if node2:
481 # returns None if the file was created between n1 and n2
479 ctx2 = context.changectx(repo, node2)
482 # returns the (file, node) present in n1 that was renamed to f in n2
480 else:
483 def renamedbetween(f, n1, n2):
481 ctx2 = context.workingctx(repo)
484 r1, r2 = map(repo.changelog.rev, (n1, n2))
482 man2 = ctx2.manifest()
483
484 # returns False if there was no rename between ctx1 and ctx2
485 # returns None if the file was created between ctx1 and ctx2
486 # returns the (file, node) present in ctx1 that was renamed to f in ctx2
487 def renamed(f):
488 startrev = ctx1.rev()
489 c = ctx2
490 crev = c.rev()
491 if crev is None:
492 crev = repo.changelog.count()
485 orig = f
493 orig = f
486 src = None
494 while crev > startrev:
487 while r2 > r1:
495 if f in c.files():
488 cl = getchangelog(n2)
489 if f in cl[3]:
490 m = getmanifest(cl[0])
491 try:
496 try:
492 src = getfile(f).renamed(m[f])
497 src = getfilectx(f, c).renamed()
493 except KeyError:
498 except revlog.LookupError:
494 return None
499 return None
495 if src:
500 if src:
496 f = src[0]
501 f = src[0]
497 n2 = repo.changelog.parents(n2)[0]
502 crev = c.parents()[0].rev()
498 r2 = repo.changelog.rev(n2)
503 # try to reuse
499 cl = getchangelog(n1)
504 c = getctx(crev)
500 m = getmanifest(cl[0])
505 if f not in man1:
501 if f not in m:
502 return None
506 return None
503 if f == orig:
507 if f == orig:
504 return False
508 return False
505 return f, m[f]
509 return f
506
507 if node2:
508 change = getchangelog(node2)
509 mmap2 = getmanifest(change[0])
510 _date2 = util.datestr(change[2])
511 def date2(f):
512 return _date2
513 def read(f):
514 return getfile(f).read(mmap2[f])
515 def renamed(f):
516 return renamedbetween(f, node1, node2)
517 else:
518 tz = util.makedate()[1]
519 _date2 = util.datestr()
520 def date2(f):
521 try:
522 return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz))
523 except OSError, err:
524 if err.errno != errno.ENOENT: raise
525 return _date2
526 def read(f):
527 return repo.wread(f)
528 def renamed(f):
529 src = repo.dirstate.copied(f)
530 parent = repo.dirstate.parents()[0]
531 if src:
532 f = src
533 of = renamedbetween(f, node1, parent)
534 if of or of is None:
535 return of
536 elif src:
537 cl = getchangelog(parent)[0]
538 return (src, getmanifest(cl)[src])
539 else:
540 return None
541
510
542 if repo.ui.quiet:
511 if repo.ui.quiet:
543 r = None
512 r = None
@@ -551,20 +520,21 b' def diff(repo, node1=None, node2=None, f'
551 src = renamed(f)
520 src = renamed(f)
552 if src:
521 if src:
553 copied[f] = src
522 copied[f] = src
554 srcs = [x[1][0] for x in copied.items()]
523 srcs = [x[1] for x in copied.items()]
555
524
556 all = modified + added + removed
525 all = modified + added + removed
557 all.sort()
526 all.sort()
558 gone = {}
527 gone = {}
528
559 for f in all:
529 for f in all:
560 to = None
530 to = None
561 tn = None
531 tn = None
562 dodiff = True
532 dodiff = True
563 header = []
533 header = []
564 if f in mmap:
534 if f in man1:
565 to = getfile(f).read(mmap[f])
535 to = getfilectx(f, ctx1).data()
566 if f not in removed:
536 if f not in removed:
567 tn = read(f)
537 tn = getfilectx(f, ctx2).data()
568 if opts.git:
538 if opts.git:
569 def gitmode(x):
539 def gitmode(x):
570 return x and '100755' or '100644'
540 return x and '100755' or '100644'
@@ -575,13 +545,10 b' def diff(repo, node1=None, node2=None, f'
575
545
576 a, b = f, f
546 a, b = f, f
577 if f in added:
547 if f in added:
578 if node2:
548 mode = gitmode(man2.execf(f))
579 mode = gitmode(mmap2.execf(f))
580 else:
581 mode = gitmode(util.is_exec(repo.wjoin(f), None))
582 if f in copied:
549 if f in copied:
583 a, arev = copied[f]
550 a = copied[f]
584 omode = gitmode(mmap.execf(a))
551 omode = gitmode(man1.execf(a))
585 addmodehdr(header, omode, mode)
552 addmodehdr(header, omode, mode)
586 if a in removed and a not in gone:
553 if a in removed and a not in gone:
587 op = 'rename'
554 op = 'rename'
@@ -590,7 +557,7 b' def diff(repo, node1=None, node2=None, f'
590 op = 'copy'
557 op = 'copy'
591 header.append('%s from %s\n' % (op, a))
558 header.append('%s from %s\n' % (op, a))
592 header.append('%s to %s\n' % (op, f))
559 header.append('%s to %s\n' % (op, f))
593 to = getfile(a).read(arev)
560 to = getfilectx(a, ctx1).data()
594 else:
561 else:
595 header.append('new file mode %s\n' % mode)
562 header.append('new file mode %s\n' % mode)
596 if util.binary(tn):
563 if util.binary(tn):
@@ -599,14 +566,11 b' def diff(repo, node1=None, node2=None, f'
599 if f in srcs:
566 if f in srcs:
600 dodiff = False
567 dodiff = False
601 else:
568 else:
602 mode = gitmode(mmap.execf(f))
569 mode = gitmode(man1.execf(f))
603 header.append('deleted file mode %s\n' % mode)
570 header.append('deleted file mode %s\n' % mode)
604 else:
571 else:
605 omode = gitmode(mmap.execf(f))
572 omode = gitmode(man1.execf(f))
606 if node2:
573 nmode = gitmode(man2.execf(f))
607 nmode = gitmode(mmap2.execf(f))
608 else:
609 nmode = gitmode(util.is_exec(repo.wjoin(f), mmap.execf(f)))
610 addmodehdr(header, omode, nmode)
574 addmodehdr(header, omode, nmode)
611 if util.binary(to) or util.binary(tn):
575 if util.binary(to) or util.binary(tn):
612 dodiff = 'binary'
576 dodiff = 'binary'
@@ -616,7 +580,10 b' def diff(repo, node1=None, node2=None, f'
616 fp.write(''.join(header))
580 fp.write(''.join(header))
617 b85diff(fp, to, tn)
581 b85diff(fp, to, tn)
618 elif dodiff:
582 elif dodiff:
619 text = mdiff.unidiff(to, date1, tn, date2(f), f, r, opts=opts)
583 text = mdiff.unidiff(to, date1,
584 # ctx2 date may be dynamic
585 tn, util.datestr(ctx2.date()),
586 f, r, opts=opts)
620 if text or len(header) > 1:
587 if text or len(header) > 1:
621 fp.write(''.join(header))
588 fp.write(''.join(header))
622 fp.write(text)
589 fp.write(text)
@@ -628,12 +595,13 b" def export(repo, revs, template='hg-%h.p"
628 total = len(revs)
595 total = len(revs)
629 revwidth = max([len(str(rev)) for rev in revs])
596 revwidth = max([len(str(rev)) for rev in revs])
630
597
631 def single(node, seqno, fp):
598 def single(rev, seqno, fp):
632 parents = [p for p in repo.changelog.parents(node) if p != nullid]
599 ctx = repo.changectx(rev)
600 node = ctx.node()
601 parents = [p.node() for p in ctx.parents() if p]
633 if switch_parent:
602 if switch_parent:
634 parents.reverse()
603 parents.reverse()
635 prev = (parents and parents[0]) or nullid
604 prev = (parents and parents[0]) or nullid
636 change = repo.changelog.read(node)
637
605
638 if not fp:
606 if not fp:
639 fp = cmdutil.make_file(repo, template, node, total=total,
607 fp = cmdutil.make_file(repo, template, node, total=total,
@@ -642,13 +610,13 b" def export(repo, revs, template='hg-%h.p"
642 repo.ui.note("%s\n" % fp.name)
610 repo.ui.note("%s\n" % fp.name)
643
611
644 fp.write("# HG changeset patch\n")
612 fp.write("# HG changeset patch\n")
645 fp.write("# User %s\n" % change[1])
613 fp.write("# User %s\n" % ctx.user())
646 fp.write("# Date %d %d\n" % change[2])
614 fp.write("# Date %d %d\n" % ctx.date())
647 fp.write("# Node ID %s\n" % hex(node))
615 fp.write("# Node ID %s\n" % hex(node))
648 fp.write("# Parent %s\n" % hex(prev))
616 fp.write("# Parent %s\n" % hex(prev))
649 if len(parents) > 1:
617 if len(parents) > 1:
650 fp.write("# Parent %s\n" % hex(parents[1]))
618 fp.write("# Parent %s\n" % hex(parents[1]))
651 fp.write(change[4].rstrip())
619 fp.write(ctx.description().rstrip())
652 fp.write("\n\n")
620 fp.write("\n\n")
653
621
654 diff(repo, prev, node, fp=fp, opts=opts)
622 diff(repo, prev, node, fp=fp, opts=opts)
@@ -656,7 +624,7 b" def export(repo, revs, template='hg-%h.p"
656 fp.close()
624 fp.close()
657
625
658 for seqno, rev in enumerate(revs):
626 for seqno, rev in enumerate(revs):
659 single(repo.lookup(rev), seqno+1, fp)
627 single(rev, seqno+1, fp)
660
628
661 def diffstat(patchlines):
629 def diffstat(patchlines):
662 fd, name = tempfile.mkstemp(prefix="hg-patchbomb-", suffix=".txt")
630 fd, name = tempfile.mkstemp(prefix="hg-patchbomb-", suffix=".txt")
@@ -9,9 +9,6 b''
9 class RepoError(Exception):
9 class RepoError(Exception):
10 pass
10 pass
11
11
12 class LookupError(RepoError):
13 pass
14
15 class repository(object):
12 class repository(object):
16 def capable(self, name):
13 def capable(self, name):
17 '''tell whether repo supports named capability.
14 '''tell whether repo supports named capability.
@@ -11,10 +11,9 b' of the GNU General Public License, incor'
11 """
11 """
12
12
13 from node import *
13 from node import *
14 from i18n import gettext as _
14 from i18n import _
15 from demandload import demandload
15 import binascii, changegroup, errno, ancestor, mdiff, os
16 demandload(globals(), "binascii changegroup errno ancestor mdiff os")
16 import sha, struct, util, zlib
17 demandload(globals(), "sha struct util zlib")
18
17
19 # revlog version strings
18 # revlog version strings
20 REVLOGV0 = 0
19 REVLOGV0 = 0
@@ -282,6 +281,7 b' class lazymap(object):'
282 del self.p.map[key]
281 del self.p.map[key]
283
282
284 class RevlogError(Exception): pass
283 class RevlogError(Exception): pass
284 class LookupError(RevlogError): pass
285
285
286 class revlog(object):
286 class revlog(object):
287 """
287 """
@@ -472,7 +472,7 b' class revlog(object):'
472 try:
472 try:
473 return self.nodemap[node]
473 return self.nodemap[node]
474 except KeyError:
474 except KeyError:
475 raise RevlogError(_('%s: no node %s') % (self.indexfile, hex(node)))
475 raise LookupError(_('%s: no node %s') % (self.indexfile, hex(node)))
476 def linkrev(self, node):
476 def linkrev(self, node):
477 return (node == nullid) and nullrev or self.index[self.rev(node)][-4]
477 return (node == nullid) and nullrev or self.index[self.rev(node)][-4]
478 def parents(self, node):
478 def parents(self, node):
@@ -767,7 +767,7 b' class revlog(object):'
767 node = id
767 node = id
768 r = self.rev(node) # quick search the index
768 r = self.rev(node) # quick search the index
769 return node
769 return node
770 except RevlogError:
770 except LookupError:
771 pass # may be partial hex id
771 pass # may be partial hex id
772 try:
772 try:
773 # str(rev)
773 # str(rev)
@@ -796,7 +796,7 b' class revlog(object):'
796 for n in self.nodemap:
796 for n in self.nodemap:
797 if n.startswith(bin_id) and hex(n).startswith(id):
797 if n.startswith(bin_id) and hex(n).startswith(id):
798 if node is not None:
798 if node is not None:
799 raise RevlogError(_("Ambiguous identifier"))
799 raise LookupError(_("Ambiguous identifier"))
800 node = n
800 node = n
801 if node is not None:
801 if node is not None:
802 return node
802 return node
@@ -816,7 +816,7 b' class revlog(object):'
816 if n:
816 if n:
817 return n
817 return n
818
818
819 raise RevlogError(_("No match found"))
819 raise LookupError(_("No match found"))
820
820
821 def cmp(self, node, text):
821 def cmp(self, node, text):
822 """compare text with a given file revision"""
822 """compare text with a given file revision"""
@@ -1156,13 +1156,13 b' class revlog(object):'
1156
1156
1157 for p in (p1, p2):
1157 for p in (p1, p2):
1158 if not p in self.nodemap:
1158 if not p in self.nodemap:
1159 raise RevlogError(_("unknown parent %s") % short(p))
1159 raise LookupError(_("unknown parent %s") % short(p))
1160
1160
1161 if not chain:
1161 if not chain:
1162 # retrieve the parent revision of the delta chain
1162 # retrieve the parent revision of the delta chain
1163 chain = p1
1163 chain = p1
1164 if not chain in self.nodemap:
1164 if not chain in self.nodemap:
1165 raise RevlogError(_("unknown base %s") % short(chain[:4]))
1165 raise LookupError(_("unknown base %s") % short(chain[:4]))
1166
1166
1167 # full versions are inserted when the needed deltas become
1167 # full versions are inserted when the needed deltas become
1168 # comparable to the uncompressed text or when the previous
1168 # comparable to the uncompressed text or when the previous
@@ -7,9 +7,8 b''
7
7
8 from node import *
8 from node import *
9 from remoterepo import *
9 from remoterepo import *
10 from i18n import gettext as _
10 from i18n import _
11 from demandload import *
11 import hg, os, re, stat, util
12 demandload(globals(), "hg os re stat util")
13
12
14 class sshrepository(remoterepository):
13 class sshrepository(remoterepository):
15 def __init__(self, ui, path, create=0):
14 def __init__(self, ui, path, create=0):
@@ -6,10 +6,9 b''
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8
8
9 from demandload import demandload
9 from i18n import _
10 from i18n import gettext as _
11 from node import *
10 from node import *
12 demandload(globals(), "os streamclone sys tempfile util")
11 import os, streamclone, sys, tempfile, util
13
12
14 class sshserver(object):
13 class sshserver(object):
15 def __init__(self, ui, repo):
14 def __init__(self, ui, repo):
@@ -7,10 +7,9 b''
7 # This software may be used and distributed according to the terms
7 # This software may be used and distributed according to the terms
8 # of the GNU General Public License, incorporated herein by reference.
8 # of the GNU General Public License, incorporated herein by reference.
9
9
10 from demandload import *
10 from i18n import _
11 from i18n import gettext as _
11 import changelog, filelog, httprangereader
12 demandload(globals(), "changelog filelog httprangereader")
12 import repo, localrepo, manifest, os, urllib, urllib2, util
13 demandload(globals(), "repo localrepo manifest os urllib urllib2 util")
14
13
15 class rangereader(httprangereader.httprangereader):
14 class rangereader(httprangereader.httprangereader):
16 def read(self, size=None):
15 def read(self, size=None):
@@ -5,9 +5,8 b''
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import demandload
8 from i18n import _
9 from i18n import gettext as _
9 import os, stat, util, lock
10 demandload(globals(), "os stat util lock")
11
10
12 # if server supports streaming clone, it advertises "stream"
11 # if server supports streaming clone, it advertises "stream"
13 # capability with value that is version+flags of repo it is serving.
12 # capability with value that is version+flags of repo it is serving.
@@ -5,10 +5,9 b''
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import demandload
8 from i18n import _
9 from i18n import gettext as _
10 from node import *
9 from node import *
11 demandload(globals(), "cgi re sys os time urllib util textwrap")
10 import cgi, re, sys, os, time, urllib, util, textwrap
12
11
13 def parsestring(s, quoted=True):
12 def parsestring(s, quoted=True):
14 '''parse a string using simple c-like syntax.
13 '''parse a string using simple c-like syntax.
@@ -11,9 +11,8 b''
11 # This software may be used and distributed according to the terms
11 # This software may be used and distributed according to the terms
12 # of the GNU General Public License, incorporated herein by reference.
12 # of the GNU General Public License, incorporated herein by reference.
13
13
14 from demandload import demandload
14 from i18n import _
15 from i18n import gettext as _
15 import os
16 demandload(globals(), 'os')
17
16
18 class transaction(object):
17 class transaction(object):
19 def __init__(self, report, opener, journal, after=None):
18 def __init__(self, report, opener, journal, after=None):
@@ -5,10 +5,9 b''
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from i18n import gettext as _
8 from i18n import _
9 from demandload import *
9 import errno, getpass, os, re, socket, sys, tempfile
10 demandload(globals(), "errno getpass os re socket sys tempfile")
10 import ConfigParser, traceback, util
11 demandload(globals(), "ConfigParser traceback util")
12
11
13 def dupconfig(orig):
12 def dupconfig(orig):
14 new = util.configparser(orig.defaults())
13 new = util.configparser(orig.defaults())
@@ -386,6 +385,9 b' class ui(object):'
386 if not sys.stdout.closed: sys.stdout.flush()
385 if not sys.stdout.closed: sys.stdout.flush()
387 for a in args:
386 for a in args:
388 sys.stderr.write(str(a))
387 sys.stderr.write(str(a))
388 # stderr may be buffered under win32 when redirected to files,
389 # including stdout.
390 if not sys.stderr.closed: sys.stderr.flush()
389 except IOError, inst:
391 except IOError, inst:
390 if inst.errno != errno.EPIPE:
392 if inst.errno != errno.EPIPE:
391 raise
393 raise
@@ -12,10 +12,9 b' This contains helper routines that are i'
12 platform-specific details from the core.
12 platform-specific details from the core.
13 """
13 """
14
14
15 from i18n import gettext as _
15 from i18n import _
16 from demandload import *
16 import cStringIO, errno, getpass, popen2, re, shutil, sys, tempfile
17 demandload(globals(), "cStringIO errno getpass popen2 re shutil sys tempfile")
17 import os, threading, time, calendar, ConfigParser, locale
18 demandload(globals(), "os threading time calendar ConfigParser locale")
19
18
20 _encoding = os.environ.get("HGENCODING") or locale.getpreferredencoding() \
19 _encoding = os.environ.get("HGENCODING") or locale.getpreferredencoding() \
21 or "ascii"
20 or "ascii"
@@ -694,9 +693,47 b' def checkfolding(path):'
694 except:
693 except:
695 return True
694 return True
696
695
696 def checkexec(path):
697 """
698 Check whether the given path is on a filesystem with UNIX-like exec flags
699
700 Requires a directory (like /foo/.hg)
701 """
702 fh, fn = tempfile.mkstemp("", "", path)
703 os.close(fh)
704 m = os.stat(fn).st_mode
705 os.chmod(fn, m ^ 0111)
706 r = (os.stat(fn).st_mode != m)
707 os.unlink(fn)
708 return r
709
710 def execfunc(path, fallback):
711 '''return an is_exec() function with default to fallback'''
712 if checkexec(path):
713 return lambda x: is_exec(os.path.join(path, x))
714 return fallback
715
716 def checklink(path):
717 """check whether the given path is on a symlink-capable filesystem"""
718 # mktemp is not racy because symlink creation will fail if the
719 # file already exists
720 name = tempfile.mktemp(dir=path)
721 try:
722 os.symlink(".", name)
723 os.unlink(name)
724 return True
725 except (OSError, AttributeError):
726 return False
727
728 def linkfunc(path, fallback):
729 '''return an is_link() function with default to fallback'''
730 if checklink(path):
731 return lambda x: is_link(os.path.join(path, x))
732 return fallback
733
697 # Platform specific variants
734 # Platform specific variants
698 if os.name == 'nt':
735 if os.name == 'nt':
699 demandload(globals(), "msvcrt")
736 import msvcrt
700 nulldev = 'NUL:'
737 nulldev = 'NUL:'
701
738
702 class winstdout:
739 class winstdout:
@@ -753,10 +790,10 b" if os.name == 'nt':"
753 '''return False if pid dead, True if running or not known'''
790 '''return False if pid dead, True if running or not known'''
754 return True
791 return True
755
792
756 def is_exec(f, last):
793 def set_exec(f, mode):
757 return last
794 pass
758
795
759 def set_exec(f, mode):
796 def set_link(f, mode):
760 pass
797 pass
761
798
762 def set_binary(fd):
799 def set_binary(fd):
@@ -798,6 +835,8 b" if os.name == 'nt':"
798
835
799 else:
836 else:
800 nulldev = '/dev/null'
837 nulldev = '/dev/null'
838 _umask = os.umask(0)
839 os.umask(_umask)
801
840
802 def rcfiles(path):
841 def rcfiles(path):
803 rcs = [os.path.join(path, 'hgrc')]
842 rcs = [os.path.join(path, 'hgrc')]
@@ -828,7 +867,7 b' else:'
828 pf = pf[1:-1] # Remove the quotes
867 pf = pf[1:-1] # Remove the quotes
829 return pf
868 return pf
830
869
831 def is_exec(f, last):
870 def is_exec(f):
832 """check whether a file is executable"""
871 """check whether a file is executable"""
833 return (os.lstat(f).st_mode & 0100 != 0)
872 return (os.lstat(f).st_mode & 0100 != 0)
834
873
@@ -839,12 +878,34 b' else:'
839 if mode:
878 if mode:
840 # Turn on +x for every +r bit when making a file executable
879 # Turn on +x for every +r bit when making a file executable
841 # and obey umask.
880 # and obey umask.
842 umask = os.umask(0)
881 os.chmod(f, s | (s & 0444) >> 2 & ~_umask)
843 os.umask(umask)
844 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
845 else:
882 else:
846 os.chmod(f, s & 0666)
883 os.chmod(f, s & 0666)
847
884
885 def is_link(f):
886 """check whether a file is a symlink"""
887 return (os.lstat(f).st_mode & 0120000 == 0120000)
888
889 def set_link(f, mode):
890 """make a file a symbolic link/regular file
891
892 if a file is changed to a link, its contents become the link data
893 if a link is changed to a file, its link data become its contents
894 """
895
896 m = is_link(f)
897 if m == bool(mode):
898 return
899
900 if mode: # switch file to link
901 data = file(f).read()
902 os.unlink(f)
903 os.symlink(data, f)
904 else:
905 data = os.readlink(f)
906 os.unlink(f)
907 file(f, "w").write(data)
908
848 def set_binary(fd):
909 def set_binary(fd):
849 pass
910 pass
850
911
@@ -13,10 +13,10 b''
13
13
14 import win32api
14 import win32api
15
15
16 from demandload import *
16 from i18n import _
17 from i18n import gettext as _
17 import errno, os, pywintypes, win32con, win32file, win32process
18 demandload(globals(), 'errno os pywintypes win32con win32file win32process')
18 import cStringIO, winerror
19 demandload(globals(), 'cStringIO win32com.shell:shell,shellcon winerror')
19 from win32com.shell import shell,shellcon
20
20
21 class WinError:
21 class WinError:
22 winerror_map = {
22 winerror_map = {
@@ -6,7 +6,7 b''
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from node import *
8 from node import *
9 from i18n import gettext as _
9 from i18n import _
10 import revlog, mdiff
10 import revlog, mdiff
11
11
12 def verify(repo):
12 def verify(repo):
@@ -13,9 +13,11 b' import os'
13 from distutils.core import setup, Extension
13 from distutils.core import setup, Extension
14 from distutils.command.install_data import install_data
14 from distutils.command.install_data import install_data
15
15
16 # mercurial.packagescan must be the first mercurial module imported
17 import mercurial.packagescan
18 import mercurial.version
16 import mercurial.version
17 import mercurial.demandimport
18 mercurial.demandimport.enable = lambda: None
19
20 extra = {}
19
21
20 # py2exe needs to be installed to work
22 # py2exe needs to be installed to work
21 try:
23 try:
@@ -35,34 +37,10 b' try:'
35 except ImportError:
37 except ImportError:
36 pass
38 pass
37
39
38 # Due to the use of demandload py2exe is not finding the modules.
40 extra['console'] = ['hg']
39 # packagescan.getmodules creates a list of modules included in
40 # the mercurial package plus dependant modules.
41 from py2exe.build_exe import py2exe as build_exe
42
41
43 class py2exe_for_demandload(build_exe):
44 """ overwrites the py2exe command class for getting the build
45 directory and for setting the 'includes' option."""
46 def initialize_options(self):
47 self.build_lib = None
48 build_exe.initialize_options(self)
49 def finalize_options(self):
50 # Get the build directory, ie. where to search for modules.
51 self.set_undefined_options('build',
52 ('build_lib', 'build_lib'))
53 # Sets the 'includes' option with the list of needed modules
54 if not self.includes:
55 self.includes = []
56 else:
57 self.includes = self.includes.split(',')
58 mercurial.packagescan.scan(self.build_lib, 'mercurial')
59 mercurial.packagescan.scan(self.build_lib, 'mercurial.hgweb')
60 mercurial.packagescan.scan(self.build_lib, 'hgext')
61 self.includes += mercurial.packagescan.getmodules()
62 build_exe.finalize_options(self)
63 except ImportError:
42 except ImportError:
64 py2exe_for_demandload = None
43 pass
65
66
44
67 # specify version string, otherwise 'hg identify' will be used:
45 # specify version string, otherwise 'hg identify' will be used:
68 version = ''
46 version = ''
@@ -75,10 +53,6 b' class install_package_data(install_data)'
75
53
76 mercurial.version.remember_version(version)
54 mercurial.version.remember_version(version)
77 cmdclass = {'install_data': install_package_data}
55 cmdclass = {'install_data': install_package_data}
78 py2exe_opts = {}
79 if py2exe_for_demandload is not None:
80 cmdclass['py2exe'] = py2exe_for_demandload
81 py2exe_opts['console'] = ['hg']
82
56
83 setup(name='mercurial',
57 setup(name='mercurial',
84 version=mercurial.version.get_version(),
58 version=mercurial.version.get_version(),
@@ -100,4 +74,4 b" setup(name='mercurial',"
100 license='COPYING',
74 license='COPYING',
101 readme='contrib/macosx/Readme.html',
75 readme='contrib/macosx/Readme.html',
102 welcome='contrib/macosx/Welcome.html')),
76 welcome='contrib/macosx/Welcome.html')),
103 **py2exe_opts)
77 **extra)
@@ -14,3 +14,8 b" diffblock = '#lines#'"
14 filediff = filediff.tmpl
14 filediff = filediff.tmpl
15 fileannotate = fileannotate.tmpl
15 fileannotate = fileannotate.tmpl
16 annotateline = '#author#@#rev#: #line#'
16 annotateline = '#author#@#rev#: #line#'
17 manifest = manifest.tmpl
18 manifestdirentry = 'drwxr-xr-x {basename}\n'
19 manifestfileentry = '{permissions|permissions} {size} {basename}\n'
20 index = index.tmpl
21 indexentry = '#url#\n'
@@ -1,93 +1,7 b''
1 A simple testing framework
2
3 To run the tests, do:
1 To run the tests, do:
4
2
5 cd tests/
3 cd tests/
6 python run-tests.py
4 python run-tests.py
7
5
8 This finds all scripts in the test directory named test-* and executes
6 See http://www.selenic.com/mercurial/wiki/index.cgi/WritingTests for
9 them. The scripts can be either shell scripts or Python. Each test is
7 more information on writing tests.
10 run in a temporary directory that is removed when the test is complete.
11
12 A test-<x> succeeds if the script returns success and its output
13 matches test-<x>.out. If the new output doesn't match, it is stored in
14 test-<x>.err.
15
16 There are some tricky points here that you should be aware of when
17 writing tests:
18
19 - hg commit and hg merge want user interaction
20
21 for commit use -m "text"
22 for hg merge, set HGMERGE to something noninteractive (like true or merge)
23
24 - changeset hashes will change based on user and date which make
25 things like hg history output change
26
27 use commit -m "test" -u test -d "1000000 0"
28
29 - diff and export may show the current time
30
31 use -D/--nodates to strip the dates
32
33 - You can append your own hgrc settings to the file that the environment
34 variable HGRCPATH points to. This file is cleared before running a test.
35
36 You also need to be careful that the tests are portable from one platform
37 to another. You're probably working on Linux, where the GNU toolchain has
38 more (or different) functionality than on MacOS, *BSD, Solaris, AIX, etc.
39 While testing on all platforms is the only sure-fire way to make sure that
40 you've written portable code, here's a list of problems that have been
41 found and fixed in the tests. Another, more comprehensive list may be
42 found in the GNU Autoconf manual, online here:
43
44 http://www.gnu.org/software/autoconf/manual/html_node/Portable-Shell.html
45
46 sh:
47
48 The Bourne shell is a very basic shell. /bin/sh on Linux is typically
49 bash, which even in Bourne-shell mode has many features that Bourne shells
50 on other Unix systems don't have (and even on Linux /bin/sh isn't
51 guaranteed to be bash). You'll need to be careful about constructs that
52 seem ubiquitous, but are actually not available in the least common
53 denominator. While using another shell (ksh, bash explicitly, posix shell,
54 etc.) explicitly may seem like another option, these may not exist in a
55 portable location, and so are generally probably not a good idea. You may
56 find that rewriting the test in python will be easier.
57
58 - don't use pushd/popd; save the output of "pwd" and use "cd" in place of
59 the pushd, and cd back to the saved pwd instead of popd.
60
61 - don't use math expressions like let, (( ... )), or $(( ... )); use "expr"
62 instead.
63
64 grep:
65
66 - don't use the -q option; redirect stdout to /dev/null instead.
67
68 - don't use extended regular expressions with grep; use egrep instead, and
69 don't escape any regex operators.
70
71 sed:
72
73 - make sure that the beginning-of-line matcher ("^") is at the very
74 beginning of the expression -- it may not be supported inside parens.
75
76 echo:
77
78 - echo may interpret "\n" and print a newline; use printf instead if you
79 want a literal "\n" (backslash + n).
80
81 false:
82
83 - false is guaranteed only to return a non-zero value; you cannot depend on
84 it being 1. On Solaris in particular, /bin/false returns 255. Rewrite
85 your test to not depend on a particular return value, or create a
86 temporary "false" executable, and call that instead.
87
88 diff:
89
90 - don't use the -N option. There's no particularly good workaround short
91 of writing a reasonably complicated replacement script, but substituting
92 gdiff for diff if you can't rewrite the test not to need -N will probably
93 do.
@@ -4,6 +4,8 b" echo 'syntax error' > badext.py"
4 abspath=`pwd`/badext.py
4 abspath=`pwd`/badext.py
5
5
6 echo '[extensions]' >> $HGRCPATH
6 echo '[extensions]' >> $HGRCPATH
7 echo "gpg =" >> $HGRCPATH
8 echo "hgext.gpg =" >> $HGRCPATH
7 echo "badext = $abspath" >> $HGRCPATH
9 echo "badext = $abspath" >> $HGRCPATH
8
10
9 hg -q help help
11 hg -q help help
@@ -1,4 +1,5 b''
1 *** failed to import extension badext: invalid syntax (badext.py, line 1)
1 *** failed to import extension badext: invalid syntax (badext.py, line 1)
2 extension 'hgext.gpg' overrides commands: sigs sigcheck sign
2 hg help [COMMAND]
3 hg help [COMMAND]
3
4
4 show help for a command, extension, or list of commands
5 show help for a command, extension, or list of commands
@@ -21,8 +21,7 b' abort: no match under directory .../test'
21 dir/file
21 dir/file
22 does-not-exist: No such file or directory
22 does-not-exist: No such file or directory
23 abort: file .../test/does-not-exist not found!
23 abort: file .../test/does-not-exist not found!
24 baz: unsupported file type (type is symbolic link)
24 abort: file .../test/baz not tracked!
25 abort: can't commit .../test/baz: unsupported file type!
26 abort: file .../test/quux not tracked!
25 abort: file .../test/quux not tracked!
27 dir/file
26 dir/file
28 % partial subdir commit test
27 % partial subdir commit test
@@ -17,8 +17,11 b" hg commit -m 3 -u eggs -d '3 0'"
17 head -n 3 port > port1
17 head -n 3 port > port1
18 mv port1 port
18 mv port1 port
19 hg commit -m 4 -u spam -d '4 0'
19 hg commit -m 4 -u spam -d '4 0'
20 echo % simple
20 hg grep port port
21 hg grep port port
22 echo % all
21 hg grep --all -nu port port
23 hg grep --all -nu port port
24 echo % other
22 hg grep import port
25 hg grep import port
23
26
24 hg cp port port2
27 hg cp port port2
@@ -28,3 +31,22 b" hg grep -f 'import$' port2"
28 echo deport >> port2
31 echo deport >> port2
29 hg commit -m 5 -u eggs -d '6 0'
32 hg commit -m 5 -u eggs -d '6 0'
30 hg grep -f --all -nu port port2
33 hg grep -f --all -nu port port2
34
35 cd ..
36 hg init t2
37 cd t2
38 hg grep foobar foo
39 hg grep foobar
40 echo blue >> color
41 echo black >> color
42 hg add color
43 hg ci -m 0 -d '0 0'
44 echo orange >> color
45 hg ci -m 1 -d '0 0'
46 echo black > color
47 hg ci -m 2 -d '0 0'
48 echo orange >> color
49 echo blue >> color
50 hg ci -m 3 -d '0 0'
51 hg grep orange
52 hg grep --all orange
@@ -1,6 +1,8 b''
1 % simple
1 port:4:export
2 port:4:export
2 port:4:vaportight
3 port:4:vaportight
3 port:4:import/export
4 port:4:import/export
5 % all
4 port:4:4:-:spam:import/export
6 port:4:4:-:spam:import/export
5 port:3:4:+:eggs:import/export
7 port:3:4:+:eggs:import/export
6 port:2:1:-:spam:import
8 port:2:1:-:spam:import
@@ -10,6 +12,7 b' port:2:2:+:spam:vaportight'
10 port:2:3:+:spam:import/export
12 port:2:3:+:spam:import/export
11 port:1:2:+:eggs:export
13 port:1:2:+:eggs:export
12 port:0:1:+:spam:import
14 port:0:1:+:spam:import
15 % other
13 port:4:import/export
16 port:4:import/export
14 % follow
17 % follow
15 port:0:import
18 port:0:import
@@ -23,3 +26,7 b' port:2:2:+:spam:vaportight'
23 port:2:3:+:spam:import/export
26 port:2:3:+:spam:import/export
24 port:1:2:+:eggs:export
27 port:1:2:+:eggs:export
25 port:0:1:+:spam:import
28 port:0:1:+:spam:import
29 color:3:orange
30 color:3:+:orange
31 color:2:-:orange
32 color:1:+:orange
@@ -1,11 +1,12 b''
1 adding bar
1 adding foo
2 adding foo
2 adding bomb
3 adding bomb
3 adding a.c
4 adding a.c
4 adding dir/a.o
5 adding dir/a.o
5 adding dir/b.o
6 adding dir/b.o
7 M dir/b.o
6 ! a.c
8 ! a.c
7 ! dir/a.o
9 ! dir/a.o
8 ! dir/b.o
9 ? .hgignore
10 ? .hgignore
10 a.c: unsupported file type (type is fifo)
11 a.c: unsupported file type (type is fifo)
11 ! a.c
12 ! a.c
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now