##// END OF EJS Templates
Turn on +x for every +r bit when making a file executable and obey umask.
Thomas Arendsen Hein -
r298:91c9fd6a default
parent child Browse files
Show More
@@ -1,1261 +1,1266 b''
1 # hg.py - repository classes for mercurial
1 # hg.py - repository classes for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 import sys, struct, os
8 import sys, struct, os
9 from revlog import *
9 from revlog import *
10 from demandload import *
10 from demandload import *
11 demandload(globals(), "re lock urllib urllib2 transaction time socket")
11 demandload(globals(), "re lock urllib urllib2 transaction time socket")
12 demandload(globals(), "tempfile byterange difflib")
12 demandload(globals(), "tempfile byterange difflib")
13
13
14 def is_exec(f):
14 def is_exec(f):
15 return (os.stat(f).st_mode & 0100 != 0)
15 return (os.stat(f).st_mode & 0100 != 0)
16
16
17 def set_exec(f, mode):
17 def set_exec(f, mode):
18 s = os.stat(f).st_mode
18 s = os.stat(f).st_mode
19 if (s & 0100 != 0) == mode:
19 if (s & 0100 != 0) == mode:
20 return
20 return
21 os.chmod(f, s & 0666 | (mode * 0111))
21 if mode:
22 umask = os.umask(0)
23 os.umask(umask)
24 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
25 else:
26 os.chmod(f, s & 0666)
22
27
23 class filelog(revlog):
28 class filelog(revlog):
24 def __init__(self, opener, path):
29 def __init__(self, opener, path):
25 revlog.__init__(self, opener,
30 revlog.__init__(self, opener,
26 os.path.join("data", path + ".i"),
31 os.path.join("data", path + ".i"),
27 os.path.join("data", path + ".d"))
32 os.path.join("data", path + ".d"))
28
33
29 def read(self, node):
34 def read(self, node):
30 return self.revision(node)
35 return self.revision(node)
31 def add(self, text, transaction, link, p1=None, p2=None):
36 def add(self, text, transaction, link, p1=None, p2=None):
32 return self.addrevision(text, transaction, link, p1, p2)
37 return self.addrevision(text, transaction, link, p1, p2)
33
38
34 def annotate(self, node):
39 def annotate(self, node):
35
40
36 def decorate(text, rev):
41 def decorate(text, rev):
37 return [(rev, l) for l in text.splitlines(1)]
42 return [(rev, l) for l in text.splitlines(1)]
38
43
39 def strip(annotation):
44 def strip(annotation):
40 return [e[1] for e in annotation]
45 return [e[1] for e in annotation]
41
46
42 def pair(parent, child):
47 def pair(parent, child):
43 new = []
48 new = []
44 sm = difflib.SequenceMatcher(None, strip(parent), strip(child))
49 sm = difflib.SequenceMatcher(None, strip(parent), strip(child))
45 for o, m, n, s, t in sm.get_opcodes():
50 for o, m, n, s, t in sm.get_opcodes():
46 if o == 'equal':
51 if o == 'equal':
47 new += parent[m:n]
52 new += parent[m:n]
48 else:
53 else:
49 new += child[s:t]
54 new += child[s:t]
50 return new
55 return new
51
56
52 # find all ancestors
57 # find all ancestors
53 needed = {node:1}
58 needed = {node:1}
54 visit = [node]
59 visit = [node]
55 while visit:
60 while visit:
56 n = visit.pop(0)
61 n = visit.pop(0)
57 for p in self.parents(n):
62 for p in self.parents(n):
58 if p not in needed:
63 if p not in needed:
59 needed[p] = 1
64 needed[p] = 1
60 visit.append(p)
65 visit.append(p)
61 else:
66 else:
62 # count how many times we'll use this
67 # count how many times we'll use this
63 needed[p] += 1
68 needed[p] += 1
64
69
65 # sort by revision which is a topological order
70 # sort by revision which is a topological order
66 visit = needed.keys()
71 visit = needed.keys()
67 visit = [ (self.rev(n), n) for n in visit ]
72 visit = [ (self.rev(n), n) for n in visit ]
68 visit.sort()
73 visit.sort()
69 visit = [ p[1] for p in visit ]
74 visit = [ p[1] for p in visit ]
70 hist = {}
75 hist = {}
71
76
72 for n in visit:
77 for n in visit:
73 curr = decorate(self.read(n), self.linkrev(n))
78 curr = decorate(self.read(n), self.linkrev(n))
74 for p in self.parents(n):
79 for p in self.parents(n):
75 if p != nullid:
80 if p != nullid:
76 curr = pair(hist[p], curr)
81 curr = pair(hist[p], curr)
77 # trim the history of unneeded revs
82 # trim the history of unneeded revs
78 needed[p] -= 1
83 needed[p] -= 1
79 if not needed[p]:
84 if not needed[p]:
80 del hist[p]
85 del hist[p]
81 hist[n] = curr
86 hist[n] = curr
82
87
83 return hist[n]
88 return hist[n]
84
89
85 class manifest(revlog):
90 class manifest(revlog):
86 def __init__(self, opener):
91 def __init__(self, opener):
87 self.mapcache = None
92 self.mapcache = None
88 self.listcache = None
93 self.listcache = None
89 self.addlist = None
94 self.addlist = None
90 revlog.__init__(self, opener, "00manifest.i", "00manifest.d")
95 revlog.__init__(self, opener, "00manifest.i", "00manifest.d")
91
96
92 def read(self, node):
97 def read(self, node):
93 if self.mapcache and self.mapcache[0] == node:
98 if self.mapcache and self.mapcache[0] == node:
94 return self.mapcache[1].copy()
99 return self.mapcache[1].copy()
95 text = self.revision(node)
100 text = self.revision(node)
96 map = {}
101 map = {}
97 flag = {}
102 flag = {}
98 self.listcache = (text, text.splitlines(1))
103 self.listcache = (text, text.splitlines(1))
99 for l in self.listcache[1]:
104 for l in self.listcache[1]:
100 (f, n) = l.split('\0')
105 (f, n) = l.split('\0')
101 map[f] = bin(n[:40])
106 map[f] = bin(n[:40])
102 flag[f] = (n[40:-1] == "x")
107 flag[f] = (n[40:-1] == "x")
103 self.mapcache = (node, map, flag)
108 self.mapcache = (node, map, flag)
104 return map
109 return map
105
110
106 def readflags(self, node):
111 def readflags(self, node):
107 if self.mapcache or self.mapcache[0] != node:
112 if self.mapcache or self.mapcache[0] != node:
108 self.read(node)
113 self.read(node)
109 return self.mapcache[2]
114 return self.mapcache[2]
110
115
111 def diff(self, a, b):
116 def diff(self, a, b):
112 # this is sneaky, as we're not actually using a and b
117 # this is sneaky, as we're not actually using a and b
113 if self.listcache and self.addlist and self.listcache[0] == a:
118 if self.listcache and self.addlist and self.listcache[0] == a:
114 d = mdiff.diff(self.listcache[1], self.addlist, 1)
119 d = mdiff.diff(self.listcache[1], self.addlist, 1)
115 if mdiff.patch(a, d) != b:
120 if mdiff.patch(a, d) != b:
116 sys.stderr.write("*** sortdiff failed, falling back ***\n")
121 sys.stderr.write("*** sortdiff failed, falling back ***\n")
117 return mdiff.textdiff(a, b)
122 return mdiff.textdiff(a, b)
118 return d
123 return d
119 else:
124 else:
120 return mdiff.textdiff(a, b)
125 return mdiff.textdiff(a, b)
121
126
122 def add(self, map, flags, transaction, link, p1=None, p2=None):
127 def add(self, map, flags, transaction, link, p1=None, p2=None):
123 files = map.keys()
128 files = map.keys()
124 files.sort()
129 files.sort()
125
130
126 self.addlist = ["%s\000%s%s\n" %
131 self.addlist = ["%s\000%s%s\n" %
127 (f, hex(map[f]), flags[f] and "x" or '')
132 (f, hex(map[f]), flags[f] and "x" or '')
128 for f in files]
133 for f in files]
129 text = "".join(self.addlist)
134 text = "".join(self.addlist)
130
135
131 n = self.addrevision(text, transaction, link, p1, p2)
136 n = self.addrevision(text, transaction, link, p1, p2)
132 self.mapcache = (n, map)
137 self.mapcache = (n, map)
133 self.listcache = (text, self.addlist)
138 self.listcache = (text, self.addlist)
134 self.addlist = None
139 self.addlist = None
135
140
136 return n
141 return n
137
142
138 class changelog(revlog):
143 class changelog(revlog):
139 def __init__(self, opener):
144 def __init__(self, opener):
140 revlog.__init__(self, opener, "00changelog.i", "00changelog.d")
145 revlog.__init__(self, opener, "00changelog.i", "00changelog.d")
141
146
142 def extract(self, text):
147 def extract(self, text):
143 if not text:
148 if not text:
144 return (nullid, "", "0", [], "")
149 return (nullid, "", "0", [], "")
145 last = text.index("\n\n")
150 last = text.index("\n\n")
146 desc = text[last + 2:]
151 desc = text[last + 2:]
147 l = text[:last].splitlines()
152 l = text[:last].splitlines()
148 manifest = bin(l[0])
153 manifest = bin(l[0])
149 user = l[1]
154 user = l[1]
150 date = l[2]
155 date = l[2]
151 files = l[3:]
156 files = l[3:]
152 return (manifest, user, date, files, desc)
157 return (manifest, user, date, files, desc)
153
158
154 def read(self, node):
159 def read(self, node):
155 return self.extract(self.revision(node))
160 return self.extract(self.revision(node))
156
161
157 def add(self, manifest, list, desc, transaction, p1=None, p2=None,
162 def add(self, manifest, list, desc, transaction, p1=None, p2=None,
158 user=None, date=None):
163 user=None, date=None):
159 user = (user or
164 user = (user or
160 os.environ.get("HGUSER") or
165 os.environ.get("HGUSER") or
161 os.environ.get("EMAIL") or
166 os.environ.get("EMAIL") or
162 os.environ.get("LOGNAME", "unknown") + '@' + socket.getfqdn())
167 os.environ.get("LOGNAME", "unknown") + '@' + socket.getfqdn())
163 date = date or "%d %d" % (time.time(), time.timezone)
168 date = date or "%d %d" % (time.time(), time.timezone)
164 list.sort()
169 list.sort()
165 l = [hex(manifest), user, date] + list + ["", desc]
170 l = [hex(manifest), user, date] + list + ["", desc]
166 text = "\n".join(l)
171 text = "\n".join(l)
167 return self.addrevision(text, transaction, self.count(), p1, p2)
172 return self.addrevision(text, transaction, self.count(), p1, p2)
168
173
169 class dirstate:
174 class dirstate:
170 def __init__(self, opener, ui, root):
175 def __init__(self, opener, ui, root):
171 self.opener = opener
176 self.opener = opener
172 self.root = root
177 self.root = root
173 self.dirty = 0
178 self.dirty = 0
174 self.ui = ui
179 self.ui = ui
175 self.map = None
180 self.map = None
176 self.pl = None
181 self.pl = None
177
182
178 def __del__(self):
183 def __del__(self):
179 if self.dirty:
184 if self.dirty:
180 self.write()
185 self.write()
181
186
182 def __getitem__(self, key):
187 def __getitem__(self, key):
183 try:
188 try:
184 return self.map[key]
189 return self.map[key]
185 except TypeError:
190 except TypeError:
186 self.read()
191 self.read()
187 return self[key]
192 return self[key]
188
193
189 def __contains__(self, key):
194 def __contains__(self, key):
190 if not self.map: self.read()
195 if not self.map: self.read()
191 return key in self.map
196 return key in self.map
192
197
193 def parents(self):
198 def parents(self):
194 if not self.pl:
199 if not self.pl:
195 self.read()
200 self.read()
196 return self.pl
201 return self.pl
197
202
198 def setparents(self, p1, p2 = nullid):
203 def setparents(self, p1, p2 = nullid):
199 self.dirty = 1
204 self.dirty = 1
200 self.pl = p1, p2
205 self.pl = p1, p2
201
206
202 def state(self, key):
207 def state(self, key):
203 try:
208 try:
204 return self[key][0]
209 return self[key][0]
205 except KeyError:
210 except KeyError:
206 return "?"
211 return "?"
207
212
208 def read(self):
213 def read(self):
209 if self.map is not None: return self.map
214 if self.map is not None: return self.map
210
215
211 self.map = {}
216 self.map = {}
212 self.pl = [nullid, nullid]
217 self.pl = [nullid, nullid]
213 try:
218 try:
214 st = self.opener("dirstate").read()
219 st = self.opener("dirstate").read()
215 except: return
220 except: return
216
221
217 self.pl = [st[:20], st[20: 40]]
222 self.pl = [st[:20], st[20: 40]]
218
223
219 pos = 40
224 pos = 40
220 while pos < len(st):
225 while pos < len(st):
221 e = struct.unpack(">cllll", st[pos:pos+17])
226 e = struct.unpack(">cllll", st[pos:pos+17])
222 l = e[4]
227 l = e[4]
223 pos += 17
228 pos += 17
224 f = st[pos:pos + l]
229 f = st[pos:pos + l]
225 self.map[f] = e[:4]
230 self.map[f] = e[:4]
226 pos += l
231 pos += l
227
232
228 def update(self, files, state):
233 def update(self, files, state):
229 ''' current states:
234 ''' current states:
230 n normal
235 n normal
231 m needs merging
236 m needs merging
232 r marked for removal
237 r marked for removal
233 a marked for addition'''
238 a marked for addition'''
234
239
235 if not files: return
240 if not files: return
236 self.read()
241 self.read()
237 self.dirty = 1
242 self.dirty = 1
238 for f in files:
243 for f in files:
239 if state == "r":
244 if state == "r":
240 self.map[f] = ('r', 0, 0, 0)
245 self.map[f] = ('r', 0, 0, 0)
241 else:
246 else:
242 s = os.stat(os.path.join(self.root, f))
247 s = os.stat(os.path.join(self.root, f))
243 self.map[f] = (state, s.st_mode, s.st_size, s.st_mtime)
248 self.map[f] = (state, s.st_mode, s.st_size, s.st_mtime)
244
249
245 def forget(self, files):
250 def forget(self, files):
246 if not files: return
251 if not files: return
247 self.read()
252 self.read()
248 self.dirty = 1
253 self.dirty = 1
249 for f in files:
254 for f in files:
250 try:
255 try:
251 del self.map[f]
256 del self.map[f]
252 except KeyError:
257 except KeyError:
253 self.ui.warn("not in dirstate: %s!\n" % f)
258 self.ui.warn("not in dirstate: %s!\n" % f)
254 pass
259 pass
255
260
256 def clear(self):
261 def clear(self):
257 self.map = {}
262 self.map = {}
258 self.dirty = 1
263 self.dirty = 1
259
264
260 def write(self):
265 def write(self):
261 st = self.opener("dirstate", "w")
266 st = self.opener("dirstate", "w")
262 st.write("".join(self.pl))
267 st.write("".join(self.pl))
263 for f, e in self.map.items():
268 for f, e in self.map.items():
264 e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f))
269 e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f))
265 st.write(e + f)
270 st.write(e + f)
266 self.dirty = 0
271 self.dirty = 0
267
272
268 def copy(self):
273 def copy(self):
269 self.read()
274 self.read()
270 return self.map.copy()
275 return self.map.copy()
271
276
272 # used to avoid circular references so destructors work
277 # used to avoid circular references so destructors work
273 def opener(base):
278 def opener(base):
274 p = base
279 p = base
275 def o(path, mode="r"):
280 def o(path, mode="r"):
276 if p[:7] == "http://":
281 if p[:7] == "http://":
277 f = os.path.join(p, urllib.quote(path))
282 f = os.path.join(p, urllib.quote(path))
278 return httprangereader(f)
283 return httprangereader(f)
279
284
280 f = os.path.join(p, path)
285 f = os.path.join(p, path)
281
286
282 mode += "b" # for that other OS
287 mode += "b" # for that other OS
283
288
284 if mode[0] != "r":
289 if mode[0] != "r":
285 try:
290 try:
286 s = os.stat(f)
291 s = os.stat(f)
287 except OSError:
292 except OSError:
288 d = os.path.dirname(f)
293 d = os.path.dirname(f)
289 if not os.path.isdir(d):
294 if not os.path.isdir(d):
290 os.makedirs(d)
295 os.makedirs(d)
291 else:
296 else:
292 if s.st_nlink > 1:
297 if s.st_nlink > 1:
293 file(f + ".tmp", "w").write(file(f).read())
298 file(f + ".tmp", "w").write(file(f).read())
294 os.rename(f+".tmp", f)
299 os.rename(f+".tmp", f)
295
300
296 return file(f, mode)
301 return file(f, mode)
297
302
298 return o
303 return o
299
304
300 class localrepository:
305 class localrepository:
301 def __init__(self, ui, path=None, create=0):
306 def __init__(self, ui, path=None, create=0):
302 self.remote = 0
307 self.remote = 0
303 if path and path[:7] == "http://":
308 if path and path[:7] == "http://":
304 self.remote = 1
309 self.remote = 1
305 self.path = path
310 self.path = path
306 else:
311 else:
307 if not path:
312 if not path:
308 p = os.getcwd()
313 p = os.getcwd()
309 while not os.path.isdir(os.path.join(p, ".hg")):
314 while not os.path.isdir(os.path.join(p, ".hg")):
310 p = os.path.dirname(p)
315 p = os.path.dirname(p)
311 if p == "/": raise "No repo found"
316 if p == "/": raise "No repo found"
312 path = p
317 path = p
313 self.path = os.path.join(path, ".hg")
318 self.path = os.path.join(path, ".hg")
314
319
315 self.root = path
320 self.root = path
316 self.ui = ui
321 self.ui = ui
317
322
318 if create:
323 if create:
319 os.mkdir(self.path)
324 os.mkdir(self.path)
320 os.mkdir(self.join("data"))
325 os.mkdir(self.join("data"))
321
326
322 self.opener = opener(self.path)
327 self.opener = opener(self.path)
323 self.wopener = opener(self.root)
328 self.wopener = opener(self.root)
324 self.manifest = manifest(self.opener)
329 self.manifest = manifest(self.opener)
325 self.changelog = changelog(self.opener)
330 self.changelog = changelog(self.opener)
326 self.ignorelist = None
331 self.ignorelist = None
327 self.tags = None
332 self.tags = None
328
333
329 if not self.remote:
334 if not self.remote:
330 self.dirstate = dirstate(self.opener, ui, self.root)
335 self.dirstate = dirstate(self.opener, ui, self.root)
331
336
332 def ignore(self, f):
337 def ignore(self, f):
333 if self.ignorelist is None:
338 if self.ignorelist is None:
334 self.ignorelist = []
339 self.ignorelist = []
335 try:
340 try:
336 l = self.wfile(".hgignore")
341 l = self.wfile(".hgignore")
337 for pat in l:
342 for pat in l:
338 if pat != "\n":
343 if pat != "\n":
339 self.ignorelist.append(re.compile(pat[:-1]))
344 self.ignorelist.append(re.compile(pat[:-1]))
340 except IOError: pass
345 except IOError: pass
341 for pat in self.ignorelist:
346 for pat in self.ignorelist:
342 if pat.search(f): return True
347 if pat.search(f): return True
343 return False
348 return False
344
349
345 def lookup(self, key):
350 def lookup(self, key):
346 if self.tags is None:
351 if self.tags is None:
347 self.tags = {}
352 self.tags = {}
348 try:
353 try:
349 # read each head of the tags file, ending with the tip
354 # read each head of the tags file, ending with the tip
350 # and add each tag found to the map, with "newer" ones
355 # and add each tag found to the map, with "newer" ones
351 # taking precedence
356 # taking precedence
352 fl = self.file(".hgtags")
357 fl = self.file(".hgtags")
353 h = fl.heads()
358 h = fl.heads()
354 h.reverse()
359 h.reverse()
355 for r in h:
360 for r in h:
356 for l in fl.revision(r).splitlines():
361 for l in fl.revision(r).splitlines():
357 if l:
362 if l:
358 n, k = l.split(" ")
363 n, k = l.split(" ")
359 self.tags[k] = bin(n)
364 self.tags[k] = bin(n)
360 except KeyError: pass
365 except KeyError: pass
361 try:
366 try:
362 return self.tags[key]
367 return self.tags[key]
363 except KeyError:
368 except KeyError:
364 return self.changelog.lookup(key)
369 return self.changelog.lookup(key)
365
370
366 def join(self, f):
371 def join(self, f):
367 return os.path.join(self.path, f)
372 return os.path.join(self.path, f)
368
373
369 def wjoin(self, f):
374 def wjoin(self, f):
370 return os.path.join(self.root, f)
375 return os.path.join(self.root, f)
371
376
372 def file(self, f):
377 def file(self, f):
373 if f[0] == '/': f = f[1:]
378 if f[0] == '/': f = f[1:]
374 return filelog(self.opener, f)
379 return filelog(self.opener, f)
375
380
376 def wfile(self, f, mode='r'):
381 def wfile(self, f, mode='r'):
377 return self.wopener(f, mode)
382 return self.wopener(f, mode)
378
383
379 def transaction(self):
384 def transaction(self):
380 # save dirstate for undo
385 # save dirstate for undo
381 try:
386 try:
382 ds = self.opener("dirstate").read()
387 ds = self.opener("dirstate").read()
383 except IOError:
388 except IOError:
384 ds = ""
389 ds = ""
385 self.opener("undo.dirstate", "w").write(ds)
390 self.opener("undo.dirstate", "w").write(ds)
386
391
387 return transaction.transaction(self.opener, self.join("journal"),
392 return transaction.transaction(self.opener, self.join("journal"),
388 self.join("undo"))
393 self.join("undo"))
389
394
390 def recover(self):
395 def recover(self):
391 lock = self.lock()
396 lock = self.lock()
392 if os.path.exists(self.join("recover")):
397 if os.path.exists(self.join("recover")):
393 self.ui.status("attempting to rollback interrupted transaction\n")
398 self.ui.status("attempting to rollback interrupted transaction\n")
394 return transaction.rollback(self.opener, self.join("recover"))
399 return transaction.rollback(self.opener, self.join("recover"))
395 else:
400 else:
396 self.ui.warn("no interrupted transaction available\n")
401 self.ui.warn("no interrupted transaction available\n")
397
402
398 def undo(self):
403 def undo(self):
399 lock = self.lock()
404 lock = self.lock()
400 if os.path.exists(self.join("undo")):
405 if os.path.exists(self.join("undo")):
401 self.ui.status("attempting to rollback last transaction\n")
406 self.ui.status("attempting to rollback last transaction\n")
402 transaction.rollback(self.opener, self.join("undo"))
407 transaction.rollback(self.opener, self.join("undo"))
403 self.dirstate = None
408 self.dirstate = None
404 os.rename(self.join("undo.dirstate"), self.join("dirstate"))
409 os.rename(self.join("undo.dirstate"), self.join("dirstate"))
405 self.dirstate = dirstate(self.opener, self.ui, self.root)
410 self.dirstate = dirstate(self.opener, self.ui, self.root)
406 else:
411 else:
407 self.ui.warn("no undo information available\n")
412 self.ui.warn("no undo information available\n")
408
413
409 def lock(self, wait = 1):
414 def lock(self, wait = 1):
410 try:
415 try:
411 return lock.lock(self.join("lock"), 0)
416 return lock.lock(self.join("lock"), 0)
412 except lock.LockHeld, inst:
417 except lock.LockHeld, inst:
413 if wait:
418 if wait:
414 self.ui.warn("waiting for lock held by %s\n" % inst.args[0])
419 self.ui.warn("waiting for lock held by %s\n" % inst.args[0])
415 return lock.lock(self.join("lock"), wait)
420 return lock.lock(self.join("lock"), wait)
416 raise inst
421 raise inst
417
422
418 def rawcommit(self, files, text, user, date, p1=None, p2=None):
423 def rawcommit(self, files, text, user, date, p1=None, p2=None):
419 p1 = p1 or self.dirstate.parents()[0] or nullid
424 p1 = p1 or self.dirstate.parents()[0] or nullid
420 p2 = p2 or self.dirstate.parents()[1] or nullid
425 p2 = p2 or self.dirstate.parents()[1] or nullid
421 pchange = self.changelog.read(p1)
426 pchange = self.changelog.read(p1)
422 pmmap = self.manifest.read(pchange[0])
427 pmmap = self.manifest.read(pchange[0])
423 tr = self.transaction()
428 tr = self.transaction()
424 mmap = {}
429 mmap = {}
425 linkrev = self.changelog.count()
430 linkrev = self.changelog.count()
426 for f in files:
431 for f in files:
427 try:
432 try:
428 t = file(f).read()
433 t = file(f).read()
429 except IOError:
434 except IOError:
430 self.ui.warn("Read file %s error, skipped\n" % f)
435 self.ui.warn("Read file %s error, skipped\n" % f)
431 continue
436 continue
432 r = self.file(f)
437 r = self.file(f)
433 # FIXME - need to find both parents properly
438 # FIXME - need to find both parents properly
434 prev = pmmap.get(f, nullid)
439 prev = pmmap.get(f, nullid)
435 mmap[f] = r.add(t, tr, linkrev, prev)
440 mmap[f] = r.add(t, tr, linkrev, prev)
436
441
437 mnode = self.manifest.add(mmap, tr, linkrev, pchange[0])
442 mnode = self.manifest.add(mmap, tr, linkrev, pchange[0])
438 n = self.changelog.add(mnode, files, text, tr, p1, p2, user ,date, )
443 n = self.changelog.add(mnode, files, text, tr, p1, p2, user ,date, )
439 tr.close()
444 tr.close()
440 self.dirstate.setparents(p1, p2)
445 self.dirstate.setparents(p1, p2)
441 self.dirstate.clear()
446 self.dirstate.clear()
442 self.dirstate.update(mmap.keys(), "n")
447 self.dirstate.update(mmap.keys(), "n")
443
448
444 def commit(self, files = None, text = ""):
449 def commit(self, files = None, text = ""):
445 commit = []
450 commit = []
446 remove = []
451 remove = []
447 if files:
452 if files:
448 for f in files:
453 for f in files:
449 s = self.dirstate.state(f)
454 s = self.dirstate.state(f)
450 if s in 'nmai':
455 if s in 'nmai':
451 commit.append(f)
456 commit.append(f)
452 elif s == 'r':
457 elif s == 'r':
453 remove.append(f)
458 remove.append(f)
454 else:
459 else:
455 self.ui.warn("%s not tracked!\n" % f)
460 self.ui.warn("%s not tracked!\n" % f)
456 else:
461 else:
457 (c, a, d, u) = self.diffdir(self.root)
462 (c, a, d, u) = self.diffdir(self.root)
458 commit = c + a
463 commit = c + a
459 remove = d
464 remove = d
460
465
461 if not commit and not remove:
466 if not commit and not remove:
462 self.ui.status("nothing changed\n")
467 self.ui.status("nothing changed\n")
463 return
468 return
464
469
465 p1, p2 = self.dirstate.parents()
470 p1, p2 = self.dirstate.parents()
466 c1 = self.changelog.read(p1)
471 c1 = self.changelog.read(p1)
467 c2 = self.changelog.read(p2)
472 c2 = self.changelog.read(p2)
468 m1 = self.manifest.read(c1[0])
473 m1 = self.manifest.read(c1[0])
469 mf1 = self.manifest.readflags(c1[0])
474 mf1 = self.manifest.readflags(c1[0])
470 m2 = self.manifest.read(c2[0])
475 m2 = self.manifest.read(c2[0])
471 lock = self.lock()
476 lock = self.lock()
472 tr = self.transaction()
477 tr = self.transaction()
473
478
474 # check in files
479 # check in files
475 new = {}
480 new = {}
476 linkrev = self.changelog.count()
481 linkrev = self.changelog.count()
477 commit.sort()
482 commit.sort()
478 for f in commit:
483 for f in commit:
479 self.ui.note(f + "\n")
484 self.ui.note(f + "\n")
480 try:
485 try:
481 fp = self.wjoin(f)
486 fp = self.wjoin(f)
482 mf1[f] = is_exec(fp)
487 mf1[f] = is_exec(fp)
483 t = file(fp).read()
488 t = file(fp).read()
484 except IOError:
489 except IOError:
485 self.warn("trouble committing %s!\n" % f)
490 self.warn("trouble committing %s!\n" % f)
486 raise
491 raise
487
492
488 r = self.file(f)
493 r = self.file(f)
489 fp1 = m1.get(f, nullid)
494 fp1 = m1.get(f, nullid)
490 fp2 = m2.get(f, nullid)
495 fp2 = m2.get(f, nullid)
491 new[f] = r.add(t, tr, linkrev, fp1, fp2)
496 new[f] = r.add(t, tr, linkrev, fp1, fp2)
492
497
493 # update manifest
498 # update manifest
494 m1.update(new)
499 m1.update(new)
495 for f in remove: del m1[f]
500 for f in remove: del m1[f]
496 mn = self.manifest.add(m1, mf1, tr, linkrev, c1[0], c2[0])
501 mn = self.manifest.add(m1, mf1, tr, linkrev, c1[0], c2[0])
497
502
498 # add changeset
503 # add changeset
499 new = new.keys()
504 new = new.keys()
500 new.sort()
505 new.sort()
501
506
502 if not text:
507 if not text:
503 edittext = "\n" + "HG: manifest hash %s\n" % hex(mn)
508 edittext = "\n" + "HG: manifest hash %s\n" % hex(mn)
504 edittext += "".join(["HG: changed %s\n" % f for f in new])
509 edittext += "".join(["HG: changed %s\n" % f for f in new])
505 edittext += "".join(["HG: removed %s\n" % f for f in remove])
510 edittext += "".join(["HG: removed %s\n" % f for f in remove])
506 edittext = self.ui.edit(edittext)
511 edittext = self.ui.edit(edittext)
507 if not edittext.rstrip():
512 if not edittext.rstrip():
508 return 1
513 return 1
509 text = edittext
514 text = edittext
510
515
511 n = self.changelog.add(mn, new, text, tr, p1, p2)
516 n = self.changelog.add(mn, new, text, tr, p1, p2)
512 tr.close()
517 tr.close()
513
518
514 self.dirstate.setparents(n)
519 self.dirstate.setparents(n)
515 self.dirstate.update(new, "n")
520 self.dirstate.update(new, "n")
516 self.dirstate.forget(remove)
521 self.dirstate.forget(remove)
517
522
518 def diffdir(self, path, changeset = None):
523 def diffdir(self, path, changeset = None):
519 changed = []
524 changed = []
520 added = []
525 added = []
521 unknown = []
526 unknown = []
522 mf = {}
527 mf = {}
523
528
524 if changeset:
529 if changeset:
525 change = self.changelog.read(changeset)
530 change = self.changelog.read(changeset)
526 mf = self.manifest.read(change[0])
531 mf = self.manifest.read(change[0])
527 dc = dict.fromkeys(mf)
532 dc = dict.fromkeys(mf)
528 else:
533 else:
529 changeset = self.dirstate.parents()[0]
534 changeset = self.dirstate.parents()[0]
530 change = self.changelog.read(changeset)
535 change = self.changelog.read(changeset)
531 mf = self.manifest.read(change[0])
536 mf = self.manifest.read(change[0])
532 dc = self.dirstate.copy()
537 dc = self.dirstate.copy()
533
538
534 def fcmp(fn):
539 def fcmp(fn):
535 t1 = self.wfile(fn).read()
540 t1 = self.wfile(fn).read()
536 t2 = self.file(fn).revision(mf[fn])
541 t2 = self.file(fn).revision(mf[fn])
537 return cmp(t1, t2)
542 return cmp(t1, t2)
538
543
539 for dir, subdirs, files in os.walk(self.root):
544 for dir, subdirs, files in os.walk(self.root):
540 d = dir[len(self.root)+1:]
545 d = dir[len(self.root)+1:]
541 if ".hg" in subdirs: subdirs.remove(".hg")
546 if ".hg" in subdirs: subdirs.remove(".hg")
542
547
543 for f in files:
548 for f in files:
544 fn = os.path.join(d, f)
549 fn = os.path.join(d, f)
545 try: s = os.stat(os.path.join(self.root, fn))
550 try: s = os.stat(os.path.join(self.root, fn))
546 except: continue
551 except: continue
547 if fn in dc:
552 if fn in dc:
548 c = dc[fn]
553 c = dc[fn]
549 del dc[fn]
554 del dc[fn]
550 if not c:
555 if not c:
551 if fcmp(fn):
556 if fcmp(fn):
552 changed.append(fn)
557 changed.append(fn)
553 elif c[0] == 'm':
558 elif c[0] == 'm':
554 changed.append(fn)
559 changed.append(fn)
555 elif c[0] == 'a':
560 elif c[0] == 'a':
556 added.append(fn)
561 added.append(fn)
557 elif c[0] == 'r':
562 elif c[0] == 'r':
558 unknown.append(fn)
563 unknown.append(fn)
559 elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100:
564 elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100:
560 changed.append(fn)
565 changed.append(fn)
561 elif c[1] != s.st_mode or c[3] != s.st_mtime:
566 elif c[1] != s.st_mode or c[3] != s.st_mtime:
562 if fcmp(fn):
567 if fcmp(fn):
563 changed.append(fn)
568 changed.append(fn)
564 else:
569 else:
565 if self.ignore(fn): continue
570 if self.ignore(fn): continue
566 unknown.append(fn)
571 unknown.append(fn)
567
572
568 deleted = dc.keys()
573 deleted = dc.keys()
569 deleted.sort()
574 deleted.sort()
570
575
571 return (changed, added, deleted, unknown)
576 return (changed, added, deleted, unknown)
572
577
573 def diffrevs(self, node1, node2):
578 def diffrevs(self, node1, node2):
574 changed, added = [], []
579 changed, added = [], []
575
580
576 change = self.changelog.read(node1)
581 change = self.changelog.read(node1)
577 mf1 = self.manifest.read(change[0])
582 mf1 = self.manifest.read(change[0])
578 change = self.changelog.read(node2)
583 change = self.changelog.read(node2)
579 mf2 = self.manifest.read(change[0])
584 mf2 = self.manifest.read(change[0])
580
585
581 for fn in mf2:
586 for fn in mf2:
582 if mf1.has_key(fn):
587 if mf1.has_key(fn):
583 if mf1[fn] != mf2[fn]:
588 if mf1[fn] != mf2[fn]:
584 changed.append(fn)
589 changed.append(fn)
585 del mf1[fn]
590 del mf1[fn]
586 else:
591 else:
587 added.append(fn)
592 added.append(fn)
588
593
589 deleted = mf1.keys()
594 deleted = mf1.keys()
590 deleted.sort()
595 deleted.sort()
591
596
592 return (changed, added, deleted)
597 return (changed, added, deleted)
593
598
594 def add(self, list):
599 def add(self, list):
595 for f in list:
600 for f in list:
596 p = self.wjoin(f)
601 p = self.wjoin(f)
597 if not os.path.isfile(p):
602 if not os.path.isfile(p):
598 self.ui.warn("%s does not exist!\n" % f)
603 self.ui.warn("%s does not exist!\n" % f)
599 elif self.dirstate.state(f) == 'n':
604 elif self.dirstate.state(f) == 'n':
600 self.ui.warn("%s already tracked!\n" % f)
605 self.ui.warn("%s already tracked!\n" % f)
601 else:
606 else:
602 self.dirstate.update([f], "a")
607 self.dirstate.update([f], "a")
603
608
604 def forget(self, list):
609 def forget(self, list):
605 for f in list:
610 for f in list:
606 if self.dirstate.state(f) not in 'ai':
611 if self.dirstate.state(f) not in 'ai':
607 self.ui.warn("%s not added!\n" % f)
612 self.ui.warn("%s not added!\n" % f)
608 else:
613 else:
609 self.dirstate.forget([f])
614 self.dirstate.forget([f])
610
615
611 def remove(self, list):
616 def remove(self, list):
612 for f in list:
617 for f in list:
613 p = self.wjoin(f)
618 p = self.wjoin(f)
614 if os.path.isfile(p):
619 if os.path.isfile(p):
615 self.ui.warn("%s still exists!\n" % f)
620 self.ui.warn("%s still exists!\n" % f)
616 elif f not in self.dirstate:
621 elif f not in self.dirstate:
617 self.ui.warn("%s not tracked!\n" % f)
622 self.ui.warn("%s not tracked!\n" % f)
618 else:
623 else:
619 self.dirstate.update([f], "r")
624 self.dirstate.update([f], "r")
620
625
621 def heads(self):
626 def heads(self):
622 return self.changelog.heads()
627 return self.changelog.heads()
623
628
624 def branches(self, nodes):
629 def branches(self, nodes):
625 if not nodes: nodes = [self.changelog.tip()]
630 if not nodes: nodes = [self.changelog.tip()]
626 b = []
631 b = []
627 for n in nodes:
632 for n in nodes:
628 t = n
633 t = n
629 while n:
634 while n:
630 p = self.changelog.parents(n)
635 p = self.changelog.parents(n)
631 if p[1] != nullid or p[0] == nullid:
636 if p[1] != nullid or p[0] == nullid:
632 b.append((t, n, p[0], p[1]))
637 b.append((t, n, p[0], p[1]))
633 break
638 break
634 n = p[0]
639 n = p[0]
635 return b
640 return b
636
641
637 def between(self, pairs):
642 def between(self, pairs):
638 r = []
643 r = []
639
644
640 for top, bottom in pairs:
645 for top, bottom in pairs:
641 n, l, i = top, [], 0
646 n, l, i = top, [], 0
642 f = 1
647 f = 1
643
648
644 while n != bottom:
649 while n != bottom:
645 p = self.changelog.parents(n)[0]
650 p = self.changelog.parents(n)[0]
646 if i == f:
651 if i == f:
647 l.append(n)
652 l.append(n)
648 f = f * 2
653 f = f * 2
649 n = p
654 n = p
650 i += 1
655 i += 1
651
656
652 r.append(l)
657 r.append(l)
653
658
654 return r
659 return r
655
660
656 def newer(self, nodes):
661 def newer(self, nodes):
657 m = {}
662 m = {}
658 nl = []
663 nl = []
659 pm = {}
664 pm = {}
660 cl = self.changelog
665 cl = self.changelog
661 t = l = cl.count()
666 t = l = cl.count()
662
667
663 # find the lowest numbered node
668 # find the lowest numbered node
664 for n in nodes:
669 for n in nodes:
665 l = min(l, cl.rev(n))
670 l = min(l, cl.rev(n))
666 m[n] = 1
671 m[n] = 1
667
672
668 for i in xrange(l, t):
673 for i in xrange(l, t):
669 n = cl.node(i)
674 n = cl.node(i)
670 if n in m: # explicitly listed
675 if n in m: # explicitly listed
671 pm[n] = 1
676 pm[n] = 1
672 nl.append(n)
677 nl.append(n)
673 continue
678 continue
674 for p in cl.parents(n):
679 for p in cl.parents(n):
675 if p in pm: # parent listed
680 if p in pm: # parent listed
676 pm[n] = 1
681 pm[n] = 1
677 nl.append(n)
682 nl.append(n)
678 break
683 break
679
684
680 return nl
685 return nl
681
686
682 def getchangegroup(self, remote):
687 def getchangegroup(self, remote):
683 m = self.changelog.nodemap
688 m = self.changelog.nodemap
684 search = []
689 search = []
685 fetch = []
690 fetch = []
686 seen = {}
691 seen = {}
687 seenbranch = {}
692 seenbranch = {}
688
693
689 # if we have an empty repo, fetch everything
694 # if we have an empty repo, fetch everything
690 if self.changelog.tip() == nullid:
695 if self.changelog.tip() == nullid:
691 self.ui.status("requesting all changes\n")
696 self.ui.status("requesting all changes\n")
692 return remote.changegroup([nullid])
697 return remote.changegroup([nullid])
693
698
694 # otherwise, assume we're closer to the tip than the root
699 # otherwise, assume we're closer to the tip than the root
695 self.ui.status("searching for changes\n")
700 self.ui.status("searching for changes\n")
696 heads = remote.heads()
701 heads = remote.heads()
697 unknown = []
702 unknown = []
698 for h in heads:
703 for h in heads:
699 if h not in m:
704 if h not in m:
700 unknown.append(h)
705 unknown.append(h)
701
706
702 if not unknown:
707 if not unknown:
703 self.ui.status("nothing to do!\n")
708 self.ui.status("nothing to do!\n")
704 return None
709 return None
705
710
706 unknown = remote.branches(unknown)
711 unknown = remote.branches(unknown)
707 while unknown:
712 while unknown:
708 n = unknown.pop(0)
713 n = unknown.pop(0)
709 seen[n[0]] = 1
714 seen[n[0]] = 1
710
715
711 self.ui.debug("examining %s:%s\n" % (short(n[0]), short(n[1])))
716 self.ui.debug("examining %s:%s\n" % (short(n[0]), short(n[1])))
712 if n == nullid: break
717 if n == nullid: break
713 if n in seenbranch:
718 if n in seenbranch:
714 self.ui.debug("branch already found\n")
719 self.ui.debug("branch already found\n")
715 continue
720 continue
716 if n[1] and n[1] in m: # do we know the base?
721 if n[1] and n[1] in m: # do we know the base?
717 self.ui.debug("found incomplete branch %s:%s\n"
722 self.ui.debug("found incomplete branch %s:%s\n"
718 % (short(n[0]), short(n[1])))
723 % (short(n[0]), short(n[1])))
719 search.append(n) # schedule branch range for scanning
724 search.append(n) # schedule branch range for scanning
720 seenbranch[n] = 1
725 seenbranch[n] = 1
721 else:
726 else:
722 if n[2] in m and n[3] in m:
727 if n[2] in m and n[3] in m:
723 if n[1] not in fetch:
728 if n[1] not in fetch:
724 self.ui.debug("found new changeset %s\n" %
729 self.ui.debug("found new changeset %s\n" %
725 short(n[1]))
730 short(n[1]))
726 fetch.append(n[1]) # earliest unknown
731 fetch.append(n[1]) # earliest unknown
727 continue
732 continue
728
733
729 r = []
734 r = []
730 for a in n[2:4]:
735 for a in n[2:4]:
731 if a not in seen: r.append(a)
736 if a not in seen: r.append(a)
732
737
733 if r:
738 if r:
734 self.ui.debug("requesting %s\n" %
739 self.ui.debug("requesting %s\n" %
735 " ".join(map(short, r)))
740 " ".join(map(short, r)))
736 for b in remote.branches(r):
741 for b in remote.branches(r):
737 self.ui.debug("received %s:%s\n" %
742 self.ui.debug("received %s:%s\n" %
738 (short(b[0]), short(b[1])))
743 (short(b[0]), short(b[1])))
739 if b[0] not in m and b[0] not in seen:
744 if b[0] not in m and b[0] not in seen:
740 unknown.append(b)
745 unknown.append(b)
741
746
742 while search:
747 while search:
743 n = search.pop(0)
748 n = search.pop(0)
744 l = remote.between([(n[0], n[1])])[0]
749 l = remote.between([(n[0], n[1])])[0]
745 p = n[0]
750 p = n[0]
746 f = 1
751 f = 1
747 for i in l + [n[1]]:
752 for i in l + [n[1]]:
748 if i in m:
753 if i in m:
749 if f <= 2:
754 if f <= 2:
750 self.ui.debug("found new branch changeset %s\n" %
755 self.ui.debug("found new branch changeset %s\n" %
751 short(p))
756 short(p))
752 fetch.append(p)
757 fetch.append(p)
753 else:
758 else:
754 self.ui.debug("narrowed branch search to %s:%s\n"
759 self.ui.debug("narrowed branch search to %s:%s\n"
755 % (short(p), short(i)))
760 % (short(p), short(i)))
756 search.append((p, i))
761 search.append((p, i))
757 break
762 break
758 p, f = i, f * 2
763 p, f = i, f * 2
759
764
760 for f in fetch:
765 for f in fetch:
761 if f in m:
766 if f in m:
762 raise "already have", short(f[:4])
767 raise "already have", short(f[:4])
763
768
764 self.ui.note("adding new changesets starting at " +
769 self.ui.note("adding new changesets starting at " +
765 " ".join([short(f) for f in fetch]) + "\n")
770 " ".join([short(f) for f in fetch]) + "\n")
766
771
767 return remote.changegroup(fetch)
772 return remote.changegroup(fetch)
768
773
769 def changegroup(self, basenodes):
774 def changegroup(self, basenodes):
770 nodes = self.newer(basenodes)
775 nodes = self.newer(basenodes)
771
776
772 # construct the link map
777 # construct the link map
773 linkmap = {}
778 linkmap = {}
774 for n in nodes:
779 for n in nodes:
775 linkmap[self.changelog.rev(n)] = n
780 linkmap[self.changelog.rev(n)] = n
776
781
777 # construct a list of all changed files
782 # construct a list of all changed files
778 changed = {}
783 changed = {}
779 for n in nodes:
784 for n in nodes:
780 c = self.changelog.read(n)
785 c = self.changelog.read(n)
781 for f in c[3]:
786 for f in c[3]:
782 changed[f] = 1
787 changed[f] = 1
783 changed = changed.keys()
788 changed = changed.keys()
784 changed.sort()
789 changed.sort()
785
790
786 # the changegroup is changesets + manifests + all file revs
791 # the changegroup is changesets + manifests + all file revs
787 revs = [ self.changelog.rev(n) for n in nodes ]
792 revs = [ self.changelog.rev(n) for n in nodes ]
788
793
789 for y in self.changelog.group(linkmap): yield y
794 for y in self.changelog.group(linkmap): yield y
790 for y in self.manifest.group(linkmap): yield y
795 for y in self.manifest.group(linkmap): yield y
791 for f in changed:
796 for f in changed:
792 yield struct.pack(">l", len(f) + 4) + f
797 yield struct.pack(">l", len(f) + 4) + f
793 g = self.file(f).group(linkmap)
798 g = self.file(f).group(linkmap)
794 for y in g:
799 for y in g:
795 yield y
800 yield y
796
801
797 def addchangegroup(self, generator):
802 def addchangegroup(self, generator):
798
803
799 class genread:
804 class genread:
800 def __init__(self, generator):
805 def __init__(self, generator):
801 self.g = generator
806 self.g = generator
802 self.buf = ""
807 self.buf = ""
803 def read(self, l):
808 def read(self, l):
804 while l > len(self.buf):
809 while l > len(self.buf):
805 try:
810 try:
806 self.buf += self.g.next()
811 self.buf += self.g.next()
807 except StopIteration:
812 except StopIteration:
808 break
813 break
809 d, self.buf = self.buf[:l], self.buf[l:]
814 d, self.buf = self.buf[:l], self.buf[l:]
810 return d
815 return d
811
816
812 def getchunk():
817 def getchunk():
813 d = source.read(4)
818 d = source.read(4)
814 if not d: return ""
819 if not d: return ""
815 l = struct.unpack(">l", d)[0]
820 l = struct.unpack(">l", d)[0]
816 if l <= 4: return ""
821 if l <= 4: return ""
817 return source.read(l - 4)
822 return source.read(l - 4)
818
823
819 def getgroup():
824 def getgroup():
820 while 1:
825 while 1:
821 c = getchunk()
826 c = getchunk()
822 if not c: break
827 if not c: break
823 yield c
828 yield c
824
829
825 def csmap(x):
830 def csmap(x):
826 self.ui.debug("add changeset %s\n" % short(x))
831 self.ui.debug("add changeset %s\n" % short(x))
827 return self.changelog.count()
832 return self.changelog.count()
828
833
829 def revmap(x):
834 def revmap(x):
830 return self.changelog.rev(x)
835 return self.changelog.rev(x)
831
836
832 if not generator: return
837 if not generator: return
833 changesets = files = revisions = 0
838 changesets = files = revisions = 0
834
839
835 source = genread(generator)
840 source = genread(generator)
836 lock = self.lock()
841 lock = self.lock()
837 tr = self.transaction()
842 tr = self.transaction()
838
843
839 # pull off the changeset group
844 # pull off the changeset group
840 self.ui.status("adding changesets\n")
845 self.ui.status("adding changesets\n")
841 co = self.changelog.tip()
846 co = self.changelog.tip()
842 cn = self.changelog.addgroup(getgroup(), csmap, tr, 1) # unique
847 cn = self.changelog.addgroup(getgroup(), csmap, tr, 1) # unique
843 changesets = self.changelog.rev(cn) - self.changelog.rev(co)
848 changesets = self.changelog.rev(cn) - self.changelog.rev(co)
844
849
845 # pull off the manifest group
850 # pull off the manifest group
846 self.ui.status("adding manifests\n")
851 self.ui.status("adding manifests\n")
847 mm = self.manifest.tip()
852 mm = self.manifest.tip()
848 mo = self.manifest.addgroup(getgroup(), revmap, tr)
853 mo = self.manifest.addgroup(getgroup(), revmap, tr)
849
854
850 # process the files
855 # process the files
851 self.ui.status("adding file revisions\n")
856 self.ui.status("adding file revisions\n")
852 while 1:
857 while 1:
853 f = getchunk()
858 f = getchunk()
854 if not f: break
859 if not f: break
855 self.ui.debug("adding %s revisions\n" % f)
860 self.ui.debug("adding %s revisions\n" % f)
856 fl = self.file(f)
861 fl = self.file(f)
857 o = fl.tip()
862 o = fl.tip()
858 n = fl.addgroup(getgroup(), revmap, tr)
863 n = fl.addgroup(getgroup(), revmap, tr)
859 revisions += fl.rev(n) - fl.rev(o)
864 revisions += fl.rev(n) - fl.rev(o)
860 files += 1
865 files += 1
861
866
862 self.ui.status(("modified %d files, added %d changesets" +
867 self.ui.status(("modified %d files, added %d changesets" +
863 " and %d new revisions\n")
868 " and %d new revisions\n")
864 % (files, changesets, revisions))
869 % (files, changesets, revisions))
865
870
866 tr.close()
871 tr.close()
867 return
872 return
868
873
869 def update(self, node, allow=False, force=False):
874 def update(self, node, allow=False, force=False):
870 pl = self.dirstate.parents()
875 pl = self.dirstate.parents()
871 if not force and pl[1] != nullid:
876 if not force and pl[1] != nullid:
872 self.ui.warn("aborting: outstanding uncommitted merges\n")
877 self.ui.warn("aborting: outstanding uncommitted merges\n")
873 return
878 return
874
879
875 p1, p2 = pl[0], node
880 p1, p2 = pl[0], node
876 m1n = self.changelog.read(p1)[0]
881 m1n = self.changelog.read(p1)[0]
877 m2n = self.changelog.read(p2)[0]
882 m2n = self.changelog.read(p2)[0]
878 man = self.manifest.ancestor(m1n, m2n)
883 man = self.manifest.ancestor(m1n, m2n)
879 m1 = self.manifest.read(m1n)
884 m1 = self.manifest.read(m1n)
880 mf1 = self.manifest.readflags(m1n)
885 mf1 = self.manifest.readflags(m1n)
881 m2 = self.manifest.read(m2n)
886 m2 = self.manifest.read(m2n)
882 mf2 = self.manifest.readflags(m2n)
887 mf2 = self.manifest.readflags(m2n)
883 ma = self.manifest.read(man)
888 ma = self.manifest.read(man)
884 mfa = self.manifest.readflags(m2n)
889 mfa = self.manifest.readflags(m2n)
885
890
886 (c, a, d, u) = self.diffdir(self.root)
891 (c, a, d, u) = self.diffdir(self.root)
887
892
888 # resolve the manifest to determine which files
893 # resolve the manifest to determine which files
889 # we care about merging
894 # we care about merging
890 self.ui.note("resolving manifests\n")
895 self.ui.note("resolving manifests\n")
891 self.ui.debug(" ancestor %s local %s remote %s\n" %
896 self.ui.debug(" ancestor %s local %s remote %s\n" %
892 (short(man), short(m1n), short(m2n)))
897 (short(man), short(m1n), short(m2n)))
893
898
894 merge = {}
899 merge = {}
895 get = {}
900 get = {}
896 remove = []
901 remove = []
897
902
898 # construct a working dir manifest
903 # construct a working dir manifest
899 mw = m1.copy()
904 mw = m1.copy()
900 mfw = mf1.copy()
905 mfw = mf1.copy()
901 for f in a + c + u:
906 for f in a + c + u:
902 mw[f] = ""
907 mw[f] = ""
903 mfw[f] = is_exec(self.wjoin(f))
908 mfw[f] = is_exec(self.wjoin(f))
904 for f in d:
909 for f in d:
905 if f in mw: del mw[f]
910 if f in mw: del mw[f]
906
911
907 for f, n in mw.iteritems():
912 for f, n in mw.iteritems():
908 if f in m2:
913 if f in m2:
909 s = 0
914 s = 0
910
915
911 if n != m2[f]:
916 if n != m2[f]:
912 a = ma.get(f, nullid)
917 a = ma.get(f, nullid)
913 if n != a and m2[f] != a:
918 if n != a and m2[f] != a:
914 self.ui.debug(" %s versions differ, resolve\n" % f)
919 self.ui.debug(" %s versions differ, resolve\n" % f)
915 merge[f] = (m1.get(f, nullid), m2[f])
920 merge[f] = (m1.get(f, nullid), m2[f])
916 # merge executable bits
921 # merge executable bits
917 # "if we changed or they changed, change in merge"
922 # "if we changed or they changed, change in merge"
918 a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
923 a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
919 mode = ((a^b) | (a^c)) ^ a
924 mode = ((a^b) | (a^c)) ^ a
920 merge[f] = (m1.get(f, nullid), m2[f], mode)
925 merge[f] = (m1.get(f, nullid), m2[f], mode)
921 s = 1
926 s = 1
922 elif m2[f] != a:
927 elif m2[f] != a:
923 self.ui.debug(" remote %s is newer, get\n" % f)
928 self.ui.debug(" remote %s is newer, get\n" % f)
924 get[f] = m2[f]
929 get[f] = m2[f]
925 s = 1
930 s = 1
926
931
927 if not s and mfw[f] != mf2[f]:
932 if not s and mfw[f] != mf2[f]:
928 if force:
933 if force:
929 self.ui.debug(" updating permissions for %s\n" % f)
934 self.ui.debug(" updating permissions for %s\n" % f)
930 set_exec(self.wjoin(f), mf2[f])
935 set_exec(self.wjoin(f), mf2[f])
931 else:
936 else:
932 a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
937 a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
933 mode = ((a^b) | (a^c)) ^ a
938 mode = ((a^b) | (a^c)) ^ a
934 if mode != b:
939 if mode != b:
935 self.ui.debug(" updating permissions for %s\n" % f)
940 self.ui.debug(" updating permissions for %s\n" % f)
936 set_exec(self.wjoin(f), mode)
941 set_exec(self.wjoin(f), mode)
937
942
938 del m2[f]
943 del m2[f]
939 elif f in ma:
944 elif f in ma:
940 if not force and n != ma[f]:
945 if not force and n != ma[f]:
941 r = self.ui.prompt(
946 r = self.ui.prompt(
942 (" local changed %s which remote deleted\n" % f) +
947 (" local changed %s which remote deleted\n" % f) +
943 "(k)eep or (d)elete?", "[kd]", "k")
948 "(k)eep or (d)elete?", "[kd]", "k")
944 if r == "d":
949 if r == "d":
945 remove.append(f)
950 remove.append(f)
946 else:
951 else:
947 self.ui.debug("other deleted %s\n" % f)
952 self.ui.debug("other deleted %s\n" % f)
948 remove.append(f) # other deleted it
953 remove.append(f) # other deleted it
949 else:
954 else:
950 if n == m1.get(f, nullid): # same as parent
955 if n == m1.get(f, nullid): # same as parent
951 self.ui.debug("remote deleted %s\n" % f)
956 self.ui.debug("remote deleted %s\n" % f)
952 remove.append(f)
957 remove.append(f)
953 else:
958 else:
954 self.ui.debug("working dir created %s, keeping\n" % f)
959 self.ui.debug("working dir created %s, keeping\n" % f)
955
960
956 for f, n in m2.iteritems():
961 for f, n in m2.iteritems():
957 if f[0] == "/": continue
962 if f[0] == "/": continue
958 if not force and f in ma and n != ma[f]:
963 if not force and f in ma and n != ma[f]:
959 r = self.ui.prompt(
964 r = self.ui.prompt(
960 ("remote changed %s which local deleted\n" % f) +
965 ("remote changed %s which local deleted\n" % f) +
961 "(k)eep or (d)elete?", "[kd]", "k")
966 "(k)eep or (d)elete?", "[kd]", "k")
962 if r == "d": remove.append(f)
967 if r == "d": remove.append(f)
963 else:
968 else:
964 self.ui.debug("remote created %s\n" % f)
969 self.ui.debug("remote created %s\n" % f)
965 get[f] = n
970 get[f] = n
966
971
967 del mw, m1, m2, ma
972 del mw, m1, m2, ma
968
973
969 if force:
974 if force:
970 for f in merge:
975 for f in merge:
971 get[f] = merge[f][1]
976 get[f] = merge[f][1]
972 merge = {}
977 merge = {}
973
978
974 if not merge:
979 if not merge:
975 # we don't need to do any magic, just jump to the new rev
980 # we don't need to do any magic, just jump to the new rev
976 mode = 'n'
981 mode = 'n'
977 p1, p2 = p2, nullid
982 p1, p2 = p2, nullid
978 else:
983 else:
979 if not allow:
984 if not allow:
980 self.ui.status("the following files conflict:\n")
985 self.ui.status("the following files conflict:\n")
981 for f in merge:
986 for f in merge:
982 self.ui.status(" %s\n" % f)
987 self.ui.status(" %s\n" % f)
983 self.ui.warn("aborting update due to conflicting files!\n")
988 self.ui.warn("aborting update due to conflicting files!\n")
984 self.ui.status("(use update -m to allow a merge)\n")
989 self.ui.status("(use update -m to allow a merge)\n")
985 return 1
990 return 1
986 # we have to remember what files we needed to get/change
991 # we have to remember what files we needed to get/change
987 # because any file that's different from either one of its
992 # because any file that's different from either one of its
988 # parents must be in the changeset
993 # parents must be in the changeset
989 mode = 'm'
994 mode = 'm'
990
995
991 self.dirstate.setparents(p1, p2)
996 self.dirstate.setparents(p1, p2)
992
997
993 # get the files we don't need to change
998 # get the files we don't need to change
994 files = get.keys()
999 files = get.keys()
995 files.sort()
1000 files.sort()
996 for f in files:
1001 for f in files:
997 if f[0] == "/": continue
1002 if f[0] == "/": continue
998 self.ui.note("getting %s\n" % f)
1003 self.ui.note("getting %s\n" % f)
999 t = self.file(f).read(get[f])
1004 t = self.file(f).read(get[f])
1000 try:
1005 try:
1001 self.wfile(f, "w").write(t)
1006 self.wfile(f, "w").write(t)
1002 except IOError:
1007 except IOError:
1003 os.makedirs(os.path.dirname(self.wjoin(f)))
1008 os.makedirs(os.path.dirname(self.wjoin(f)))
1004 self.wfile(f, "w").write(t)
1009 self.wfile(f, "w").write(t)
1005 set_exec(self.wjoin(f), mf2[f])
1010 set_exec(self.wjoin(f), mf2[f])
1006 self.dirstate.update([f], mode)
1011 self.dirstate.update([f], mode)
1007
1012
1008 # merge the tricky bits
1013 # merge the tricky bits
1009 files = merge.keys()
1014 files = merge.keys()
1010 files.sort()
1015 files.sort()
1011 for f in files:
1016 for f in files:
1012 self.ui.status("merging %s\n" % f)
1017 self.ui.status("merging %s\n" % f)
1013 m, o, flag = merge[f]
1018 m, o, flag = merge[f]
1014 self.merge3(f, m, o)
1019 self.merge3(f, m, o)
1015 set_exec(self.wjoin(f), flag)
1020 set_exec(self.wjoin(f), flag)
1016 self.dirstate.update([f], 'm')
1021 self.dirstate.update([f], 'm')
1017
1022
1018 for f in remove:
1023 for f in remove:
1019 self.ui.note("removing %s\n" % f)
1024 self.ui.note("removing %s\n" % f)
1020 os.unlink(f)
1025 os.unlink(f)
1021 if mode == 'n':
1026 if mode == 'n':
1022 self.dirstate.forget(remove)
1027 self.dirstate.forget(remove)
1023 else:
1028 else:
1024 self.dirstate.update(remove, 'r')
1029 self.dirstate.update(remove, 'r')
1025
1030
1026 def merge3(self, fn, my, other):
1031 def merge3(self, fn, my, other):
1027 """perform a 3-way merge in the working directory"""
1032 """perform a 3-way merge in the working directory"""
1028
1033
1029 def temp(prefix, node):
1034 def temp(prefix, node):
1030 pre = "%s~%s." % (os.path.basename(fn), prefix)
1035 pre = "%s~%s." % (os.path.basename(fn), prefix)
1031 (fd, name) = tempfile.mkstemp("", pre)
1036 (fd, name) = tempfile.mkstemp("", pre)
1032 f = os.fdopen(fd, "w")
1037 f = os.fdopen(fd, "w")
1033 f.write(fl.revision(node))
1038 f.write(fl.revision(node))
1034 f.close()
1039 f.close()
1035 return name
1040 return name
1036
1041
1037 fl = self.file(fn)
1042 fl = self.file(fn)
1038 base = fl.ancestor(my, other)
1043 base = fl.ancestor(my, other)
1039 a = self.wjoin(fn)
1044 a = self.wjoin(fn)
1040 b = temp("other", other)
1045 b = temp("other", other)
1041 c = temp("base", base)
1046 c = temp("base", base)
1042
1047
1043 self.ui.note("resolving %s\n" % fn)
1048 self.ui.note("resolving %s\n" % fn)
1044 self.ui.debug("file %s: other %s ancestor %s\n" %
1049 self.ui.debug("file %s: other %s ancestor %s\n" %
1045 (fn, short(other), short(base)))
1050 (fn, short(other), short(base)))
1046
1051
1047 cmd = os.environ.get("HGMERGE", "hgmerge")
1052 cmd = os.environ.get("HGMERGE", "hgmerge")
1048 r = os.system("%s %s %s %s" % (cmd, a, b, c))
1053 r = os.system("%s %s %s %s" % (cmd, a, b, c))
1049 if r:
1054 if r:
1050 self.ui.warn("merging %s failed!\n" % fn)
1055 self.ui.warn("merging %s failed!\n" % fn)
1051
1056
1052 os.unlink(b)
1057 os.unlink(b)
1053 os.unlink(c)
1058 os.unlink(c)
1054
1059
1055 def verify(self):
1060 def verify(self):
1056 filelinkrevs = {}
1061 filelinkrevs = {}
1057 filenodes = {}
1062 filenodes = {}
1058 manifestchangeset = {}
1063 manifestchangeset = {}
1059 changesets = revisions = files = 0
1064 changesets = revisions = files = 0
1060 errors = 0
1065 errors = 0
1061
1066
1062 self.ui.status("checking changesets\n")
1067 self.ui.status("checking changesets\n")
1063 for i in range(self.changelog.count()):
1068 for i in range(self.changelog.count()):
1064 changesets += 1
1069 changesets += 1
1065 n = self.changelog.node(i)
1070 n = self.changelog.node(i)
1066 for p in self.changelog.parents(n):
1071 for p in self.changelog.parents(n):
1067 if p not in self.changelog.nodemap:
1072 if p not in self.changelog.nodemap:
1068 self.ui.warn("changeset %s has unknown parent %s\n" %
1073 self.ui.warn("changeset %s has unknown parent %s\n" %
1069 (short(n), short(p)))
1074 (short(n), short(p)))
1070 errors += 1
1075 errors += 1
1071 try:
1076 try:
1072 changes = self.changelog.read(n)
1077 changes = self.changelog.read(n)
1073 except Exception, inst:
1078 except Exception, inst:
1074 self.ui.warn("unpacking changeset %s: %s\n" % (short(n), inst))
1079 self.ui.warn("unpacking changeset %s: %s\n" % (short(n), inst))
1075 errors += 1
1080 errors += 1
1076
1081
1077 manifestchangeset[changes[0]] = n
1082 manifestchangeset[changes[0]] = n
1078 for f in changes[3]:
1083 for f in changes[3]:
1079 filelinkrevs.setdefault(f, []).append(i)
1084 filelinkrevs.setdefault(f, []).append(i)
1080
1085
1081 self.ui.status("checking manifests\n")
1086 self.ui.status("checking manifests\n")
1082 for i in range(self.manifest.count()):
1087 for i in range(self.manifest.count()):
1083 n = self.manifest.node(i)
1088 n = self.manifest.node(i)
1084 for p in self.manifest.parents(n):
1089 for p in self.manifest.parents(n):
1085 if p not in self.manifest.nodemap:
1090 if p not in self.manifest.nodemap:
1086 self.ui.warn("manifest %s has unknown parent %s\n" %
1091 self.ui.warn("manifest %s has unknown parent %s\n" %
1087 (short(n), short(p)))
1092 (short(n), short(p)))
1088 errors += 1
1093 errors += 1
1089 ca = self.changelog.node(self.manifest.linkrev(n))
1094 ca = self.changelog.node(self.manifest.linkrev(n))
1090 cc = manifestchangeset[n]
1095 cc = manifestchangeset[n]
1091 if ca != cc:
1096 if ca != cc:
1092 self.ui.warn("manifest %s points to %s, not %s\n" %
1097 self.ui.warn("manifest %s points to %s, not %s\n" %
1093 (hex(n), hex(ca), hex(cc)))
1098 (hex(n), hex(ca), hex(cc)))
1094 errors += 1
1099 errors += 1
1095
1100
1096 try:
1101 try:
1097 delta = mdiff.patchtext(self.manifest.delta(n))
1102 delta = mdiff.patchtext(self.manifest.delta(n))
1098 except KeyboardInterrupt:
1103 except KeyboardInterrupt:
1099 print "aborted"
1104 print "aborted"
1100 sys.exit(0)
1105 sys.exit(0)
1101 except Exception, inst:
1106 except Exception, inst:
1102 self.ui.warn("unpacking manifest %s: %s\n"
1107 self.ui.warn("unpacking manifest %s: %s\n"
1103 % (short(n), inst))
1108 % (short(n), inst))
1104 errors += 1
1109 errors += 1
1105
1110
1106 ff = [ l.split('\0') for l in delta.splitlines() ]
1111 ff = [ l.split('\0') for l in delta.splitlines() ]
1107 for f, fn in ff:
1112 for f, fn in ff:
1108 filenodes.setdefault(f, {})[bin(fn[:40])] = 1
1113 filenodes.setdefault(f, {})[bin(fn[:40])] = 1
1109
1114
1110 self.ui.status("crosschecking files in changesets and manifests\n")
1115 self.ui.status("crosschecking files in changesets and manifests\n")
1111 for f in filenodes:
1116 for f in filenodes:
1112 if f not in filelinkrevs:
1117 if f not in filelinkrevs:
1113 self.ui.warn("file %s in manifest but not in changesets\n" % f)
1118 self.ui.warn("file %s in manifest but not in changesets\n" % f)
1114 errors += 1
1119 errors += 1
1115
1120
1116 for f in filelinkrevs:
1121 for f in filelinkrevs:
1117 if f not in filenodes:
1122 if f not in filenodes:
1118 self.ui.warn("file %s in changeset but not in manifest\n" % f)
1123 self.ui.warn("file %s in changeset but not in manifest\n" % f)
1119 errors += 1
1124 errors += 1
1120
1125
1121 self.ui.status("checking files\n")
1126 self.ui.status("checking files\n")
1122 ff = filenodes.keys()
1127 ff = filenodes.keys()
1123 ff.sort()
1128 ff.sort()
1124 for f in ff:
1129 for f in ff:
1125 if f == "/dev/null": continue
1130 if f == "/dev/null": continue
1126 files += 1
1131 files += 1
1127 fl = self.file(f)
1132 fl = self.file(f)
1128 nodes = { nullid: 1 }
1133 nodes = { nullid: 1 }
1129 for i in range(fl.count()):
1134 for i in range(fl.count()):
1130 revisions += 1
1135 revisions += 1
1131 n = fl.node(i)
1136 n = fl.node(i)
1132
1137
1133 if n not in filenodes[f]:
1138 if n not in filenodes[f]:
1134 self.ui.warn("%s: %d:%s not in manifests\n"
1139 self.ui.warn("%s: %d:%s not in manifests\n"
1135 % (f, i, short(n)))
1140 % (f, i, short(n)))
1136 print len(filenodes[f].keys()), fl.count(), f
1141 print len(filenodes[f].keys()), fl.count(), f
1137 errors += 1
1142 errors += 1
1138 else:
1143 else:
1139 del filenodes[f][n]
1144 del filenodes[f][n]
1140
1145
1141 flr = fl.linkrev(n)
1146 flr = fl.linkrev(n)
1142 if flr not in filelinkrevs[f]:
1147 if flr not in filelinkrevs[f]:
1143 self.ui.warn("%s:%s points to unexpected changeset %d\n"
1148 self.ui.warn("%s:%s points to unexpected changeset %d\n"
1144 % (f, short(n), fl.linkrev(n)))
1149 % (f, short(n), fl.linkrev(n)))
1145 errors += 1
1150 errors += 1
1146 else:
1151 else:
1147 filelinkrevs[f].remove(flr)
1152 filelinkrevs[f].remove(flr)
1148
1153
1149 # verify contents
1154 # verify contents
1150 try:
1155 try:
1151 t = fl.read(n)
1156 t = fl.read(n)
1152 except Exception, inst:
1157 except Exception, inst:
1153 self.ui.warn("unpacking file %s %s: %s\n"
1158 self.ui.warn("unpacking file %s %s: %s\n"
1154 % (f, short(n), inst))
1159 % (f, short(n), inst))
1155 errors += 1
1160 errors += 1
1156
1161
1157 # verify parents
1162 # verify parents
1158 (p1, p2) = fl.parents(n)
1163 (p1, p2) = fl.parents(n)
1159 if p1 not in nodes:
1164 if p1 not in nodes:
1160 self.ui.warn("file %s:%s unknown parent 1 %s" %
1165 self.ui.warn("file %s:%s unknown parent 1 %s" %
1161 (f, short(n), short(p1)))
1166 (f, short(n), short(p1)))
1162 errors += 1
1167 errors += 1
1163 if p2 not in nodes:
1168 if p2 not in nodes:
1164 self.ui.warn("file %s:%s unknown parent 2 %s" %
1169 self.ui.warn("file %s:%s unknown parent 2 %s" %
1165 (f, short(n), short(p1)))
1170 (f, short(n), short(p1)))
1166 errors += 1
1171 errors += 1
1167 nodes[n] = 1
1172 nodes[n] = 1
1168
1173
1169 # cross-check
1174 # cross-check
1170 for node in filenodes[f]:
1175 for node in filenodes[f]:
1171 self.ui.warn("node %s in manifests not in %s\n"
1176 self.ui.warn("node %s in manifests not in %s\n"
1172 % (hex(n), f))
1177 % (hex(n), f))
1173 errors += 1
1178 errors += 1
1174
1179
1175 self.ui.status("%d files, %d changesets, %d total revisions\n" %
1180 self.ui.status("%d files, %d changesets, %d total revisions\n" %
1176 (files, changesets, revisions))
1181 (files, changesets, revisions))
1177
1182
1178 if errors:
1183 if errors:
1179 self.ui.warn("%d integrity errors encountered!\n" % errors)
1184 self.ui.warn("%d integrity errors encountered!\n" % errors)
1180 return 1
1185 return 1
1181
1186
1182 class remoterepository:
1187 class remoterepository:
1183 def __init__(self, ui, path):
1188 def __init__(self, ui, path):
1184 self.url = path
1189 self.url = path
1185 self.ui = ui
1190 self.ui = ui
1186
1191
1187 def do_cmd(self, cmd, **args):
1192 def do_cmd(self, cmd, **args):
1188 self.ui.debug("sending %s command\n" % cmd)
1193 self.ui.debug("sending %s command\n" % cmd)
1189 q = {"cmd": cmd}
1194 q = {"cmd": cmd}
1190 q.update(args)
1195 q.update(args)
1191 qs = urllib.urlencode(q)
1196 qs = urllib.urlencode(q)
1192 cu = "%s?%s" % (self.url, qs)
1197 cu = "%s?%s" % (self.url, qs)
1193 return urllib.urlopen(cu)
1198 return urllib.urlopen(cu)
1194
1199
1195 def heads(self):
1200 def heads(self):
1196 d = self.do_cmd("heads").read()
1201 d = self.do_cmd("heads").read()
1197 try:
1202 try:
1198 return map(bin, d[:-1].split(" "))
1203 return map(bin, d[:-1].split(" "))
1199 except:
1204 except:
1200 self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
1205 self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
1201 raise
1206 raise
1202
1207
1203 def branches(self, nodes):
1208 def branches(self, nodes):
1204 n = " ".join(map(hex, nodes))
1209 n = " ".join(map(hex, nodes))
1205 d = self.do_cmd("branches", nodes=n).read()
1210 d = self.do_cmd("branches", nodes=n).read()
1206 try:
1211 try:
1207 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
1212 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
1208 return br
1213 return br
1209 except:
1214 except:
1210 self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
1215 self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
1211 raise
1216 raise
1212
1217
1213 def between(self, pairs):
1218 def between(self, pairs):
1214 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
1219 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
1215 d = self.do_cmd("between", pairs=n).read()
1220 d = self.do_cmd("between", pairs=n).read()
1216 try:
1221 try:
1217 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
1222 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
1218 return p
1223 return p
1219 except:
1224 except:
1220 self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
1225 self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
1221 raise
1226 raise
1222
1227
1223 def changegroup(self, nodes):
1228 def changegroup(self, nodes):
1224 n = " ".join(map(hex, nodes))
1229 n = " ".join(map(hex, nodes))
1225 zd = zlib.decompressobj()
1230 zd = zlib.decompressobj()
1226 f = self.do_cmd("changegroup", roots=n)
1231 f = self.do_cmd("changegroup", roots=n)
1227 bytes = 0
1232 bytes = 0
1228 while 1:
1233 while 1:
1229 d = f.read(4096)
1234 d = f.read(4096)
1230 bytes += len(d)
1235 bytes += len(d)
1231 if not d:
1236 if not d:
1232 yield zd.flush()
1237 yield zd.flush()
1233 break
1238 break
1234 yield zd.decompress(d)
1239 yield zd.decompress(d)
1235 self.ui.note("%d bytes of data transfered\n" % bytes)
1240 self.ui.note("%d bytes of data transfered\n" % bytes)
1236
1241
1237 def repository(ui, path=None, create=0):
1242 def repository(ui, path=None, create=0):
1238 if path and path[:7] == "http://":
1243 if path and path[:7] == "http://":
1239 return remoterepository(ui, path)
1244 return remoterepository(ui, path)
1240 if path and path[:5] == "hg://":
1245 if path and path[:5] == "hg://":
1241 return remoterepository(ui, path.replace("hg://", "http://"))
1246 return remoterepository(ui, path.replace("hg://", "http://"))
1242 if path and path[:11] == "old-http://":
1247 if path and path[:11] == "old-http://":
1243 return localrepository(ui, path.replace("old-http://", "http://"))
1248 return localrepository(ui, path.replace("old-http://", "http://"))
1244 else:
1249 else:
1245 return localrepository(ui, path, create)
1250 return localrepository(ui, path, create)
1246
1251
1247 class httprangereader:
1252 class httprangereader:
1248 def __init__(self, url):
1253 def __init__(self, url):
1249 self.url = url
1254 self.url = url
1250 self.pos = 0
1255 self.pos = 0
1251 def seek(self, pos):
1256 def seek(self, pos):
1252 self.pos = pos
1257 self.pos = pos
1253 def read(self, bytes=None):
1258 def read(self, bytes=None):
1254 opener = urllib2.build_opener(byterange.HTTPRangeHandler())
1259 opener = urllib2.build_opener(byterange.HTTPRangeHandler())
1255 urllib2.install_opener(opener)
1260 urllib2.install_opener(opener)
1256 req = urllib2.Request(self.url)
1261 req = urllib2.Request(self.url)
1257 end = ''
1262 end = ''
1258 if bytes: end = self.pos + bytes
1263 if bytes: end = self.pos + bytes
1259 req.add_header('Range', 'bytes=%d-%s' % (self.pos, end))
1264 req.add_header('Range', 'bytes=%d-%s' % (self.pos, end))
1260 f = urllib2.urlopen(req)
1265 f = urllib2.urlopen(req)
1261 return f.read()
1266 return f.read()
General Comments 0
You need to be logged in to leave comments. Login now