Mercurial > hg > mercurial-crew
annotate mercurial/localrepo.py @ 1460:40d08cf1c544
Bug fixing in localrepository.changegroupsubset. Bugs found in testing.
author | Eric Hopper <hopper@omnifarious.org> |
---|---|
date | Fri, 07 Oct 2005 19:49:25 -0700 (2005-10-08) |
parents | 1033892bbb87 |
children | 02099220ad49 |
rev | line source |
---|---|
1089 | 1 # localrepo.py - read/write repository class for mercurial |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
2 # |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
3 # Copyright 2005 Matt Mackall <mpm@selenic.com> |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
4 # |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
5 # This software may be used and distributed according to the terms |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
6 # of the GNU General Public License, incorporated herein by reference. |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
7 |
1097
1f89ccbab6ce
localrepo: adjust some imports, remove sys dependency
mpm@selenic.com
parents:
1089
diff
changeset
|
8 import struct, os, util |
1100 | 9 import filelog, manifest, changelog, dirstate, repo |
10 from node import * | |
262 | 11 from demandload import * |
1353
a0c68981a5f4
Fix misleading abort message when permissions are bad.
Eric Hopper <hopper@omnifarious.org>
parents:
1349
diff
changeset
|
12 demandload(globals(), "re lock transaction tempfile stat mdiff errno") |
499 | 13 |
60 | 14 class localrepository: |
1102
c81d264cd17d
localrepo: minor opener usage restructuring
mpm@selenic.com
parents:
1101
diff
changeset
|
15 def __init__(self, ui, path=None, create=0): |
1101 | 16 if not path: |
17 p = os.getcwd() | |
18 while not os.path.isdir(os.path.join(p, ".hg")): | |
19 oldp = p | |
20 p = os.path.dirname(p) | |
21 if p == oldp: raise repo.RepoError("no repo found") | |
22 path = p | |
23 self.path = os.path.join(path, ".hg") | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
24 |
1101 | 25 if not create and not os.path.isdir(self.path): |
26 raise repo.RepoError("repository %s not found" % self.path) | |
405 | 27 |
933
9c43d68ad59f
Fixed --repository option when handling relative path
tksoh@users.sf.net
parents:
926
diff
changeset
|
28 self.root = os.path.abspath(path) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
29 self.ui = ui |
1102
c81d264cd17d
localrepo: minor opener usage restructuring
mpm@selenic.com
parents:
1101
diff
changeset
|
30 self.opener = util.opener(self.path) |
c81d264cd17d
localrepo: minor opener usage restructuring
mpm@selenic.com
parents:
1101
diff
changeset
|
31 self.wopener = util.opener(self.root) |
1100 | 32 self.manifest = manifest.manifest(self.opener) |
33 self.changelog = changelog.changelog(self.opener) | |
343 | 34 self.tagscache = None |
35 self.nodetagscache = None | |
1258 | 36 self.encodepats = None |
37 self.decodepats = None | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
38 |
1133
899b619a7eb2
Create [web] section with short username as contact on hg init and hg clone.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1117
diff
changeset
|
39 if create: |
899b619a7eb2
Create [web] section with short username as contact on hg init and hg clone.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1117
diff
changeset
|
40 os.mkdir(self.path) |
899b619a7eb2
Create [web] section with short username as contact on hg init and hg clone.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1117
diff
changeset
|
41 os.mkdir(self.join("data")) |
899b619a7eb2
Create [web] section with short username as contact on hg init and hg clone.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1117
diff
changeset
|
42 |
1101 | 43 self.dirstate = dirstate.dirstate(self.opener, ui, self.root) |
44 try: | |
45 self.ui.readconfig(self.opener("hgrc")) | |
46 except IOError: pass | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
47 |
487 | 48 def hook(self, name, **args): |
49 s = self.ui.config("hooks", name) | |
50 if s: | |
51 self.ui.note("running hook %s: %s\n" % (name, s)) | |
52 old = {} | |
53 for k, v in args.items(): | |
54 k = k.upper() | |
55 old[k] = os.environ.get(k, None) | |
56 os.environ[k] = v | |
57 | |
1346 | 58 # Hooks run in the repository root |
59 olddir = os.getcwd() | |
60 os.chdir(self.root) | |
487 | 61 r = os.system(s) |
1346 | 62 os.chdir(olddir) |
487 | 63 |
64 for k, v in old.items(): | |
65 if v != None: | |
66 os.environ[k] = v | |
67 else: | |
68 del os.environ[k] | |
69 | |
70 if r: | |
71 self.ui.warn("abort: %s hook failed with status %d!\n" % | |
72 (name, r)) | |
73 return False | |
74 return True | |
75 | |
343 | 76 def tags(self): |
77 '''return a mapping of tag to node''' | |
477
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
78 if not self.tagscache: |
343 | 79 self.tagscache = {} |
609
2acf1f5df2e6
[PATCH] hg tag: local tag support in file .hg/localtags
Matt Mackall <mpm@selenic.com>
parents:
608
diff
changeset
|
80 def addtag(self, k, n): |
2acf1f5df2e6
[PATCH] hg tag: local tag support in file .hg/localtags
Matt Mackall <mpm@selenic.com>
parents:
608
diff
changeset
|
81 try: |
2acf1f5df2e6
[PATCH] hg tag: local tag support in file .hg/localtags
Matt Mackall <mpm@selenic.com>
parents:
608
diff
changeset
|
82 bin_n = bin(n) |
2acf1f5df2e6
[PATCH] hg tag: local tag support in file .hg/localtags
Matt Mackall <mpm@selenic.com>
parents:
608
diff
changeset
|
83 except TypeError: |
2acf1f5df2e6
[PATCH] hg tag: local tag support in file .hg/localtags
Matt Mackall <mpm@selenic.com>
parents:
608
diff
changeset
|
84 bin_n = '' |
2acf1f5df2e6
[PATCH] hg tag: local tag support in file .hg/localtags
Matt Mackall <mpm@selenic.com>
parents:
608
diff
changeset
|
85 self.tagscache[k.strip()] = bin_n |
659 | 86 |
67 | 87 try: |
254 | 88 # read each head of the tags file, ending with the tip |
89 # and add each tag found to the map, with "newer" ones | |
90 # taking precedence | |
67 | 91 fl = self.file(".hgtags") |
254 | 92 h = fl.heads() |
93 h.reverse() | |
94 for r in h: | |
994
88c15682d9b0
Fix callers to file.revision to use file.read
mpm@selenic.com
parents:
993
diff
changeset
|
95 for l in fl.read(r).splitlines(): |
254 | 96 if l: |
385
e9e1efd5291c
Fixed problems with extra spaces around tags in .hgtags
Thomas Arendsen Hein <thomas@intevation.de>
parents:
383
diff
changeset
|
97 n, k = l.split(" ", 1) |
609
2acf1f5df2e6
[PATCH] hg tag: local tag support in file .hg/localtags
Matt Mackall <mpm@selenic.com>
parents:
608
diff
changeset
|
98 addtag(self, k, n) |
477
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
99 except KeyError: |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
100 pass |
659 | 101 |
609
2acf1f5df2e6
[PATCH] hg tag: local tag support in file .hg/localtags
Matt Mackall <mpm@selenic.com>
parents:
608
diff
changeset
|
102 try: |
2acf1f5df2e6
[PATCH] hg tag: local tag support in file .hg/localtags
Matt Mackall <mpm@selenic.com>
parents:
608
diff
changeset
|
103 f = self.opener("localtags") |
2acf1f5df2e6
[PATCH] hg tag: local tag support in file .hg/localtags
Matt Mackall <mpm@selenic.com>
parents:
608
diff
changeset
|
104 for l in f: |
2acf1f5df2e6
[PATCH] hg tag: local tag support in file .hg/localtags
Matt Mackall <mpm@selenic.com>
parents:
608
diff
changeset
|
105 n, k = l.split(" ", 1) |
2acf1f5df2e6
[PATCH] hg tag: local tag support in file .hg/localtags
Matt Mackall <mpm@selenic.com>
parents:
608
diff
changeset
|
106 addtag(self, k, n) |
2acf1f5df2e6
[PATCH] hg tag: local tag support in file .hg/localtags
Matt Mackall <mpm@selenic.com>
parents:
608
diff
changeset
|
107 except IOError: |
2acf1f5df2e6
[PATCH] hg tag: local tag support in file .hg/localtags
Matt Mackall <mpm@selenic.com>
parents:
608
diff
changeset
|
108 pass |
659 | 109 |
343 | 110 self.tagscache['tip'] = self.changelog.tip() |
659 | 111 |
343 | 112 return self.tagscache |
113 | |
114 def tagslist(self): | |
115 '''return a list of tags ordered by revision''' | |
116 l = [] | |
477
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
117 for t, n in self.tags().items(): |
343 | 118 try: |
119 r = self.changelog.rev(n) | |
120 except: | |
121 r = -2 # sort to the beginning of the list if unknown | |
122 l.append((r,t,n)) | |
123 l.sort() | |
124 return [(t,n) for r,t,n in l] | |
125 | |
126 def nodetags(self, node): | |
127 '''return the tags associated with a node''' | |
128 if not self.nodetagscache: | |
129 self.nodetagscache = {} | |
130 for t,n in self.tags().items(): | |
131 self.nodetagscache.setdefault(n,[]).append(t) | |
132 return self.nodetagscache.get(node, []) | |
133 | |
134 def lookup(self, key): | |
67 | 135 try: |
343 | 136 return self.tags()[key] |
67 | 137 except KeyError: |
658
f8098ae9f5b6
Generate a friendlier except for failed lookups
Matt Mackall <mpm@selenic.com>
parents:
657
diff
changeset
|
138 try: |
f8098ae9f5b6
Generate a friendlier except for failed lookups
Matt Mackall <mpm@selenic.com>
parents:
657
diff
changeset
|
139 return self.changelog.lookup(key) |
f8098ae9f5b6
Generate a friendlier except for failed lookups
Matt Mackall <mpm@selenic.com>
parents:
657
diff
changeset
|
140 except: |
1100 | 141 raise repo.RepoError("unknown revision '%s'" % key) |
67 | 142 |
634
da5378d39269
Add a repo method to report repo device
Matt Mackall <mpm@selenic.com>
parents:
627
diff
changeset
|
143 def dev(self): |
da5378d39269
Add a repo method to report repo device
Matt Mackall <mpm@selenic.com>
parents:
627
diff
changeset
|
144 return os.stat(self.path).st_dev |
da5378d39269
Add a repo method to report repo device
Matt Mackall <mpm@selenic.com>
parents:
627
diff
changeset
|
145 |
926 | 146 def local(self): |
1101 | 147 return True |
926 | 148 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
149 def join(self, f): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
150 return os.path.join(self.path, f) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
151 |
244 | 152 def wjoin(self, f): |
153 return os.path.join(self.root, f) | |
154 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
155 def file(self, f): |
192 | 156 if f[0] == '/': f = f[1:] |
1100 | 157 return filelog.filelog(self.opener, f) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
158 |
627 | 159 def getcwd(self): |
870
a82eae840447
Teach walk code about absolute paths.
Bryan O'Sullivan <bos@serpentine.com>
parents:
839
diff
changeset
|
160 return self.dirstate.getcwd() |
627 | 161 |
291
2c4f2be05587
Add wopener for opening files in the working directory
mpm@selenic.com
parents:
288
diff
changeset
|
162 def wfile(self, f, mode='r'): |
2c4f2be05587
Add wopener for opening files in the working directory
mpm@selenic.com
parents:
288
diff
changeset
|
163 return self.wopener(f, mode) |
2c4f2be05587
Add wopener for opening files in the working directory
mpm@selenic.com
parents:
288
diff
changeset
|
164 |
1019
a9cca981c423
Create helper functions for I/O to files in the working directory
mpm@selenic.com
parents:
1013
diff
changeset
|
165 def wread(self, filename): |
1258 | 166 if self.encodepats == None: |
167 l = [] | |
168 for pat, cmd in self.ui.configitems("encode"): | |
169 mf = util.matcher("", "/", [pat], [], [])[1] | |
170 l.append((mf, cmd)) | |
171 self.encodepats = l | |
172 | |
173 data = self.wopener(filename, 'r').read() | |
174 | |
175 for mf, cmd in self.encodepats: | |
176 if mf(filename): | |
177 self.ui.debug("filtering %s through %s\n" % (filename, cmd)) | |
178 data = util.filter(data, cmd) | |
179 break | |
180 | |
181 return data | |
1019
a9cca981c423
Create helper functions for I/O to files in the working directory
mpm@selenic.com
parents:
1013
diff
changeset
|
182 |
a9cca981c423
Create helper functions for I/O to files in the working directory
mpm@selenic.com
parents:
1013
diff
changeset
|
183 def wwrite(self, filename, data, fd=None): |
1258 | 184 if self.decodepats == None: |
185 l = [] | |
186 for pat, cmd in self.ui.configitems("decode"): | |
187 mf = util.matcher("", "/", [pat], [], [])[1] | |
188 l.append((mf, cmd)) | |
189 self.decodepats = l | |
190 | |
191 for mf, cmd in self.decodepats: | |
192 if mf(filename): | |
193 self.ui.debug("filtering %s through %s\n" % (filename, cmd)) | |
194 data = util.filter(data, cmd) | |
195 break | |
196 | |
1019
a9cca981c423
Create helper functions for I/O to files in the working directory
mpm@selenic.com
parents:
1013
diff
changeset
|
197 if fd: |
a9cca981c423
Create helper functions for I/O to files in the working directory
mpm@selenic.com
parents:
1013
diff
changeset
|
198 return fd.write(data) |
a9cca981c423
Create helper functions for I/O to files in the working directory
mpm@selenic.com
parents:
1013
diff
changeset
|
199 return self.wopener(filename, 'w').write(data) |
a9cca981c423
Create helper functions for I/O to files in the working directory
mpm@selenic.com
parents:
1013
diff
changeset
|
200 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
201 def transaction(self): |
251 | 202 # save dirstate for undo |
263 | 203 try: |
204 ds = self.opener("dirstate").read() | |
205 except IOError: | |
206 ds = "" | |
785 | 207 self.opener("journal.dirstate", "w").write(ds) |
515 | 208 |
785 | 209 def after(): |
210 util.rename(self.join("journal"), self.join("undo")) | |
211 util.rename(self.join("journal.dirstate"), | |
212 self.join("undo.dirstate")) | |
213 | |
214 return transaction.transaction(self.ui.warn, self.opener, | |
215 self.join("journal"), after) | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
216 |
210 | 217 def recover(self): |
225 | 218 lock = self.lock() |
557 | 219 if os.path.exists(self.join("journal")): |
501 | 220 self.ui.status("rolling back interrupted transaction\n") |
557 | 221 return transaction.rollback(self.opener, self.join("journal")) |
210 | 222 else: |
223 self.ui.warn("no interrupted transaction available\n") | |
224 | |
225 def undo(self): | |
225 | 226 lock = self.lock() |
210 | 227 if os.path.exists(self.join("undo")): |
501 | 228 self.ui.status("rolling back last transaction\n") |
262 | 229 transaction.rollback(self.opener, self.join("undo")) |
251 | 230 self.dirstate = None |
421 | 231 util.rename(self.join("undo.dirstate"), self.join("dirstate")) |
1100 | 232 self.dirstate = dirstate.dirstate(self.opener, self.ui, self.root) |
163 | 233 else: |
210 | 234 self.ui.warn("no undo information available\n") |
162 | 235 |
1062 | 236 def lock(self, wait=1): |
161 | 237 try: |
238 return lock.lock(self.join("lock"), 0) | |
239 except lock.LockHeld, inst: | |
240 if wait: | |
241 self.ui.warn("waiting for lock held by %s\n" % inst.args[0]) | |
242 return lock.lock(self.join("lock"), wait) | |
243 raise inst | |
244 | |
203 | 245 def rawcommit(self, files, text, user, date, p1=None, p2=None): |
442 | 246 orig_parent = self.dirstate.parents()[0] or nullid |
452
a1e91c24dab5
rawcommit: do lookup of parents at the appropriate layer
mpm@selenic.com
parents:
442
diff
changeset
|
247 p1 = p1 or self.dirstate.parents()[0] or nullid |
a1e91c24dab5
rawcommit: do lookup of parents at the appropriate layer
mpm@selenic.com
parents:
442
diff
changeset
|
248 p2 = p2 or self.dirstate.parents()[1] or nullid |
302 | 249 c1 = self.changelog.read(p1) |
250 c2 = self.changelog.read(p2) | |
251 m1 = self.manifest.read(c1[0]) | |
252 mf1 = self.manifest.readflags(c1[0]) | |
253 m2 = self.manifest.read(c2[0]) | |
992
f859e9cba1b9
Fix up some bugs introduced by recent merge changes
mpm@selenic.com
parents:
991
diff
changeset
|
254 changed = [] |
302 | 255 |
442 | 256 if orig_parent == p1: |
257 update_dirstate = 1 | |
258 else: | |
259 update_dirstate = 0 | |
260 | |
203 | 261 tr = self.transaction() |
302 | 262 mm = m1.copy() |
263 mfm = mf1.copy() | |
203 | 264 linkrev = self.changelog.count() |
265 for f in files: | |
266 try: | |
1019
a9cca981c423
Create helper functions for I/O to files in the working directory
mpm@selenic.com
parents:
1013
diff
changeset
|
267 t = self.wread(f) |
441 | 268 tm = util.is_exec(self.wjoin(f), mfm.get(f, False)) |
302 | 269 r = self.file(f) |
270 mfm[f] = tm | |
990 | 271 |
272 fp1 = m1.get(f, nullid) | |
273 fp2 = m2.get(f, nullid) | |
274 | |
275 # is the same revision on two branches of a merge? | |
276 if fp2 == fp1: | |
277 fp2 = nullid | |
278 | |
279 if fp2 != nullid: | |
280 # is one parent an ancestor of the other? | |
281 fpa = r.ancestor(fp1, fp2) | |
282 if fpa == fp1: | |
283 fp1, fp2 = fp2, nullid | |
284 elif fpa == fp2: | |
285 fp2 = nullid | |
286 | |
287 # is the file unmodified from the parent? | |
288 if t == r.read(fp1): | |
289 # record the proper existing parent in manifest | |
290 # no need to add a revision | |
291 mm[f] = fp1 | |
292 continue | |
293 | |
294 mm[f] = r.add(t, {}, tr, linkrev, fp1, fp2) | |
992
f859e9cba1b9
Fix up some bugs introduced by recent merge changes
mpm@selenic.com
parents:
991
diff
changeset
|
295 changed.append(f) |
442 | 296 if update_dirstate: |
297 self.dirstate.update([f], "n") | |
203
0b486b5e0796
hg rawcommit command |