##// END OF EJS Templates
Add $HGEDITOR hook and example script...
mpm@selenic.com -
r186:9a2075c0 default
parent child Browse files
Show More
@@ -0,0 +1,21
1 #!/bin/bash
2 #
3 # This is an example of using HGEDITOR to automate the signing of
4 # commits and so on.
5
6 MANIFEST=`grep '^HG: manifest hash' $1 | cut -b 19-`
7 if grep -q "^HG: merge resolve" $1 ; then
8 # we don't sign merges
9 $EDITOR $1
10 else
11 T=`mktemp`
12 CHANGED=`grep '^HG: changed' $1 | cut -b 13-`
13 # show a diff so writing commit comments is easier
14 hg diff $CHANGED >> $T
15 echo -e "\n\nmanifest hash: $MANIFEST" > $1
16 emacs -nw $T $1
17 head -1 $1 > $T
18 echo >> $T
19 gpg -a -u $HGUSER -o - --clearsign $1 >> $T
20 mv $T $1
21 fi
@@ -1,921 +1,921
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, sha, socket, os, time, re, urllib2
8 import sys, struct, sha, socket, os, time, re, urllib2
9 import urllib
9 import urllib
10 from mercurial import byterange, lock
10 from mercurial import byterange, lock
11 from mercurial.transaction import *
11 from mercurial.transaction import *
12 from mercurial.revlog import *
12 from mercurial.revlog import *
13 from difflib import SequenceMatcher
13 from difflib import SequenceMatcher
14
14
15 class filelog(revlog):
15 class filelog(revlog):
16 def __init__(self, opener, path):
16 def __init__(self, opener, path):
17 revlog.__init__(self, opener,
17 revlog.__init__(self, opener,
18 os.path.join("data", path + ".i"),
18 os.path.join("data", path + ".i"),
19 os.path.join("data", path + ".d"))
19 os.path.join("data", path + ".d"))
20
20
21 def read(self, node):
21 def read(self, node):
22 return self.revision(node)
22 return self.revision(node)
23 def add(self, text, transaction, link, p1=None, p2=None):
23 def add(self, text, transaction, link, p1=None, p2=None):
24 return self.addrevision(text, transaction, link, p1, p2)
24 return self.addrevision(text, transaction, link, p1, p2)
25
25
26 def annotate(self, node):
26 def annotate(self, node):
27 revs = []
27 revs = []
28 while node != nullid:
28 while node != nullid:
29 revs.append(node)
29 revs.append(node)
30 node = self.parents(node)[0]
30 node = self.parents(node)[0]
31 revs.reverse()
31 revs.reverse()
32 prev = []
32 prev = []
33 annotate = []
33 annotate = []
34
34
35 for node in revs:
35 for node in revs:
36 curr = self.read(node).splitlines(1)
36 curr = self.read(node).splitlines(1)
37 linkrev = self.linkrev(node)
37 linkrev = self.linkrev(node)
38 sm = SequenceMatcher(None, prev, curr)
38 sm = SequenceMatcher(None, prev, curr)
39 new = []
39 new = []
40 for o, m, n, s, t in sm.get_opcodes():
40 for o, m, n, s, t in sm.get_opcodes():
41 if o == 'equal':
41 if o == 'equal':
42 new += annotate[m:n]
42 new += annotate[m:n]
43 else:
43 else:
44 new += [(linkrev, l) for l in curr[s:t]]
44 new += [(linkrev, l) for l in curr[s:t]]
45 annotate, prev = new, curr
45 annotate, prev = new, curr
46 return annotate
46 return annotate
47
47
48 class manifest(revlog):
48 class manifest(revlog):
49 def __init__(self, opener):
49 def __init__(self, opener):
50 self.mapcache = None
50 self.mapcache = None
51 self.listcache = None
51 self.listcache = None
52 self.addlist = None
52 self.addlist = None
53 revlog.__init__(self, opener, "00manifest.i", "00manifest.d")
53 revlog.__init__(self, opener, "00manifest.i", "00manifest.d")
54
54
55 def read(self, node):
55 def read(self, node):
56 if self.mapcache and self.mapcache[0] == node:
56 if self.mapcache and self.mapcache[0] == node:
57 return self.mapcache[1].copy()
57 return self.mapcache[1].copy()
58 text = self.revision(node)
58 text = self.revision(node)
59 map = {}
59 map = {}
60 self.listcache = (text, text.splitlines(1))
60 self.listcache = (text, text.splitlines(1))
61 for l in self.listcache[1]:
61 for l in self.listcache[1]:
62 (f, n) = l.split('\0')
62 (f, n) = l.split('\0')
63 map[f] = bin(n[:40])
63 map[f] = bin(n[:40])
64 self.mapcache = (node, map)
64 self.mapcache = (node, map)
65 return map
65 return map
66
66
67 def diff(self, a, b):
67 def diff(self, a, b):
68 # this is sneaky, as we're not actually using a and b
68 # this is sneaky, as we're not actually using a and b
69 if self.listcache and self.addlist and self.listcache[0] == a:
69 if self.listcache and self.addlist and self.listcache[0] == a:
70 d = mdiff.diff(self.listcache[1], self.addlist, 1)
70 d = mdiff.diff(self.listcache[1], self.addlist, 1)
71 if mdiff.patch(a, d) != b:
71 if mdiff.patch(a, d) != b:
72 sys.stderr.write("*** sortdiff failed, falling back ***\n")
72 sys.stderr.write("*** sortdiff failed, falling back ***\n")
73 return mdiff.textdiff(a, b)
73 return mdiff.textdiff(a, b)
74 return d
74 return d
75 else:
75 else:
76 return mdiff.textdiff(a, b)
76 return mdiff.textdiff(a, b)
77
77
78 def add(self, map, transaction, link, p1=None, p2=None):
78 def add(self, map, transaction, link, p1=None, p2=None):
79 files = map.keys()
79 files = map.keys()
80 files.sort()
80 files.sort()
81
81
82 self.addlist = ["%s\000%s\n" % (f, hex(map[f])) for f in files]
82 self.addlist = ["%s\000%s\n" % (f, hex(map[f])) for f in files]
83 text = "".join(self.addlist)
83 text = "".join(self.addlist)
84
84
85 n = self.addrevision(text, transaction, link, p1, p2)
85 n = self.addrevision(text, transaction, link, p1, p2)
86 self.mapcache = (n, map)
86 self.mapcache = (n, map)
87 self.listcache = (text, self.addlist)
87 self.listcache = (text, self.addlist)
88 self.addlist = None
88 self.addlist = None
89
89
90 return n
90 return n
91
91
92 class changelog(revlog):
92 class changelog(revlog):
93 def __init__(self, opener):
93 def __init__(self, opener):
94 revlog.__init__(self, opener, "00changelog.i", "00changelog.d")
94 revlog.__init__(self, opener, "00changelog.i", "00changelog.d")
95
95
96 def extract(self, text):
96 def extract(self, text):
97 if not text:
97 if not text:
98 return (nullid, "", "0", [], "")
98 return (nullid, "", "0", [], "")
99 last = text.index("\n\n")
99 last = text.index("\n\n")
100 desc = text[last + 2:]
100 desc = text[last + 2:]
101 l = text[:last].splitlines()
101 l = text[:last].splitlines()
102 manifest = bin(l[0])
102 manifest = bin(l[0])
103 user = l[1]
103 user = l[1]
104 date = l[2]
104 date = l[2]
105 files = l[3:]
105 files = l[3:]
106 return (manifest, user, date, files, desc)
106 return (manifest, user, date, files, desc)
107
107
108 def read(self, node):
108 def read(self, node):
109 return self.extract(self.revision(node))
109 return self.extract(self.revision(node))
110
110
111 def add(self, manifest, list, desc, transaction, p1=None, p2=None):
111 def add(self, manifest, list, desc, transaction, p1=None, p2=None):
112 user = (os.environ.get("HGUSER") or
112 user = (os.environ.get("HGUSER") or
113 os.environ.get("EMAIL") or
113 os.environ.get("EMAIL") or
114 os.environ.get("LOGNAME", "unknown") + '@' + socket.getfqdn())
114 os.environ.get("LOGNAME", "unknown") + '@' + socket.getfqdn())
115 date = "%d %d" % (time.time(), time.timezone)
115 date = "%d %d" % (time.time(), time.timezone)
116 list.sort()
116 list.sort()
117 l = [hex(manifest), user, date] + list + ["", desc]
117 l = [hex(manifest), user, date] + list + ["", desc]
118 text = "\n".join(l)
118 text = "\n".join(l)
119 return self.addrevision(text, transaction, self.count(), p1, p2)
119 return self.addrevision(text, transaction, self.count(), p1, p2)
120
120
121 class dircache:
121 class dircache:
122 def __init__(self, opener, ui):
122 def __init__(self, opener, ui):
123 self.opener = opener
123 self.opener = opener
124 self.dirty = 0
124 self.dirty = 0
125 self.ui = ui
125 self.ui = ui
126 self.map = None
126 self.map = None
127 def __del__(self):
127 def __del__(self):
128 if self.dirty: self.write()
128 if self.dirty: self.write()
129 def __getitem__(self, key):
129 def __getitem__(self, key):
130 try:
130 try:
131 return self.map[key]
131 return self.map[key]
132 except TypeError:
132 except TypeError:
133 self.read()
133 self.read()
134 return self[key]
134 return self[key]
135
135
136 def read(self):
136 def read(self):
137 if self.map is not None: return self.map
137 if self.map is not None: return self.map
138
138
139 self.map = {}
139 self.map = {}
140 try:
140 try:
141 st = self.opener("dircache").read()
141 st = self.opener("dircache").read()
142 except: return
142 except: return
143
143
144 pos = 0
144 pos = 0
145 while pos < len(st):
145 while pos < len(st):
146 e = struct.unpack(">llll", st[pos:pos+16])
146 e = struct.unpack(">llll", st[pos:pos+16])
147 l = e[3]
147 l = e[3]
148 pos += 16
148 pos += 16
149 f = st[pos:pos + l]
149 f = st[pos:pos + l]
150 self.map[f] = e[:3]
150 self.map[f] = e[:3]
151 pos += l
151 pos += l
152
152
153 def update(self, files):
153 def update(self, files):
154 if not files: return
154 if not files: return
155 self.read()
155 self.read()
156 self.dirty = 1
156 self.dirty = 1
157 for f in files:
157 for f in files:
158 try:
158 try:
159 s = os.stat(f)
159 s = os.stat(f)
160 self.map[f] = (s.st_mode, s.st_size, s.st_mtime)
160 self.map[f] = (s.st_mode, s.st_size, s.st_mtime)
161 except IOError:
161 except IOError:
162 self.remove(f)
162 self.remove(f)
163
163
164 def taint(self, files):
164 def taint(self, files):
165 if not files: return
165 if not files: return
166 self.read()
166 self.read()
167 self.dirty = 1
167 self.dirty = 1
168 for f in files:
168 for f in files:
169 self.map[f] = (0, -1, 0)
169 self.map[f] = (0, -1, 0)
170
170
171 def remove(self, files):
171 def remove(self, files):
172 if not files: return
172 if not files: return
173 self.read()
173 self.read()
174 self.dirty = 1
174 self.dirty = 1
175 for f in files:
175 for f in files:
176 try:
176 try:
177 del self.map[f]
177 del self.map[f]
178 except KeyError:
178 except KeyError:
179 self.ui.warn("Not in dircache: %s\n" % f)
179 self.ui.warn("Not in dircache: %s\n" % f)
180 pass
180 pass
181
181
182 def clear(self):
182 def clear(self):
183 self.map = {}
183 self.map = {}
184 self.dirty = 1
184 self.dirty = 1
185
185
186 def write(self):
186 def write(self):
187 st = self.opener("dircache", "w")
187 st = self.opener("dircache", "w")
188 for f, e in self.map.items():
188 for f, e in self.map.items():
189 e = struct.pack(">llll", e[0], e[1], e[2], len(f))
189 e = struct.pack(">llll", e[0], e[1], e[2], len(f))
190 st.write(e + f)
190 st.write(e + f)
191 self.dirty = 0
191 self.dirty = 0
192
192
193 def copy(self):
193 def copy(self):
194 self.read()
194 self.read()
195 return self.map.copy()
195 return self.map.copy()
196
196
197 # used to avoid circular references so destructors work
197 # used to avoid circular references so destructors work
198 def opener(base):
198 def opener(base):
199 p = base
199 p = base
200 def o(path, mode="r"):
200 def o(path, mode="r"):
201 if p[:7] == "http://":
201 if p[:7] == "http://":
202 f = os.path.join(p, urllib.quote(path))
202 f = os.path.join(p, urllib.quote(path))
203 return httprangereader(f)
203 return httprangereader(f)
204
204
205 f = os.path.join(p, path)
205 f = os.path.join(p, path)
206
206
207 if mode != "r":
207 if mode != "r":
208 try:
208 try:
209 s = os.stat(f)
209 s = os.stat(f)
210 except OSError:
210 except OSError:
211 d = os.path.dirname(f)
211 d = os.path.dirname(f)
212 if not os.path.isdir(d):
212 if not os.path.isdir(d):
213 os.makedirs(d)
213 os.makedirs(d)
214 else:
214 else:
215 if s.st_nlink > 1:
215 if s.st_nlink > 1:
216 file(f + ".tmp", "w").write(file(f).read())
216 file(f + ".tmp", "w").write(file(f).read())
217 os.rename(f+".tmp", f)
217 os.rename(f+".tmp", f)
218
218
219 return file(f, mode)
219 return file(f, mode)
220
220
221 return o
221 return o
222
222
223 class localrepository:
223 class localrepository:
224 def __init__(self, ui, path=None, create=0):
224 def __init__(self, ui, path=None, create=0):
225 self.remote = 0
225 self.remote = 0
226 if path and path[:7] == "http://":
226 if path and path[:7] == "http://":
227 self.remote = 1
227 self.remote = 1
228 self.path = path
228 self.path = path
229 else:
229 else:
230 if not path:
230 if not path:
231 p = os.getcwd()
231 p = os.getcwd()
232 while not os.path.isdir(os.path.join(p, ".hg")):
232 while not os.path.isdir(os.path.join(p, ".hg")):
233 p = os.path.dirname(p)
233 p = os.path.dirname(p)
234 if p == "/": raise "No repo found"
234 if p == "/": raise "No repo found"
235 path = p
235 path = p
236 self.path = os.path.join(path, ".hg")
236 self.path = os.path.join(path, ".hg")
237
237
238 self.root = path
238 self.root = path
239 self.ui = ui
239 self.ui = ui
240
240
241 if create:
241 if create:
242 os.mkdir(self.path)
242 os.mkdir(self.path)
243 os.mkdir(self.join("data"))
243 os.mkdir(self.join("data"))
244
244
245 self.opener = opener(self.path)
245 self.opener = opener(self.path)
246 self.manifest = manifest(self.opener)
246 self.manifest = manifest(self.opener)
247 self.changelog = changelog(self.opener)
247 self.changelog = changelog(self.opener)
248 self.ignorelist = None
248 self.ignorelist = None
249 self.tags = None
249 self.tags = None
250
250
251 if not self.remote:
251 if not self.remote:
252 self.dircache = dircache(self.opener, ui)
252 self.dircache = dircache(self.opener, ui)
253 try:
253 try:
254 self.current = bin(self.opener("current").read())
254 self.current = bin(self.opener("current").read())
255 except IOError:
255 except IOError:
256 self.current = None
256 self.current = None
257
257
258 def setcurrent(self, node):
258 def setcurrent(self, node):
259 self.current = node
259 self.current = node
260 self.opener("current", "w").write(hex(node))
260 self.opener("current", "w").write(hex(node))
261
261
262 def ignore(self, f):
262 def ignore(self, f):
263 if self.ignorelist is None:
263 if self.ignorelist is None:
264 self.ignorelist = []
264 self.ignorelist = []
265 try:
265 try:
266 l = open(os.path.join(self.root, ".hgignore"))
266 l = open(os.path.join(self.root, ".hgignore"))
267 for pat in l:
267 for pat in l:
268 if pat != "\n":
268 if pat != "\n":
269 self.ignorelist.append(re.compile(pat[:-1]))
269 self.ignorelist.append(re.compile(pat[:-1]))
270 except IOError: pass
270 except IOError: pass
271 for pat in self.ignorelist:
271 for pat in self.ignorelist:
272 if pat.search(f): return True
272 if pat.search(f): return True
273 return False
273 return False
274
274
275 def lookup(self, key):
275 def lookup(self, key):
276 if self.tags is None:
276 if self.tags is None:
277 self.tags = {}
277 self.tags = {}
278 try:
278 try:
279 fl = self.file(".hgtags")
279 fl = self.file(".hgtags")
280 for l in fl.revision(fl.tip()).splitlines():
280 for l in fl.revision(fl.tip()).splitlines():
281 if l:
281 if l:
282 n, k = l.split(" ")
282 n, k = l.split(" ")
283 self.tags[k] = bin(n)
283 self.tags[k] = bin(n)
284 except KeyError: pass
284 except KeyError: pass
285 try:
285 try:
286 return self.tags[key]
286 return self.tags[key]
287 except KeyError:
287 except KeyError:
288 return self.changelog.lookup(key)
288 return self.changelog.lookup(key)
289
289
290 def join(self, f):
290 def join(self, f):
291 return os.path.join(self.path, f)
291 return os.path.join(self.path, f)
292
292
293 def file(self, f):
293 def file(self, f):
294 return filelog(self.opener, f)
294 return filelog(self.opener, f)
295
295
296 def transaction(self):
296 def transaction(self):
297 return transaction(self.opener, self.join("journal"),
297 return transaction(self.opener, self.join("journal"),
298 self.join("undo"))
298 self.join("undo"))
299
299
300 def recover(self, f = "journal"):
300 def recover(self, f = "journal"):
301 self.lock()
301 self.lock()
302 if os.path.exists(self.join(f)):
302 if os.path.exists(self.join(f)):
303 self.ui.status("attempting to rollback %s information\n" % f)
303 self.ui.status("attempting to rollback %s information\n" % f)
304 return rollback(self.opener, self.join(f))
304 return rollback(self.opener, self.join(f))
305 else:
305 else:
306 self.ui.warn("no %s information available\n" % f)
306 self.ui.warn("no %s information available\n" % f)
307
307
308 def lock(self, wait = 1):
308 def lock(self, wait = 1):
309 try:
309 try:
310 return lock.lock(self.join("lock"), 0)
310 return lock.lock(self.join("lock"), 0)
311 except lock.LockHeld, inst:
311 except lock.LockHeld, inst:
312 if wait:
312 if wait:
313 self.ui.warn("waiting for lock held by %s\n" % inst.args[0])
313 self.ui.warn("waiting for lock held by %s\n" % inst.args[0])
314 return lock.lock(self.join("lock"), wait)
314 return lock.lock(self.join("lock"), wait)
315 raise inst
315 raise inst
316
316
317 def commit(self, parent, update = None, text = ""):
317 def commit(self, parent, update = None, text = ""):
318 self.lock()
318 self.lock()
319 try:
319 try:
320 remove = [ l[:-1] for l in self.opener("to-remove") ]
320 remove = [ l[:-1] for l in self.opener("to-remove") ]
321 os.unlink(self.join("to-remove"))
321 os.unlink(self.join("to-remove"))
322
322
323 except IOError:
323 except IOError:
324 remove = []
324 remove = []
325
325
326 if update == None:
326 if update == None:
327 update = self.diffdir(self.root, parent)[0]
327 update = self.diffdir(self.root, parent)[0]
328
328
329 if not update:
329 if not update:
330 self.ui.status("nothing changed\n")
330 self.ui.status("nothing changed\n")
331 return
331 return
332
332
333 tr = self.transaction()
333 tr = self.transaction()
334
334
335 # check in files
335 # check in files
336 new = {}
336 new = {}
337 linkrev = self.changelog.count()
337 linkrev = self.changelog.count()
338 update.sort()
338 update.sort()
339 for f in update:
339 for f in update:
340 self.ui.note(f + "\n")
340 self.ui.note(f + "\n")
341 try:
341 try:
342 t = file(f).read()
342 t = file(f).read()
343 except IOError:
343 except IOError:
344 remove.append(f)
344 remove.append(f)
345 continue
345 continue
346 r = self.file(f)
346 r = self.file(f)
347 new[f] = r.add(t, tr, linkrev)
347 new[f] = r.add(t, tr, linkrev)
348
348
349 # update manifest
349 # update manifest
350 mmap = self.manifest.read(self.manifest.tip())
350 mmap = self.manifest.read(self.manifest.tip())
351 mmap.update(new)
351 mmap.update(new)
352 for f in remove:
352 for f in remove:
353 del mmap[f]
353 del mmap[f]
354 mnode = self.manifest.add(mmap, tr, linkrev)
354 mnode = self.manifest.add(mmap, tr, linkrev)
355
355
356 # add changeset
356 # add changeset
357 new = new.keys()
357 new = new.keys()
358 new.sort()
358 new.sort()
359
359
360 edittext = text + "\n" + "HG: manifest hash %s\n" % hex(mnode)
360 edittext = text + "\n" + "HG: manifest hash %s\n" % hex(mnode)
361 edittext += "".join(["HG: changed %s\n" % f for f in new])
361 edittext += "".join(["HG: changed %s\n" % f for f in new])
362 edittext += "".join(["HG: removed %s\n" % f for f in remove])
362 edittext += "".join(["HG: removed %s\n" % f for f in remove])
363 edittext = self.ui.edit(edittext)
363 edittext = self.ui.edit(edittext)
364
364
365 n = self.changelog.add(mnode, new, edittext, tr)
365 n = self.changelog.add(mnode, new, edittext, tr)
366 tr.close()
366 tr.close()
367
367
368 self.setcurrent(n)
368 self.setcurrent(n)
369 self.dircache.update(new)
369 self.dircache.update(new)
370 self.dircache.remove(remove)
370 self.dircache.remove(remove)
371
371
372 def checkout(self, node):
372 def checkout(self, node):
373 # checkout is really dumb at the moment
373 # checkout is really dumb at the moment
374 # it ought to basically merge
374 # it ought to basically merge
375 change = self.changelog.read(node)
375 change = self.changelog.read(node)
376 l = self.manifest.read(change[0]).items()
376 l = self.manifest.read(change[0]).items()
377 l.sort()
377 l.sort()
378
378
379 for f,n in l:
379 for f,n in l:
380 if f[0] == "/": continue
380 if f[0] == "/": continue
381 self.ui.note(f, "\n")
381 self.ui.note(f, "\n")
382 t = self.file(f).revision(n)
382 t = self.file(f).revision(n)
383 try:
383 try:
384 file(f, "w").write(t)
384 file(f, "w").write(t)
385 except IOError:
385 except IOError:
386 os.makedirs(os.path.dirname(f))
386 os.makedirs(os.path.dirname(f))
387 file(f, "w").write(t)
387 file(f, "w").write(t)
388
388
389 self.setcurrent(node)
389 self.setcurrent(node)
390 self.dircache.clear()
390 self.dircache.clear()
391 self.dircache.update([f for f,n in l])
391 self.dircache.update([f for f,n in l])
392
392
393 def diffdir(self, path, changeset):
393 def diffdir(self, path, changeset):
394 changed = []
394 changed = []
395 mf = {}
395 mf = {}
396 added = []
396 added = []
397
397
398 if changeset:
398 if changeset:
399 change = self.changelog.read(changeset)
399 change = self.changelog.read(changeset)
400 mf = self.manifest.read(change[0])
400 mf = self.manifest.read(change[0])
401
401
402 if changeset == self.current:
402 if changeset == self.current:
403 dc = self.dircache.copy()
403 dc = self.dircache.copy()
404 else:
404 else:
405 dc = dict.fromkeys(mf)
405 dc = dict.fromkeys(mf)
406
406
407 def fcmp(fn):
407 def fcmp(fn):
408 t1 = file(os.path.join(self.root, fn)).read()
408 t1 = file(os.path.join(self.root, fn)).read()
409 t2 = self.file(fn).revision(mf[fn])
409 t2 = self.file(fn).revision(mf[fn])
410 return cmp(t1, t2)
410 return cmp(t1, t2)
411
411
412 for dir, subdirs, files in os.walk(self.root):
412 for dir, subdirs, files in os.walk(self.root):
413 d = dir[len(self.root)+1:]
413 d = dir[len(self.root)+1:]
414 if ".hg" in subdirs: subdirs.remove(".hg")
414 if ".hg" in subdirs: subdirs.remove(".hg")
415
415
416 for f in files:
416 for f in files:
417 fn = os.path.join(d, f)
417 fn = os.path.join(d, f)
418 try: s = os.stat(os.path.join(self.root, fn))
418 try: s = os.stat(os.path.join(self.root, fn))
419 except: continue
419 except: continue
420 if fn in dc:
420 if fn in dc:
421 c = dc[fn]
421 c = dc[fn]
422 del dc[fn]
422 del dc[fn]
423 if not c:
423 if not c:
424 if fcmp(fn):
424 if fcmp(fn):
425 changed.append(fn)
425 changed.append(fn)
426 elif c[1] != s.st_size:
426 elif c[1] != s.st_size:
427 changed.append(fn)
427 changed.append(fn)
428 elif c[0] != s.st_mode or c[2] != s.st_mtime:
428 elif c[0] != s.st_mode or c[2] != s.st_mtime:
429 if fcmp(fn):
429 if fcmp(fn):
430 changed.append(fn)
430 changed.append(fn)
431 else:
431 else:
432 if self.ignore(fn): continue
432 if self.ignore(fn): continue
433 added.append(fn)
433 added.append(fn)
434
434
435 deleted = dc.keys()
435 deleted = dc.keys()
436 deleted.sort()
436 deleted.sort()
437
437
438 return (changed, added, deleted)
438 return (changed, added, deleted)
439
439
440 def diffrevs(self, node1, node2):
440 def diffrevs(self, node1, node2):
441 changed, added = [], []
441 changed, added = [], []
442
442
443 change = self.changelog.read(node1)
443 change = self.changelog.read(node1)
444 mf1 = self.manifest.read(change[0])
444 mf1 = self.manifest.read(change[0])
445 change = self.changelog.read(node2)
445 change = self.changelog.read(node2)
446 mf2 = self.manifest.read(change[0])
446 mf2 = self.manifest.read(change[0])
447
447
448 for fn in mf2:
448 for fn in mf2:
449 if mf1.has_key(fn):
449 if mf1.has_key(fn):
450 if mf1[fn] != mf2[fn]:
450 if mf1[fn] != mf2[fn]:
451 changed.append(fn)
451 changed.append(fn)
452 del mf1[fn]
452 del mf1[fn]
453 else:
453 else:
454 added.append(fn)
454 added.append(fn)
455
455
456 deleted = mf1.keys()
456 deleted = mf1.keys()
457 deleted.sort()
457 deleted.sort()
458
458
459 return (changed, added, deleted)
459 return (changed, added, deleted)
460
460
461 def add(self, list):
461 def add(self, list):
462 self.dircache.taint(list)
462 self.dircache.taint(list)
463
463
464 def remove(self, list):
464 def remove(self, list):
465 dl = self.opener("to-remove", "a")
465 dl = self.opener("to-remove", "a")
466 for f in list:
466 for f in list:
467 dl.write(f + "\n")
467 dl.write(f + "\n")
468
468
469 def branches(self, nodes):
469 def branches(self, nodes):
470 if not nodes: nodes = [self.changelog.tip()]
470 if not nodes: nodes = [self.changelog.tip()]
471 b = []
471 b = []
472 for n in nodes:
472 for n in nodes:
473 t = n
473 t = n
474 while n:
474 while n:
475 p = self.changelog.parents(n)
475 p = self.changelog.parents(n)
476 if p[1] != nullid or p[0] == nullid:
476 if p[1] != nullid or p[0] == nullid:
477 b.append((t, n, p[0], p[1]))
477 b.append((t, n, p[0], p[1]))
478 break
478 break
479 n = p[0]
479 n = p[0]
480 return b
480 return b
481
481
482 def between(self, pairs):
482 def between(self, pairs):
483 r = []
483 r = []
484
484
485 for top, bottom in pairs:
485 for top, bottom in pairs:
486 n, l, i = top, [], 0
486 n, l, i = top, [], 0
487 f = 1
487 f = 1
488
488
489 while n != bottom:
489 while n != bottom:
490 p = self.changelog.parents(n)[0]
490 p = self.changelog.parents(n)[0]
491 if i == f:
491 if i == f:
492 l.append(n)
492 l.append(n)
493 f = f * 2
493 f = f * 2
494 n = p
494 n = p
495 i += 1
495 i += 1
496
496
497 r.append(l)
497 r.append(l)
498
498
499 return r
499 return r
500
500
501 def newer(self, nodes):
501 def newer(self, nodes):
502 m = {}
502 m = {}
503 nl = []
503 nl = []
504 pm = {}
504 pm = {}
505 cl = self.changelog
505 cl = self.changelog
506 t = l = cl.count()
506 t = l = cl.count()
507
507
508 # find the lowest numbered node
508 # find the lowest numbered node
509 for n in nodes:
509 for n in nodes:
510 l = min(l, cl.rev(n))
510 l = min(l, cl.rev(n))
511 m[n] = 1
511 m[n] = 1
512
512
513 for i in xrange(l, t):
513 for i in xrange(l, t):
514 n = cl.node(i)
514 n = cl.node(i)
515 if n in m: # explicitly listed
515 if n in m: # explicitly listed
516 pm[n] = 1
516 pm[n] = 1
517 nl.append(n)
517 nl.append(n)
518 continue
518 continue
519 for p in cl.parents(n):
519 for p in cl.parents(n):
520 if p in pm: # parent listed
520 if p in pm: # parent listed
521 pm[n] = 1
521 pm[n] = 1
522 nl.append(n)
522 nl.append(n)
523 break
523 break
524
524
525 return nl
525 return nl
526
526
527 def getchangegroup(self, remote):
527 def getchangegroup(self, remote):
528 tip = remote.branches([])[0]
528 tip = remote.branches([])[0]
529 self.ui.debug("remote tip branch is %s:%s\n" %
529 self.ui.debug("remote tip branch is %s:%s\n" %
530 (short(tip[0]), short(tip[1])))
530 (short(tip[0]), short(tip[1])))
531 m = self.changelog.nodemap
531 m = self.changelog.nodemap
532 unknown = [tip]
532 unknown = [tip]
533 search = []
533 search = []
534 fetch = []
534 fetch = []
535 seen = {}
535 seen = {}
536 seenbranch = {}
536 seenbranch = {}
537
537
538 if tip[0] in m:
538 if tip[0] in m:
539 self.ui.note("nothing to do!\n")
539 self.ui.note("nothing to do!\n")
540 return None
540 return None
541
541
542 while unknown:
542 while unknown:
543 n = unknown.pop(0)
543 n = unknown.pop(0)
544 seen[n[0]] = 1
544 seen[n[0]] = 1
545
545
546 self.ui.debug("examining %s:%s\n" % (short(n[0]), short(n[1])))
546 self.ui.debug("examining %s:%s\n" % (short(n[0]), short(n[1])))
547 if n == nullid: break
547 if n == nullid: break
548 if n in seenbranch:
548 if n in seenbranch:
549 self.ui.debug("branch already found\n")
549 self.ui.debug("branch already found\n")
550 continue
550 continue
551 if n[1] and n[1] in m: # do we know the base?
551 if n[1] and n[1] in m: # do we know the base?
552 self.ui.debug("found incomplete branch %s:%s\n"
552 self.ui.debug("found incomplete branch %s:%s\n"
553 % (short(n[0]), short(n[1])))
553 % (short(n[0]), short(n[1])))
554 search.append(n) # schedule branch range for scanning
554 search.append(n) # schedule branch range for scanning
555 seenbranch[n] = 1
555 seenbranch[n] = 1
556 else:
556 else:
557 if n[2] in m and n[3] in m:
557 if n[2] in m and n[3] in m:
558 if n[1] not in fetch:
558 if n[1] not in fetch:
559 self.ui.debug("found new changeset %s\n" %
559 self.ui.debug("found new changeset %s\n" %
560 short(n[1]))
560 short(n[1]))
561 fetch.append(n[1]) # earliest unknown
561 fetch.append(n[1]) # earliest unknown
562 continue
562 continue
563
563
564 r = []
564 r = []
565 for a in n[2:4]:
565 for a in n[2:4]:
566 if a not in seen: r.append(a)
566 if a not in seen: r.append(a)
567
567
568 if r:
568 if r:
569 self.ui.debug("requesting %s\n" %
569 self.ui.debug("requesting %s\n" %
570 " ".join(map(short, r)))
570 " ".join(map(short, r)))
571 for b in remote.branches(r):
571 for b in remote.branches(r):
572 self.ui.debug("received %s:%s\n" %
572 self.ui.debug("received %s:%s\n" %
573 (short(b[0]), short(b[1])))
573 (short(b[0]), short(b[1])))
574 if b[0] not in m and b[0] not in seen:
574 if b[0] not in m and b[0] not in seen:
575 unknown.append(b)
575 unknown.append(b)
576
576
577 while search:
577 while search:
578 n = search.pop(0)
578 n = search.pop(0)
579 l = remote.between([(n[0], n[1])])[0]
579 l = remote.between([(n[0], n[1])])[0]
580 p = n[0]
580 p = n[0]
581 f = 1
581 f = 1
582 for i in l + [n[1]]:
582 for i in l + [n[1]]:
583 if i in m:
583 if i in m:
584 if f <= 2:
584 if f <= 2:
585 self.ui.debug("found new branch changeset %s\n" %
585 self.ui.debug("found new branch changeset %s\n" %
586 short(p))
586 short(p))
587 fetch.append(p)
587 fetch.append(p)
588 else:
588 else:
589 self.ui.debug("narrowed branch search to %s:%s\n"
589 self.ui.debug("narrowed branch search to %s:%s\n"
590 % (short(p), short(i)))
590 % (short(p), short(i)))
591 search.append((p, i))
591 search.append((p, i))
592 break
592 break
593 p, f = i, f * 2
593 p, f = i, f * 2
594
594
595 for f in fetch:
595 for f in fetch:
596 if f in m:
596 if f in m:
597 raise "already have", short(f[:4])
597 raise "already have", short(f[:4])
598
598
599 self.ui.note("adding new changesets starting at " +
599 self.ui.note("adding new changesets starting at " +
600 " ".join([short(f) for f in fetch]) + "\n")
600 " ".join([short(f) for f in fetch]) + "\n")
601
601
602 return remote.changegroup(fetch)
602 return remote.changegroup(fetch)
603
603
604 def changegroup(self, basenodes):
604 def changegroup(self, basenodes):
605 nodes = self.newer(basenodes)
605 nodes = self.newer(basenodes)
606
606
607 # construct the link map
607 # construct the link map
608 linkmap = {}
608 linkmap = {}
609 for n in nodes:
609 for n in nodes:
610 linkmap[self.changelog.rev(n)] = n
610 linkmap[self.changelog.rev(n)] = n
611
611
612 # construct a list of all changed files
612 # construct a list of all changed files
613 changed = {}
613 changed = {}
614 for n in nodes:
614 for n in nodes:
615 c = self.changelog.read(n)
615 c = self.changelog.read(n)
616 for f in c[3]:
616 for f in c[3]:
617 changed[f] = 1
617 changed[f] = 1
618 changed = changed.keys()
618 changed = changed.keys()
619 changed.sort()
619 changed.sort()
620
620
621 # the changegroup is changesets + manifests + all file revs
621 # the changegroup is changesets + manifests + all file revs
622 revs = [ self.changelog.rev(n) for n in nodes ]
622 revs = [ self.changelog.rev(n) for n in nodes ]
623
623
624 yield self.changelog.group(linkmap)
624 yield self.changelog.group(linkmap)
625 yield self.manifest.group(linkmap)
625 yield self.manifest.group(linkmap)
626
626
627 for f in changed:
627 for f in changed:
628 g = self.file(f).group(linkmap)
628 g = self.file(f).group(linkmap)
629 if not g: raise "couldn't find change to %s" % f
629 if not g: raise "couldn't find change to %s" % f
630 l = struct.pack(">l", len(f))
630 l = struct.pack(">l", len(f))
631 yield "".join([l, f, g])
631 yield "".join([l, f, g])
632
632
633 def addchangegroup(self, generator):
633 def addchangegroup(self, generator):
634 self.lock()
634 self.lock()
635 class genread:
635 class genread:
636 def __init__(self, generator):
636 def __init__(self, generator):
637 self.g = generator
637 self.g = generator
638 self.buf = ""
638 self.buf = ""
639 def read(self, l):
639 def read(self, l):
640 while l > len(self.buf):
640 while l > len(self.buf):
641 try:
641 try:
642 self.buf += self.g.next()
642 self.buf += self.g.next()
643 except StopIteration:
643 except StopIteration:
644 break
644 break
645 d, self.buf = self.buf[:l], self.buf[l:]
645 d, self.buf = self.buf[:l], self.buf[l:]
646 return d
646 return d
647
647
648 if not generator: return
648 if not generator: return
649 source = genread(generator)
649 source = genread(generator)
650
650
651 def getchunk(add = 0):
651 def getchunk(add = 0):
652 d = source.read(4)
652 d = source.read(4)
653 if not d: return ""
653 if not d: return ""
654 l = struct.unpack(">l", d)[0]
654 l = struct.unpack(">l", d)[0]
655 return source.read(l - 4 + add)
655 return source.read(l - 4 + add)
656
656
657 tr = self.transaction()
657 tr = self.transaction()
658 simple = True
658 simple = True
659 need = {}
659 need = {}
660
660
661 self.ui.status("adding changesets\n")
661 self.ui.status("adding changesets\n")
662 # pull off the changeset group
662 # pull off the changeset group
663 def report(x):
663 def report(x):
664 self.ui.debug("add changeset %s\n" % short(x))
664 self.ui.debug("add changeset %s\n" % short(x))
665 return self.changelog.count()
665 return self.changelog.count()
666
666
667 csg = getchunk()
667 csg = getchunk()
668 co = self.changelog.tip()
668 co = self.changelog.tip()
669 cn = self.changelog.addgroup(csg, report, tr)
669 cn = self.changelog.addgroup(csg, report, tr)
670
670
671 self.ui.status("adding manifests\n")
671 self.ui.status("adding manifests\n")
672 # pull off the manifest group
672 # pull off the manifest group
673 mfg = getchunk()
673 mfg = getchunk()
674 mm = self.manifest.tip()
674 mm = self.manifest.tip()
675 mo = self.manifest.addgroup(mfg, lambda x: self.changelog.rev(x), tr)
675 mo = self.manifest.addgroup(mfg, lambda x: self.changelog.rev(x), tr)
676
676
677 # do we need a resolve?
677 # do we need a resolve?
678 if self.changelog.ancestor(co, cn) != co:
678 if self.changelog.ancestor(co, cn) != co:
679 simple = False
679 simple = False
680 resolverev = self.changelog.count()
680 resolverev = self.changelog.count()
681
681
682 # resolve the manifest to determine which files
682 # resolve the manifest to determine which files
683 # we care about merging
683 # we care about merging
684 self.ui.status("resolving manifests\n")
684 self.ui.status("resolving manifests\n")
685 ma = self.manifest.ancestor(mm, mo)
685 ma = self.manifest.ancestor(mm, mo)
686 omap = self.manifest.read(mo) # other
686 omap = self.manifest.read(mo) # other
687 amap = self.manifest.read(ma) # ancestor
687 amap = self.manifest.read(ma) # ancestor
688 mmap = self.manifest.read(mm) # mine
688 mmap = self.manifest.read(mm) # mine
689 nmap = {}
689 nmap = {}
690
690
691 self.ui.debug(" ancestor %s local %s remote %s\n" %
691 self.ui.debug(" ancestor %s local %s remote %s\n" %
692 (short(ma), short(mm), short(mo)))
692 (short(ma), short(mm), short(mo)))
693
693
694 for f, mid in mmap.iteritems():
694 for f, mid in mmap.iteritems():
695 if f in omap:
695 if f in omap:
696 if mid != omap[f]:
696 if mid != omap[f]:
697 self.ui.debug(" %s versions differ, do resolve\n" % f)
697 self.ui.debug(" %s versions differ, do resolve\n" % f)
698 need[f] = mid # use merged version or local version
698 need[f] = mid # use merged version or local version
699 else:
699 else:
700 nmap[f] = mid # keep ours
700 nmap[f] = mid # keep ours
701 del omap[f]
701 del omap[f]
702 elif f in amap:
702 elif f in amap:
703 if mid != amap[f]:
703 if mid != amap[f]:
704 r = self.ui.prompt(
704 r = self.ui.prompt(
705 (" local changed %s which remote deleted\n" % f) +
705 (" local changed %s which remote deleted\n" % f) +
706 "(k)eep or (d)elete?", "[kd]", "k")
706 "(k)eep or (d)elete?", "[kd]", "k")
707 if r == "k": nmap[f] = mid
707 if r == "k": nmap[f] = mid
708 else:
708 else:
709 self.ui.debug("other deleted %s\n" % f)
709 self.ui.debug("other deleted %s\n" % f)
710 pass # other deleted it
710 pass # other deleted it
711 else:
711 else:
712 self.ui.debug("local created %s\n" %f)
712 self.ui.debug("local created %s\n" %f)
713 nmap[f] = mid # we created it
713 nmap[f] = mid # we created it
714
714
715 del mmap
715 del mmap
716
716
717 for f, oid in omap.iteritems():
717 for f, oid in omap.iteritems():
718 if f in amap:
718 if f in amap:
719 if oid != amap[f]:
719 if oid != amap[f]:
720 r = self.ui.prompt(
720 r = self.ui.prompt(
721 ("remote changed %s which local deleted\n" % f) +
721 ("remote changed %s which local deleted\n" % f) +
722 "(k)eep or (d)elete?", "[kd]", "k")
722 "(k)eep or (d)elete?", "[kd]", "k")
723 if r == "k": nmap[f] = oid
723 if r == "k": nmap[f] = oid
724 else:
724 else:
725 pass # probably safe
725 pass # probably safe
726 else:
726 else:
727 self.ui.debug("remote created %s, do resolve\n" % f)
727 self.ui.debug("remote created %s, do resolve\n" % f)
728 need[f] = oid
728 need[f] = oid
729
729
730 del omap
730 del omap
731 del amap
731 del amap
732
732
733 new = need.keys()
733 new = need.keys()
734 new.sort()
734 new.sort()
735
735
736 # process the files
736 # process the files
737 self.ui.status("adding files\n")
737 self.ui.status("adding files\n")
738 while 1:
738 while 1:
739 f = getchunk(4)
739 f = getchunk(4)
740 if not f: break
740 if not f: break
741 fg = getchunk()
741 fg = getchunk()
742 self.ui.debug("adding %s revisions\n" % f)
742 self.ui.debug("adding %s revisions\n" % f)
743 fl = self.file(f)
743 fl = self.file(f)
744 o = fl.tip()
744 o = fl.tip()
745 n = fl.addgroup(fg, lambda x: self.changelog.rev(x), tr)
745 n = fl.addgroup(fg, lambda x: self.changelog.rev(x), tr)
746 if f in need:
746 if f in need:
747 del need[f]
747 del need[f]
748 # manifest resolve determined we need to merge the tips
748 # manifest resolve determined we need to merge the tips
749 nmap[f] = self.merge3(fl, f, o, n, tr, resolverev)
749 nmap[f] = self.merge3(fl, f, o, n, tr, resolverev)
750
750
751 if need:
751 if need:
752 # we need to do trivial merges on local files
752 # we need to do trivial merges on local files
753 for f in new:
753 for f in new:
754 if f not in need: continue
754 if f not in need: continue
755 fl = self.file(f)
755 fl = self.file(f)
756 nmap[f] = self.merge3(fl, f, need[f], fl.tip(), tr, resolverev)
756 nmap[f] = self.merge3(fl, f, need[f], fl.tip(), tr, resolverev)
757
757
758 # For simple merges, we don't need to resolve manifests or changesets
758 # For simple merges, we don't need to resolve manifests or changesets
759 if simple:
759 if simple:
760 self.ui.debug("simple merge, skipping resolve\n")
760 self.ui.debug("simple merge, skipping resolve\n")
761 tr.close()
761 tr.close()
762 return
762 return
763
763
764 node = self.manifest.add(nmap, tr, resolverev, mm, mo)
764 node = self.manifest.add(nmap, tr, resolverev, mm, mo)
765
765
766 # Now all files and manifests are merged, we add the changed files
766 # Now all files and manifests are merged, we add the changed files
767 # and manifest id to the changelog
767 # and manifest id to the changelog
768 self.ui.status("committing merge changeset\n")
768 self.ui.status("committing merge changeset\n")
769 if co == cn: cn = -1
769 if co == cn: cn = -1
770
770
771 edittext = "\nHG: merge resolve\n" + \
771 edittext = "\nHG: merge resolve\n" + \
772 "HG: manifest hash %s\n" % hex(mnode) + \
772 "HG: manifest hash %s\n" % hex(mnode) + \
773 "".join(["HG: changed %s\n" % f for f in new])
773 "".join(["HG: changed %s\n" % f for f in new])
774 edittext = self.ui.edit(edittext)
774 edittext = self.ui.edit(edittext)
775 n = self.changelog.add(node, new, edittext, tr, co, cn)
775 n = self.changelog.add(node, new, edittext, tr, co, cn)
776
776
777 tr.close()
777 tr.close()
778
778
779 def merge3(self, fl, fn, my, other, transaction, link):
779 def merge3(self, fl, fn, my, other, transaction, link):
780 """perform a 3-way merge and append the result"""
780 """perform a 3-way merge and append the result"""
781
781
782 def temp(prefix, node):
782 def temp(prefix, node):
783 pre = "%s~%s." % (os.path.basename(fn), prefix)
783 pre = "%s~%s." % (os.path.basename(fn), prefix)
784 (fd, name) = tempfile.mkstemp("", pre)
784 (fd, name) = tempfile.mkstemp("", pre)
785 f = os.fdopen(fd, "w")
785 f = os.fdopen(fd, "w")
786 f.write(fl.revision(node))
786 f.write(fl.revision(node))
787 f.close()
787 f.close()
788 return name
788 return name
789
789
790 base = fl.ancestor(my, other)
790 base = fl.ancestor(my, other)
791 self.ui.note("resolving %s\n" % fn)
791 self.ui.note("resolving %s\n" % fn)
792 self.ui.debug("local %s remote %s ancestor %s\n" %
792 self.ui.debug("local %s remote %s ancestor %s\n" %
793 (short(my), short(other), short(base)))
793 (short(my), short(other), short(base)))
794
794
795 if my == base:
795 if my == base:
796 text = fl.revision(other)
796 text = fl.revision(other)
797 else:
797 else:
798 a = temp("local", my)
798 a = temp("local", my)
799 b = temp("remote", other)
799 b = temp("remote", other)
800 c = temp("parent", base)
800 c = temp("parent", base)
801
801
802 cmd = os.environ["HGMERGE"]
802 cmd = os.environ["HGMERGE"]
803 self.ui.debug("invoking merge with %s\n" % cmd)
803 self.ui.debug("invoking merge with %s\n" % cmd)
804 r = os.system("%s %s %s %s %s" % (cmd, a, b, c, fn))
804 r = os.system("%s %s %s %s %s" % (cmd, a, b, c, fn))
805 if r:
805 if r:
806 raise "Merge failed!"
806 raise "Merge failed!"
807
807
808 text = open(a).read()
808 text = open(a).read()
809 os.unlink(a)
809 os.unlink(a)
810 os.unlink(b)
810 os.unlink(b)
811 os.unlink(c)
811 os.unlink(c)
812
812
813 return fl.add(text, transaction, link, my, other)
813 return fl.add(text, transaction, link, my, other)
814
814
815 class remoterepository:
815 class remoterepository:
816 def __init__(self, ui, path):
816 def __init__(self, ui, path):
817 self.url = path
817 self.url = path
818 self.ui = ui
818 self.ui = ui
819
819
820 def do_cmd(self, cmd, **args):
820 def do_cmd(self, cmd, **args):
821 self.ui.debug("sending %s command\n" % cmd)
821 self.ui.debug("sending %s command\n" % cmd)
822 q = {"cmd": cmd}
822 q = {"cmd": cmd}
823 q.update(args)
823 q.update(args)
824 qs = urllib.urlencode(q)
824 qs = urllib.urlencode(q)
825 cu = "%s?%s" % (self.url, qs)
825 cu = "%s?%s" % (self.url, qs)
826 return urllib.urlopen(cu)
826 return urllib.urlopen(cu)
827
827
828 def branches(self, nodes):
828 def branches(self, nodes):
829 n = " ".join(map(hex, nodes))
829 n = " ".join(map(hex, nodes))
830 d = self.do_cmd("branches", nodes=n).read()
830 d = self.do_cmd("branches", nodes=n).read()
831 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
831 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
832 return br
832 return br
833
833
834 def between(self, pairs):
834 def between(self, pairs):
835 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
835 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
836 d = self.do_cmd("between", pairs=n).read()
836 d = self.do_cmd("between", pairs=n).read()
837 p = [ map(bin, l.split(" ")) for l in d.splitlines() ]
837 p = [ map(bin, l.split(" ")) for l in d.splitlines() ]
838 return p
838 return p
839
839
840 def changegroup(self, nodes):
840 def changegroup(self, nodes):
841 n = " ".join(map(hex, nodes))
841 n = " ".join(map(hex, nodes))
842 zd = zlib.decompressobj()
842 zd = zlib.decompressobj()
843 f = self.do_cmd("changegroup", roots=n)
843 f = self.do_cmd("changegroup", roots=n)
844 while 1:
844 while 1:
845 d = f.read(4096)
845 d = f.read(4096)
846 if not d:
846 if not d:
847 yield zd.flush()
847 yield zd.flush()
848 break
848 break
849 yield zd.decompress(d)
849 yield zd.decompress(d)
850
850
851 def repository(ui, path=None, create=0):
851 def repository(ui, path=None, create=0):
852 if path and path[:7] == "http://":
852 if path and path[:7] == "http://":
853 return remoterepository(ui, path)
853 return remoterepository(ui, path)
854 if path and path[:5] == "hg://":
854 if path and path[:5] == "hg://":
855 return remoterepository(ui, path.replace("hg://", "http://"))
855 return remoterepository(ui, path.replace("hg://", "http://"))
856 if path and path[:11] == "old-http://":
856 if path and path[:11] == "old-http://":
857 return localrepository(ui, path.replace("old-http://", "http://"))
857 return localrepository(ui, path.replace("old-http://", "http://"))
858 else:
858 else:
859 return localrepository(ui, path, create)
859 return localrepository(ui, path, create)
860
860
861 class ui:
861 class ui:
862 def __init__(self, verbose=False, debug=False, quiet=False,
862 def __init__(self, verbose=False, debug=False, quiet=False,
863 interactive=True):
863 interactive=True):
864 self.quiet = quiet and not verbose and not debug
864 self.quiet = quiet and not verbose and not debug
865 self.verbose = verbose or debug
865 self.verbose = verbose or debug
866 self.debugflag = debug
866 self.debugflag = debug
867 self.interactive = interactive
867 self.interactive = interactive
868 def write(self, *args):
868 def write(self, *args):
869 for a in args:
869 for a in args:
870 sys.stdout.write(str(a))
870 sys.stdout.write(str(a))
871 def readline(self):
871 def readline(self):
872 return sys.stdin.readline()[:-1]
872 return sys.stdin.readline()[:-1]
873 def prompt(self, msg, pat, default = "y"):
873 def prompt(self, msg, pat, default = "y"):
874 if not self.interactive: return default
874 if not self.interactive: return default
875 while 1:
875 while 1:
876 self.write(msg, " ")
876 self.write(msg, " ")
877 r = self.readline()
877 r = self.readline()
878 if re.match(pat, r):
878 if re.match(pat, r):
879 return r
879 return r
880 else:
880 else:
881 self.write("unrecognized response\n")
881 self.write("unrecognized response\n")
882 def status(self, *msg):
882 def status(self, *msg):
883 if not self.quiet: self.write(*msg)
883 if not self.quiet: self.write(*msg)
884 def warn(self, msg):
884 def warn(self, msg):
885 self.write(*msg)
885 self.write(*msg)
886 def note(self, *msg):
886 def note(self, *msg):
887 if self.verbose: self.write(*msg)
887 if self.verbose: self.write(*msg)
888 def debug(self, *msg):
888 def debug(self, *msg):
889 if self.debugflag: self.write(*msg)
889 if self.debugflag: self.write(*msg)
890 def edit(self, text):
890 def edit(self, text):
891 (fd, name) = tempfile.mkstemp("hg")
891 (fd, name) = tempfile.mkstemp("hg")
892 f = os.fdopen(fd, "w")
892 f = os.fdopen(fd, "w")
893 f.write(text)
893 f.write(text)
894 f.close()
894 f.close()
895
895
896 editor = os.environ.get("EDITOR", "vi")
896 editor = os.environ.get("HGEDITOR") or os.environ.get("EDITOR", "vi")
897 r = os.system("%s %s" % (editor, name))
897 r = os.system("%s %s" % (editor, name))
898
898 if r:
899 if r:
899 raise "Edit failed!"
900 raise "Edit failed!"
900
901
901 t = open(name).read()
902 t = open(name).read()
902 t = re.sub("(?m)^HG:.*\n", "", t)
903 t = re.sub("(?m)^HG:.*\n", "", t)
903
904
904 return t
905 return t
905
906
906
907 class httprangereader:
907 class httprangereader:
908 def __init__(self, url):
908 def __init__(self, url):
909 self.url = url
909 self.url = url
910 self.pos = 0
910 self.pos = 0
911 def seek(self, pos):
911 def seek(self, pos):
912 self.pos = pos
912 self.pos = pos
913 def read(self, bytes=None):
913 def read(self, bytes=None):
914 opener = urllib2.build_opener(byterange.HTTPRangeHandler())
914 opener = urllib2.build_opener(byterange.HTTPRangeHandler())
915 urllib2.install_opener(opener)
915 urllib2.install_opener(opener)
916 req = urllib2.Request(self.url)
916 req = urllib2.Request(self.url)
917 end = ''
917 end = ''
918 if bytes: end = self.pos + bytes
918 if bytes: end = self.pos + bytes
919 req.add_header('Range', 'bytes=%d-%s' % (self.pos, end))
919 req.add_header('Range', 'bytes=%d-%s' % (self.pos, end))
920 f = urllib2.urlopen(req)
920 f = urllib2.urlopen(req)
921 return f.read()
921 return f.read()
General Comments 0
You need to be logged in to leave comments. Login now