##// END OF EJS Templates
Migrate rawcommit, import, export, history, and merge...
mpm@selenic.com -
r246:96cde50a default
parent child Browse files
Show More
@@ -1,411 +1,244 b''
1 1 #!/usr/bin/env python
2 2 #
3 3 # mercurial - a minimal scalable distributed SCM
4 4 # v0.5b "katje"
5 5 #
6 6 # Copyright 2005 Matt Mackall <mpm@selenic.com>
7 7 #
8 8 # This software may be used and distributed according to the terms
9 9 # of the GNU General Public License, incorporated herein by reference.
10 10
11 11 # the psyco compiler makes commits a bit faster
12 12 # and makes changegroup merge about 20 times slower!
13 13 # try:
14 14 # import psyco
15 15 # psyco.full()
16 16 # except:
17 17 # pass
18 18
19 import sys, os, time
19 import sys
20 20 from mercurial import hg, mdiff, fancyopts, ui, commands
21 21
22 def filterfiles(list, files):
23 l = [ x for x in list if x in files ]
24
25 for f in files:
26 if f[-1] != os.sep: f += os.sep
27 l += [ x for x in list if x.startswith(f) ]
28 return l
29
30 def diff(files = None, node1 = None, node2 = None):
31 def date(c):
32 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
33
34 if node2:
35 change = repo.changelog.read(node2)
36 mmap2 = repo.manifest.read(change[0])
37 (c, a, d) = repo.diffrevs(node1, node2)
38 def read(f): return repo.file(f).read(mmap2[f])
39 date2 = date(change)
40 else:
41 date2 = time.asctime()
42 if not node1:
43 node1 = repo.dirstate.parents()[0]
44 (c, a, d, u) = repo.diffdir(repo.root, node1)
45 def read(f): return file(os.path.join(repo.root, f)).read()
46
47 change = repo.changelog.read(node1)
48 mmap = repo.manifest.read(change[0])
49 date1 = date(change)
50
51 if files:
52 c, a, d = map(lambda x: filterfiles(x, files), (c, a, d))
53
54 for f in c:
55 to = repo.file(f).read(mmap[f])
56 tn = read(f)
57 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
58 for f in a:
59 to = ""
60 tn = read(f)
61 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
62 for f in d:
63 to = repo.file(f).read(mmap[f])
64 tn = ""
65 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
66
67
68 22 try:
69 23 sys.exit(commands.dispatch(sys.argv[1:]))
70 24 except commands.UnknownCommand:
71 25 # fall through
72 26 pass
73 27
74 28 options = {}
75 29 opts = [('v', 'verbose', None, 'verbose'),
76 30 ('d', 'debug', None, 'debug'),
77 31 ('q', 'quiet', None, 'quiet'),
78 32 ('y', 'noninteractive', None, 'run non-interactively'),
79 33 ]
80 34
81 35 args = fancyopts.fancyopts(sys.argv[1:], opts, options,
82 36 'hg [options] <command> [command options] [files]')
83 37
84 38 try:
85 39 cmd = args[0]
86 40 args = args[1:]
87 41 except:
88 42 cmd = "help"
89 43
90 44 ui = ui.ui(options["verbose"], options["debug"], options["quiet"],
91 45 not options["noninteractive"])
92 46
93 47 try:
94 48 repo = hg.repository(ui=ui)
95 49 except IOError:
96 50 ui.warn("Unable to open repository\n")
97 51 sys.exit(0)
98 52
99 relpath = None
100 if os.getcwd() != repo.root:
101 relpath = os.getcwd()[len(repo.root) + 1: ]
102
103 elif cmd == "rawcommit":
104 "raw commit interface"
105 rc = {}
106 opts = [('p', 'parent', [], 'parent'),
107 ('d', 'date', "", 'data'),
108 ('u', 'user', "", 'user'),
109 ('F', 'files', "", 'file list'),
110 ('t', 'text', "", 'commit text'),
111 ('l', 'logfile', "", 'commit text file')
112 ]
113 args = fancyopts.fancyopts(args, opts, rc,
114 "hg rawcommit [options] files")
115 text = rc['text']
116 if not text and rc['logfile']:
117 try: text = open(rc['logfile']).read()
118 except IOError: pass
119 if not text and not rc['logfile']:
120 print "missing commit text"
121 sys.exit(0)
122 if rc['files']:
123 files = open(rc['files']).read().splitlines()
124 else:
125 files = args
126
127 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
128
129
130 elif cmd == "import" or cmd == "patch":
131 try:
132 import psyco
133 psyco.full()
134 except:
135 pass
136
137 ioptions = {}
138 opts = [('p', 'strip', 1, 'path strip'),
139 ('b', 'base', "", 'base path'),
140 ('q', 'quiet', "", 'silence diff')
141 ]
142
143 args = fancyopts.fancyopts(args, opts, ioptions,
144 'hg import [options] <patch names>')
145 d = ioptions["base"]
146 strip = ioptions["strip"]
147 quiet = ioptions["quiet"] and "> /dev/null" or ""
148
149 for patch in args:
150 ui.status("applying %s\n" % patch)
151 pf = os.path.join(d, patch)
152
153 text = ""
154 for l in file(pf):
155 if l[:4] == "--- ": break
156 text += l
157
158 f = os.popen("lsdiff --strip %d %s" % (strip, pf))
159 files = filter(None, map(lambda x: x.rstrip(), f.read().splitlines()))
160 f.close()
161
162 if files:
163 if os.system("patch -p%d < %s %s" % (strip, pf, quiet)):
164 raise "patch failed!"
165 repo.commit(files, text)
166
167 elif cmd == "export":
168 node = repo.lookup(args[0])
169 prev, other = repo.changelog.parents(node)
170 change = repo.changelog.read(node)
171 print "# HG changeset patch"
172 print "# User %s" % change[1]
173 print "# Node ID %s" % hg.hex(node)
174 print "# Parent %s" % hg.hex(prev)
175 print
176 if other != hg.nullid:
177 print "# Parent %s" % hg.hex(other)
178 print change[4]
179
180 diff(None, prev, node)
181
182 elif cmd == "debugchangegroup":
53 if cmd == "debugchangegroup":
183 54 newer = repo.newer(map(repo.lookup, args))
184 55 for chunk in repo.changegroup(newer):
185 56 sys.stdout.write(chunk)
186 57
187 58 elif cmd == "debugaddchangegroup":
188 59 data = sys.stdin.read()
189 60 repo.addchangegroup(data)
190 61
191 elif cmd == "history":
192 for i in range(repo.changelog.count()):
193 n = repo.changelog.node(i)
194 changes = repo.changelog.read(n)
195 (p1, p2) = repo.changelog.parents(n)
196 (h, h1, h2) = map(hg.hex, (n, p1, p2))
197 (i1, i2) = map(repo.changelog.rev, (p1, p2))
198 print "rev: %4d:%s" % (i, h)
199 print "parents: %4d:%s" % (i1, h1)
200 if i2: print " %4d:%s" % (i2, h2)
201 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
202 hg.hex(changes[0]))
203 print "user:", changes[1]
204 print "date:", time.asctime(
205 time.localtime(float(changes[2].split(' ')[0])))
206 if ui.verbose: print "files:", " ".join(changes[3])
207 print "description:"
208 print changes[4]
209
210 62 elif cmd == "dump":
211 63 if args:
212 64 r = repo.file(args[0])
213 65 n = r.tip()
214 66 if len(args) > 1: n = r.lookup(args[1])
215 67 sys.stdout.write(r.read(n))
216 68 else:
217 69 print "missing filename"
218 70
219 71 elif cmd == "dumpmanifest":
220 72 n = repo.manifest.tip()
221 73 if len(args) > 0:
222 74 n = repo.manifest.lookup(args[0])
223 75 m = repo.manifest.read(n)
224 76 files = m.keys()
225 77 files.sort()
226 78
227 79 for f in files:
228 80 print hg.hex(m[f]), f
229 81
230 82 elif cmd == "debugindex":
231 83 if ".hg" not in args[0]:
232 84 args[0] = ".hg/data/" + repo.file(args[0]).encodepath(args[0]) + "i"
233 85
234 86 r = hg.revlog(open, args[0], "")
235 87 print " rev offset length base linkrev"+\
236 88 " p1 p2 nodeid"
237 89 for i in range(r.count()):
238 90 e = r.index[i]
239 91 print "% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s.." % (
240 92 i, e[0], e[1], e[2], e[3],
241 93 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5]))
242 94
243 95 elif cmd == "debugindexdot":
244 96 if ".hg" not in args[0]:
245 97 args[0] = ".hg/data/" + repo.file(args[0]).encodepath(args[0]) + "i"
246 98
247 99 r = hg.revlog(open, args[0], "")
248 100 print "digraph G {"
249 101 for i in range(r.count()):
250 102 e = r.index[i]
251 103 print "\t%d -> %d" % (r.rev(e[4]), i)
252 104 if e[5] != hg.nullid:
253 105 print "\t%d -> %d" % (r.rev(e[5]), i)
254 106 print "}"
255 107
256 elif cmd == "merge":
257 if args:
258 paths = {}
259 try:
260 pf = os.path.join(os.environ["HOME"], ".hgpaths")
261 for l in file(pf):
262 name, path = l.split()
263 paths[name] = path
264 except:
265 pass
266
267 if args[0] in paths: args[0] = paths[args[0]]
268
269 other = hg.repository(ui, args[0])
270 cg = repo.getchangegroup(other)
271 repo.addchangegroup(cg)
272 else:
273 print "missing source repository"
274
275 108 elif cmd == "tags":
276 109 repo.lookup(0) # prime the cache
277 110 i = repo.tags.items()
278 111 i.sort()
279 112 for k, n in i:
280 113 try:
281 114 r = repo.changelog.rev(n)
282 115 except KeyError:
283 116 r = "?"
284 117 print "%-30s %5d:%s" % (k, repo.changelog.rev(n), hg.hex(n))
285 118
286 119 elif cmd == "verify":
287 120 filelinkrevs = {}
288 121 filenodes = {}
289 122 manifestchangeset = {}
290 123 changesets = revisions = files = 0
291 124 errors = 0
292 125
293 126 ui.status("checking changesets\n")
294 127 for i in range(repo.changelog.count()):
295 128 changesets += 1
296 129 n = repo.changelog.node(i)
297 130 for p in repo.changelog.parents(n):
298 131 if p not in repo.changelog.nodemap:
299 132 ui.warn("changeset %s has unknown parent %s\n" %
300 133 (hg.short(n), hg.short(p)))
301 134 errors += 1
302 135 try:
303 136 changes = repo.changelog.read(n)
304 137 except Exception, inst:
305 138 ui.warn("unpacking changeset %s: %s\n" % (short(n), inst))
306 139 errors += 1
307 140
308 141 manifestchangeset[changes[0]] = n
309 142 for f in changes[3]:
310 143 filelinkrevs.setdefault(f, []).append(i)
311 144
312 145 ui.status("checking manifests\n")
313 146 for i in range(repo.manifest.count()):
314 147 n = repo.manifest.node(i)
315 148 for p in repo.manifest.parents(n):
316 149 if p not in repo.manifest.nodemap:
317 150 ui.warn("manifest %s has unknown parent %s\n" %
318 151 (hg.short(n), hg.short(p)))
319 152 errors += 1
320 153 ca = repo.changelog.node(repo.manifest.linkrev(n))
321 154 cc = manifestchangeset[n]
322 155 if ca != cc:
323 156 ui.warn("manifest %s points to %s, not %s\n" %
324 157 (hg.hex(n), hg.hex(ca), hg.hex(cc)))
325 158 errors += 1
326 159
327 160 try:
328 161 delta = mdiff.patchtext(repo.manifest.delta(n))
329 162 except KeyboardInterrupt:
330 163 print "aborted"
331 164 sys.exit(0)
332 165 except Exception, inst:
333 166 ui.warn("unpacking manifest %s: %s\n" % (hg.short(n), inst))
334 167 errors += 1
335 168
336 169 ff = [ l.split('\0') for l in delta.splitlines() ]
337 170 for f, fn in ff:
338 171 filenodes.setdefault(f, {})[hg.bin(fn)] = 1
339 172
340 173 ui.status("crosschecking files in changesets and manifests\n")
341 174 for f in filenodes:
342 175 if f not in filelinkrevs:
343 176 ui.warn("file %s in manifest but not in changesets\n" % f)
344 177 errors += 1
345 178
346 179 for f in filelinkrevs:
347 180 if f not in filenodes:
348 181 ui.warn("file %s in changeset but not in manifest\n" % f)
349 182 errors += 1
350 183
351 184 ui.status("checking files\n")
352 185 ff = filenodes.keys()
353 186 ff.sort()
354 187 for f in ff:
355 188 if f == "/dev/null": continue
356 189 files += 1
357 190 fl = repo.file(f)
358 191 nodes = { hg.nullid: 1 }
359 192 for i in range(fl.count()):
360 193 revisions += 1
361 194 n = fl.node(i)
362 195
363 196 if n not in filenodes[f]:
364 197 ui.warn("%s: %d:%s not in manifests\n" % (f, i, hg.short(n)))
365 198 print len(filenodes[f].keys()), fl.count(), f
366 199 errors += 1
367 200 else:
368 201 del filenodes[f][n]
369 202
370 203 flr = fl.linkrev(n)
371 204 if flr not in filelinkrevs[f]:
372 205 ui.warn("%s:%s points to unexpected changeset rev %d\n"
373 206 % (f, hg.short(n), fl.linkrev(n)))
374 207 errors += 1
375 208 else:
376 209 filelinkrevs[f].remove(flr)
377 210
378 211 # verify contents
379 212 try:
380 213 t = fl.read(n)
381 214 except Exception, inst:
382 215 ui.warn("unpacking file %s %s: %s\n" % (f, hg.short(n), inst))
383 216 errors += 1
384 217
385 218 # verify parents
386 219 (p1, p2) = fl.parents(n)
387 220 if p1 not in nodes:
388 221 ui.warn("file %s:%s unknown parent 1 %s" %
389 222 (f, hg.short(n), hg.short(p1)))
390 223 errors += 1
391 224 if p2 not in nodes:
392 225 ui.warn("file %s:%s unknown parent 2 %s" %
393 226 (f, hg.short(n), hg.short(p1)))
394 227 errors += 1
395 228 nodes[n] = 1
396 229
397 230 # cross-check
398 231 for node in filenodes[f]:
399 232 ui.warn("node %s in manifests not in %s\n" % (hg.hex(n), f))
400 233 errors += 1
401 234
402 235 ui.status("%d files, %d changesets, %d total revisions\n" %
403 236 (files, changesets, revisions))
404 237
405 238 if errors:
406 239 ui.warn("%d integrity errors encountered!\n" % errors)
407 240 sys.exit(1)
408 241
409 242 else:
410 243 if cmd: ui.warn("unknown command\n\n")
411 244 sys.exit(1)
@@ -1,386 +1,502 b''
1 1 import os, re, traceback, sys, signal, time, mdiff
2 2 from mercurial import fancyopts, ui, hg
3 3
4 4 class UnknownCommand(Exception): pass
5 5
6 6 def filterfiles(filters, files):
7 7 l = [ x for x in files if x in filters ]
8 8
9 9 for t in filters:
10 10 if t and t[-1] != os.sep: t += os.sep
11 11 l += [ x for x in files if x.startswith(t) ]
12 12 return l
13 13
14 14 def relfilter(repo, files):
15 15 if os.getcwd() != repo.root:
16 16 p = os.getcwd()[len(repo.root) + 1: ]
17 17 return filterfiles(p, files)
18 18 return files
19 19
20 20 def relpath(repo, args):
21 21 if os.getcwd() != repo.root:
22 22 p = os.getcwd()[len(repo.root) + 1: ]
23 23 return [ os.path.normpath(os.path.join(p, x)) for x in args ]
24 24 return args
25 25
26 26 def dodiff(repo, files = None, node1 = None, node2 = None):
27 27 def date(c):
28 28 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
29 29
30 30 if node2:
31 31 change = repo.changelog.read(node2)
32 32 mmap2 = repo.manifest.read(change[0])
33 33 (c, a, d) = repo.diffrevs(node1, node2)
34 34 def read(f): return repo.file(f).read(mmap2[f])
35 35 date2 = date(change)
36 36 else:
37 37 date2 = time.asctime()
38 38 (c, a, d, u) = repo.diffdir(repo.root, node1)
39 39 if not node1:
40 40 node1 = repo.dirstate.parents()[0]
41 41 def read(f): return file(os.path.join(repo.root, f)).read()
42 42
43 43 change = repo.changelog.read(node1)
44 44 mmap = repo.manifest.read(change[0])
45 45 date1 = date(change)
46 46
47 47 if files:
48 48 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
49 49
50 50 for f in c:
51 51 to = repo.file(f).read(mmap[f])
52 52 tn = read(f)
53 53 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
54 54 for f in a:
55 55 to = ""
56 56 tn = read(f)
57 57 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
58 58 for f in d:
59 59 to = repo.file(f).read(mmap[f])
60 60 tn = ""
61 61 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
62 62
63 63 def help(ui, cmd=None):
64 64 '''show help'''
65 65 if cmd:
66 66 try:
67 67 i = find(cmd)
68 68 ui.write("%s\n\n" % i[2])
69 69 ui.write(i[0].__doc__, "\n")
70 70 except UnknownCommand:
71 71 ui.warn("unknown command %s", cmd)
72 72 sys.exit(0)
73 73
74 74 ui.status("""\
75 75 hg commands:
76 76
77 77 add [files...] add the given files in the next commit
78 78 addremove add all new files, delete all missing files
79 79 annotate [files...] show changeset number per file line
80 80 branch <path> create a branch of <path> in this directory
81 81 checkout [changeset] checkout the latest or given changeset
82 82 commit commit all changes to the repository
83 83 diff [files...] diff working directory (or selected files)
84 84 dump <file> [rev] dump the latest or given revision of a file
85 85 dumpmanifest [rev] dump the latest or given revision of the manifest
86 86 export <rev> dump the changeset header and diffs for a revision
87 87 history show changeset history
88 88 init create a new repository in this directory
89 89 log <file> show revision history of a single file
90 90 merge <path> merge changes from <path> into local repository
91 91 recover rollback an interrupted transaction
92 92 remove [files...] remove the given files in the next commit
93 93 serve export the repository via HTTP
94 94 status show new, missing, and changed files in working dir
95 95 tags show current changeset tags
96 96 undo undo the last transaction
97 97 """)
98 98
99 99 def add(ui, repo, file, *files):
100 100 '''add the specified files on the next commit'''
101 101 repo.add(relpath(repo, (file,) + files))
102 102
103 103 def addremove(ui, repo):
104 104 (c, a, d, u) = repo.diffdir(repo.root)
105 105 repo.add(a)
106 106 repo.remove(d)
107 107
108 108 def annotate(u, repo, file, *files, **ops):
109 109 def getnode(rev):
110 110 return hg.short(repo.changelog.node(rev))
111 111
112 112 def getname(rev):
113 113 try:
114 114 return bcache[rev]
115 115 except KeyError:
116 116 cl = repo.changelog.read(repo.changelog.node(rev))
117 117 name = cl[1]
118 118 f = name.find('@')
119 119 if f >= 0:
120 120 name = name[:f]
121 121 bcache[rev] = name
122 122 return name
123 123
124 124 bcache = {}
125 125 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
126 126 if not ops['user'] and not ops['changeset']:
127 127 ops['number'] = 1
128 128
129 129 node = repo.dirstate.parents()[0]
130 130 if ops['revision']:
131 131 node = repo.changelog.lookup(ops['revision'])
132 132 change = repo.changelog.read(node)
133 133 mmap = repo.manifest.read(change[0])
134 134 maxuserlen = 0
135 135 maxchangelen = 0
136 136 for f in relpath(repo, (file,) + files):
137 137 lines = repo.file(f).annotate(mmap[f])
138 138 pieces = []
139 139
140 140 for o, f in opmap:
141 141 if ops[o]:
142 142 l = [ f(n) for n,t in lines ]
143 143 m = max(map(len, l))
144 144 pieces.append([ "%*s" % (m, x) for x in l])
145 145
146 146 for p,l in zip(zip(*pieces), lines):
147 147 u.write(" ".join(p) + ": " + l[1])
148 148
149 149 def branch(ui, path):
150 150 '''branch from a local repository'''
151 151 # this should eventually support remote repos
152 152 os.system("cp -al %s/.hg .hg" % path)
153 153
154 154 def checkout(ui, repo, changeset=None):
155 155 '''checkout a given changeset or the current tip'''
156 156 (c, a, d, u) = repo.diffdir(repo.root)
157 157 if c or a or d:
158 158 ui.warn("aborting (outstanding changes in working directory)\n")
159 159 sys.exit(1)
160 160
161 161 node = repo.changelog.tip()
162 162 if changeset:
163 163 node = repo.lookup(changeset)
164 164 repo.checkout(node)
165 165
166 166 def commit(ui, repo, *files):
167 167 """commit the specified files or all outstanding changes"""
168 168 repo.commit(relpath(repo, files))
169 169
170 170 def diff(ui, repo, *files, **opts):
171 171 revs = []
172 172 if opts['rev']:
173 173 revs = map(lambda x: repo.lookup(x), opts['rev'])
174 174
175 175 if len(revs) > 2:
176 176 self.ui.warn("too many revisions to diff\n")
177 177 sys.exit(1)
178 178
179 179 if files:
180 180 files = relpath(repo, files)
181 181 else:
182 182 files = relpath(repo, [""])
183 183
184 184 dodiff(repo, files, *revs)
185 185
186 def export(ui, repo, changeset):
187 node = repo.lookup(changeset)
188 prev, other = repo.changelog.parents(node)
189 change = repo.changelog.read(node)
190 print "# HG changeset patch"
191 print "# User %s" % change[1]
192 print "# Node ID %s" % hg.hex(node)
193 print "# Parent %s" % hg.hex(prev)
194 print
195 if other != hg.nullid:
196 print "# Parent %s" % hg.hex(other)
197 print change[4].rstrip()
198 print
199
200 dodiff(repo, None, prev, node)
201
186 202 def forget(ui, repo, file, *files):
187 203 """don't add the specified files on the next commit"""
188 204 repo.forget(relpath(repo, (file,) + files))
189 205
190 206 def heads(ui, repo):
191 207 '''show current repository heads'''
192 208 for n in repo.changelog.heads():
193 209 i = repo.changelog.rev(n)
194 210 changes = repo.changelog.read(n)
195 211 (p1, p2) = repo.changelog.parents(n)
196 212 (h, h1, h2) = map(hg.hex, (n, p1, p2))
197 213 (i1, i2) = map(repo.changelog.rev, (p1, p2))
198 214 print "rev: %4d:%s" % (i, h)
199 215 print "parents: %4d:%s" % (i1, h1)
200 216 if i2: print " %4d:%s" % (i2, h2)
201 217 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
202 218 hg.hex(changes[0]))
203 219 print "user:", changes[1]
204 220 print "date:", time.asctime(
205 221 time.localtime(float(changes[2].split(' ')[0])))
206 222 if ui.verbose: print "files:", " ".join(changes[3])
207 223 print "description:"
208 224 print changes[4]
209 225
226 def history(ui, repo):
227 """show the changelog history"""
228 for i in range(repo.changelog.count()):
229 n = repo.changelog.node(i)
230 changes = repo.changelog.read(n)
231 (p1, p2) = repo.changelog.parents(n)
232 (h, h1, h2) = map(hg.hex, (n, p1, p2))
233 (i1, i2) = map(repo.changelog.rev, (p1, p2))
234 print "rev: %4d:%s" % (i, h)
235 print "parents: %4d:%s" % (i1, h1)
236 if i2: print " %4d:%s" % (i2, h2)
237 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
238 hg.hex(changes[0]))
239 print "user:", changes[1]
240 print "date:", time.asctime(
241 time.localtime(float(changes[2].split(' ')[0])))
242 if ui.verbose: print "files:", " ".join(changes[3])
243 print "description:"
244 print changes[4]
245
246 def patch(ui, repo, patches, opts):
247 """import an ordered set of patches"""
248 try:
249 import psyco
250 psyco.full()
251 except:
252 pass
253
254 d = opts["base"]
255 strip = opts["strip"]
256 quiet = opts["quiet"] and "> /dev/null" or ""
257
258 for patch in patches:
259 ui.status("applying %s\n" % patch)
260 pf = os.path.join(d, patch)
261
262 text = ""
263 for l in file(pf):
264 if l[:4] == "--- ": break
265 text += l
266
267 f = os.popen("lsdiff --strip %d %s" % (strip, pf))
268 files = filter(None, map(lambda x: x.rstrip(), f.read().splitlines()))
269 f.close()
270
271 if files:
272 if os.system("patch -p%d < %s %s" % (strip, pf, quiet)):
273 raise "patch failed!"
274 repo.commit(files, text)
275
210 276 def init(ui):
211 277 """create a repository"""
212 278 hg.repository(ui, ".", create=1)
213 279
214 280 def log(ui, repo, f):
215 281 f = relpath(repo, [f])[0]
216 282
217 283 r = repo.file(f)
218 284 for i in range(r.count()):
219 285 n = r.node(i)
220 286 (p1, p2) = r.parents(n)
221 287 (h, h1, h2) = map(hg.hex, (n, p1, p2))
222 288 (i1, i2) = map(r.rev, (p1, p2))
223 289 cr = r.linkrev(n)
224 290 cn = hg.hex(repo.changelog.node(cr))
225 291 print "rev: %4d:%s" % (i, h)
226 292 print "changeset: %4d:%s" % (cr, cn)
227 293 print "parents: %4d:%s" % (i1, h1)
228 294 if i2: print " %4d:%s" % (i2, h2)
229 295 changes = repo.changelog.read(repo.changelog.node(cr))
230 296 print "user: %s" % changes[1]
231 297 print "date: %s" % time.asctime(
232 298 time.localtime(float(changes[2].split(' ')[0])))
233 299 print "description:"
234 300 print changes[4].rstrip()
235 301 print
236 302
237 303 def parents(ui, repo, node = None):
238 304 '''show the parents of the current working dir'''
239 305 if node:
240 306 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
241 307 else:
242 308 p = repo.dirstate.parents()
243 309
244 310 for n in p:
245 311 if n != hg.nullid:
246 312 ui.write("%d:%s\n" % (repo.changelog.rev(n), hg.hex(n)))
247 313
314 def pull(ui, repo, source):
315 """pull changes from the specified source"""
316 paths = {}
317 try:
318 pf = os.path.expanduser("~/.hgpaths")
319 for l in file(pf):
320 name, path = l.split()
321 paths[name] = path
322 except IOError:
323 pass
324
325 if source in paths: source = paths[source]
326
327 other = hg.repository(ui, source)
328 cg = repo.getchangegroup(other)
329 repo.addchangegroup(cg)
330
331 def rawcommit(ui, repo, files, rc):
332 "raw commit interface"
333
334 text = rc['text']
335 if not text and rc['logfile']:
336 try: text = open(rc['logfile']).read()
337 except IOError: pass
338 if not text and not rc['logfile']:
339 print "missing commit text"
340 return 1
341
342 files = relpath(repo, files)
343 if rc['files']:
344 files += open(rc['files']).read().splitlines()
345
346 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
347
248 348 def recover(ui, repo):
249 349 repo.recover()
250 350
251 351 def remove(ui, repo, file, *files):
252 352 """remove the specified files on the next commit"""
253 353 repo.remove(relpath(repo, (file,) + files))
254 354
255 355 def resolve(ui, repo, node=None):
256 356 '''merge a given node or the current tip into the working dir'''
257 357 if not node:
258 358 node = repo.changelog.tip()
259 359 else:
260 360 node = repo.lookup(node)
261 361 repo.resolve(node)
262 362
263 363 def serve(ui, repo, **opts):
264 364 from mercurial import hgweb
265 365 hgweb.server(repo.root, opts["name"], opts["templates"],
266 366 opts["address"], opts["port"])
267 367
268 368 def status(ui, repo):
269 369 '''show changed files in the working directory
270 370
271 371 C = changed
272 372 A = added
273 373 R = removed
274 374 ? = not tracked'''
275 375
276 376 (c, a, d, u) = repo.diffdir(repo.root)
277 377 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
278 378
279 379 for f in c: print "C", f
280 380 for f in a: print "A", f
281 381 for f in d: print "R", f
282 382 for f in u: print "?", f
283 383
284 384 def tip(ui, repo):
285 385 n = repo.changelog.tip()
286 386 t = repo.changelog.rev(n)
287 387 ui.status("%d:%s\n" % (t, hg.hex(n)))
288 388
289 389 def undo(ui, repo):
290 390 repo.undo()
291 391
292 392 table = {
293 393 "add": (add, [], "hg add [files]"),
294 394 "addremove": (addremove, [], "hg addremove"),
295 395 "ann|annotate": (annotate,
296 396 [('r', 'revision', '', 'revision'),
297 397 ('u', 'user', None, 'show user'),
298 398 ('n', 'number', None, 'show revision number'),
299 399 ('c', 'changeset', None, 'show changeset')],
300 400 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
301 401 "branch|clone": (branch, [], 'hg branch [path]'),
302 402 "checkout|co": (checkout, [], 'hg checkout [changeset]'),
303 403 "commit|ci": (commit, [], 'hg commit [files]'),
304 404 "diff": (diff, [('r', 'rev', [], 'revision')],
305 405 'hg diff [-r A] [-r B] [files]'),
406 "export": (export, [], "hg export <changeset>"),
306 407 "forget": (forget, [], "hg forget [files]"),
307 408 "heads": (heads, [], 'hg heads'),
409 "history": (history, [], 'hg history'),
308 410 "help": (help, [], 'hg help [command]'),
309 411 "init": (init, [], 'hg init'),
310 412 "log": (log, [], 'hg log <file>'),
311 413 "parents": (parents, [], 'hg parents [node]'),
414 "patch|import": (patch,
415 [('p', 'strip', 1, 'path strip'),
416 ('b', 'base', "", 'base path'),
417 ('q', 'quiet', "", 'silence diff')],
418 "hg import [options] patches"),
419 "pull|merge": (pull, [], 'hg pull [source]'),
420 "rawcommit": (rawcommit,
421 [('p', 'parent', [], 'parent'),
422 ('d', 'date', "", 'data'),
423 ('u', 'user', "", 'user'),
424 ('F', 'files', "", 'file list'),
425 ('t', 'text', "", 'commit text'),
426 ('l', 'logfile', "", 'commit text file')],
427 'hg rawcommit [options] [files]'),
312 428 "recover": (recover, [], "hg recover"),
313 429 "remove": (remove, [], "hg remove [files]"),
314 430 "resolve": (resolve, [], 'hg resolve [node]'),
315 431 "serve": (serve, [('p', 'port', 8000, 'listen port'),
316 432 ('a', 'address', '', 'interface address'),
317 433 ('n', 'name', os.getcwd(), 'repository name'),
318 434 ('t', 'templates', "", 'template map')],
319 435 "hg serve [options]"),
320 436 "status": (status, [], 'hg status'),
321 437 "tip": (tip, [], 'hg tip'),
322 438 "undo": (undo, [], 'hg undo'),
323 439 }
324 440
325 441 norepo = "init branch help"
326 442
327 443 def find(cmd):
328 444 i = None
329 445 for e in table.keys():
330 446 if re.match(e + "$", cmd):
331 447 return table[e]
332 448
333 449 raise UnknownCommand(cmd)
334 450
335 451 class SignalInterrupt(Exception): pass
336 452
337 453 def catchterm(*args):
338 454 raise SignalInterrupt
339 455
340 456 def dispatch(args):
341 457 options = {}
342 458 opts = [('v', 'verbose', None, 'verbose'),
343 459 ('d', 'debug', None, 'debug'),
344 460 ('q', 'quiet', None, 'quiet'),
345 461 ('y', 'noninteractive', None, 'run non-interactively'),
346 462 ]
347 463
348 464 args = fancyopts.fancyopts(args, opts, options,
349 465 'hg [options] <command> [options] [files]')
350 466
351 467 if not args:
352 468 cmd = "help"
353 469 else:
354 470 cmd, args = args[0], args[1:]
355 471
356 472 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
357 473 not options["noninteractive"])
358 474
359 475 # deal with unfound commands later
360 476 i = find(cmd)
361 477
362 478 signal.signal(signal.SIGTERM, catchterm)
363 479
364 480 cmdoptions = {}
365 481 args = fancyopts.fancyopts(args, i[1], cmdoptions, i[2])
366 482
367 483 if cmd not in norepo.split():
368 484 repo = hg.repository(ui = u)
369 485 d = lambda: i[0](u, repo, *args, **cmdoptions)
370 486 else:
371 487 d = lambda: i[0](u, *args, **cmdoptions)
372 488
373 489 try:
374 d()
490 return d()
375 491 except SignalInterrupt:
376 492 u.warn("killed!\n")
377 493 except KeyboardInterrupt:
378 494 u.warn("interrupted!\n")
379 495 except TypeError, inst:
380 496 # was this an argument error?
381 497 tb = traceback.extract_tb(sys.exc_info()[2])
382 498 if len(tb) > 2: # no
383 499 raise
384 500 u.warn("%s: invalid arguments\n" % i[0].__name__)
385 501 u.warn("syntax: %s\n" % i[2])
386 502 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now