comparison hg @ 0:9117c6561b0b

Add back links from file revisions to changeset revisions Add simple transaction support Add hg verify Improve caching in revlog Fix a bunch of bugs Self-hosting now that the metadata is close to finalized
author mpm@selenic.com
date Tue, 03 May 2005 13:16:10 -0800
parents
children 5f249577ac40
comparison
equal deleted inserted replaced
-1:000000000000 0:9117c6561b0b
1 #!/usr/bin/env python
2 #
3 # mercurial - a minimal scalable distributed SCM
4 # v0.4c "oedipa maas"
5 #
6 # Copyright 2005 Matt Mackall <mpm@selenic.com>
7 #
8 # This software may be used and distributed according to the terms
9 # of the GNU General Public License, incorporated herein by reference.
10
11 # the psyco compiler makes commits about twice as fast
12 try:
13 import psyco
14 psyco.full()
15 except:
16 pass
17
18 import sys, os
19 from mercurial import hg, mdiff, fancyopts
20
21 options = {}
22 opts = [('v', 'verbose', None, 'verbose'),
23 ('d', 'debug', None, 'debug')]
24
25 args = fancyopts.fancyopts(sys.argv[1:], opts, options,
26 'hg [options] <command> [command options] [files]')
27
28 try:
29 cmd = args[0]
30 args = args[1:]
31 except:
32 cmd = ""
33
34 ui = hg.ui(options["verbose"], options["debug"])
35
36 if cmd == "init":
37 repo = hg.repository(ui, ".", create=1)
38 sys.exit(0)
39 elif cmd == "branch" or cmd == "clone":
40 os.system("cp -al %s/.hg .hg" % args[0])
41 sys.exit(0)
42 else:
43 repo = hg.repository(ui=ui)
44
45 if cmd == "checkout" or cmd == "co":
46 node = repo.changelog.tip()
47 if len(args): rev = int(args[0])
48 repo.checkout(node)
49
50 elif cmd == "add":
51 repo.add(args)
52
53 elif cmd == "remove" or cmd == "rm" or cmd == "del" or cmd == "delete":
54 repo.remove(args)
55
56 elif cmd == "commit" or cmd == "checkin" or cmd == "ci":
57 if 1:
58 if len(args) > 0:
59 repo.commit(args)
60 else:
61 repo.commit()
62
63 elif cmd == "import" or cmd == "patch":
64 ioptions = {}
65 opts = [('p', 'strip', 1, 'path strip'),
66 ('b', 'base', "", 'base path')]
67
68 args = fancyopts.fancyopts(args, opts, ioptions,
69 'hg import [options] <patch names>')
70 d = ioptions["base"]
71 strip = ioptions["strip"]
72
73 for patch in args:
74 ui.status("applying %s\n" % patch)
75 pf = d + patch
76 os.system("patch -p%d < %s > /dev/null" % (strip, pf))
77 f = os.popen("lsdiff --strip %d %s" % (strip, pf))
78 files = f.read().splitlines()
79 f.close()
80 repo.commit(files)
81
82 elif cmd == "status":
83 (c, a, d) = repo.diffdir(repo.root)
84 for f in c: print "C", f
85 for f in a: print "?", f
86 for f in d: print "R", f
87
88 elif cmd == "diff":
89 mmap = {}
90 if repo.current:
91 change = repo.changelog.read(repo.current)
92 mmap = repo.manifest.read(change[0])
93
94 (c, a, d) = repo.diffdir(repo.root)
95 for f in c:
96 to = repo.file(f).read(mmap[f])
97 tn = file(f).read()
98 sys.stdout.write(mdiff.unidiff(to, tn, f))
99 for f in a:
100 to = ""
101 tn = file(f).read()
102 sys.stdout.write(mdiff.unidiff(to, tn, f))
103 for f in d:
104 to = repo.file(f).read(mmap[f])
105 tn = ""
106 sys.stdout.write(mdiff.unidiff(to, tn, f))
107
108 elif cmd == "addremove":
109 (c, a, d) = repo.diffdir(repo.root)
110 repo.add(a)
111 repo.remove(d)
112
113 elif cmd == "history":
114 for i in range(repo.changelog.count()):
115 n = repo.changelog.node(i)
116 changes = repo.changelog.read(n)
117 (p1, p2) = repo.changelog.parents(n)
118 (h, h1, h2) = map(hg.hex, (n, p1, p2))
119 (i1, i2) = map(repo.changelog.rev, (p1, p2))
120 print "rev: %4d:%s" % (i, h)
121 print "parents: %4d:%s" % (i1, h1)
122 if i2: print " %4d:%s" % (i2, h2)
123 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
124 hg.hex(changes[0]))
125 print "user:", changes[1]
126 print "files:", len(changes[3])
127 print "description:"
128 print changes[4]
129
130 elif cmd == "log":
131 if args:
132 r = repo.file(args[0])
133 for i in range(r.count()):
134 n = r.node(i)
135 (p1, p2) = r.parents(n)
136 (h, h1, h2) = map(hg.hex, (n, p1, p2))
137 (i1, i2) = map(r.rev, (p1, p2))
138 cr = r.linkrev(n)
139 cn = hg.hex(repo.changelog.node(cr))
140 print "rev: %4d:%s" % (i, h)
141 print "changeset: %4d:%s" % (cr, cn)
142 print "parents: %4d:%s" % (i1, h1)
143 if i2: print " %4d:%s" % (i2, h2)
144 else:
145 print "missing filename"
146
147 elif cmd == "dump":
148 if args:
149 r = repo.file(args[0])
150 n = r.tip()
151 if len(args) > 1: n = hg.bin(args[1])
152 sys.stdout.write(r.read(n))
153 else:
154 print "missing filename"
155
156 elif cmd == "dumpmanifest":
157 n = repo.manifest.tip()
158 if len(args) > 0:
159 n = hg.bin(args[0])
160 m = repo.manifest.read(n)
161 files = m.keys()
162 files.sort()
163
164 for f in files:
165 print hg.hex(m[f]), f
166
167 elif cmd == "merge":
168 if args:
169 other = hg.repository(ui, args[0])
170 repo.merge(other)
171 else:
172 print "missing source repository"
173
174 elif cmd == "verify":
175 filelinkrevs = {}
176 filenodes = {}
177 manifestchangeset = {}
178 changesets = revisions = files = 0
179
180 print "checking changesets"
181 for i in range(repo.changelog.count()):
182 changesets += 1
183 n = repo.changelog.node(i)
184 changes = repo.changelog.read(n)
185 manifestchangeset[changes[0]] = n
186 for f in changes[3]:
187 revisions += 1
188 filelinkrevs.setdefault(f, []).append(i)
189
190 print "checking manifests"
191 for i in range(repo.manifest.count()):
192 n = repo.manifest.node(i)
193 ca = repo.changelog.node(repo.manifest.linkrev(n))
194 cc = manifestchangeset[n]
195 if ca != cc:
196 print "manifest %s points to %s, not %s" % \
197 (hg.hex(n), hg.hex(ca), hg.hex(cc))
198 m = repo.manifest.read(n)
199 for f, fn in m.items():
200 filenodes.setdefault(f, {})[fn] = 1
201
202 print "crosschecking files in changesets and manifests"
203 for f in filenodes:
204 if f not in filelinkrevs:
205 print "file %s in manifest but not in changesets"
206
207 for f in filelinkrevs:
208 if f not in filenodes:
209 print "file %s in changeset but not in manifest"
210
211 print "checking files"
212 for f in filenodes:
213 files += 1
214 fl = repo.file(f)
215 nodes = {"\0"*20: 1}
216 for i in range(fl.count()):
217 n = fl.node(i)
218 if n not in filenodes[f]:
219 print "%s:%s not in manifests" % (f, hg.hex(n))
220 if fl.linkrev(n) not in filelinkrevs[f]:
221 print "%s:%s points to unknown changeset %s" \
222 % (f, hg.hex(n), hg.hex(fl.changeset(n)))
223 t = fl.read(n)
224 (p1, p2) = fl.parents(n)
225 if p1 not in nodes:
226 print "%s:%s unknown parent 1 %s" % (f, hg.hex(n), hg.hex(p1))
227 if p2 not in nodes:
228 print "file %s:%s unknown parent %s" % (f, hg.hex(n), hg.hex(p1))
229
230 nodes[n] = 1
231
232 print "%d files, %d changesets, %d total revisions" % (files, changesets,
233 revisions)
234
235 else:
236 print """\
237 unknown command
238
239 commands:
240
241 init create a new repository in this directory
242 branch <path> create a branch of <path> in this directory
243 merge <path> merge changes from <path> into local repository
244 checkout [changeset] checkout the latest or given changeset
245 status show new, missing, and changed files in working dir
246 add [files...] add the given files in the next commit
247 remove [files...] remove the given files in the next commit
248 addremove add all new files, delete all missing files
249 commit commit all changes to the repository
250 history show changeset history
251 log <file> show revision history of a single file
252 dump <file> [rev] dump the latest or given revision of a file
253 dumpmanifest [rev] dump the latest or given revision of the manifest
254 """
255 sys.exit(1)