Mercurial > hg > mercurial-crew-with-dirclash
annotate mercurial/hg.py @ 535:fba26990604a
Deal with failed clone/transaction interaction
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Deal with failed clone/transaction interaction
> What is happening is that something in the transaction machinery is
> causing the directory to be completely recreated.
The transaction gets rolled back by its destructor. This is critical
so it happens whenever an exception occurs that unwinds the stack.
Unfortunately, what's happening with clone is we're trying to delete
the directory during exception propagation. And a reference to the
transaction is held in the exception backtrace stack frames so it
still exists until the exception is completely resolved.
So there's no way to do the directory delete inside the exception
handling cleanly.
But we can handle it similarly to the transaction itself: use an
object with a destructor.
manifest hash: fc38550a20d64d08333f256bbedc312493c1390b
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.0 (GNU/Linux)
iD8DBQFCxDT2ywK+sNU5EO8RAjikAJ0Tej56rAutxQDfYzVbFGtT1sEC5ACgmVds
/fwdQyHn+FwshugqXLemUaM=
=3f78
-----END PGP SIGNATURE-----
author | mpm@selenic.com |
---|---|
date | Thu, 30 Jun 2005 10:07:50 -0800 |
parents | aace5b681fe9 |
children | c15b4bc0a11c eda4c32c167a |
rev | line source |
---|---|
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
1 # hg.py - repository classes for mercurial |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
2 # |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
3 # Copyright 2005 Matt Mackall <mpm@selenic.com> |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
4 # |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
5 # This software may be used and distributed according to the terms |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
6 # of the GNU General Public License, incorporated herein by reference. |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
7 |
249 | 8 import sys, struct, os |
419
28511fc21073
[PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
418
diff
changeset
|
9 import util |
262 | 10 from revlog import * |
11 from demandload import * | |
12 demandload(globals(), "re lock urllib urllib2 transaction time socket") | |
434 | 13 demandload(globals(), "tempfile httprangereader bdiff") |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
14 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
15 class filelog(revlog): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
16 def __init__(self, opener, path): |
144
ea9188538222
Fix transaction handling bug by reverting fileopener change
mpm@selenic.com
parents:
140
diff
changeset
|
17 revlog.__init__(self, opener, |
ea9188538222
Fix transaction handling bug by reverting fileopener change
mpm@selenic.com
parents:
140
diff
changeset
|
18 os.path.join("data", path + ".i"), |
ea9188538222
Fix transaction handling bug by reverting fileopener change
mpm@selenic.com
parents:
140
diff
changeset
|
19 os.path.join("data", path + ".d")) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
20 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
21 def read(self, node): |
360 | 22 t = self.revision(node) |
23 if t[:2] != '\1\n': | |
24 return t | |
25 s = t.find('\1\n', 2) | |
26 return t[s+2:] | |
27 | |
28 def readmeta(self, node): | |
29 t = self.revision(node) | |
30 if t[:2] != '\1\n': | |
31 return t | |
32 s = t.find('\1\n', 2) | |
33 mt = t[2:s] | |
34 for l in mt.splitlines(): | |
35 k, v = l.split(": ", 1) | |
36 m[k] = v | |
37 return m | |
38 | |
39 def add(self, text, meta, transaction, link, p1=None, p2=None): | |
40 if meta or text[:2] == '\1\n': | |
41 mt = "" | |
42 if meta: | |
43 mt = [ "%s: %s\n" % (k, v) for k,v in meta.items() ] | |
44 text = "\1\n" + "".join(mt) + "\1\n" + text | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
45 return self.addrevision(text, transaction, link, p1, p2) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
46 |
79 | 47 def annotate(self, node): |
199 | 48 |
49 def decorate(text, rev): | |
436 | 50 return ([rev] * len(text.splitlines()), text) |
199 | 51 |
52 def pair(parent, child): | |
436 | 53 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]): |
471 | 54 child[0][b1:b2] = parent[0][a1:a2] |
55 return child | |
199 | 56 |
200 | 57 # find all ancestors |
216
201115f2859b
hg annotate: actually annotate the given version
mpm@selenic.com
parents:
210
diff
changeset
|
58 needed = {node:1} |
199 | 59 visit = [node] |
60 while visit: | |
61 n = visit.pop(0) | |
62 for p in self.parents(n): | |
63 if p not in needed: | |
64 needed[p] = 1 | |
65 visit.append(p) | |
200 | 66 else: |
67 # count how many times we'll use this | |
68 needed[p] += 1 | |
199 | 69 |
200 | 70 # sort by revision which is a topological order |
471 | 71 visit = [ (self.rev(n), n) for n in needed.keys() ] |
199 | 72 visit.sort() |
73 hist = {} | |
74 | |
471 | 75 for r,n in visit: |
199 | 76 curr = decorate(self.read(n), self.linkrev(n)) |
77 for p in self.parents(n): | |
78 if p != nullid: | |
79 curr = pair(hist[p], curr) | |
200 | 80 # trim the history of unneeded revs |
81 needed[p] -= 1 | |
82 if not needed[p]: | |
83 del hist[p] | |
199 | 84 hist[n] = curr |
85 | |
436 | 86 return zip(hist[n][0], hist[n][1].splitlines(1)) |
79 | 87 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
88 class manifest(revlog): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
89 def __init__(self, opener): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
90 self.mapcache = None |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
91 self.listcache = None |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
92 self.addlist = None |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
93 revlog.__init__(self, opener, "00manifest.i", "00manifest.d") |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
94 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
95 def read(self, node): |
313 | 96 if node == nullid: return {} # don't upset local cache |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
97 if self.mapcache and self.mapcache[0] == node: |
90 | 98 return self.mapcache[1].copy() |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
99 text = self.revision(node) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
100 map = {} |
276 | 101 flag = {} |
25
daa724b27300
Fix corruption from manifest.listcache optimization
mpm@selenic.com
parents:
20
diff
changeset
|
102 self.listcache = (text, text.splitlines(1)) |
daa724b27300
Fix corruption from manifest.listcache optimization
mpm@selenic.com
parents:
20
diff
changeset
|
103 for l in self.listcache[1]: |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
104 (f, n) = l.split('\0') |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
105 map[f] = bin(n[:40]) |
276 | 106 flag[f] = (n[40:-1] == "x") |
107 self.mapcache = (node, map, flag) | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
108 return map |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
109 |
276 | 110 def readflags(self, node): |
313 | 111 if node == nullid: return {} # don't upset local cache |
358
9f4077d7ef6f
[PATCH] manifest.readflags performance buglet
mpm@selenic.com
parents:
350
diff
changeset
|
112 if not self.mapcache or self.mapcache[0] != node: |
276 | 113 self.read(node) |
114 return self.mapcache[2] | |
115 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
116 def diff(self, a, b): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
117 # this is sneaky, as we're not actually using a and b |
140 | 118 if self.listcache and self.addlist and self.listcache[0] == a: |
98 | 119 d = mdiff.diff(self.listcache[1], self.addlist, 1) |
120 if mdiff.patch(a, d) != b: | |
121 sys.stderr.write("*** sortdiff failed, falling back ***\n") | |
122 return mdiff.textdiff(a, b) | |
123 return d | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
124 else: |
44 | 125 return mdiff.textdiff(a, b) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
126 |
276 | 127 def add(self, map, flags, transaction, link, p1=None, p2=None): |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
128 files = map.keys() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
129 files.sort() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
130 |
276 | 131 self.addlist = ["%s\000%s%s\n" % |
132 (f, hex(map[f]), flags[f] and "x" or '') | |
133 for f in files] | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
134 text = "".join(self.addlist) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
135 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
136 n = self.addrevision(text, transaction, link, p1, p2) |
302 | 137 self.mapcache = (n, map, flags) |
25
daa724b27300
Fix corruption from manifest.listcache optimization
mpm@selenic.com
parents:
20
diff
changeset
|
138 self.listcache = (text, self.addlist) |
140 | 139 self.addlist = None |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
140 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
141 return n |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
142 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
143 class changelog(revlog): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
144 def __init__(self, opener): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
145 revlog.__init__(self, opener, "00changelog.i", "00changelog.d") |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
146 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
147 def extract(self, text): |
37 | 148 if not text: |
40 | 149 return (nullid, "", "0", [], "") |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
150 last = text.index("\n\n") |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
151 desc = text[last + 2:] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
152 l = text[:last].splitlines() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
153 manifest = bin(l[0]) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
154 user = l[1] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
155 date = l[2] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
156 files = l[3:] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
157 return (manifest, user, date, files, desc) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
158 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
159 def read(self, node): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
160 return self.extract(self.revision(node)) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
161 |
203 | 162 def add(self, manifest, list, desc, transaction, p1=None, p2=None, |
163 user=None, date=None): | |
164 user = (user or | |
165 os.environ.get("HGUSER") or | |
55
2add70d51441
From: Thomas Arendsen Hein <thomas@intevation.de>
mpm@selenic.com
parents:
48
diff
changeset
|
166 os.environ.get("EMAIL") or |
504 | 167 (os.environ.get("LOGNAME", |
168 os.environ.get("USERNAME", "unknown")) | |
169 + '@' + socket.getfqdn())) | |
203 | 170 date = date or "%d %d" % (time.time(), time.timezone) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
171 list.sort() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
172 l = [hex(manifest), user, date] + list + ["", desc] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
173 text = "\n".join(l) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
174 return self.addrevision(text, transaction, self.count(), p1, p2) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
175 |
220 | 176 class dirstate: |
244 | 177 def __init__(self, opener, ui, root): |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
178 self.opener = opener |
244 | 179 self.root = root |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
180 self.dirty = 0 |
20 | 181 self.ui = ui |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
182 self.map = None |
227 | 183 self.pl = None |
363 | 184 self.copies = {} |
220 | 185 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
186 def __del__(self): |
220 | 187 if self.dirty: |
188 self.write() | |
189 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
190 def __getitem__(self, key): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
191 try: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
192 return self.map[key] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
193 except TypeError: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
194 self.read() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
195 return self[key] |
220 | 196 |
197 def __contains__(self, key): | |
198 if not self.map: self.read() | |
199 return key in self.map | |
200 | |
227 | 201 def parents(self): |
202 if not self.pl: | |
203 self.read() | |
204 return self.pl | |
205 | |
206 def setparents(self, p1, p2 = nullid): | |
207 self.dirty = 1 | |
208 self.pl = p1, p2 | |
209 | |
220 | 210 def state(self, key): |
211 try: | |
212 return self[key][0] | |
213 except KeyError: | |
214 return "?" | |
215 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
216 def read(self): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
217 if self.map is not None: return self.map |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
218 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
219 self.map = {} |
227 | 220 self.pl = [nullid, nullid] |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
221 try: |
220 | 222 st = self.opener("dirstate").read() |
311 | 223 if not st: return |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
224 except: return |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
225 |
227 | 226 self.pl = [st[:20], st[20: 40]] |
227 | |
228 pos = 40 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
229 while pos < len(st): |
220 | 230 e = struct.unpack(">cllll", st[pos:pos+17]) |
231 l = e[4] | |
232 pos += 17 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
233 f = st[pos:pos + l] |
515 | 234 if '\0' in f: |
363 | 235 f, c = f.split('\0') |
236 self.copies[f] = c | |
220 | 237 self.map[f] = e[:4] |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
238 pos += l |
363 | 239 |
240 def copy(self, source, dest): | |
241 self.read() | |
242 self.dirty = 1 | |
243 self.copies[dest] = source | |
244 | |
245 def copied(self, file): | |
246 return self.copies.get(file, None) | |
515 | 247 |
220 | 248 def update(self, files, state): |
249 ''' current states: | |
250 n normal | |
231 | 251 m needs merging |
220 | 252 r marked for removal |
253 a marked for addition''' | |
254 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
255 if not files: return |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
256 self.read() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
257 self.dirty = 1 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
258 for f in files: |
220 | 259 if state == "r": |
260 self.map[f] = ('r', 0, 0, 0) | |
261 else: | |
253 | 262 s = os.stat(os.path.join(self.root, f)) |
263 self.map[f] = (state, s.st_mode, s.st_size, s.st_mtime) | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
264 |
220 | 265 def forget(self, files): |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
266 if not files: return |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
267 self.read() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
268 self.dirty = 1 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
269 for f in files: |
20 | 270 try: |
271 del self.map[f] | |
272 except KeyError: | |
220 | 273 self.ui.warn("not in dirstate: %s!\n" % f) |
20 | 274 pass |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
275 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
276 def clear(self): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
277 self.map = {} |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
278 self.dirty = 1 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
279 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
280 def write(self): |
220 | 281 st = self.opener("dirstate", "w") |
227 | 282 st.write("".join(self.pl)) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
283 for f, e in self.map.items(): |
363 | 284 c = self.copied(f) |
285 if c: | |
286 f = f + "\0" + c | |
220 | 287 e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f)) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
288 st.write(e + f) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
289 self.dirty = 0 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
290 |
363 | 291 def dup(self): |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
292 self.read() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
293 return self.map.copy() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
294 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
295 # used to avoid circular references so destructors work |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
296 def opener(base): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
297 p = base |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
298 def o(path, mode="r"): |
15
6daf7757e92b
Fix network pull of repo files with "%" in their base64 encoding.
mpm@selenic.com
parents:
10
diff
changeset
|
299 if p[:7] == "http://": |
6daf7757e92b
Fix network pull of repo files with "%" in their base64 encoding.
mpm@selenic.com
parents:
10
diff
changeset
|
300 f = os.path.join(p, urllib.quote(path)) |
372 | 301 return httprangereader.httprangereader(f) |
15
6daf7757e92b
Fix network pull of repo files with "%" in their base64 encoding.
mpm@selenic.com
parents:
10
diff
changeset
|
302 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
303 f = os.path.join(p, path) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
304 |
292 | 305 mode += "b" # for that other OS |
306 | |
307 if mode[0] != "r": | |
110
c37c7f784ee3
Move hg from storing files in data with base64 encoding to full
mpm@selenic.com
parents:
109
diff
changeset
|
308 try: |
c37c7f784ee3
Move hg from storing files in data with base64 encoding to full
mpm@selenic.com
parents:
109
diff
changeset
|
309 s = os.stat(f) |
c37c7f784ee3
Move hg from storing files in data with base64 encoding to full
mpm@selenic.com
parents:
109
diff
changeset
|
310 except OSError: |
c37c7f784ee3
Move hg from storing files in data with base64 encoding to full
mpm@selenic.com
parents:
109
diff
changeset
|
311 d = os.path.dirname(f) |
c37c7f784ee3
Move hg from storing files in data with base64 encoding to full
mpm@selenic.com
parents:
109
diff
changeset
|
312 if not os.path.isdir(d): |
c37c7f784ee3
Move hg from storing files in data with base64 encoding to full
mpm@selenic.com
parents:
109
diff
changeset
|
313 os.makedirs(d) |
c37c7f784ee3
Move hg from storing files in data with base64 encoding to full
mpm@selenic.com
parents:
109
diff
changeset
|
314 else: |
c37c7f784ee3
Move hg from storing files in data with base64 encoding to full
mpm@selenic.com
parents:
109
diff
changeset
|
315 if s.st_nlink > 1: |
417 | 316 file(f + ".tmp", "wb").write(file(f, "rb").read()) |
421 | 317 util.rename(f+".tmp", f) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
318 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
319 return file(f, mode) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
320 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
321 return o |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
322 |
499 | 323 class RepoError(Exception): pass |
324 | |
60 | 325 class localrepository: |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
326 def __init__(self, ui, path=None, create=0): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
327 self.remote = 0 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
328 if path and path[:7] == "http://": |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
329 self.remote = 1 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
330 self.path = path |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
331 else: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
332 if not path: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
333 p = os.getcwd() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
334 while not os.path.isdir(os.path.join(p, ".hg")): |
420
dbe86d465e09
[PATCH] Repo locator fix for the other `OS'
mpm@selenic.com
parents:
419
diff
changeset
|
335 oldp = p |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
336 p = os.path.dirname(p) |
499 | 337 if p == oldp: raise RepoError("no repo found") |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
338 path = p |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
339 self.path = os.path.join(path, ".hg") |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
340 |
405 | 341 if not create and not os.path.isdir(self.path): |
499 | 342 raise RepoError("repository %s not found" % self.path) |
405 | 343 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
344 self.root = path |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
345 self.ui = ui |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
346 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
347 if create: |
515 | 348 os.mkdir(self.path) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
349 os.mkdir(self.join("data")) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
350 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
351 self.opener = opener(self.path) |
291
2c4f2be05587
Add wopener for opening files in the working directory
mpm@selenic.com
parents:
288
diff
changeset
|
352 self.wopener = opener(self.root) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
353 self.manifest = manifest(self.opener) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
354 self.changelog = changelog(self.opener) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
355 self.ignorelist = None |
343 | 356 self.tagscache = None |
357 self.nodetagscache = None | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
358 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
359 if not self.remote: |
244 | 360 self.dirstate = dirstate(self.opener, ui, self.root) |
337 | 361 try: |
362 self.ui.readconfig(self.opener("hgrc")) | |
363 except IOError: pass | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
364 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
365 def ignore(self, f): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
366 if self.ignorelist is None: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
367 self.ignorelist = [] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
368 try: |
417 | 369 l = file(self.wjoin(".hgignore")) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
370 for pat in l: |
9 | 371 if pat != "\n": |
419
28511fc21073
[PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
418
diff
changeset
|
372 self.ignorelist.append(re.compile(util.pconvert(pat[:-1]))) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
373 except IOError: pass |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
374 for pat in self.ignorelist: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
375 if pat.search(f): return True |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
376 return False |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
377 |
487 | 378 def hook(self, name, **args): |
379 s = self.ui.config("hooks", name) | |
380 if s: | |
381 self.ui.note("running hook %s: %s\n" % (name, s)) | |
382 old = {} | |
383 for k, v in args.items(): | |
384 k = k.upper() | |
385 old[k] = os.environ.get(k, None) | |
386 os.environ[k] = v | |
387 | |
388 r = os.system(s) | |
389 | |
390 for k, v in old.items(): | |
391 if v != None: | |
392 os.environ[k] = v | |
393 else: | |
394 del os.environ[k] | |
395 | |
396 if r: | |
397 self.ui.warn("abort: %s hook failed with status %d!\n" % | |
398 (name, r)) | |
399 return False | |
400 return True | |
401 | |
343 | 402 def tags(self): |
403 '''return a mapping of tag to node''' | |
477
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
404 if not self.tagscache: |
343 | 405 self.tagscache = {} |
67 | 406 try: |
254 | 407 # read each head of the tags file, ending with the tip |
408 # and add each tag found to the map, with "newer" ones | |
409 # taking precedence | |
67 | 410 fl = self.file(".hgtags") |
254 | 411 h = fl.heads() |
412 h.reverse() | |
413 for r in h: | |
414 for l in fl.revision(r).splitlines(): | |
415 if l: | |
385
e9e1efd5291c
Fixed problems with extra spaces around tags in .hgtags
Thomas Arendsen Hein <thomas@intevation.de>
parents:
383
diff
changeset
|
416 n, k = l.split(" ", 1) |
477
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
417 try: |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
418 bin_n = bin(n) |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
419 except TypeError: |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
420 bin_n = '' |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
421 self.tagscache[k.strip()] = bin_n |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
422 except KeyError: |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
423 pass |
454 | 424 for k, n in self.ui.configitems("tags"): |
477
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
425 try: |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
426 bin_n = bin(n) |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
427 except TypeError: |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
428 bin_n = '' |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
429 self.tagscache[k] = bin_n |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
430 |
343 | 431 self.tagscache['tip'] = self.changelog.tip() |
432 | |
433 return self.tagscache | |
434 | |
435 def tagslist(self): | |
436 '''return a list of tags ordered by revision''' | |
437 l = [] | |
477
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
438 for t, n in self.tags().items(): |
343 | 439 try: |
440 r = self.changelog.rev(n) | |
441 except: | |
442 r = -2 # sort to the beginning of the list if unknown | |
443 l.append((r,t,n)) | |
444 l.sort() | |
445 return [(t,n) for r,t,n in l] | |
446 | |
447 def nodetags(self, node): | |
448 '''return the tags associated with a node''' | |
449 if not self.nodetagscache: | |
450 self.nodetagscache = {} | |
451 for t,n in self.tags().items(): | |
452 self.nodetagscache.setdefault(n,[]).append(t) | |
453 return self.nodetagscache.get(node, []) | |
454 | |
455 def lookup(self, key): | |
67 | 456 try: |
343 | 457 return self.tags()[key] |
67 | 458 except KeyError: |
459 return self.changelog.lookup(key) | |
460 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
461 def join(self, f): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
462 return os.path.join(self.path, f) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
463 |
244 | 464 def wjoin(self, f): |
465 return os.path.join(self.root, f) | |
466 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
467 def file(self, f): |
192 | 468 if f[0] == '/': f = f[1:] |
144
ea9188538222
Fix transaction handling bug by reverting fileopener change
mpm@selenic.com
parents:
140
diff
changeset
|
469 return filelog(self.opener, f) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
470 |
291
2c4f2be05587
Add wopener for opening files in the working directory
mpm@selenic.com
parents:
288
diff
changeset
|
471 def wfile(self, f, mode='r'): |
2c4f2be05587
Add wopener for opening files in the working directory
mpm@selenic.com
parents:
288
diff
changeset
|
472 return self.wopener(f, mode) |
2c4f2be05587
Add wopener for opening files in the working directory
mpm@selenic.com
parents:
288
diff
changeset
|
473 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
474 def transaction(self): |
251 | 475 # save dirstate for undo |
263 | 476 try: |
477 ds = self.opener("dirstate").read() | |
478 except IOError: | |
479 ds = "" | |
251 | 480 self.opener("undo.dirstate", "w").write(ds) |
515 | 481 |
262 | 482 return transaction.transaction(self.opener, self.join("journal"), |
483 self.join("undo")) | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
484 |
210 | 485 def recover(self): |
225 | 486 lock = self.lock() |
210 | 487 if os.path.exists(self.join("recover")): |
501 | 488 self.ui.status("rolling back interrupted transaction\n") |
262 | 489 return transaction.rollback(self.opener, self.join("recover")) |
210 | 490 else: |
491 self.ui.warn("no interrupted transaction available\n") | |
492 | |
493 def undo(self): | |
225 | 494 lock = self.lock() |
210 | 495 if os.path.exists(self.join("undo")): |
501 | 496 self.ui.status("rolling back last transaction\n") |
262 | 497 transaction.rollback(self.opener, self.join("undo")) |
251 | 498 self.dirstate = None |
421 | 499 util.rename(self.join("undo.dirstate"), self.join("dirstate")) |
251 | 500 self.dirstate = dirstate(self.opener, self.ui, self.root) |
163 | 501 else: |
210 | 502 self.ui.warn("no undo information available\n") |
162 | 503 |
161 | 504 def lock(self, wait = 1): |
505 try: | |
506 return lock.lock(self.join("lock"), 0) | |
507 except lock.LockHeld, inst: | |
508 if wait: | |
509 self.ui.warn("waiting for lock held by %s\n" % inst.args[0]) | |
510 return lock.lock(self.join("lock"), wait) | |
511 raise inst | |
512 | |
203 | 513 def rawcommit(self, files, text, user, date, p1=None, p2=None): |
442 | 514 orig_parent = self.dirstate.parents()[0] or nullid |
452
a1e91c24dab5
rawcommit: do lookup of parents at the appropriate layer
mpm@selenic.com
parents:
442
diff
changeset
|
515 p1 = p1 or self.dirstate.parents()[0] or nullid |
a1e91c24dab5
rawcommit: do lookup of parents at the appropriate layer
mpm@selenic.com
parents:
442
diff
changeset
|
516 p2 = p2 or self.dirstate.parents()[1] or nullid |
302 | 517 c1 = self.changelog.read(p1) |
518 c2 = self.changelog.read(p2) | |
519 m1 = self.manifest.read(c1[0]) | |
520 mf1 = self.manifest.readflags(c1[0]) | |
521 m2 = self.manifest.read(c2[0]) | |
522 | |
442 | 523 if orig_parent == p1: |
524 update_dirstate = 1 | |
525 else: | |
526 update_dirstate = 0 | |
527 | |
203 | 528 tr = self.transaction() |
302 | 529 mm = m1.copy() |
530 mfm = mf1.copy() | |
203 | 531 linkrev = self.changelog.count() |
532 for f in files: | |
533 try: | |
302 | 534 t = self.wfile(f).read() |
441 | 535 tm = util.is_exec(self.wjoin(f), mfm.get(f, False)) |
302 | 536 r = self.file(f) |
537 mfm[f] = tm | |
360 | 538 mm[f] = r.add(t, {}, tr, linkrev, |
302 | 539 m1.get(f, nullid), m2.get(f, nullid)) |
442 | 540 if update_dirstate: |
541 self.dirstate.update([f], "n") | |
203 | 542 except IOError: |
314
3402cb9a4c06
More tweaking to rawcommit for repo conversion
mpm@selenic.com
parents:
313
diff
changeset
|
543 try: |
3402cb9a4c06
More tweaking to rawcommit for repo conversion
mpm@selenic.com
parents:
313
diff
changeset
|
544 del mm[f] |
3402cb9a4c06
More tweaking to rawcommit for repo conversion
mpm@selenic.com
parents:
313
diff
changeset
|
545 del mfm[f] |
442 | 546 if update_dirstate: |
547 self.dirstate.forget([f]) | |
314
3402cb9a4c06
More tweaking to rawcommit for repo conversion
mpm@selenic.com
parents:
313
diff
changeset
|
548 except: |
3402cb9a4c06
More tweaking to rawcommit for repo conversion
mpm@selenic.com
parents:
313
diff
changeset
|
549 # deleted from p2? |
3402cb9a4c06
More tweaking to rawcommit for repo conversion
mpm@selenic.com
parents:
313
diff
changeset
|
550 pass |
203 | 551 |
302 | 552 mnode = self.manifest.add(mm, mfm, tr, linkrev, c1[0], c2[0]) |
553 n = self.changelog.add(mnode, files, text, tr, p1, p2, user, date) | |
203 | 554 tr.close() |
442 | 555 if update_dirstate: |
556 self.dirstate.setparents(n, nullid) | |
203 | 557 |
317 | 558 def commit(self, files = None, text = "", user = None, date = None): |
220 | 559 commit = [] |
560 remove = [] | |
561 if files: | |
562 for f in files: | |
563 s = self.dirstate.state(f) | |
244 | 564 if s in 'nmai': |
220 | 565 commit.append(f) |
566 elif s == 'r': | |
567 remove.append(f) | |
568 else: | |
244 | 569 self.ui.warn("%s not tracked!\n" % f) |
220 | 570 else: |
230 | 571 (c, a, d, u) = self.diffdir(self.root) |
220 | 572 commit = c + a |
573 remove = d | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
574 |
220 | 575 if not commit and not remove: |
151 | 576 self.ui.status("nothing changed\n") |
577 return | |
578 | |
487 | 579 if not self.hook("precommit"): |
580 return 1 | |
581 | |
229 | 582 p1, p2 = self.dirstate.parents() |
583 c1 = self.changelog.read(p1) | |
584 c2 = self.changelog.read(p2) | |
585 m1 = self.manifest.read(c1[0]) | |
276 | 586 mf1 = self.manifest.readflags(c1[0]) |
229 | 587 m2 = self.manifest.read(c2[0]) |
225 | 588 lock = self.lock() |
151 | 589 tr = self.transaction() |
590 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
591 # check in files |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
592 new = {} |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
593 linkrev = self.changelog.count() |
220 | 594 commit.sort() |
595 for f in commit: | |
83 | 596 self.ui.note(f + "\n") |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
597 try: |
441 | 598 mf1[f] = util.is_exec(self.wjoin(f), mf1.get(f, False)) |
418 | 599 t = self.wfile(f).read() |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
600 except IOError: |
220 | 601 self.warn("trouble committing %s!\n" % f) |
602 raise | |
603 | |
363 | 604 meta = {} |
605 cp = self.dirstate.copied(f) | |
606 if cp: | |
607 meta["copy"] = cp | |
608 meta["copyrev"] = hex(m1.get(cp, m2.get(cp, nullid))) | |
609 self.ui.debug(" %s: copy %s:%s\n" % (f, cp, meta["copyrev"])) | |
610 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
611 r = self.file(f) |
229 | 612 fp1 = m1.get(f, nullid) |
613 fp2 = m2.get(f, nullid) | |
363 | 614 new[f] = r.add(t, meta, tr, linkrev, fp1, fp2) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
615 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
616 # update manifest |
229 | 617 m1.update(new) |
416
5e9e8b8d2629
[PATCH] Removal of a file added by merging branches
mpm@selenic.com
parents:
415
diff
changeset
|
618 for f in remove: |
5e9e8b8d2629
[PATCH] Removal of a file added by merging branches
mpm@selenic.com
parents:
415
diff
changeset
|
619 if f in m1: |
5e9e8b8d2629
[PATCH] Removal of a file added by merging branches
mpm@selenic.com
parents:
415
diff
changeset
|
620 del m1[f] |
276 | 621 mn = self.manifest.add(m1, mf1, tr, linkrev, c1[0], c2[0]) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
622 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
623 # add changeset |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
624 new = new.keys() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
625 new.sort() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
626 |
288 | 627 if not text: |
628 edittext = "\n" + "HG: manifest hash %s\n" % hex(mn) | |
629 edittext += "".join(["HG: changed %s\n" % f for f in new]) | |
630 edittext += "".join(["HG: removed %s\n" % f for f in remove]) | |
631 edittext = self.ui.edit(edittext) | |
632 if not edittext.rstrip(): | |
633 return 1 | |
634 text = edittext | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
635 |
317 | 636 n = self.changelog.add(mn, new, text, tr, p1, p2, user, date) |
487 | 637 |
638 if not self.hook("commit", node=hex(n)): | |
639 return 1 | |
640 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
641 tr.close() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
642 |
229 | 643 self.dirstate.setparents(n) |
220 | 644 self.dirstate.update(new, "n") |
645 self.dirstate.forget(remove) | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
646 |
230 | 647 def diffdir(self, path, changeset = None): |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
648 changed = [] |
220 | 649 added = [] |
650 unknown = [] | |
4
ce3bd728b858
Fix exception handling for reading current working version
mpm@selenic.com
parents:
0
diff
changeset
|
651 mf = {} |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
652 |
29 | 653 if changeset: |
654 change = self.changelog.read(changeset) | |
4
ce3bd728b858
Fix exception handling for reading current working version
mpm@selenic.com
parents:
0
diff
changeset
|
655 mf = self.manifest.read(change[0]) |
230 | 656 dc = dict.fromkeys(mf) |
657 else: | |
658 changeset = self.dirstate.parents()[0] | |
659 change = self.changelog.read(changeset) | |
660 mf = self.manifest.read(change[0]) | |
363 | 661 dc = self.dirstate.dup() |
29 | 662 |
663 def fcmp(fn): | |
291
2c4f2be05587
Add wopener for opening files in the working directory
mpm@selenic.com
parents:
288
diff
changeset
|
664 t1 = self.wfile(fn).read() |
29 | 665 t2 = self.file(fn).revision(mf[fn]) |
666 return cmp(t1, t2) | |
667 | |
312 | 668 for dir, subdirs, files in os.walk(path): |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
669 d = dir[len(self.root)+1:] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
670 if ".hg" in subdirs: subdirs.remove(".hg") |
515 | 671 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
672 for f in files: |
419
28511fc21073
[PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
418
diff
changeset
|
673 fn = util.pconvert(os.path.join(d, f)) |
64 | 674 try: s = os.stat(os.path.join(self.root, fn)) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
675 except: continue |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
676 if fn in dc: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
677 c = dc[fn] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
678 del dc[fn] |
220 | 679 if not c: |
29 | 680 if fcmp(fn): |
681 changed.append(fn) | |
231 | 682 elif c[0] == 'm': |
683 changed.append(fn) | |
220 | 684 elif c[0] == 'a': |
685 added.append(fn) | |
686 elif c[0] == 'r': | |
687 unknown.append(fn) | |
276 | 688 elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100: |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
689 changed.append(fn) |
220 | 690 elif c[1] != s.st_mode or c[3] != s.st_mtime: |
29 | 691 if fcmp(fn): |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
692 changed.append(fn) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
693 else: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
694 if self.ignore(fn): continue |
220 | 695 unknown.append(fn) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
696 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
697 deleted = dc.keys() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
698 deleted.sort() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
699 |
220 | 700 return (changed, added, deleted, unknown) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
701 |
32 | 702 def diffrevs(self, node1, node2): |
33 | 703 changed, added = [], [] |
32 | 704 |
705 change = self.changelog.read(node1) | |
706 mf1 = self.manifest.read(change[0]) | |
33 | 707 change = self.changelog.read(node2) |
32 | 708 mf2 = self.manifest.read(change[0]) |
709 | |
710 for fn in mf2: | |
711 if mf1.has_key(fn): | |
712 if mf1[fn] != mf2[fn]: | |
713 changed.append(fn) | |
714 del mf1[fn] | |
715 else: | |
716 added.append(fn) | |
515 | 717 |
32 | 718 deleted = mf1.keys() |
719 deleted.sort() | |
515 | 720 |
32 | 721 return (changed, added, deleted) |
722 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
723 def add(self, list): |
220 | 724 for f in list: |
244 | 725 p = self.wjoin(f) |
220 | 726 if not os.path.isfile(p): |
727 self.ui.warn("%s does not exist!\n" % f) | |
728 elif self.dirstate.state(f) == 'n': | |
729 self.ui.warn("%s already tracked!\n" % f) | |
730 else: | |
731 self.dirstate.update([f], "a") | |
732 | |
733 def forget(self, list): | |
734 for f in list: | |
735 if self.dirstate.state(f) not in 'ai': | |
736 self.ui.warn("%s not added!\n" % f) | |
737 else: | |
738 self.dirstate.forget([f]) | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
739 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
740 def remove(self, list): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
741 for f in list: |
244 | 742 p = self.wjoin(f) |
220 | 743 if os.path.isfile(p): |
744 self.ui.warn("%s still exists!\n" % f) | |
402 | 745 elif self.dirstate.state(f) == 'a': |
746 self.ui.warn("%s never committed!\n" % f) | |
747 self.dirstate.forget(f) | |
220 | 748 elif f not in self.dirstate: |
749 self.ui.warn("%s not tracked!\n" % f) | |
750 else: | |
751 self.dirstate.update([f], "r") | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
752 |
363 | 753 def copy(self, source, dest): |
754 p = self.wjoin(dest) | |
755 if not os.path.isfile(dest): | |
756 self.ui.warn("%s does not exist!\n" % dest) | |
757 else: | |
758 if self.dirstate.state(dest) == '?': | |
759 self.dirstate.update([dest], "a") | |
760 self.dirstate.copy(source, dest) | |
761 | |
222 | 762 def heads(self): |
763 return self.changelog.heads() | |
764 | |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
765 def branches(self, nodes): |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
766 if not nodes: nodes = [self.changelog.tip()] |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
767 b = [] |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
768 for n in nodes: |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
769 t = n |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
770 while n: |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
771 p = self.changelog.parents(n) |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
772 if p[1] != nullid or p[0] == nullid: |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
773 b.append((t, n, p[0], p[1])) |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
774 break |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
775 n = p[0] |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
776 return b |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
777 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
778 def between(self, pairs): |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
779 r = [] |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
780 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
781 for top, bottom in pairs: |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
782 n, l, i = top, [], 0 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
783 f = 1 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
784 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
785 while n != bottom: |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
786 p = self.changelog.parents(n)[0] |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
787 if i == f: |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
788 l.append(n) |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
789 f = f * 2 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
790 n = p |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
791 i += 1 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
792 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
793 r.append(l) |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
794 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
795 return r |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
796 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
797 def newer(self, nodes): |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
798 m = {} |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
799 nl = [] |
94 | 800 pm = {} |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
801 cl = self.changelog |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
802 t = l = cl.count() |
94 | 803 |
804 # find the lowest numbered node | |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
805 for n in nodes: |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
806 l = min(l, cl.rev(n)) |
94 | 807 m[n] = 1 |
46 | 808 |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
809 for i in xrange(l, t): |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
810 n = cl.node(i) |
94 | 811 if n in m: # explicitly listed |
812 pm[n] = 1 | |
813 nl.append(n) | |
814 continue | |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
815 for p in cl.parents(n): |
94 | 816 if p in pm: # parent listed |
817 pm[n] = 1 | |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
818 nl.append(n) |
94 | 819 break |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
820 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
821 return nl |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
822 |
516 | 823 def findincoming(self, remote): |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
824 m = self.changelog.nodemap |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
825 search = [] |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
826 fetch = [] |
148
c32286d0a665
Improve pruning of branches in outstanding changeset algorithm
mpm@selenic.com
parents:
146
diff
changeset
|
827 seen = {} |
c32286d0a665
Improve pruning of branches in outstanding changeset algorithm
mpm@selenic.com
parents:
146
diff
changeset
|
828 seenbranch = {} |
192 | 829 |
190
3dd5ce2fddb6
merge: short-circuit search for merge into empty repo
mpm@selenic.com
parents:
187
diff
changeset
|
830 # if we have an empty repo, fetch everything |
3dd5ce2fddb6
merge: short-circuit search for merge into empty repo
mpm@selenic.com
parents:
187
diff
changeset
|
831 if self.changelog.tip() == nullid: |
222 | 832 self.ui.status("requesting all changes\n") |
516 | 833 return [nullid] |
190
3dd5ce2fddb6
merge: short-circuit search for merge into empty repo
mpm@selenic.com
parents:
187
diff
changeset
|
834 |
3dd5ce2fddb6
merge: short-circuit search for merge into empty repo
mpm@selenic.com
parents:
187
diff
changeset
|
835 # otherwise, assume we're closer to the tip than the root |
222 | 836 self.ui.status("searching for changes\n") |
837 heads = remote.heads() | |
838 unknown = [] | |
839 for h in heads: | |
840 if h not in m: | |
841 unknown.append(h) | |
46 | 842 |
222 | 843 if not unknown: |
60 | 844 return None |
324 | 845 |
846 rep = {} | |
847 reqcnt = 0 | |
515 | 848 |
222 | 849 unknown = remote.branches(unknown) |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
850 while unknown: |
324 | 851 r = [] |
852 while unknown: | |
853 n = unknown.pop(0) | |
854 if n[0] in seen: | |
855 continue | |
148
c32286d0a665
Improve pruning of branches in outstanding changeset algorithm
mpm@selenic.com
parents:
146
diff
changeset
|
856 |
324 | 857 self.ui.debug("examining %s:%s\n" % (short(n[0]), short(n[1]))) |
858 if n[0] == nullid: | |
859 break | |
328 | 860 if n in seenbranch: |
324 | 861 self.ui.debug("branch already found\n") |
862 continue | |
863 if n[1] and n[1] in m: # do we know the base? | |
864 self.ui.debug("found incomplete branch %s:%s\n" | |
865 % (short(n[0]), short(n[1]))) | |
866 search.append(n) # schedule branch range for scanning | |
328 | 867 seenbranch[n] = 1 |
324 | 868 else: |
869 if n[1] not in seen and n[1] not in fetch: | |
870 if n[2] in m and n[3] in m: | |
871 self.ui.debug("found new changeset %s\n" % | |
872 short(n[1])) | |
873 fetch.append(n[1]) # earliest unknown | |
874 continue | |
875 | |
876 for a in n[2:4]: | |
877 if a not in rep: | |
878 r.append(a) | |
879 rep[a] = 1 | |
880 | |
328 | 881 seen[n[0]] = 1 |
882 | |
324 | 883 if r: |
884 reqcnt += 1 | |
885 self.ui.debug("request %d: %s\n" % | |
886 (reqcnt, " ".join(map(short, r)))) | |
887 for p in range(0, len(r), 10): | |
888 for b in remote.branches(r[p:p+10]): | |
148
c32286d0a665
Improve pruning of branches in outstanding changeset algorithm
mpm@selenic.com
parents:
146
diff
changeset
|
889 self.ui.debug("received %s:%s\n" % |
c32286d0a665
Improve pruning of branches in outstanding changeset algorithm
mpm@selenic.com
parents:
146
diff
changeset
|
890 (short(b[0]), short(b[1]))) |
c32286d0a665
Improve pruning of branches in outstanding changeset algorithm
mpm@selenic.com
parents:
146
diff
changeset
|
891 if b[0] not in m and b[0] not in seen: |
c32286d0a665
Improve pruning of branches in outstanding changeset algorithm
mpm@selenic.com
parents:
146
diff
changeset
|
892 unknown.append(b) |
515 | 893 |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
894 while search: |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
895 n = search.pop(0) |
324 | 896 reqcnt += 1 |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
897 l = remote.between([(n[0], n[1])])[0] |
328 | 898 l.append(n[1]) |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
899 p = n[0] |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
900 f = 1 |
328 | 901 for i in l: |
902 self.ui.debug("narrowing %d:%d %s\n" % (f, len(l), short(i))) | |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
903 if i in m: |
85 | 904 if f <= 2: |
83 | 905 self.ui.debug("found new branch changeset %s\n" % |
906 short(p)) | |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
907 fetch.append(p) |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
908 else: |
83 | 909 self.ui.debug("narrowed branch search to %s:%s\n" |
910 % (short(p), short(i))) | |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
911 search.append((p, i)) |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
912 break |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
913 p, f = i, f * 2 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
914 |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
915 for f in fetch: |
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
916 if f in m: |
499 | 917 raise RepoError("already have changeset " + short(f[:4])) |
83 | 918 |
511 | 919 if fetch == [nullid]: |
514
874e577e332e
change unrelated repository error to a warning
mpm@selenic.com
parents:
511
diff
changeset
|
920 self.ui.warn("warning: pulling from an unrelated repository!\n") |
511 | 921 |
94 | 922 self.ui.note("adding new changesets starting at " + |
83 | 923 " ".join([short(f) for f in fetch]) + "\n") |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
924 |
324 | 925 self.ui.debug("%d total queries\n" % reqcnt) |
926 | |
516 | 927 return fetch |
928 | |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
929 def changegroup(self, basenodes): |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
930 nodes = self.newer(basenodes) |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
931 |
46 | 932 # construct the link map |
933 linkmap = {} | |
934 for n in nodes: | |
935 linkmap[self.changelog.rev(n)] = n | |
936 | |
937 # construct a list of all changed files | |
938 changed = {} | |
939 for n in nodes: | |
940 c = self.changelog.read(n) | |
941 for f in c[3]: | |
942 changed[f] = 1 | |
943 changed = changed.keys() | |
944 changed.sort() | |
945 | |
946 # the changegroup is changesets + manifests + all file revs | |
947 revs = [ self.changelog.rev(n) for n in nodes ] | |
948 | |
192 | 949 for y in self.changelog.group(linkmap): yield y |
950 for y in self.manifest.group(linkmap): yield y | |
46 | 951 for f in changed: |
192 | 952 yield struct.pack(">l", len(f) + 4) + f |
46 | 953 g = self.file(f).group(linkmap) |
192 | 954 for y in g: |
955 yield y | |
46 | 956 |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
957 def addchangegroup(self, generator): |
222 | 958 |
959 class genread: | |
960 def __init__(self, generator): | |
961 self.g = generator | |
962 self.buf = "" | |
963 def read(self, l): | |
964 while l > len(self.buf): | |
965 try: | |
966 self.buf += self.g.next() | |
967 except StopIteration: | |
968 break | |
969 d, self.buf = self.buf[:l], self.buf[l:] | |
970 return d | |
515 | 971 |
222 | 972 def getchunk(): |
973 d = source.read(4) | |
974 if not d: return "" | |
975 l = struct.unpack(">l", d)[0] | |
976 if l <= 4: return "" | |
977 return source.read(l - 4) | |
978 | |
979 def getgroup(): | |
980 while 1: | |
981 c = getchunk() | |
982 if not c: break | |
983 yield c | |
984 | |
985 def csmap(x): | |
986 self.ui.debug("add changeset %s\n" % short(x)) | |
987 return self.changelog.count() | |
988 | |
989 def revmap(x): | |
990 return self.changelog.rev(x) | |
991 | |
992 if not generator: return | |
993 changesets = files = revisions = 0 | |
225 | 994 |
222 | 995 source = genread(generator) |
225 | 996 lock = self.lock() |
222 | 997 tr = self.transaction() |
998 | |
999 # pull off the changeset group | |
1000 self.ui.status("adding changesets\n") | |
1001 co = self.changelog.tip() | |
224
ccbcc4d76f81
fix bad assumption about uniqueness of file versions
mpm@selenic.com
parents:
223
diff
changeset
|
1002 cn = self.changelog.addgroup(getgroup(), csmap, tr, 1) # unique |
222 | 1003 changesets = self.changelog.rev(cn) - self.changelog.rev(co) |
1004 | |
1005 # pull off the manifest group | |
1006 self.ui.status("adding manifests\n") | |
1007 mm = self.manifest.tip() | |
1008 mo = self.manifest.addgroup(getgroup(), revmap, tr) | |
1009 | |
1010 # process the files | |
1011 self.ui.status("adding file revisions\n") | |
1012 while 1: | |
1013 f = getchunk() | |
1014 if not f: break | |
1015 self.ui.debug("adding %s revisions\n" % f) | |
1016 fl = self.file(f) | |
529
aace5b681fe9
Attempt to fix negative revision count from pull
mpm@selenic.com
parents:
522
diff
changeset
|
1017 o = fl.count() |
222 | 1018 n = fl.addgroup(getgroup(), revmap, tr) |
529
aace5b681fe9
Attempt to fix negative revision count from pull
mpm@selenic.com
parents:
522
diff
changeset
|
1019 revisions += fl.count() - o |
222 | 1020 files += 1 |
1021 | |
1022 self.ui.status(("modified %d files, added %d changesets" + | |
1023 " and %d new revisions\n") | |
1024 % (files, changesets, revisions)) | |
1025 | |
1026 tr.close() | |
1027 return | |
1028 | |
275 | 1029 def update(self, node, allow=False, force=False): |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1030 pl = self.dirstate.parents() |
275 | 1031 if not force and pl[1] != nullid: |
254 | 1032 self.ui.warn("aborting: outstanding uncommitted merges\n") |
46 | 1033 return |
1034 | |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1035 p1, p2 = pl[0], node |
305 | 1036 pa = self.changelog.ancestor(p1, p2) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1037 m1n = self.changelog.read(p1)[0] |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1038 m2n = self.changelog.read(p2)[0] |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1039 man = self.manifest.ancestor(m1n, m2n) |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1040 m1 = self.manifest.read(m1n) |
276 | 1041 mf1 = self.manifest.readflags(m1n) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1042 m2 = self.manifest.read(m2n) |
276 | 1043 mf2 = self.manifest.readflags(m2n) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1044 ma = self.manifest.read(man) |
412 | 1045 mfa = self.manifest.readflags(man) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1046 |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1047 (c, a, d, u) = self.diffdir(self.root) |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1048 |
408
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1049 # is this a jump, or a merge? i.e. is there a linear path |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1050 # from p1 to p2? |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1051 linear_path = (pa == p1 or pa == p2) |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1052 |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1053 # resolve the manifest to determine which files |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1054 # we care about merging |
254 | 1055 self.ui.note("resolving manifests\n") |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1056 self.ui.debug(" ancestor %s local %s remote %s\n" % |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1057 (short(man), short(m1n), short(m2n))) |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1058 |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1059 merge = {} |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1060 get = {} |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1061 remove = [] |
305 | 1062 mark = {} |
46 | 1063 |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1064 # construct a working dir manifest |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1065 mw = m1.copy() |
276 | 1066 mfw = mf1.copy() |
254 | 1067 for f in a + c + u: |
1068 mw[f] = "" | |
441 | 1069 mfw[f] = util.is_exec(self.wjoin(f), mfw.get(f, False)) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1070 for f in d: |
254 | 1071 if f in mw: del mw[f] |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1072 |
408
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1073 # If we're jumping between revisions (as opposed to merging), |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1074 # and if neither the working directory nor the target rev has |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1075 # the file, then we need to remove it from the dirstate, to |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1076 # prevent the dirstate from listing the file when it is no |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1077 # longer in the manifest. |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1078 if linear_path and f not in m2: |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1079 self.dirstate.forget((f,)) |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1080 |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1081 for f, n in mw.iteritems(): |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1082 if f in m2: |
277
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1083 s = 0 |
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1084 |
407
0e0d0670b2bc
[PATCH] Merging identical changes from another branch
mpm@selenic.com
parents:
405
diff
changeset
|
1085 # is the wfile new since m1, and match m2? |
428 | 1086 if f not in m1: |
407
0e0d0670b2bc
[PATCH] Merging identical changes from another branch
mpm@selenic.com
parents:
405
diff
changeset
|
1087 t1 = self.wfile(f).read() |
0e0d0670b2bc
[PATCH] Merging identical changes from another branch
mpm@selenic.com
parents:
405
diff
changeset
|
1088 t2 = self.file(f).revision(m2[f]) |
0e0d0670b2bc
[PATCH] Merging identical changes from another branch
mpm@selenic.com
parents:
405
diff
changeset
|
1089 if cmp(t1, t2) == 0: |
0e0d0670b2bc
[PATCH] Merging identical changes from another branch
mpm@selenic.com
parents:
405
diff
changeset
|
1090 mark[f] = 1 |
0e0d0670b2bc
[PATCH] Merging identical changes from another branch
mpm@selenic.com
parents:
405
diff
changeset
|
1091 n = m2[f] |
0e0d0670b2bc
[PATCH] Merging identical changes from another branch
mpm@selenic.com
parents:
405
diff
changeset
|
1092 del t1, t2 |
0e0d0670b2bc
[PATCH] Merging identical changes from another branch
mpm@selenic.com
parents:
405
diff
changeset
|
1093 |
296
a3d83bf86755
hg update: fix clobbering files when going backwards
mpm@selenic.com
parents:
292
diff
changeset
|
1094 # are files different? |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1095 if n != m2[f]: |
254 | 1096 a = ma.get(f, nullid) |
296
a3d83bf86755
hg update: fix clobbering files when going backwards
mpm@selenic.com
parents:
292
diff
changeset
|
1097 # are both different from the ancestor? |
254 | 1098 if n != a and m2[f] != a: |
273
4f8174389001
merge: Fix bug where we overwrote local when local was newer
mpm@selenic.com
parents:
263
diff
changeset
|
1099 self.ui.debug(" %s versions differ, resolve\n" % f) |
276 | 1100 # merge executable bits |
1101 # "if we changed or they changed, change in merge" | |
1102 a, b, c = mfa.get(f, 0), mfw[f], mf2[f] | |
1103 mode = ((a^b) | (a^c)) ^ a | |
1104 merge[f] = (m1.get(f, nullid), m2[f], mode) | |
277
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1105 s = 1 |
305 | 1106 # are we clobbering? |
1107 # is remote's version newer? | |
1108 # or are we going back in time? | |
1109 elif force or m2[f] != a or (p2 == pa and mw[f] == m1[f]): | |
273
4f8174389001
merge: Fix bug where we overwrote local when local was newer
mpm@selenic.com
parents:
263
diff
changeset
|
1110 self.ui.debug(" remote %s is newer, get\n" % f) |
254 | 1111 get[f] = m2[f] |
277
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1112 s = 1 |
305 | 1113 else: |
1114 mark[f] = 1 | |
277
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1115 |
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1116 if not s and mfw[f] != mf2[f]: |
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1117 if force: |
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1118 self.ui.debug(" updating permissions for %s\n" % f) |
441 | 1119 util.set_exec(self.wjoin(f), mf2[f]) |
277
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1120 else: |
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1121 a, b, c = mfa.get(f, 0), mfw[f], mf2[f] |
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1122 mode = ((a^b) | (a^c)) ^ a |
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1123 if mode != b: |
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1124 self.ui.debug(" updating permissions for %s\n" % f) |
441 | 1125 util.set_exec(self.wjoin(f), mode) |
305 | 1126 mark[f] = 1 |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1127 del m2[f] |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1128 elif f in ma: |
275 | 1129 if not force and n != ma[f]: |
415
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1130 r = "" |
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1131 if linear_path or allow: |
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1132 r = self.ui.prompt( |
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1133 (" local changed %s which remote deleted\n" % f) + |
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1134 "(k)eep or (d)elete?", "[kd]", "k") |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1135 if r == "d": |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1136 remove.append(f) |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1137 else: |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1138 self.ui.debug("other deleted %s\n" % f) |
254 | 1139 remove.append(f) # other deleted it |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1140 else: |
254 | 1141 if n == m1.get(f, nullid): # same as parent |
383
4862a134e2c2
hg merge: fix time asymmetry bug with deleting files on update to past
mpm@selenic.com
parents:
377
diff
changeset
|
1142 if p2 == pa: # going backwards? |
4862a134e2c2
hg merge: fix time asymmetry bug with deleting files on update to past
mpm@selenic.com
parents:
377
diff
changeset
|
1143 self.ui.debug("remote deleted %s\n" % f) |
4862a134e2c2
hg merge: fix time asymmetry bug with deleting files on update to past
mpm@selenic.com
parents:
377
diff
changeset
|
1144 remove.append(f) |
4862a134e2c2
hg merge: fix time asymmetry bug with deleting files on update to past
mpm@selenic.com
parents:
377
diff
changeset
|
1145 else: |
4862a134e2c2
hg merge: fix time asymmetry bug with deleting files on update to past
mpm@selenic.com
parents:
377
diff
changeset
|
1146 self.ui.debug("local created %s, keeping\n" % f) |
254 | 1147 else: |
1148 self.ui.debug("working dir created %s, keeping\n" % f) | |
46 | 1149 |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1150 for f, n in m2.iteritems(): |
256 | 1151 if f[0] == "/": continue |
275 | 1152 if not force and f in ma and n != ma[f]: |
415
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1153 r = "" |
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1154 if linear_path or allow: |
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1155 r = self.ui.prompt( |
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1156 ("remote changed %s which local deleted\n" % f) + |
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1157 "(k)eep or (d)elete?", "[kd]", "k") |
275 | 1158 if r == "d": remove.append(f) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1159 else: |
254 | 1160 self.ui.debug("remote created %s\n" % f) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1161 get[f] = n |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1162 |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1163 del mw, m1, m2, ma |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1164 |
275 | 1165 if force: |
1166 for f in merge: | |
1167 get[f] = merge[f][1] | |
1168 merge = {} | |
1169 | |
408
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1170 if linear_path: |
254 | 1171 # we don't need to do any magic, just jump to the new rev |
1172 mode = 'n' | |
1173 p1, p2 = p2, nullid | |
1174 else: | |
275 | 1175 if not allow: |
305 | 1176 self.ui.status("this update spans a branch" + |
1177 " affecting the following files:\n") | |
1178 fl = merge.keys() + get.keys() | |
1179 fl.sort() | |
1180 for f in fl: | |
1181 cf = "" | |
1182 if f in merge: cf = " (resolve)" | |
1183 self.ui.status(" %s%s\n" % (f, cf)) | |
1184 self.ui.warn("aborting update spanning branches!\n") | |
1185 self.ui.status("(use update -m to perform a branch merge)\n") | |
275 | 1186 return 1 |
254 | 1187 # we have to remember what files we needed to get/change |
1188 # because any file that's different from either one of its | |
1189 # parents must be in the changeset | |
1190 mode = 'm' | |
305 | 1191 self.dirstate.update(mark.keys(), "m") |
254 | 1192 |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1193 self.dirstate.setparents(p1, p2) |
191
d7e859cf2f1b
merge: add count of new manifests, files, and revisions
mpm@selenic.com
parents:
190
diff
changeset
|
1194 |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1195 # get the files we don't need to change |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1196 files = get.keys() |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1197 files.sort() |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1198 for f in files: |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1199 if f[0] == "/": continue |
273
4f8174389001
merge: Fix bug where we overwrote local when local was newer
mpm@selenic.com
parents:
263
diff
changeset
|
1200 self.ui.note("getting %s\n" % f) |
276 | 1201 t = self.file(f).read(get[f]) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1202 try: |
291
2c4f2be05587
Add wopener for opening files in the working directory
mpm@selenic.com
parents:
288
diff
changeset
|
1203 self.wfile(f, "w").write(t) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1204 except IOError: |
297
0dbcf3c9ff20
Fixed usage of removed variable 'wp'.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
292
diff
changeset
|
1205 os.makedirs(os.path.dirname(self.wjoin(f))) |
291
2c4f2be05587
Add wopener for opening files in the working directory
mpm@selenic.com
parents:
288
diff
changeset
|
1206 self.wfile(f, "w").write(t) |
441 | 1207 util.set_exec(self.wjoin(f), mf2[f]) |
254 | 1208 self.dirstate.update([f], mode) |
46 | 1209 |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1210 # merge the tricky bits |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1211 files = merge.keys() |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1212 files.sort() |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1213 for f in files: |
256 | 1214 self.ui.status("merging %s\n" % f) |
276 | 1215 m, o, flag = merge[f] |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1216 self.merge3(f, m, o) |
441 | 1217 util.set_exec(self.wjoin(f), flag) |
254 | 1218 self.dirstate.update([f], 'm') |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1219 |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1220 for f in remove: |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1221 self.ui.note("removing %s\n" % f) |
254 | 1222 os.unlink(f) |
1223 if mode == 'n': | |
1224 self.dirstate.forget(remove) | |
1225 else: | |
1226 self.dirstate.update(remove, 'r') | |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1227 |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1228 def merge3(self, fn, my, other): |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1229 """perform a 3-way merge in the working directory""" |
249 | 1230 |
96 | 1231 def temp(prefix, node): |
1232 pre = "%s~%s." % (os.path.basename(fn), prefix) | |
1233 (fd, name) = tempfile.mkstemp("", pre) | |
417 | 1234 f = os.fdopen(fd, "wb") |
96 | 1235 f.write(fl.revision(node)) |
1236 f.close() | |
1237 return name | |
1238 | |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1239 fl = self.file(fn) |
96 | 1240 base = fl.ancestor(my, other) |
244 | 1241 a = self.wjoin(fn) |
346 | 1242 b = temp("base", base) |
1243 c = temp("other", other) | |
96 | 1244 |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1245 self.ui.note("resolving %s\n" % fn) |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1246 self.ui.debug("file %s: other %s ancestor %s\n" % |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1247 (fn, short(other), short(base))) |
96 | 1248 |
240 | 1249 cmd = os.environ.get("HGMERGE", "hgmerge") |
1250 r = os.system("%s %s %s %s" % (cmd, a, b, c)) | |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1251 if r: |
275 | 1252 self.ui.warn("merging %s failed!\n" % fn) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1253 |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1254 os.unlink(b) |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1255 os.unlink(c) |
96 | 1256 |
247 | 1257 def verify(self): |
1258 filelinkrevs = {} | |
1259 filenodes = {} | |
1260 changesets = revisions = files = 0 | |
1261 errors = 0 | |
1262 | |
302 | 1263 seen = {} |
247 | 1264 self.ui.status("checking changesets\n") |
1265 for i in range(self.changelog.count()): | |
1266 changesets += 1 | |
1267 n = self.changelog.node(i) | |
302 | 1268 if n in seen: |
1269 self.ui.warn("duplicate changeset at revision %d\n" % i) | |
1270 errors += 1 | |
1271 seen[n] = 1 | |
515 | 1272 |
247 | 1273 for p in self.changelog.parents(n): |
1274 if p not in self.changelog.nodemap: | |
1275 self.ui.warn("changeset %s has unknown parent %s\n" % | |
1276 (short(n), short(p))) | |
1277 errors += 1 | |
1278 try: | |
1279 changes = self.changelog.read(n) | |
1280 except Exception, inst: | |
1281 self.ui.warn("unpacking changeset %s: %s\n" % (short(n), inst)) | |
1282 errors += 1 | |
1283 | |
1284 for f in changes[3]: | |
1285 filelinkrevs.setdefault(f, []).append(i) | |
1286 | |
302 | 1287 seen = {} |
247 | 1288 self.ui.status("checking manifests\n") |
1289 for i in range(self.manifest.count()): | |
1290 n = self.manifest.node(i) | |
302 | 1291 if n in seen: |
1292 self.ui.warn("duplicate manifest at revision %d\n" % i) | |
1293 errors += 1 | |
1294 seen[n] = 1 | |
515 | 1295 |
247 | 1296 for p in self.manifest.parents(n): |
1297 if p not in self.manifest.nodemap: | |
1298 self.ui.warn("manifest %s has unknown parent %s\n" % | |
1299 (short(n), short(p))) | |
1300 errors += 1 | |
1301 | |
1302 try: | |
1303 delta = mdiff.patchtext(self.manifest.delta(n)) | |
1304 except KeyboardInterrupt: | |
1305 print "aborted" | |
1306 sys.exit(0) | |
1307 except Exception, inst: | |
1308 self.ui.warn("unpacking manifest %s: %s\n" | |
1309 % (short(n), inst)) | |
1310 errors += 1 | |
1311 | |
1312 ff = [ l.split('\0') for l in delta.splitlines() ] | |
1313 for f, fn in ff: | |
284 | 1314 filenodes.setdefault(f, {})[bin(fn[:40])] = 1 |
247 | 1315 |
1316 self.ui.status("crosschecking files in changesets and manifests\n") | |
1317 for f in filenodes: | |
1318 if f not in filelinkrevs: | |
1319 self.ui.warn("file %s in manifest but not in changesets\n" % f) | |
1320 errors += 1 | |
1321 | |
1322 for f in filelinkrevs: | |
1323 if f not in filenodes: | |
1324 self.ui.warn("file %s in changeset but not in manifest\n" % f) | |
1325 errors += 1 | |
1326 | |
1327 self.ui.status("checking files\n") | |
1328 ff = filenodes.keys() | |
1329 ff.sort() | |
1330 for f in ff: | |
1331 if f == "/dev/null": continue | |
1332 files += 1 | |
1333 fl = self.file(f) | |
1334 nodes = { nullid: 1 } | |
302 | 1335 seen = {} |
247 | 1336 for i in range(fl.count()): |
1337 revisions += 1 | |
1338 n = fl.node(i) | |
1339 | |
302 | 1340 if n in seen: |
1341 self.ui.warn("%s: duplicate revision %d\n" % (f, i)) | |
1342 errors += 1 | |
1343 | |
247 | 1344 if n not in filenodes[f]: |
1345 self.ui.warn("%s: %d:%s not in manifests\n" | |
1346 % (f, i, short(n))) | |
1347 print len(filenodes[f].keys()), fl.count(), f | |
1348 errors += 1 | |
1349 else: | |
1350 del filenodes[f][n] | |
1351 | |
1352 flr = fl.linkrev(n) | |
1353 if flr not in filelinkrevs[f]: | |
1354 self.ui.warn("%s:%s points to unexpected changeset %d\n" | |
1355 % (f, short(n), fl.linkrev(n))) | |
1356 errors += 1 | |
1357 else: | |
1358 filelinkrevs[f].remove(flr) | |
1359 | |
1360 # verify contents | |
1361 try: | |
1362 t = fl.read(n) | |
1363 except Exception, inst: | |
1364 self.ui.warn("unpacking file %s %s: %s\n" | |
1365 % (f, short(n), inst)) | |
1366 errors += 1 | |
1367 | |
1368 # verify parents | |
1369 (p1, p2) = fl.parents(n) | |
1370 if p1 not in nodes: | |
1371 self.ui.warn("file %s:%s unknown parent 1 %s" % | |
1372 (f, short(n), short(p1))) | |
1373 errors += 1 | |
1374 if p2 not in nodes: | |
1375 self.ui.warn("file %s:%s unknown parent 2 %s" % | |
1376 (f, short(n), short(p1))) | |
1377 errors += 1 | |
1378 nodes[n] = 1 | |
1379 | |
1380 # cross-check | |
1381 for node in filenodes[f]: | |
1382 self.ui.warn("node %s in manifests not in %s\n" | |
1383 % (hex(n), f)) | |
1384 errors += 1 | |
1385 | |
1386 self.ui.status("%d files, %d changesets, %d total revisions\n" % | |
1387 (files, changesets, revisions)) | |
1388 | |
1389 if errors: | |
1390 self.ui.warn("%d integrity errors encountered!\n" % errors) | |
1391 return 1 | |
1392 | |
60 | 1393 class remoterepository: |
1394 def __init__(self, ui, path): | |
176
1d8e9637a0a4
Change hg: protocol name to http: and http: to old-http:
mpm@selenic.com
parents:
171
diff
changeset
|
1395 self.url = path |
60 | 1396 self.ui = ui |
321 | 1397 no_list = [ "localhost", "127.0.0.1" ] |
1398 host = ui.config("http_proxy", "host") | |
424
9294dce4b633
Allow override of HTTP_PROXY, http_proxy and no_proxy; make no_proxy work.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
385
diff
changeset
|
1399 if host is None: |
9294dce4b633
Allow override of HTTP_PROXY, http_proxy and no_proxy; make no_proxy work.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
385
diff
changeset
|
1400 host = os.environ.get("http_proxy") |
426
8c90ab5644c9
Allow hgrc's proxy host and $http_proxy env var to start with http://
Thomas Arendsen Hein <thomas@intevation.de>
parents:
424
diff
changeset
|
1401 if host and host.startswith('http://'): |
8c90ab5644c9
Allow hgrc's proxy host and $http_proxy env var to start with http://
Thomas Arendsen Hein <thomas@intevation.de>
parents:
424
diff
changeset
|
1402 host = host[7:] |
321 | 1403 user = ui.config("http_proxy", "user") |
1404 passwd = ui.config("http_proxy", "passwd") | |
1405 no = ui.config("http_proxy", "no") | |
424
9294dce4b633
Allow override of HTTP_PROXY, http_proxy and no_proxy; make no_proxy work.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
385
diff
changeset
|
1406 if no is None: |
9294dce4b633
Allow override of HTTP_PROXY, http_proxy and no_proxy; make no_proxy work.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
385
diff
changeset
|
1407 no = os.environ.get("no_proxy") |
321 | 1408 if no: |
1409 no_list = no_list + no.split(",") | |
515 | 1410 |
321 | 1411 no_proxy = 0 |
1412 for h in no_list: | |
1413 if (path.startswith("http://" + h + "/") or | |
1414 path.startswith("http://" + h + ":") or | |
1415 path == "http://" + h): | |
1416 no_proxy = 1 | |
1417 | |
1418 # Note: urllib2 takes proxy values from the environment and those will | |
1419 # take precedence | |
424
9294dce4b633
Allow override of HTTP_PROXY, http_proxy and no_proxy; make no_proxy work.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
385
diff
changeset
|
1420 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]: |
9294dce4b633
Allow override of HTTP_PROXY, http_proxy and no_proxy; make no_proxy work.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
385
diff
changeset
|
1421 if os.environ.has_key(env): |
9294dce4b633
Allow override of HTTP_PROXY, http_proxy and no_proxy; make no_proxy work.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
385
diff
changeset
|
1422 del os.environ[env] |
321 | 1423 |
1424 proxy_handler = urllib2.BaseHandler() | |
1425 if host and not no_proxy: | |
1426 proxy_handler = urllib2.ProxyHandler({"http" : "http://" + host}) | |
1427 | |
1428 authinfo = None | |
1429 if user and passwd: | |
1430 passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm() | |
1431 passmgr.add_password(None, host, user, passwd) | |
1432 authinfo = urllib2.ProxyBasicAuthHandler(passmgr) | |
1433 | |
1434 opener = urllib2.build_opener(proxy_handler, authinfo) | |
1435 urllib2.install_opener(opener) | |
60 | 1436 |
1437 def do_cmd(self, cmd, **args): | |
83 | 1438 self.ui.debug("sending %s command\n" % cmd) |
60 | 1439 q = {"cmd": cmd} |
1440 q.update(args) | |
1441 qs = urllib.urlencode(q) | |
1442 cu = "%s?%s" % (self.url, qs) | |
321 | 1443 return urllib2.urlopen(cu) |
60 | 1444 |
222 | 1445 def heads(self): |
1446 d = self.do_cmd("heads").read() | |
1447 try: | |
1448 return map(bin, d[:-1].split(" ")) | |
1449 except: | |
1450 self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n") | |
1451 raise | |
1452 | |
60 | 1453 def branches(self, nodes): |
1454 n = " ".join(map(hex, nodes)) | |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1455 d = self.do_cmd("branches", nodes=n).read() |
217 | 1456 try: |
1457 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ] | |
1458 return br | |
1459 except: | |
1460 self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n") | |
1461 raise | |
60 | 1462 |
1463 def between(self, pairs): | |
1464 n = "\n".join(["-".join(map(hex, p)) for p in pairs]) | |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1465 d = self.do_cmd("between", pairs=n).read() |
217 | 1466 try: |
1467 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ] | |
1468 return p | |
1469 except: | |
1470 self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n") | |
1471 raise | |
60 | 1472 |
1473 def changegroup(self, nodes): | |
1474 n = " ".join(map(hex, nodes)) | |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1475 zd = zlib.decompressobj() |
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1476 f = self.do_cmd("changegroup", roots=n) |
192 | 1477 bytes = 0 |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1478 while 1: |
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1479 d = f.read(4096) |
192 | 1480 bytes += len(d) |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1481 if not d: |
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1482 yield zd.flush() |
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1483 break |
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1484 yield zd.decompress(d) |
192 | 1485 self.ui.note("%d bytes of data transfered\n" % bytes) |
60 | 1486 |
1487 def repository(ui, path=None, create=0): | |
176
1d8e9637a0a4
Change hg: protocol name to http: and http: to old-http:
mpm@selenic.com
parents:
171
diff
changeset
|
1488 if path and path[:7] == "http://": |
1d8e9637a0a4
Change hg: protocol name to http: and http: to old-http:
mpm@selenic.com
parents:
171
diff
changeset
|
1489 return remoterepository(ui, path) |
60 | 1490 if path and path[:5] == "hg://": |
176
1d8e9637a0a4
Change hg: protocol name to http: and http: to old-http:
mpm@selenic.com
parents:
171
diff
changeset
|
1491 return remoterepository(ui, path.replace("hg://", "http://")) |
1d8e9637a0a4
Change hg: protocol name to http: and http: to old-http:
mpm@selenic.com
parents:
171
diff
changeset
|
1492 if path and path[:11] == "old-http://": |
1d8e9637a0a4
Change hg: protocol name to http: and http: to old-http:
mpm@selenic.com
parents:
171
diff
changeset
|
1493 return localrepository(ui, path.replace("old-http://", "http://")) |
60 | 1494 else: |
1495 return localrepository(ui, path, create) | |
1496 |