Mercurial > hg > mercurial-crew-with-dirclash
comparison mercurial/hg.py @ 220:3113a94c1bff
change dircache into dirstate
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
change dircache into dirstate
The dircache now tracks adds and removes directly
diffdir now makes a proper distinction between added and unknown files
Add a forget command to unadd files
Undo tries to fix up the state of just the files in the undone commit
Add and remove complain about files that are not in a proper state of
existence
manifest hash: ca0cd6abc5e119670acf11a54fefa2bc986eadf3
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.0 (GNU/Linux)
iD8DBQFCn7TRywK+sNU5EO8RAhnSAKC2oHg1HJOCGsvpUYj4SBEq0HmuJQCgr5gl
jEBTs5AFD5IhF73YAgrcnkE=
=prQA
-----END PGP SIGNATURE-----
author | mpm@selenic.com |
---|---|
date | Thu, 02 Jun 2005 17:39:29 -0800 |
parents | e6d6497a6331 |
children | 87484f627422 |
comparison
equal
deleted
inserted
replaced
219:8ff4532376a4 | 220:3113a94c1bff |
---|---|
147 list.sort() | 147 list.sort() |
148 l = [hex(manifest), user, date] + list + ["", desc] | 148 l = [hex(manifest), user, date] + list + ["", desc] |
149 text = "\n".join(l) | 149 text = "\n".join(l) |
150 return self.addrevision(text, transaction, self.count(), p1, p2) | 150 return self.addrevision(text, transaction, self.count(), p1, p2) |
151 | 151 |
152 class dircache: | 152 class dirstate: |
153 def __init__(self, opener, ui): | 153 def __init__(self, opener, ui): |
154 self.opener = opener | 154 self.opener = opener |
155 self.dirty = 0 | 155 self.dirty = 0 |
156 self.ui = ui | 156 self.ui = ui |
157 self.map = None | 157 self.map = None |
158 | |
158 def __del__(self): | 159 def __del__(self): |
159 if self.dirty: self.write() | 160 if self.dirty: |
161 self.write() | |
162 | |
160 def __getitem__(self, key): | 163 def __getitem__(self, key): |
161 try: | 164 try: |
162 return self.map[key] | 165 return self.map[key] |
163 except TypeError: | 166 except TypeError: |
164 self.read() | 167 self.read() |
165 return self[key] | 168 return self[key] |
166 | 169 |
170 def __contains__(self, key): | |
171 if not self.map: self.read() | |
172 return key in self.map | |
173 | |
174 def state(self, key): | |
175 try: | |
176 return self[key][0] | |
177 except KeyError: | |
178 return "?" | |
179 | |
167 def read(self): | 180 def read(self): |
168 if self.map is not None: return self.map | 181 if self.map is not None: return self.map |
169 | 182 |
170 self.map = {} | 183 self.map = {} |
171 try: | 184 try: |
172 st = self.opener("dircache").read() | 185 st = self.opener("dirstate").read() |
173 except: return | 186 except: return |
174 | 187 |
175 pos = 0 | 188 pos = 0 |
176 while pos < len(st): | 189 while pos < len(st): |
177 e = struct.unpack(">llll", st[pos:pos+16]) | 190 e = struct.unpack(">cllll", st[pos:pos+17]) |
178 l = e[3] | 191 l = e[4] |
179 pos += 16 | 192 pos += 17 |
180 f = st[pos:pos + l] | 193 f = st[pos:pos + l] |
181 self.map[f] = e[:3] | 194 self.map[f] = e[:4] |
182 pos += l | 195 pos += l |
183 | 196 |
184 def update(self, files): | 197 def update(self, files, state): |
198 ''' current states: | |
199 n normal | |
200 i invalid | |
201 r marked for removal | |
202 a marked for addition''' | |
203 | |
185 if not files: return | 204 if not files: return |
186 self.read() | 205 self.read() |
187 self.dirty = 1 | 206 self.dirty = 1 |
188 for f in files: | 207 for f in files: |
189 try: | 208 if state == "r": |
190 s = os.stat(f) | 209 self.map[f] = ('r', 0, 0, 0) |
191 self.map[f] = (s.st_mode, s.st_size, s.st_mtime) | 210 else: |
192 except IOError: | 211 try: |
193 self.remove(f) | 212 s = os.stat(f) |
194 | 213 self.map[f] = (state, s.st_mode, s.st_size, s.st_mtime) |
195 def taint(self, files): | 214 except OSError: |
196 if not files: return | 215 if state != "i": raise |
197 self.read() | 216 self.map[f] = ('r', 0, 0, 0) |
198 self.dirty = 1 | 217 |
199 for f in files: | 218 def forget(self, files): |
200 self.map[f] = (0, -1, 0) | |
201 | |
202 def remove(self, files): | |
203 if not files: return | 219 if not files: return |
204 self.read() | 220 self.read() |
205 self.dirty = 1 | 221 self.dirty = 1 |
206 for f in files: | 222 for f in files: |
207 try: | 223 try: |
208 del self.map[f] | 224 del self.map[f] |
209 except KeyError: | 225 except KeyError: |
210 self.ui.warn("Not in dircache: %s\n" % f) | 226 self.ui.warn("not in dirstate: %s!\n" % f) |
211 pass | 227 pass |
212 | 228 |
213 def clear(self): | 229 def clear(self): |
214 self.map = {} | 230 self.map = {} |
215 self.dirty = 1 | 231 self.dirty = 1 |
216 | 232 |
217 def write(self): | 233 def write(self): |
218 st = self.opener("dircache", "w") | 234 st = self.opener("dirstate", "w") |
219 for f, e in self.map.items(): | 235 for f, e in self.map.items(): |
220 e = struct.pack(">llll", e[0], e[1], e[2], len(f)) | 236 e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f)) |
221 st.write(e + f) | 237 st.write(e + f) |
222 self.dirty = 0 | 238 self.dirty = 0 |
223 | 239 |
224 def copy(self): | 240 def copy(self): |
225 self.read() | 241 self.read() |
278 self.changelog = changelog(self.opener) | 294 self.changelog = changelog(self.opener) |
279 self.ignorelist = None | 295 self.ignorelist = None |
280 self.tags = None | 296 self.tags = None |
281 | 297 |
282 if not self.remote: | 298 if not self.remote: |
283 self.dircache = dircache(self.opener, ui) | 299 self.dirstate = dirstate(self.opener, ui) |
284 try: | 300 try: |
285 self.current = bin(self.opener("current").read()) | 301 self.current = bin(self.opener("current").read()) |
286 except IOError: | 302 except IOError: |
287 self.current = None | 303 self.current = None |
288 | 304 |
338 self.ui.warn("no interrupted transaction available\n") | 354 self.ui.warn("no interrupted transaction available\n") |
339 | 355 |
340 def undo(self): | 356 def undo(self): |
341 self.lock() | 357 self.lock() |
342 if os.path.exists(self.join("undo")): | 358 if os.path.exists(self.join("undo")): |
359 f = self.changelog.read(self.changelog.tip())[3] | |
343 self.ui.status("attempting to rollback last transaction\n") | 360 self.ui.status("attempting to rollback last transaction\n") |
344 rollback(self.opener, self.join("undo")) | 361 rollback(self.opener, self.join("undo")) |
345 self.manifest = manifest(self.opener) | 362 self.manifest = manifest(self.opener) |
346 self.changelog = changelog(self.opener) | 363 self.changelog = changelog(self.opener) |
347 | 364 |
348 self.ui.status("discarding dircache\n") | 365 self.ui.status("discarding dirstate\n") |
349 node = self.changelog.tip() | 366 node = self.changelog.tip() |
350 mf = self.changelog.read(node)[0] | |
351 mm = self.manifest.read(mf) | |
352 f = mm.keys() | |
353 f.sort() | 367 f.sort() |
354 | 368 |
355 self.setcurrent(node) | 369 self.setcurrent(node) |
356 self.dircache.clear() | 370 self.dirstate.update(f, 'i') |
357 self.dircache.taint(f) | |
358 | 371 |
359 else: | 372 else: |
360 self.ui.warn("no undo information available\n") | 373 self.ui.warn("no undo information available\n") |
361 | 374 |
362 def lock(self, wait = 1): | 375 def lock(self, wait = 1): |
387 | 400 |
388 mnode = self.manifest.add(mmap, tr, linkrev, pchange[0]) | 401 mnode = self.manifest.add(mmap, tr, linkrev, pchange[0]) |
389 n = self.changelog.add(mnode, files, text, tr, p1, p2, user ,date, ) | 402 n = self.changelog.add(mnode, files, text, tr, p1, p2, user ,date, ) |
390 tr.close() | 403 tr.close() |
391 self.setcurrent(n) | 404 self.setcurrent(n) |
392 self.dircache.clear() | 405 self.dirstate.clear() |
393 self.dircache.update(mmap) | 406 self.dirstate.update(mmap.keys(), "n") |
394 | 407 |
395 def commit(self, parent, update = None, text = ""): | 408 def commit(self, parent, files = None, text = ""): |
396 self.lock() | 409 self.lock() |
397 try: | 410 |
398 remove = [ l[:-1] for l in self.opener("to-remove") ] | 411 commit = [] |
399 os.unlink(self.join("to-remove")) | 412 remove = [] |
400 | 413 if files: |
401 except IOError: | 414 for f in files: |
402 remove = [] | 415 s = self.dirstate.state(f) |
403 | 416 if s in 'cai': |
404 if update == None: | 417 commit.append(f) |
405 update = self.diffdir(self.root, parent)[0] | 418 elif s == 'r': |
406 | 419 remove.append(f) |
407 if not update: | 420 else: |
421 self.warn("%s not tracked!\n") | |
422 else: | |
423 (c, a, d, u) = self.diffdir(self.root, parent) | |
424 commit = c + a | |
425 remove = d | |
426 | |
427 if not commit and not remove: | |
408 self.ui.status("nothing changed\n") | 428 self.ui.status("nothing changed\n") |
409 return | 429 return |
410 | 430 |
411 tr = self.transaction() | 431 tr = self.transaction() |
412 | 432 |
413 # check in files | 433 # check in files |
414 new = {} | 434 new = {} |
415 linkrev = self.changelog.count() | 435 linkrev = self.changelog.count() |
416 update.sort() | 436 commit.sort() |
417 for f in update: | 437 for f in commit: |
418 self.ui.note(f + "\n") | 438 self.ui.note(f + "\n") |
419 try: | 439 try: |
420 t = file(f).read() | 440 t = file(f).read() |
421 except IOError: | 441 except IOError: |
422 remove.append(f) | 442 self.warn("trouble committing %s!\n" % f) |
423 continue | 443 raise |
444 | |
424 r = self.file(f) | 445 r = self.file(f) |
425 new[f] = r.add(t, tr, linkrev) | 446 new[f] = r.add(t, tr, linkrev) |
426 | 447 |
427 # update manifest | 448 # update manifest |
428 mmap = self.manifest.read(self.manifest.tip()) | 449 mmap = self.manifest.read(self.manifest.tip()) |
442 | 463 |
443 n = self.changelog.add(mnode, new, edittext, tr) | 464 n = self.changelog.add(mnode, new, edittext, tr) |
444 tr.close() | 465 tr.close() |
445 | 466 |
446 self.setcurrent(n) | 467 self.setcurrent(n) |
447 self.dircache.update(new) | 468 self.dirstate.update(new, "n") |
448 self.dircache.remove(remove) | 469 self.dirstate.forget(remove) |
449 | 470 |
450 def checkout(self, node): | 471 def checkout(self, node): |
451 # checkout is really dumb at the moment | 472 # checkout is really dumb at the moment |
452 # it ought to basically merge | 473 # it ought to basically merge |
453 change = self.changelog.read(node) | 474 change = self.changelog.read(node) |
463 except IOError: | 484 except IOError: |
464 os.makedirs(os.path.dirname(f)) | 485 os.makedirs(os.path.dirname(f)) |
465 file(f, "w").write(t) | 486 file(f, "w").write(t) |
466 | 487 |
467 self.setcurrent(node) | 488 self.setcurrent(node) |
468 self.dircache.clear() | 489 self.dirstate.clear() |
469 self.dircache.update([f for f,n in l]) | 490 self.dirstate.update([f for f,n in l], "n") |
470 | 491 |
471 def diffdir(self, path, changeset): | 492 def diffdir(self, path, changeset): |
472 changed = [] | 493 changed = [] |
494 added = [] | |
495 unknown = [] | |
473 mf = {} | 496 mf = {} |
474 added = [] | |
475 | 497 |
476 if changeset: | 498 if changeset: |
477 change = self.changelog.read(changeset) | 499 change = self.changelog.read(changeset) |
478 mf = self.manifest.read(change[0]) | 500 mf = self.manifest.read(change[0]) |
479 | 501 |
480 if changeset == self.current: | 502 if changeset == self.current: |
481 dc = self.dircache.copy() | 503 dc = self.dirstate.copy() |
482 else: | 504 else: |
483 dc = dict.fromkeys(mf) | 505 dc = dict.fromkeys(mf) |
484 | 506 |
485 def fcmp(fn): | 507 def fcmp(fn): |
486 t1 = file(os.path.join(self.root, fn)).read() | 508 t1 = file(os.path.join(self.root, fn)).read() |
496 try: s = os.stat(os.path.join(self.root, fn)) | 518 try: s = os.stat(os.path.join(self.root, fn)) |
497 except: continue | 519 except: continue |
498 if fn in dc: | 520 if fn in dc: |
499 c = dc[fn] | 521 c = dc[fn] |
500 del dc[fn] | 522 del dc[fn] |
501 if not c or c[1] < 0: | 523 if not c: |
502 if fcmp(fn): | 524 if fcmp(fn): |
503 changed.append(fn) | 525 changed.append(fn) |
504 elif c[1] != s.st_size: | 526 if c[0] == 'i': |
527 if fn not in mf: | |
528 added.append(fn) | |
529 elif fcmp(fn): | |
530 changed.append(fn) | |
531 elif c[0] == 'a': | |
532 added.append(fn) | |
533 elif c[0] == 'r': | |
534 unknown.append(fn) | |
535 elif c[2] != s.st_size: | |
505 changed.append(fn) | 536 changed.append(fn) |
506 elif c[0] != s.st_mode or c[2] != s.st_mtime: | 537 elif c[1] != s.st_mode or c[3] != s.st_mtime: |
507 if fcmp(fn): | 538 if fcmp(fn): |
508 changed.append(fn) | 539 changed.append(fn) |
509 else: | 540 else: |
510 if self.ignore(fn): continue | 541 if self.ignore(fn): continue |
511 added.append(fn) | 542 unknown.append(fn) |
512 | 543 |
513 deleted = dc.keys() | 544 deleted = dc.keys() |
514 deleted.sort() | 545 deleted.sort() |
515 | 546 |
516 return (changed, added, deleted) | 547 return (changed, added, deleted, unknown) |
517 | 548 |
518 def diffrevs(self, node1, node2): | 549 def diffrevs(self, node1, node2): |
519 changed, added = [], [] | 550 changed, added = [], [] |
520 | 551 |
521 change = self.changelog.read(node1) | 552 change = self.changelog.read(node1) |
535 deleted.sort() | 566 deleted.sort() |
536 | 567 |
537 return (changed, added, deleted) | 568 return (changed, added, deleted) |
538 | 569 |
539 def add(self, list): | 570 def add(self, list): |
540 self.dircache.taint(list) | 571 for f in list: |
572 p = os.path.join(self.root, f) | |
573 if not os.path.isfile(p): | |
574 self.ui.warn("%s does not exist!\n" % f) | |
575 elif self.dirstate.state(f) == 'n': | |
576 self.ui.warn("%s already tracked!\n" % f) | |
577 else: | |
578 self.dirstate.update([f], "a") | |
579 | |
580 def forget(self, list): | |
581 for f in list: | |
582 if self.dirstate.state(f) not in 'ai': | |
583 self.ui.warn("%s not added!\n" % f) | |
584 else: | |
585 self.dirstate.forget([f]) | |
541 | 586 |
542 def remove(self, list): | 587 def remove(self, list): |
543 dl = self.opener("to-remove", "a") | |
544 for f in list: | 588 for f in list: |
545 dl.write(f + "\n") | 589 p = os.path.join(self.root, f) |
590 if os.path.isfile(p): | |
591 self.ui.warn("%s still exists!\n" % f) | |
592 elif f not in self.dirstate: | |
593 self.ui.warn("%s not tracked!\n" % f) | |
594 else: | |
595 self.dirstate.update([f], "r") | |
546 | 596 |
547 def branches(self, nodes): | 597 def branches(self, nodes): |
548 if not nodes: nodes = [self.changelog.tip()] | 598 if not nodes: nodes = [self.changelog.tip()] |
549 b = [] | 599 b = [] |
550 for n in nodes: | 600 for n in nodes: |