diff --git a/hg b/hg index 8ff4532376a41375b54ffade603d524c706606b4_aGc=..3113a94c1bff3f166a3f33ec8698b549ed1811e0_aGc= 100644 --- a/hg +++ b/hg @@ -67,7 +67,7 @@ date2 = time.asctime() if not node1: node1 = repo.current - (c, a, d) = repo.diffdir(repo.root, node1) + (c, a, d, u) = repo.diffdir(repo.root, node1) a = [] # ignore unknown files in repo, by popular request def read(f): return file(os.path.join(repo.root, f)).read() @@ -79,9 +79,7 @@ c, a, d = map(lambda x: filterfiles(x, files), (c, a, d)) for f in c: - to = "" - if mmap.has_key(f): - to = repo.file(f).read(mmap[f]) + to = repo.file(f).read(mmap[f]) tn = read(f) sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f)) for f in a: @@ -132,6 +130,9 @@ elif cmd == "add": repo.add(args) +elif cmd == "forget": + repo.forget(args) + elif cmd == "remove" or cmd == "rm" or cmd == "del" or cmd == "delete": repo.remove(args) @@ -250,7 +251,7 @@ repo.addchangegroup(data) elif cmd == "addremove": - (c, a, d) = repo.diffdir(repo.root, repo.current) + (c, a, d, u) = repo.diffdir(repo.root, repo.current) repo.add(a) repo.remove(d) @@ -355,8 +356,8 @@ print "}" elif cmd == "merge": - (c, a, d) = repo.diffdir(repo.root, repo.current) - if c: + (c, a, d, u) = repo.diffdir(repo.root, repo.current) + if c or a or d: ui.warn("aborting (outstanding changes in working directory)\n") sys.exit(1) diff --git a/mercurial/commands.py b/mercurial/commands.py index 8ff4532376a41375b54ffade603d524c706606b4_bWVyY3VyaWFsL2NvbW1hbmRzLnB5..3113a94c1bff3f166a3f33ec8698b549ed1811e0_bWVyY3VyaWFsL2NvbW1hbmRzLnB5 100644 --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -70,8 +70,8 @@ def checkout(ui, repo, changeset=None): '''checkout a given changeset or the current tip''' - (c, a, d) = repo.diffdir(repo.root, repo.current) - if c: + (c, a, d, u) = repo.diffdir(repo.root, repo.current) + if c or a or d: ui.warn("aborting (outstanding changes in working directory)\n") sys.exit(1) @@ -129,7 +129,7 @@ A = added R = removed ? = not tracked''' - (c, a, d) = repo.diffdir(repo.root, repo.current) - (c, a, d) = map(lambda x: relfilter(repo, x), (c, a, d)) + (c, a, d, u) = repo.diffdir(repo.root, repo.current) + (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u)) for f in c: print "C", f @@ -134,4 +134,4 @@ for f in c: print "C", f - for f in a: print "?", f + for f in a: print "A", f for f in d: print "R", f @@ -137,4 +137,5 @@ for f in d: print "R", f + for f in u: print "?", f def undo(ui, repo): repo.undo() diff --git a/mercurial/hg.py b/mercurial/hg.py index 8ff4532376a41375b54ffade603d524c706606b4_bWVyY3VyaWFsL2hnLnB5..3113a94c1bff3f166a3f33ec8698b549ed1811e0_bWVyY3VyaWFsL2hnLnB5 100644 --- a/mercurial/hg.py +++ b/mercurial/hg.py @@ -149,9 +149,9 @@ text = "\n".join(l) return self.addrevision(text, transaction, self.count(), p1, p2) -class dircache: +class dirstate: def __init__(self, opener, ui): self.opener = opener self.dirty = 0 self.ui = ui self.map = None @@ -153,6 +153,7 @@ def __init__(self, opener, ui): self.opener = opener self.dirty = 0 self.ui = ui self.map = None + def __del__(self): @@ -158,8 +159,10 @@ def __del__(self): - if self.dirty: self.write() + if self.dirty: + self.write() + def __getitem__(self, key): try: return self.map[key] except TypeError: self.read() return self[key] @@ -160,12 +163,22 @@ def __getitem__(self, key): try: return self.map[key] except TypeError: self.read() return self[key] - + + def __contains__(self, key): + if not self.map: self.read() + return key in self.map + + def state(self, key): + try: + return self[key][0] + except KeyError: + return "?" + def read(self): if self.map is not None: return self.map self.map = {} try: @@ -167,10 +180,10 @@ def read(self): if self.map is not None: return self.map self.map = {} try: - st = self.opener("dircache").read() + st = self.opener("dirstate").read() except: return pos = 0 while pos < len(st): @@ -173,8 +186,8 @@ except: return pos = 0 while pos < len(st): - e = struct.unpack(">llll", st[pos:pos+16]) - l = e[3] - pos += 16 + e = struct.unpack(">cllll", st[pos:pos+17]) + l = e[4] + pos += 17 f = st[pos:pos + l] @@ -180,4 +193,4 @@ f = st[pos:pos + l] - self.map[f] = e[:3] + self.map[f] = e[:4] pos += l @@ -182,7 +195,13 @@ pos += l - def update(self, files): + def update(self, files, state): + ''' current states: + n normal + i invalid + r marked for removal + a marked for addition''' + if not files: return self.read() self.dirty = 1 for f in files: @@ -185,10 +204,14 @@ if not files: return self.read() self.dirty = 1 for f in files: - try: - s = os.stat(f) - self.map[f] = (s.st_mode, s.st_size, s.st_mtime) - except IOError: - self.remove(f) + if state == "r": + self.map[f] = ('r', 0, 0, 0) + else: + try: + s = os.stat(f) + self.map[f] = (state, s.st_mode, s.st_size, s.st_mtime) + except OSError: + if state != "i": raise + self.map[f] = ('r', 0, 0, 0) @@ -194,12 +217,5 @@ - def taint(self, files): - if not files: return - self.read() - self.dirty = 1 - for f in files: - self.map[f] = (0, -1, 0) - - def remove(self, files): + def forget(self, files): if not files: return self.read() self.dirty = 1 @@ -207,7 +223,7 @@ try: del self.map[f] except KeyError: - self.ui.warn("Not in dircache: %s\n" % f) + self.ui.warn("not in dirstate: %s!\n" % f) pass def clear(self): @@ -215,5 +231,5 @@ self.dirty = 1 def write(self): - st = self.opener("dircache", "w") + st = self.opener("dirstate", "w") for f, e in self.map.items(): @@ -219,5 +235,5 @@ for f, e in self.map.items(): - e = struct.pack(">llll", e[0], e[1], e[2], len(f)) + e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f)) st.write(e + f) self.dirty = 0 @@ -280,7 +296,7 @@ self.tags = None if not self.remote: - self.dircache = dircache(self.opener, ui) + self.dirstate = dirstate(self.opener, ui) try: self.current = bin(self.opener("current").read()) except IOError: @@ -340,8 +356,9 @@ def undo(self): self.lock() if os.path.exists(self.join("undo")): + f = self.changelog.read(self.changelog.tip())[3] self.ui.status("attempting to rollback last transaction\n") rollback(self.opener, self.join("undo")) self.manifest = manifest(self.opener) self.changelog = changelog(self.opener) @@ -343,7 +360,7 @@ self.ui.status("attempting to rollback last transaction\n") rollback(self.opener, self.join("undo")) self.manifest = manifest(self.opener) self.changelog = changelog(self.opener) - self.ui.status("discarding dircache\n") + self.ui.status("discarding dirstate\n") node = self.changelog.tip() @@ -349,7 +366,4 @@ node = self.changelog.tip() - mf = self.changelog.read(node)[0] - mm = self.manifest.read(mf) - f = mm.keys() f.sort() self.setcurrent(node) @@ -353,8 +367,7 @@ f.sort() self.setcurrent(node) - self.dircache.clear() - self.dircache.taint(f) + self.dirstate.update(f, 'i') else: self.ui.warn("no undo information available\n") @@ -389,6 +402,6 @@ n = self.changelog.add(mnode, files, text, tr, p1, p2, user ,date, ) tr.close() self.setcurrent(n) - self.dircache.clear() - self.dircache.update(mmap) + self.dirstate.clear() + self.dirstate.update(mmap.keys(), "n") @@ -394,3 +407,3 @@ - def commit(self, parent, update = None, text = ""): + def commit(self, parent, files = None, text = ""): self.lock() @@ -396,5 +409,2 @@ self.lock() - try: - remove = [ l[:-1] for l in self.opener("to-remove") ] - os.unlink(self.join("to-remove")) @@ -400,4 +410,17 @@ - except IOError: - remove = [] + commit = [] + remove = [] + if files: + for f in files: + s = self.dirstate.state(f) + if s in 'cai': + commit.append(f) + elif s == 'r': + remove.append(f) + else: + self.warn("%s not tracked!\n") + else: + (c, a, d, u) = self.diffdir(self.root, parent) + commit = c + a + remove = d @@ -403,8 +426,5 @@ - if update == None: - update = self.diffdir(self.root, parent)[0] - - if not update: + if not commit and not remove: self.ui.status("nothing changed\n") return @@ -413,9 +433,9 @@ # check in files new = {} linkrev = self.changelog.count() - update.sort() - for f in update: + commit.sort() + for f in commit: self.ui.note(f + "\n") try: t = file(f).read() except IOError: @@ -418,9 +438,10 @@ self.ui.note(f + "\n") try: t = file(f).read() except IOError: - remove.append(f) - continue + self.warn("trouble committing %s!\n" % f) + raise + r = self.file(f) new[f] = r.add(t, tr, linkrev) @@ -444,8 +465,8 @@ tr.close() self.setcurrent(n) - self.dircache.update(new) - self.dircache.remove(remove) + self.dirstate.update(new, "n") + self.dirstate.forget(remove) def checkout(self, node): # checkout is really dumb at the moment @@ -465,8 +486,8 @@ file(f, "w").write(t) self.setcurrent(node) - self.dircache.clear() - self.dircache.update([f for f,n in l]) + self.dirstate.clear() + self.dirstate.update([f for f,n in l], "n") def diffdir(self, path, changeset): changed = [] @@ -470,4 +491,6 @@ def diffdir(self, path, changeset): changed = [] + added = [] + unknown = [] mf = {} @@ -473,8 +496,7 @@ mf = {} - added = [] if changeset: change = self.changelog.read(changeset) mf = self.manifest.read(change[0]) if changeset == self.current: @@ -475,10 +497,10 @@ if changeset: change = self.changelog.read(changeset) mf = self.manifest.read(change[0]) if changeset == self.current: - dc = self.dircache.copy() + dc = self.dirstate.copy() else: dc = dict.fromkeys(mf) @@ -498,6 +520,6 @@ if fn in dc: c = dc[fn] del dc[fn] - if not c or c[1] < 0: + if not c: if fcmp(fn): changed.append(fn) @@ -502,4 +524,13 @@ if fcmp(fn): changed.append(fn) - elif c[1] != s.st_size: + if c[0] == 'i': + if fn not in mf: + added.append(fn) + elif fcmp(fn): + changed.append(fn) + elif c[0] == 'a': + added.append(fn) + elif c[0] == 'r': + unknown.append(fn) + elif c[2] != s.st_size: changed.append(fn) @@ -505,6 +536,6 @@ changed.append(fn) - elif c[0] != s.st_mode or c[2] != s.st_mtime: + elif c[1] != s.st_mode or c[3] != s.st_mtime: if fcmp(fn): changed.append(fn) else: if self.ignore(fn): continue @@ -507,9 +538,9 @@ if fcmp(fn): changed.append(fn) else: if self.ignore(fn): continue - added.append(fn) + unknown.append(fn) deleted = dc.keys() deleted.sort() @@ -512,8 +543,8 @@ deleted = dc.keys() deleted.sort() - return (changed, added, deleted) + return (changed, added, deleted, unknown) def diffrevs(self, node1, node2): changed, added = [], [] @@ -537,6 +568,20 @@ return (changed, added, deleted) def add(self, list): - self.dircache.taint(list) + for f in list: + p = os.path.join(self.root, f) + if not os.path.isfile(p): + self.ui.warn("%s does not exist!\n" % f) + elif self.dirstate.state(f) == 'n': + self.ui.warn("%s already tracked!\n" % f) + else: + self.dirstate.update([f], "a") + + def forget(self, list): + for f in list: + if self.dirstate.state(f) not in 'ai': + self.ui.warn("%s not added!\n" % f) + else: + self.dirstate.forget([f]) def remove(self, list): @@ -541,4 +586,3 @@ def remove(self, list): - dl = self.opener("to-remove", "a") for f in list: @@ -544,5 +588,11 @@ for f in list: - dl.write(f + "\n") + p = os.path.join(self.root, f) + if os.path.isfile(p): + self.ui.warn("%s still exists!\n" % f) + elif f not in self.dirstate: + self.ui.warn("%s not tracked!\n" % f) + else: + self.dirstate.update([f], "r") def branches(self, nodes): if not nodes: nodes = [self.changelog.tip()]