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