##// END OF EJS Templates
Update docs for annotate and diff.
Update docs for annotate and diff.

File last commit:

r730:d2dc7663 default
r734:d4e161d6 default
Show More
hg.py
1927 lines | 61.9 KiB | text/x-python | PythonLexer
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 # hg.py - repository classes for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
mpm@selenic.com
import and startup cleanups...
r249 import sys, struct, os
mpm@selenic.com
[PATCH] file seperator handling for the other 'OS'...
r419 import util
mpm@selenic.com
implement demand loading hack...
r262 from revlog import *
from demandload import *
demandload(globals(), "re lock urllib urllib2 transaction time socket")
mpm@selenic.com
Replace difflib with bdiff for annotate...
r434 demandload(globals(), "tempfile httprangereader bdiff")
Matt Mackall
Show remote client output with "remote:"
r646 demandload(globals(), "bisect select")
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
class filelog(revlog):
def __init__(self, opener, path):
mpm@selenic.com
Fix transaction handling bug by reverting fileopener change
r144 revlog.__init__(self, opener,
os.path.join("data", path + ".i"),
os.path.join("data", path + ".d"))
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
def read(self, node):
mpm@selenic.com
filelog: add metadata support...
r360 t = self.revision(node)
Matt Mackall
Reapply startswith() changes that got lost with stale edit...
r686 if not t.startswith('\1\n'):
mpm@selenic.com
filelog: add metadata support...
r360 return t
s = t.find('\1\n', 2)
return t[s+2:]
def readmeta(self, node):
t = self.revision(node)
Matt Mackall
Reapply startswith() changes that got lost with stale edit...
r686 if not t.startswith('\1\n'):
mpm@selenic.com
filelog: add metadata support...
r360 return t
s = t.find('\1\n', 2)
mt = t[2:s]
for l in mt.splitlines():
k, v = l.split(": ", 1)
m[k] = v
return m
def add(self, text, meta, transaction, link, p1=None, p2=None):
Matt Mackall
Reapply startswith() changes that got lost with stale edit...
r686 if meta or text.startswith('\1\n'):
mpm@selenic.com
filelog: add metadata support...
r360 mt = ""
if meta:
mt = [ "%s: %s\n" % (k, v) for k,v in meta.items() ]
text = "\1\n" + "".join(mt) + "\1\n" + text
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 return self.addrevision(text, transaction, link, p1, p2)
mpm@selenic.com
Add basic annotation support...
r79 def annotate(self, node):
mpm@selenic.com
annotate: deal with merges...
r199
def decorate(text, rev):
mpm@selenic.com
Optimize annotate a bit...
r436 return ([rev] * len(text.splitlines()), text)
mpm@selenic.com
annotate: deal with merges...
r199
def pair(parent, child):
mpm@selenic.com
Optimize annotate a bit...
r436 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
mpm@selenic.com
Minor annotate performance tweaks...
r471 child[0][b1:b2] = parent[0][a1:a2]
return child
mpm@selenic.com
annotate: deal with merges...
r199
mpm@selenic.com
annotate: memory efficiency...
r200 # find all ancestors
mpm@selenic.com
hg annotate: actually annotate the given version...
r216 needed = {node:1}
mpm@selenic.com
annotate: deal with merges...
r199 visit = [node]
while visit:
n = visit.pop(0)
for p in self.parents(n):
if p not in needed:
needed[p] = 1
visit.append(p)
mpm@selenic.com
annotate: memory efficiency...
r200 else:
# count how many times we'll use this
needed[p] += 1
mpm@selenic.com
annotate: deal with merges...
r199
mpm@selenic.com
annotate: memory efficiency...
r200 # sort by revision which is a topological order
mpm@selenic.com
Minor annotate performance tweaks...
r471 visit = [ (self.rev(n), n) for n in needed.keys() ]
mpm@selenic.com
annotate: deal with merges...
r199 visit.sort()
hist = {}
mpm@selenic.com
Minor annotate performance tweaks...
r471 for r,n in visit:
mpm@selenic.com
annotate: deal with merges...
r199 curr = decorate(self.read(n), self.linkrev(n))
for p in self.parents(n):
if p != nullid:
curr = pair(hist[p], curr)
mpm@selenic.com
annotate: memory efficiency...
r200 # trim the history of unneeded revs
needed[p] -= 1
if not needed[p]:
del hist[p]
mpm@selenic.com
annotate: deal with merges...
r199 hist[n] = curr
mpm@selenic.com
Optimize annotate a bit...
r436 return zip(hist[n][0], hist[n][1].splitlines(1))
mpm@selenic.com
Add basic annotation support...
r79
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 class manifest(revlog):
def __init__(self, opener):
self.mapcache = None
self.listcache = None
self.addlist = None
revlog.__init__(self, opener, "00manifest.i", "00manifest.d")
def read(self, node):
mpm@selenic.com
Minor caching improvement for manifest...
r313 if node == nullid: return {} # don't upset local cache
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 if self.mapcache and self.mapcache[0] == node:
mpm@selenic.com
Fix dodiff/changes...
r561 return self.mapcache[1]
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 text = self.revision(node)
map = {}
mpm@selenic.com
add tracking of execute permissions...
r276 flag = {}
mpm@selenic.com
Fix corruption from manifest.listcache optimization...
r25 self.listcache = (text, text.splitlines(1))
for l in self.listcache[1]:
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 (f, n) = l.split('\0')
map[f] = bin(n[:40])
mpm@selenic.com
add tracking of execute permissions...
r276 flag[f] = (n[40:-1] == "x")
self.mapcache = (node, map, flag)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 return map
mpm@selenic.com
add tracking of execute permissions...
r276 def readflags(self, node):
mpm@selenic.com
Minor caching improvement for manifest...
r313 if node == nullid: return {} # don't upset local cache
mpm@selenic.com
[PATCH] manifest.readflags performance buglet...
r358 if not self.mapcache or self.mapcache[0] != node:
mpm@selenic.com
add tracking of execute permissions...
r276 self.read(node)
return self.mapcache[2]
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 def diff(self, a, b):
# this is sneaky, as we're not actually using a and b
mpm@selenic.com
Minor safety checks to manifest diff
r140 if self.listcache and self.addlist and self.listcache[0] == a:
mpm@selenic.com
Add paranoia to diff code
r98 d = mdiff.diff(self.listcache[1], self.addlist, 1)
if mdiff.patch(a, d) != b:
sys.stderr.write("*** sortdiff failed, falling back ***\n")
return mdiff.textdiff(a, b)
return d
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 else:
mpm@selenic.com
Fix occassional diff bug with manifests
r44 return mdiff.textdiff(a, b)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
mason@suse.com
Performance enhancements for manifest.add()...
r644 def add(self, map, flags, transaction, link, p1=None, p2=None,changed=None):
# directly generate the mdiff delta from the data collected during
# the bisect loop below
def gendelta(delta):
i = 0
result = []
while i < len(delta):
start = delta[i][2]
end = delta[i][3]
l = delta[i][4]
if l == None:
l = ""
while i < len(delta) - 1 and start <= delta[i+1][2] and end >= delta[i+1][2]:
if delta[i+1][3] > end:
end = delta[i+1][3]
if delta[i+1][4]:
l += delta[i+1][4]
i += 1
result.append(struct.pack(">lll", start, end, len(l)) + l)
i += 1
return result
# apply the changes collected during the bisect loop to our addlist
def addlistdelta(addlist, delta):
# apply the deltas to the addlist. start from the bottom up
# so changes to the offsets don't mess things up.
i = len(delta)
while i > 0:
i -= 1
start = delta[i][0]
end = delta[i][1]
if delta[i][4]:
addlist[start:end] = [delta[i][4]]
else:
del addlist[start:end]
return addlist
# calculate the byte offset of the start of each line in the
# manifest
def calcoffsets(addlist):
offsets = [0] * (len(addlist) + 1)
offset = 0
i = 0
while i < len(addlist):
offsets[i] = offset
offset += len(addlist[i])
i += 1
offsets[i] = offset
return offsets
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
mason@suse.com
Performance enhancements for manifest.add()...
r644 # if we're using the listcache, make sure it is valid and
# parented by the same node we're diffing against
if not changed or not self.listcache or not p1 or self.mapcache[0] != p1:
files = map.keys()
files.sort()
self.addlist = ["%s\000%s%s\n" %
(f, hex(map[f]), flags[f] and "x" or '')
for f in files]
cachedelta = None
else:
addlist = self.listcache[1]
# find the starting offset for each line in the add list
offsets = calcoffsets(addlist)
# combine the changed lists into one list for sorting
work = [[x, 0] for x in changed[0]]
work[len(work):] = [[x, 1] for x in changed[1]]
work.sort()
delta = []
bs = 0
for w in work:
f = w[0]
# bs will either be the index of the item or the insertion point
bs = bisect.bisect(addlist, f, bs)
if bs < len(addlist):
fn = addlist[bs][:addlist[bs].index('\0')]
else:
fn = None
if w[1] == 0:
l = "%s\000%s%s\n" % (f, hex(map[f]), flags[f] and "x" or '')
else:
l = None
start = bs
if fn != f:
# item not found, insert a new one
Matt Mackall
Whitespace cleanup...
r659 end = bs
mason@suse.com
Performance enhancements for manifest.add()...
r644 if w[1] == 1:
Thomas Arendsen Hein
Added missing newline after two error messages....
r713 sys.stderr.write("failed to remove %s from manifest\n"
% f)
mason@suse.com
Performance enhancements for manifest.add()...
r644 sys.exit(1)
else:
# item is found, replace/delete the existing line
end = bs + 1
delta.append([start, end, offsets[start], offsets[end], l])
self.addlist = addlistdelta(addlist, delta)
if self.mapcache[0] == self.tip():
cachedelta = "".join(gendelta(delta))
else:
cachedelta = None
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 text = "".join(self.addlist)
mason@suse.com
Performance enhancements for manifest.add()...
r644 if cachedelta and mdiff.patch(self.listcache[0], cachedelta) != text:
Thomas Arendsen Hein
Added missing newline after two error messages....
r713 sys.stderr.write("manifest delta failure\n")
mason@suse.com
Performance enhancements for manifest.add()...
r644 sys.exit(1)
n = self.addrevision(text, transaction, link, p1, p2, cachedelta)
mpm@selenic.com
various fixups for git import...
r302 self.mapcache = (n, map, flags)
mpm@selenic.com
Fix corruption from manifest.listcache optimization...
r25 self.listcache = (text, self.addlist)
mpm@selenic.com
Minor safety checks to manifest diff
r140 self.addlist = None
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
return n
class changelog(revlog):
def __init__(self, opener):
revlog.__init__(self, opener, "00changelog.i", "00changelog.d")
def extract(self, text):
mpm@selenic.com
Move hex/bin bits to revlog...
r37 if not text:
mpm@selenic.com
Date is an int as a string in changelog
r40 return (nullid, "", "0", [], "")
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 last = text.index("\n\n")
desc = text[last + 2:]
l = text[:last].splitlines()
manifest = bin(l[0])
user = l[1]
date = l[2]
files = l[3:]
return (manifest, user, date, files, desc)
def read(self, node):
return self.extract(self.revision(node))
mpm@selenic.com
hg rawcommit command...
r203 def add(self, manifest, list, desc, transaction, p1=None, p2=None,
user=None, date=None):
date = date or "%d %d" % (time.time(), time.timezone)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 list.sort()
l = [hex(manifest), user, date] + list + ["", desc]
text = "\n".join(l)
return self.addrevision(text, transaction, self.count(), p1, p2)
mpm@selenic.com
change dircache into dirstate...
r220 class dirstate:
mpm@selenic.com
root relative IO and valid commit states...
r244 def __init__(self, opener, ui, root):
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 self.opener = opener
mpm@selenic.com
root relative IO and valid commit states...
r244 self.root = root
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 self.dirty = 0
mpm@selenic.com
The actual hg remove fix from Thomas Hein
r20 self.ui = ui
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 self.map = None
mpm@selenic.com
move repo.current to dirstate.parents()...
r227 self.pl = None
mpm@selenic.com
Add hg copy...
r363 self.copies = {}
Bryan O'Sullivan
Work on walk code.
r723 self.ignorefunc = None
def wjoin(self, f):
return os.path.join(self.root, f)
def ignore(self, f):
if not self.ignorefunc:
bigpat = []
try:
l = file(self.wjoin(".hgignore"))
for pat in l:
if pat != "\n":
p = util.pconvert(pat[:-1])
try:
r = re.compile(p)
except:
self.ui.warn("ignoring invalid ignore"
+ " regular expression '%s'\n" % p)
else:
bigpat.append(util.pconvert(pat[:-1]))
except IOError: pass
s = "(?:%s)" % (")|(?:".join(bigpat))
r = re.compile(s)
self.ignorefunc = r.search
return self.ignorefunc(f)
mpm@selenic.com
change dircache into dirstate...
r220
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 def __del__(self):
mpm@selenic.com
change dircache into dirstate...
r220 if self.dirty:
self.write()
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 def __getitem__(self, key):
try:
return self.map[key]
except TypeError:
self.read()
return self[key]
mpm@selenic.com
change dircache into dirstate...
r220
def __contains__(self, key):
if not self.map: self.read()
return key in self.map
mpm@selenic.com
move repo.current to dirstate.parents()...
r227 def parents(self):
if not self.pl:
self.read()
return self.pl
Bryan O'Sullivan
Work on walk code.
r723 def markdirty(self):
if not self.dirty:
self.dirty = 1
mpm@selenic.com
move repo.current to dirstate.parents()...
r227 def setparents(self, p1, p2 = nullid):
Bryan O'Sullivan
Work on walk code.
r723 self.markdirty()
mpm@selenic.com
move repo.current to dirstate.parents()...
r227 self.pl = p1, p2
mpm@selenic.com
change dircache into dirstate...
r220 def state(self, key):
try:
return self[key][0]
except KeyError:
return "?"
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 def read(self):
if self.map is not None: return self.map
self.map = {}
mpm@selenic.com
move repo.current to dirstate.parents()...
r227 self.pl = [nullid, nullid]
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 try:
mpm@selenic.com
change dircache into dirstate...
r220 st = self.opener("dirstate").read()
mpm@selenic.com
fix KeyErrors from reading empty dirstate...
r311 if not st: return
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 except: return
mpm@selenic.com
move repo.current to dirstate.parents()...
r227 self.pl = [st[:20], st[20: 40]]
pos = 40
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 while pos < len(st):
mpm@selenic.com
change dircache into dirstate...
r220 e = struct.unpack(">cllll", st[pos:pos+17])
l = e[4]
pos += 17
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 f = st[pos:pos + l]
mpm@selenic.com
Whitespace cleanups...
r515 if '\0' in f:
mpm@selenic.com
Add hg copy...
r363 f, c = f.split('\0')
self.copies[f] = c
mpm@selenic.com
change dircache into dirstate...
r220 self.map[f] = e[:4]
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 pos += l
mpm@selenic.com
Add hg copy...
r363
def copy(self, source, dest):
self.read()
Bryan O'Sullivan
Work on walk code.
r723 self.markdirty()
mpm@selenic.com
Add hg copy...
r363 self.copies[dest] = source
def copied(self, file):
return self.copies.get(file, None)
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
change dircache into dirstate...
r220 def update(self, files, state):
''' current states:
n normal
mpm@selenic.com
add 'm' state to dirstates...
r231 m needs merging
mpm@selenic.com
change dircache into dirstate...
r220 r marked for removal
a marked for addition'''
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 if not files: return
self.read()
Bryan O'Sullivan
Work on walk code.
r723 self.markdirty()
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 for f in files:
mpm@selenic.com
change dircache into dirstate...
r220 if state == "r":
self.map[f] = ('r', 0, 0, 0)
else:
mpm@selenic.com
Remove invalid state from dirstate...
r253 s = os.stat(os.path.join(self.root, f))
self.map[f] = (state, s.st_mode, s.st_size, s.st_mtime)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
mpm@selenic.com
change dircache into dirstate...
r220 def forget(self, files):
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 if not files: return
self.read()
Bryan O'Sullivan
Work on walk code.
r723 self.markdirty()
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 for f in files:
mpm@selenic.com
The actual hg remove fix from Thomas Hein
r20 try:
del self.map[f]
except KeyError:
mpm@selenic.com
change dircache into dirstate...
r220 self.ui.warn("not in dirstate: %s!\n" % f)
mpm@selenic.com
The actual hg remove fix from Thomas Hein
r20 pass
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
def clear(self):
self.map = {}
Bryan O'Sullivan
Work on walk code.
r723 self.markdirty()
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
def write(self):
mpm@selenic.com
change dircache into dirstate...
r220 st = self.opener("dirstate", "w")
mpm@selenic.com
move repo.current to dirstate.parents()...
r227 st.write("".join(self.pl))
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 for f, e in self.map.items():
mpm@selenic.com
Add hg copy...
r363 c = self.copied(f)
if c:
f = f + "\0" + c
mpm@selenic.com
change dircache into dirstate...
r220 e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f))
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 st.write(e + f)
self.dirty = 0
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724 def walk(self, files = None, match = util.always):
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 self.read()
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 dc = self.map.copy()
Bryan O'Sullivan
Work on walk code.
r723 # walk all files by default
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 if not files: files = [self.root]
Bryan O'Sullivan
Work on walk code.
r723 def traverse():
mpm@selenic.com
Move dirstate.uniq to util.unique...
r556 for f in util.unique(files):
mpm@selenic.com
Propagate file list through dodiff...
r537 f = os.path.join(self.root, f)
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 if os.path.isdir(f):
for dir, subdirs, fl in os.walk(f):
d = dir[len(self.root) + 1:]
Bryan O'Sullivan
Work on walk code.
r723 if d == '.hg':
subdirs[:] = []
continue
mwilli2@localhost.localdomain
.hgignore speedups patch incorporating Matt's feedback....
r669 for sd in subdirs:
Bryan O'Sullivan
Work on walk code.
r723 ds = os.path.join(d, sd +'/')
if self.ignore(ds) or not match(ds):
mwilli2@localhost.localdomain
.hgignore speedups patch incorporating Matt's feedback....
r669 subdirs.remove(sd)
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 for fn in fl:
fn = util.pconvert(os.path.join(d, fn))
Bryan O'Sullivan
Add a source designator to the walk methods....
r726 yield 'f', fn
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 else:
Bryan O'Sullivan
Add a source designator to the walk methods....
r726 yield 'f', f[len(self.root) + 1:]
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536
mwilli2@localhost.localdomain
.hgignore speedups patch incorporating Matt's feedback....
r669 for k in dc.keys():
Bryan O'Sullivan
Add a source designator to the walk methods....
r726 yield 'm', k
mwilli2@localhost.localdomain
.hgignore speedups patch incorporating Matt's feedback....
r669
Bryan O'Sullivan
Work on walk code.
r723 # yield only files that match: all in dirstate, others only if
# not in .hgignore
Bryan O'Sullivan
Add a source designator to the walk methods....
r726 for src, fn in util.unique(traverse()):
Bryan O'Sullivan
Work on walk code.
r723 if fn in dc:
del dc[fn]
elif self.ignore(fn):
continue
if match(fn):
Bryan O'Sullivan
Add a source designator to the walk methods....
r726 yield src, fn
Bryan O'Sullivan
Work on walk code.
r723
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724 def changes(self, files = None, match = util.always):
Bryan O'Sullivan
Work on walk code.
r723 self.read()
dc = self.map.copy()
lookup, changed, added, unknown = [], [], [], []
Bryan O'Sullivan
Add a source designator to the walk methods....
r726 for src, fn in self.walk(files, match):
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 try: s = os.stat(os.path.join(self.root, fn))
except: continue
if fn in dc:
c = dc[fn]
del dc[fn]
if c[0] == 'm':
changed.append(fn)
elif c[0] == 'a':
added.append(fn)
elif c[0] == 'r':
unknown.append(fn)
elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100:
changed.append(fn)
elif c[1] != s.st_mode or c[3] != s.st_mtime:
lookup.append(fn)
else:
Bryan O'Sullivan
Work on walk code.
r723 if match(fn): unknown.append(fn)
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536
Bryan O'Sullivan
Only walk over files that match our criteria.
r730 return (lookup, changed, added, filter(match, dc.keys()), unknown)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
# used to avoid circular references so destructors work
def opener(base):
p = base
def o(path, mode="r"):
Matt Mackall
Reapply startswith() changes that got lost with stale edit...
r686 if p.startswith("http://"):
mpm@selenic.com
Fix network pull of repo files with "%" in their base64 encoding.
r15 f = os.path.join(p, urllib.quote(path))
mpm@selenic.com
Move httprangereader into its own file...
r372 return httprangereader.httprangereader(f)
mpm@selenic.com
Fix network pull of repo files with "%" in their base64 encoding.
r15
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 f = os.path.join(p, path)
mpm@selenic.com
Make most file opening binary...
r292 mode += "b" # for that other OS
if mode[0] != "r":
mpm@selenic.com
Move hg from storing files in data with base64 encoding to full...
r110 try:
s = os.stat(f)
except OSError:
d = os.path.dirname(f)
if not os.path.isdir(d):
os.makedirs(d)
else:
if s.st_nlink > 1:
mpm@selenic.com
[PATCH] file type fixes for the other 'OS'...
r417 file(f + ".tmp", "wb").write(file(f, "rb").read())
mpm@selenic.com
[PATCH] rename under the other OS...
r421 util.rename(f+".tmp", f)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
return file(f, mode)
return o
mpm@selenic.com
Add exception class for repository errors...
r499 class RepoError(Exception): pass
mpm@selenic.com
Add hg:// protocol...
r60 class localrepository:
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 def __init__(self, ui, path=None, create=0):
self.remote = 0
Matt Mackall
Reapply startswith() changes that got lost with stale edit...
r686 if path and path.startswith("http://"):
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 self.remote = 1
self.path = path
else:
if not path:
p = os.getcwd()
while not os.path.isdir(os.path.join(p, ".hg")):
mpm@selenic.com
[PATCH] Repo locator fix for the other `OS'...
r420 oldp = p
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 p = os.path.dirname(p)
mpm@selenic.com
Add exception class for repository errors...
r499 if p == oldp: raise RepoError("no repo found")
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 path = p
self.path = os.path.join(path, ".hg")
mpm@selenic.com
Check if repository exists...
r405 if not create and not os.path.isdir(self.path):
mpm@selenic.com
Add exception class for repository errors...
r499 raise RepoError("repository %s not found" % self.path)
mpm@selenic.com
Check if repository exists...
r405
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 self.root = path
self.ui = ui
if create:
mpm@selenic.com
Whitespace cleanups...
r515 os.mkdir(self.path)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 os.mkdir(self.join("data"))
self.opener = opener(self.path)
mpm@selenic.com
Add wopener for opening files in the working directory...
r291 self.wopener = opener(self.root)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 self.manifest = manifest(self.opener)
self.changelog = changelog(self.opener)
mpm@selenic.com
rework all code using tags...
r343 self.tagscache = None
self.nodetagscache = None
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
if not self.remote:
mpm@selenic.com
root relative IO and valid commit states...
r244 self.dirstate = dirstate(self.opener, ui, self.root)
mpm@selenic.com
Add support for .hg/hgrc file...
r337 try:
self.ui.readconfig(self.opener("hgrc"))
except IOError: pass
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
mpm@selenic.com
Add initial hook support...
r487 def hook(self, name, **args):
s = self.ui.config("hooks", name)
if s:
self.ui.note("running hook %s: %s\n" % (name, s))
old = {}
for k, v in args.items():
k = k.upper()
old[k] = os.environ.get(k, None)
os.environ[k] = v
r = os.system(s)
for k, v in old.items():
if v != None:
os.environ[k] = v
else:
del os.environ[k]
if r:
self.ui.warn("abort: %s hook failed with status %d!\n" %
(name, r))
return False
return True
mpm@selenic.com
rework all code using tags...
r343 def tags(self):
'''return a mapping of tag to node'''
Thomas Arendsen Hein
Handle errors in .hgtags or hgrc [tags] section more gracefully....
r477 if not self.tagscache:
mpm@selenic.com
rework all code using tags...
r343 self.tagscache = {}
Matt Mackall
[PATCH] hg tag: local tag support in file .hg/localtags...
r609 def addtag(self, k, n):
try:
bin_n = bin(n)
except TypeError:
bin_n = ''
self.tagscache[k.strip()] = bin_n
Matt Mackall
Whitespace cleanup...
r659
mpm@selenic.com
Add tag support
r67 try:
mpm@selenic.com
unify checkout and resolve into update...
r254 # read each head of the tags file, ending with the tip
# and add each tag found to the map, with "newer" ones
# taking precedence
mpm@selenic.com
Add tag support
r67 fl = self.file(".hgtags")
mpm@selenic.com
unify checkout and resolve into update...
r254 h = fl.heads()
h.reverse()
for r in h:
for l in fl.revision(r).splitlines():
if l:
Thomas Arendsen Hein
Fixed problems with extra spaces around tags in .hgtags...
r385 n, k = l.split(" ", 1)
Matt Mackall
[PATCH] hg tag: local tag support in file .hg/localtags...
r609 addtag(self, k, n)
Thomas Arendsen Hein
Handle errors in .hgtags or hgrc [tags] section more gracefully....
r477 except KeyError:
pass
Matt Mackall
Whitespace cleanup...
r659
Matt Mackall
[PATCH] hg tag: local tag support in file .hg/localtags...
r609 try:
f = self.opener("localtags")
for l in f:
n, k = l.split(" ", 1)
addtag(self, k, n)
except IOError:
pass
Matt Mackall
Whitespace cleanup...
r659
mpm@selenic.com
rework all code using tags...
r343 self.tagscache['tip'] = self.changelog.tip()
Matt Mackall
Whitespace cleanup...
r659
mpm@selenic.com
rework all code using tags...
r343 return self.tagscache
def tagslist(self):
'''return a list of tags ordered by revision'''
l = []
Thomas Arendsen Hein
Handle errors in .hgtags or hgrc [tags] section more gracefully....
r477 for t, n in self.tags().items():
mpm@selenic.com
rework all code using tags...
r343 try:
r = self.changelog.rev(n)
except:
r = -2 # sort to the beginning of the list if unknown
l.append((r,t,n))
l.sort()
return [(t,n) for r,t,n in l]
def nodetags(self, node):
'''return the tags associated with a node'''
if not self.nodetagscache:
self.nodetagscache = {}
for t,n in self.tags().items():
self.nodetagscache.setdefault(n,[]).append(t)
return self.nodetagscache.get(node, [])
def lookup(self, key):
mpm@selenic.com
Add tag support
r67 try:
mpm@selenic.com
rework all code using tags...
r343 return self.tags()[key]
mpm@selenic.com
Add tag support
r67 except KeyError:
Matt Mackall
Generate a friendlier except for failed lookups...
r658 try:
return self.changelog.lookup(key)
except:
raise RepoError("unknown revision '%s'" % key)
mpm@selenic.com
Add tag support
r67
Matt Mackall
Add a repo method to report repo device...
r634 def dev(self):
if self.remote: return -1
return os.stat(self.path).st_dev
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 def join(self, f):
return os.path.join(self.path, f)
mpm@selenic.com
root relative IO and valid commit states...
r244 def wjoin(self, f):
return os.path.join(self.root, f)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 def file(self, f):
mpm@selenic.com
Changes to network protocol...
r192 if f[0] == '/': f = f[1:]
mpm@selenic.com
Fix transaction handling bug by reverting fileopener change
r144 return filelog(self.opener, f)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
Bryan O'Sullivan
Add locate command....
r627 def getcwd(self):
cwd = os.getcwd()
if cwd == self.root: return ''
return cwd[len(self.root) + 1:]
mpm@selenic.com
Add wopener for opening files in the working directory...
r291 def wfile(self, f, mode='r'):
return self.wopener(f, mode)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 def transaction(self):
mpm@selenic.com
backup dirstate for undo...
r251 # save dirstate for undo
mpm@selenic.com
Fix empty repository transaction bug...
r263 try:
ds = self.opener("dirstate").read()
except IOError:
ds = ""
mpm@selenic.com
backup dirstate for undo...
r251 self.opener("undo.dirstate", "w").write(ds)
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
Remove all remaining print statements...
r582 return transaction.transaction(self.ui.warn,
self.opener, self.join("journal"),
mpm@selenic.com
implement demand loading hack...
r262 self.join("undo"))
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
mpm@selenic.com
hg undo: fixup working dir state...
r210 def recover(self):
mpm@selenic.com
fix repo locking...
r225 lock = self.lock()
mpm@selenic.com
recover: the journal is named 'journal'...
r557 if os.path.exists(self.join("journal")):
mpm@selenic.com
Better messages for rollback and undo...
r501 self.ui.status("rolling back interrupted transaction\n")
mpm@selenic.com
recover: the journal is named 'journal'...
r557 return transaction.rollback(self.opener, self.join("journal"))
mpm@selenic.com
hg undo: fixup working dir state...
r210 else:
self.ui.warn("no interrupted transaction available\n")
def undo(self):
mpm@selenic.com
fix repo locking...
r225 lock = self.lock()
mpm@selenic.com
hg undo: fixup working dir state...
r210 if os.path.exists(self.join("undo")):
mpm@selenic.com
Better messages for rollback and undo...
r501 self.ui.status("rolling back last transaction\n")
mpm@selenic.com
implement demand loading hack...
r262 transaction.rollback(self.opener, self.join("undo"))
mpm@selenic.com
backup dirstate for undo...
r251 self.dirstate = None
mpm@selenic.com
[PATCH] rename under the other OS...
r421 util.rename(self.join("undo.dirstate"), self.join("dirstate"))
mpm@selenic.com
backup dirstate for undo...
r251 self.dirstate = dirstate(self.opener, self.ui, self.root)
mpm@selenic.com
Make undo and recover friendlier...
r163 else:
mpm@selenic.com
hg undo: fixup working dir state...
r210 self.ui.warn("no undo information available\n")
mpm@selenic.com
Implement recover and undo commands...
r162
mpm@selenic.com
Simply repository locking...
r161 def lock(self, wait = 1):
try:
return lock.lock(self.join("lock"), 0)
except lock.LockHeld, inst:
if wait:
self.ui.warn("waiting for lock held by %s\n" % inst.args[0])
return lock.lock(self.join("lock"), wait)
raise inst
mpm@selenic.com
hg rawcommit command...
r203 def rawcommit(self, files, text, user, date, p1=None, p2=None):
mpm@selenic.com
rawcommit dirstate tweak...
r442 orig_parent = self.dirstate.parents()[0] or nullid
mpm@selenic.com
rawcommit: do lookup of parents at the appropriate layer...
r452 p1 = p1 or self.dirstate.parents()[0] or nullid
p2 = p2 or self.dirstate.parents()[1] or nullid
mpm@selenic.com
various fixups for git import...
r302 c1 = self.changelog.read(p1)
c2 = self.changelog.read(p2)
m1 = self.manifest.read(c1[0])
mf1 = self.manifest.readflags(c1[0])
m2 = self.manifest.read(c2[0])
mpm@selenic.com
rawcommit dirstate tweak...
r442 if orig_parent == p1:
update_dirstate = 1
else:
update_dirstate = 0
mpm@selenic.com
hg rawcommit command...
r203 tr = self.transaction()
mpm@selenic.com
various fixups for git import...
r302 mm = m1.copy()
mfm = mf1.copy()
mpm@selenic.com
hg rawcommit command...
r203 linkrev = self.changelog.count()
for f in files:
try:
mpm@selenic.com
various fixups for git import...
r302 t = self.wfile(f).read()
mpm@selenic.com
Permission handling for the other OS...
r441 tm = util.is_exec(self.wjoin(f), mfm.get(f, False))
mpm@selenic.com
various fixups for git import...
r302 r = self.file(f)
mfm[f] = tm
mpm@selenic.com
filelog: add metadata support...
r360 mm[f] = r.add(t, {}, tr, linkrev,
mpm@selenic.com
various fixups for git import...
r302 m1.get(f, nullid), m2.get(f, nullid))
mpm@selenic.com
rawcommit dirstate tweak...
r442 if update_dirstate:
self.dirstate.update([f], "n")
mpm@selenic.com
hg rawcommit command...
r203 except IOError:
mpm@selenic.com
More tweaking to rawcommit for repo conversion...
r314 try:
del mm[f]
del mfm[f]
mpm@selenic.com
rawcommit dirstate tweak...
r442 if update_dirstate:
self.dirstate.forget([f])
mpm@selenic.com
More tweaking to rawcommit for repo conversion...
r314 except:
# deleted from p2?
pass
mpm@selenic.com
hg rawcommit command...
r203
mpm@selenic.com
various fixups for git import...
r302 mnode = self.manifest.add(mm, mfm, tr, linkrev, c1[0], c2[0])
Matt Mackall
Add username/merge/editor to .hgrc...
r608 user = user or self.ui.username()
mpm@selenic.com
various fixups for git import...
r302 n = self.changelog.add(mnode, files, text, tr, p1, p2, user, date)
mpm@selenic.com
hg rawcommit command...
r203 tr.close()
mpm@selenic.com
rawcommit dirstate tweak...
r442 if update_dirstate:
self.dirstate.setparents(n, nullid)
mpm@selenic.com
hg rawcommit command...
r203
mpm@selenic.com
hg commit: user and date options...
r317 def commit(self, files = None, text = "", user = None, date = None):
mpm@selenic.com
change dircache into dirstate...
r220 commit = []
remove = []
if files:
for f in files:
s = self.dirstate.state(f)
mpm@selenic.com
root relative IO and valid commit states...
r244 if s in 'nmai':
mpm@selenic.com
change dircache into dirstate...
r220 commit.append(f)
elif s == 'r':
remove.append(f)
else:
mpm@selenic.com
root relative IO and valid commit states...
r244 self.ui.warn("%s not tracked!\n" % f)
mpm@selenic.com
change dircache into dirstate...
r220 else:
Bryan O'Sullivan
Work on walk code.
r723 (c, a, d, u) = self.changes()
mpm@selenic.com
change dircache into dirstate...
r220 commit = c + a
remove = d
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
mpm@selenic.com
change dircache into dirstate...
r220 if not commit and not remove:
mpm@selenic.com
Bail on attempts to do an empty commit
r151 self.ui.status("nothing changed\n")
return
mpm@selenic.com
Add initial hook support...
r487 if not self.hook("precommit"):
return 1
mpm@selenic.com
teach commit about dirstate.parents()...
r229 p1, p2 = self.dirstate.parents()
c1 = self.changelog.read(p1)
c2 = self.changelog.read(p2)
m1 = self.manifest.read(c1[0])
mpm@selenic.com
add tracking of execute permissions...
r276 mf1 = self.manifest.readflags(c1[0])
mpm@selenic.com
teach commit about dirstate.parents()...
r229 m2 = self.manifest.read(c2[0])
mpm@selenic.com
fix repo locking...
r225 lock = self.lock()
mpm@selenic.com
Bail on attempts to do an empty commit
r151 tr = self.transaction()
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 # check in files
new = {}
linkrev = self.changelog.count()
mpm@selenic.com
change dircache into dirstate...
r220 commit.sort()
for f in commit:
mpm@selenic.com
Add -q quiet option...
r83 self.ui.note(f + "\n")
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 try:
mpm@selenic.com
Permission handling for the other OS...
r441 mf1[f] = util.is_exec(self.wjoin(f), mf1.get(f, False))
mpm@selenic.com
Minor tweak to binary mode patch...
r418 t = self.wfile(f).read()
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 except IOError:
mark.williamson@cl.cam.ac.uk
A number of minor fixes to problems that pychecker found....
r667 self.ui.warn("trouble committing %s!\n" % f)
mpm@selenic.com
change dircache into dirstate...
r220 raise
mpm@selenic.com
Add hg copy...
r363 meta = {}
cp = self.dirstate.copied(f)
if cp:
meta["copy"] = cp
meta["copyrev"] = hex(m1.get(cp, m2.get(cp, nullid)))
mpm@selenic.com
More whitespace cleanups...
r575 self.ui.debug(" %s: copy %s:%s\n" % (f, cp, meta["copyrev"]))
mpm@selenic.com
Add hg copy...
r363
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 r = self.file(f)
mpm@selenic.com
teach commit about dirstate.parents()...
r229 fp1 = m1.get(f, nullid)
fp2 = m2.get(f, nullid)
mpm@selenic.com
Add hg copy...
r363 new[f] = r.add(t, meta, tr, linkrev, fp1, fp2)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
# update manifest
mpm@selenic.com
teach commit about dirstate.parents()...
r229 m1.update(new)
mpm@selenic.com
[PATCH] Removal of a file added by merging branches...
r416 for f in remove:
if f in m1:
del m1[f]
mason@suse.com
Performance enhancements for manifest.add()...
r644 mn = self.manifest.add(m1, mf1, tr, linkrev, c1[0], c2[0], (new,remove))
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
# add changeset
new = new.keys()
new.sort()
mpm@selenic.com
commit: edit text fixups...
r288 if not text:
edittext = "\n" + "HG: manifest hash %s\n" % hex(mn)
edittext += "".join(["HG: changed %s\n" % f for f in new])
edittext += "".join(["HG: removed %s\n" % f for f in remove])
edittext = self.ui.edit(edittext)
if not edittext.rstrip():
return 1
text = edittext
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
Matt Mackall
Add username/merge/editor to .hgrc...
r608 user = user or self.ui.username()
mpm@selenic.com
hg commit: user and date options...
r317 n = self.changelog.add(mn, new, text, tr, p1, p2, user, date)
mpm@selenic.com
Add initial hook support...
r487
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 tr.close()
mpm@selenic.com
teach commit about dirstate.parents()...
r229 self.dirstate.setparents(n)
mpm@selenic.com
change dircache into dirstate...
r220 self.dirstate.update(new, "n")
self.dirstate.forget(remove)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
Matt Mackall
Move commit hook after commit completes...
r660 if not self.hook("commit", node=hex(n)):
return 1
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724 def walk(self, node = None, files = [], match = util.always):
if node:
Bryan O'Sullivan
Add a source designator to the walk methods....
r726 for fn in self.manifest.read(self.changelog.read(node)[0]):
yield 'm', fn
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724 else:
Bryan O'Sullivan
Add a source designator to the walk methods....
r726 for src, fn in self.dirstate.walk(files, match):
yield src, fn
Bryan O'Sullivan
Work on walk code.
r723
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724 def changes(self, node1 = None, node2 = None, files = [],
match = util.always):
mpm@selenic.com
repo.changes: fix duplicate changes...
r566 mf2, u = None, []
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 def fcmp(fn, mf):
mpm@selenic.com
Add wopener for opening files in the working directory...
r291 t1 = self.wfile(fn).read()
mpm@selenic.com
Make diffdir take a revision argument
r29 t2 = self.file(fn).revision(mf[fn])
return cmp(t1, t2)
Bryan O'Sullivan
Work on walk code.
r723 def mfmatches(node):
mf = dict(self.manifest.read(node))
for fn in mf.keys():
if not match(fn):
del mf[fn]
return mf
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 # are we comparing the working directory?
mpm@selenic.com
Fix dodiff/changes...
r561 if not node2:
Bryan O'Sullivan
Work on walk code.
r723 l, c, a, d, u = self.dirstate.changes(files, match)
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536
# are we comparing working dir against its parent?
mpm@selenic.com
Fix dodiff/changes...
r561 if not node1:
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 if l:
# do a full compare of any files that might have changed
change = self.changelog.read(self.dirstate.parents()[0])
Bryan O'Sullivan
Work on walk code.
r723 mf2 = mfmatches(change[0])
mpm@selenic.com
Fix braindamage in repo.changes...
r548 for f in l:
mpm@selenic.com
Fix dodiff/changes...
r561 if fcmp(f, mf2):
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 c.append(f)
mpm@selenic.com
Fix dodiff/changes...
r561
for l in c, a, d, u:
l.sort()
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 return (c, a, d, u)
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 # are we comparing working dir against non-tip?
# generate a pseudo-manifest for the working dir
mpm@selenic.com
Fix dodiff/changes...
r561 if not node2:
if not mf2:
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 change = self.changelog.read(self.dirstate.parents()[0])
Bryan O'Sullivan
Work on walk code.
r723 mf2 = mfmatches(change[0])
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 for f in a + c + l:
mpm@selenic.com
Fix dodiff/changes...
r561 mf2[f] = ""
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 for f in d:
mpm@selenic.com
Fix dodiff/changes...
r561 if f in mf2: del mf2[f]
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 else:
mpm@selenic.com
Fix dodiff/changes...
r561 change = self.changelog.read(node2)
Bryan O'Sullivan
Work on walk code.
r723 mf2 = mfmatches(change[0])
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
mpm@selenic.com
repo.changes: fix duplicate changes...
r566 # flush lists from dirstate before comparing manifests
c, a = [], []
mpm@selenic.com
Fix dodiff/changes...
r561 change = self.changelog.read(node1)
Bryan O'Sullivan
Work on walk code.
r723 mf1 = mfmatches(change[0])
mpm@selenic.com
Add diffrevs function to compare two nodes
r32
for fn in mf2:
if mf1.has_key(fn):
if mf1[fn] != mf2[fn]:
mpm@selenic.com
Fix dodiff/changes...
r561 if mf2[fn] != "" or fcmp(fn, mf1):
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 c.append(fn)
mpm@selenic.com
Add diffrevs function to compare two nodes
r32 del mf1[fn]
else:
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 a.append(fn)
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 d = mf1.keys()
mpm@selenic.com
Fix dodiff/changes...
r561
for l in c, a, d, u:
l.sort()
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 return (c, a, d, u)
mpm@selenic.com
Add diffrevs function to compare two nodes
r32
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 def add(self, list):
mpm@selenic.com
change dircache into dirstate...
r220 for f in list:
mpm@selenic.com
root relative IO and valid commit states...
r244 p = self.wjoin(f)
shaleh@speakeasy.net
* clean up error handling when user requests to use a non file object...
r611 if not os.path.exists(p):
Matt Mackall
Whitespace cleanup...
r659 self.ui.warn("%s does not exist!\n" % f)
shaleh@speakeasy.net
* clean up error handling when user requests to use a non file object...
r611 elif not os.path.isfile(p):
self.ui.warn("%s not added: mercurial only supports files currently\n" % f)
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724 elif self.dirstate.state(f) in 'an':
mpm@selenic.com
change dircache into dirstate...
r220 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])
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
def remove(self, list):
for f in list:
mpm@selenic.com
root relative IO and valid commit states...
r244 p = self.wjoin(f)
shaleh@speakeasy.net
* clean up error handling when user requests to use a non file object...
r611 if os.path.exists(p):
mpm@selenic.com
change dircache into dirstate...
r220 self.ui.warn("%s still exists!\n" % f)
mpm@selenic.com
[PATCH] (3/4) Removing an added file...
r402 elif self.dirstate.state(f) == 'a':
self.ui.warn("%s never committed!\n" % f)
Matt Mackall
dirstate.forget() takes a list...
r657 self.dirstate.forget([f])
mpm@selenic.com
change dircache into dirstate...
r220 elif f not in self.dirstate:
self.ui.warn("%s not tracked!\n" % f)
else:
self.dirstate.update([f], "r")
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
mpm@selenic.com
Add hg copy...
r363 def copy(self, source, dest):
p = self.wjoin(dest)
shaleh@speakeasy.net
* clean up error handling when user requests to use a non file object...
r611 if not os.path.exists(dest):
mpm@selenic.com
Add hg copy...
r363 self.ui.warn("%s does not exist!\n" % dest)
shaleh@speakeasy.net
* clean up error handling when user requests to use a non file object...
r611 elif not os.path.isfile(dest):
Matt Mackall
Whitespace cleanup...
r659 self.ui.warn("copy failed: %s is not a file\n" % dest)
mpm@selenic.com
Add hg copy...
r363 else:
if self.dirstate.state(dest) == '?':
self.dirstate.update([dest], "a")
self.dirstate.copy(source, dest)
mpm@selenic.com
make pull work for multiple heads...
r222 def heads(self):
return self.changelog.heads()
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 def branches(self, nodes):
if not nodes: nodes = [self.changelog.tip()]
b = []
for n in nodes:
t = n
while n:
p = self.changelog.parents(n)
if p[1] != nullid or p[0] == nullid:
b.append((t, n, p[0], p[1]))
break
n = p[0]
return b
def between(self, pairs):
r = []
for top, bottom in pairs:
n, l, i = top, [], 0
f = 1
while n != bottom:
p = self.changelog.parents(n)[0]
if i == f:
mpm@selenic.com
More whitespace cleanups...
r575 l.append(n)
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 f = f * 2
n = p
i += 1
r.append(l)
return r
def newer(self, nodes):
m = {}
nl = []
mpm@selenic.com
Refactor merge code...
r94 pm = {}
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 cl = self.changelog
t = l = cl.count()
mpm@selenic.com
Refactor merge code...
r94
# find the lowest numbered node
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 for n in nodes:
l = min(l, cl.rev(n))
mpm@selenic.com
Refactor merge code...
r94 m[n] = 1
mpm@selenic.com
Add changegroup support
r46
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 for i in xrange(l, t):
n = cl.node(i)
mpm@selenic.com
Refactor merge code...
r94 if n in m: # explicitly listed
pm[n] = 1
nl.append(n)
continue
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 for p in cl.parents(n):
mpm@selenic.com
Refactor merge code...
r94 if p in pm: # parent listed
pm[n] = 1
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 nl.append(n)
mpm@selenic.com
Refactor merge code...
r94 break
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56
return nl
Matt Mackall
Add a function to calculate the outgoing changegroup
r621 def findincoming(self, remote, base={}):
mpm@selenic.com
Fix up a bunch of bugs in the new merge code...
r65 m = self.changelog.nodemap
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 search = []
fetch = []
mpm@selenic.com
Improve pruning of branches in outstanding changeset algorithm...
r148 seen = {}
seenbranch = {}
mpm@selenic.com
Changes to network protocol...
r192
Matt Mackall
Move the empty changeset detection out of findincoming to pull...
r636 # assume we're closer to the tip than the root
mpm@selenic.com
Actually warn on pulling from an unrelated repository...
r579 # and start by examining the heads
mpm@selenic.com
make pull work for multiple heads...
r222 self.ui.status("searching for changes\n")
heads = remote.heads()
unknown = []
for h in heads:
if h not in m:
unknown.append(h)
Matt Mackall
Add a function to calculate the outgoing changegroup
r621 else:
base[h] = 1
mpm@selenic.com
Add changegroup support
r46
mpm@selenic.com
make pull work for multiple heads...
r222 if not unknown:
mpm@selenic.com
Add hg:// protocol...
r60 return None
mpm@selenic.com
hg merge: some getchangegroup fixups...
r324
rep = {}
reqcnt = 0
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
Actually warn on pulling from an unrelated repository...
r579 # search through remote branches
# a 'branch' here is a linear segment of history, with four parts:
# head, root, first parent, second parent
# (a branch always has two parents (or none) by definition)
mpm@selenic.com
make pull work for multiple heads...
r222 unknown = remote.branches(unknown)
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 while unknown:
mpm@selenic.com
hg merge: some getchangegroup fixups...
r324 r = []
while unknown:
n = unknown.pop(0)
if n[0] in seen:
continue
mpm@selenic.com
Improve pruning of branches in outstanding changeset algorithm...
r148
mpm@selenic.com
hg merge: some getchangegroup fixups...
r324 self.ui.debug("examining %s:%s\n" % (short(n[0]), short(n[1])))
if n[0] == nullid:
break
mpm@selenic.com
hg pull: more query fixes...
r328 if n in seenbranch:
mpm@selenic.com
hg merge: some getchangegroup fixups...
r324 self.ui.debug("branch already found\n")
continue
if n[1] and n[1] in m: # do we know the base?
self.ui.debug("found incomplete branch %s:%s\n"
% (short(n[0]), short(n[1])))
search.append(n) # schedule branch range for scanning
mpm@selenic.com
hg pull: more query fixes...
r328 seenbranch[n] = 1
mpm@selenic.com
hg merge: some getchangegroup fixups...
r324 else:
if n[1] not in seen and n[1] not in fetch:
if n[2] in m and n[3] in m:
self.ui.debug("found new changeset %s\n" %
short(n[1]))
fetch.append(n[1]) # earliest unknown
mpm@selenic.com
Actually warn on pulling from an unrelated repository...
r579 base[n[2]] = 1 # latest known
mpm@selenic.com
hg merge: some getchangegroup fixups...
r324 continue
for a in n[2:4]:
if a not in rep:
r.append(a)
rep[a] = 1
mpm@selenic.com
hg pull: more query fixes...
r328 seen[n[0]] = 1
mpm@selenic.com
hg merge: some getchangegroup fixups...
r324 if r:
reqcnt += 1
self.ui.debug("request %d: %s\n" %
(reqcnt, " ".join(map(short, r))))
for p in range(0, len(r), 10):
for b in remote.branches(r[p:p+10]):
mpm@selenic.com
Improve pruning of branches in outstanding changeset algorithm...
r148 self.ui.debug("received %s:%s\n" %
(short(b[0]), short(b[1])))
if b[0] not in m and b[0] not in seen:
unknown.append(b)
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
Actually warn on pulling from an unrelated repository...
r579 # do binary search on the branches we found
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 while search:
n = search.pop(0)
mpm@selenic.com
hg merge: some getchangegroup fixups...
r324 reqcnt += 1
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 l = remote.between([(n[0], n[1])])[0]
mpm@selenic.com
hg pull: more query fixes...
r328 l.append(n[1])
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 p = n[0]
f = 1
mpm@selenic.com
hg pull: more query fixes...
r328 for i in l:
self.ui.debug("narrowing %d:%d %s\n" % (f, len(l), short(i)))
mpm@selenic.com
Fix up a bunch of bugs in the new merge code...
r65 if i in m:
mpm@selenic.com
Fix merge bug, I hope
r85 if f <= 2:
mpm@selenic.com
Add -q quiet option...
r83 self.ui.debug("found new branch changeset %s\n" %
short(p))
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 fetch.append(p)
mpm@selenic.com
Actually warn on pulling from an unrelated repository...
r579 base[i] = 1
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 else:
mpm@selenic.com
Add -q quiet option...
r83 self.ui.debug("narrowed branch search to %s:%s\n"
% (short(p), short(i)))
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 search.append((p, i))
mpm@selenic.com
Fix up a bunch of bugs in the new merge code...
r65 break
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 p, f = i, f * 2
mpm@selenic.com
Actually warn on pulling from an unrelated repository...
r579 # sanity check our fetch list
mpm@selenic.com
Fix up a bunch of bugs in the new merge code...
r65 for f in fetch:
if f in m:
mpm@selenic.com
Add exception class for repository errors...
r499 raise RepoError("already have changeset " + short(f[:4]))
mpm@selenic.com
Add -q quiet option...
r83
mpm@selenic.com
Actually warn on pulling from an unrelated repository...
r579 if base.keys() == [nullid]:
mpm@selenic.com
change unrelated repository error to a warning...
r514 self.ui.warn("warning: pulling from an unrelated repository!\n")
mpm@selenic.com
Disallow merging of unrelated projects...
r511
mpm@selenic.com
Refactor merge code...
r94 self.ui.note("adding new changesets starting at " +
mpm@selenic.com
Add -q quiet option...
r83 " ".join([short(f) for f in fetch]) + "\n")
mpm@selenic.com
Fix up a bunch of bugs in the new merge code...
r65
mpm@selenic.com
hg merge: some getchangegroup fixups...
r324 self.ui.debug("%d total queries\n" % reqcnt)
mpm@selenic.com
Change getchangegroup to findincoming...
r516 return fetch
Matt Mackall
Add a function to calculate the outgoing changegroup
r621 def findoutgoing(self, remote):
base = {}
Matt Mackall
Fix up the broken bits in findoutgoing
r637 self.findincoming(remote, base)
Matt Mackall
Add a function to calculate the outgoing changegroup
r621 remain = dict.fromkeys(self.changelog.nodemap)
# prune everything remote has from the tree
Matt Mackall
Fix up the broken bits in findoutgoing
r637 del remain[nullid]
Matt Mackall
Add a function to calculate the outgoing changegroup
r621 remove = base.keys()
while remove:
n = remove.pop(0)
if n in remain:
del remain[n]
for p in self.changelog.parents(n):
Matt Mackall
Fix up the broken bits in findoutgoing
r637 remove.append(p)
Matt Mackall
Add a function to calculate the outgoing changegroup
r621
# find every node whose parents have been pruned
subset = []
for n in remain:
p1, p2 = self.changelog.parents(n)
if p1 not in remain and p2 not in remain:
subset.append(n)
# this is the set of all roots we have to push
return subset
Matt Mackall
Add generic repo commands for pull and push
r622 def pull(self, remote):
lock = self.lock()
Matt Mackall
Move the empty changeset detection out of findincoming to pull...
r636
# if we have an empty repo, fetch everything
if self.changelog.tip() == nullid:
self.ui.status("requesting all changes\n")
fetch = [nullid]
else:
fetch = self.findincoming(remote)
Matt Mackall
Add generic repo commands for pull and push
r622 if not fetch:
self.ui.status("no changes found\n")
return 1
cg = remote.changegroup(fetch)
return self.addchangegroup(cg)
def push(self, remote):
lock = remote.lock()
update = self.findoutgoing(remote)
if not update:
self.ui.status("no changes found\n")
return 1
cg = self.changegroup(update)
return remote.addchangegroup(cg)
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 def changegroup(self, basenodes):
mpm@selenic.com
make pull work for multiple heads...
r222 class genread:
def __init__(self, generator):
self.g = generator
self.buf = ""
def read(self, l):
while l > len(self.buf):
try:
self.buf += self.g.next()
except StopIteration:
break
d, self.buf = self.buf[:l], self.buf[l:]
return d
mpm@selenic.com
Whitespace cleanups...
r515
Matt Mackall
Protocol switch from using generators to stream-like objects....
r635 def gengroup():
nodes = self.newer(basenodes)
# construct the link map
linkmap = {}
for n in nodes:
linkmap[self.changelog.rev(n)] = n
# construct a list of all changed files
changed = {}
for n in nodes:
c = self.changelog.read(n)
for f in c[3]:
changed[f] = 1
changed = changed.keys()
changed.sort()
# the changegroup is changesets + manifests + all file revs
revs = [ self.changelog.rev(n) for n in nodes ]
for y in self.changelog.group(linkmap): yield y
for y in self.manifest.group(linkmap): yield y
for f in changed:
yield struct.pack(">l", len(f) + 4) + f
g = self.file(f).group(linkmap)
for y in g:
yield y
yield struct.pack(">l", 0)
return genread(gengroup())
def addchangegroup(self, source):
mpm@selenic.com
make pull work for multiple heads...
r222 def getchunk():
d = source.read(4)
if not d: return ""
l = struct.unpack(">l", d)[0]
if l <= 4: return ""
return source.read(l - 4)
def getgroup():
while 1:
c = getchunk()
if not c: break
yield c
def csmap(x):
self.ui.debug("add changeset %s\n" % short(x))
return self.changelog.count()
def revmap(x):
return self.changelog.rev(x)
Matt Mackall
Protocol switch from using generators to stream-like objects....
r635 if not source: return
mpm@selenic.com
make pull work for multiple heads...
r222 changesets = files = revisions = 0
mpm@selenic.com
fix repo locking...
r225
mpm@selenic.com
make pull work for multiple heads...
r222 tr = self.transaction()
# pull off the changeset group
self.ui.status("adding changesets\n")
co = self.changelog.tip()
mpm@selenic.com
fix bad assumption about uniqueness of file versions...
r224 cn = self.changelog.addgroup(getgroup(), csmap, tr, 1) # unique
mpm@selenic.com
make pull work for multiple heads...
r222 changesets = self.changelog.rev(cn) - self.changelog.rev(co)
# pull off the manifest group
self.ui.status("adding manifests\n")
mm = self.manifest.tip()
mo = self.manifest.addgroup(getgroup(), revmap, tr)
# process the files
self.ui.status("adding file revisions\n")
while 1:
f = getchunk()
if not f: break
self.ui.debug("adding %s revisions\n" % f)
fl = self.file(f)
mpm@selenic.com
Attempt to fix negative revision count from pull...
r529 o = fl.count()
mpm@selenic.com
make pull work for multiple heads...
r222 n = fl.addgroup(getgroup(), revmap, tr)
mpm@selenic.com
Attempt to fix negative revision count from pull...
r529 revisions += fl.count() - o
mpm@selenic.com
make pull work for multiple heads...
r222 files += 1
self.ui.status(("modified %d files, added %d changesets" +
" and %d new revisions\n")
% (files, changesets, revisions))
tr.close()
return
mpm@selenic.com
[PATCH] hg revert...
r588 def update(self, node, allow=False, force=False, choose=None,
moddirstate=True):
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 pl = self.dirstate.parents()
mpm@selenic.com
various merge improvements...
r275 if not force and pl[1] != nullid:
mpm@selenic.com
unify checkout and resolve into update...
r254 self.ui.warn("aborting: outstanding uncommitted merges\n")
mpm@selenic.com
Minor merge fixups...
r690 return 1
mpm@selenic.com
Add changegroup support
r46
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 p1, p2 = pl[0], node
mpm@selenic.com
more merge fixes...
r305 pa = self.changelog.ancestor(p1, p2)
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 m1n = self.changelog.read(p1)[0]
m2n = self.changelog.read(p2)[0]
man = self.manifest.ancestor(m1n, m2n)
m1 = self.manifest.read(m1n)
mpm@selenic.com
add tracking of execute permissions...
r276 mf1 = self.manifest.readflags(m1n)
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 m2 = self.manifest.read(m2n)
mpm@selenic.com
add tracking of execute permissions...
r276 mf2 = self.manifest.readflags(m2n)
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 ma = self.manifest.read(man)
mpm@selenic.com
[PATCH]: Typo in localrepository.update...
r412 mfa = self.manifest.readflags(man)
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232
Bryan O'Sullivan
Work on walk code.
r723 (c, a, d, u) = self.changes()
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232
mpm@selenic.com
[PATCH] Merging files that are deleted in both branches...
r408 # is this a jump, or a merge? i.e. is there a linear path
# from p1 to p2?
linear_path = (pa == p1 or pa == p2)
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 # resolve the manifest to determine which files
# we care about merging
mpm@selenic.com
unify checkout and resolve into update...
r254 self.ui.note("resolving manifests\n")
Matt Mackall
Fix bug in reverting deleted files...
r650 self.ui.debug(" force %s allow %s moddirstate %s linear %s\n" %
(force, allow, moddirstate, linear_path))
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 self.ui.debug(" ancestor %s local %s remote %s\n" %
(short(man), short(m1n), short(m2n)))
merge = {}
get = {}
remove = []
mpm@selenic.com
more merge fixes...
r305 mark = {}
mpm@selenic.com
Add changegroup support
r46
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 # construct a working dir manifest
mw = m1.copy()
mpm@selenic.com
add tracking of execute permissions...
r276 mfw = mf1.copy()
mpm@selenic.com
Handle unknown files better on update...
r576 umap = dict.fromkeys(u)
mpm@selenic.com
unify checkout and resolve into update...
r254 for f in a + c + u:
mw[f] = ""
mpm@selenic.com
Permission handling for the other OS...
r441 mfw[f] = util.is_exec(self.wjoin(f), mfw.get(f, False))
mpm@selenic.com
Handle unknown files better on update...
r576
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 for f in d:
mpm@selenic.com
unify checkout and resolve into update...
r254 if f in mw: del mw[f]
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232
mpm@selenic.com
[PATCH] Merging files that are deleted in both branches...
r408 # If we're jumping between revisions (as opposed to merging),
# and if neither the working directory nor the target rev has
# the file, then we need to remove it from the dirstate, to
# prevent the dirstate from listing the file when it is no
# longer in the manifest.
mpm@selenic.com
[PATCH] hg revert...
r588 if moddirstate and linear_path and f not in m2:
mpm@selenic.com
[PATCH] Merging files that are deleted in both branches...
r408 self.dirstate.forget((f,))
mpm@selenic.com
Handle unknown files better on update...
r576 # Compare manifests
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 for f, n in mw.iteritems():
mpm@selenic.com
[PATCH] hg revert...
r588 if choose and not choose(f): continue
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 if f in m2:
mpm@selenic.com
merge: update permissions even if file contents didn't change...
r277 s = 0
mpm@selenic.com
[PATCH] Merging identical changes from another branch...
r407 # is the wfile new since m1, and match m2?
mpm@selenic.com
Fix typo in merging new files...
r428 if f not in m1:
mpm@selenic.com
[PATCH] Merging identical changes from another branch...
r407 t1 = self.wfile(f).read()
t2 = self.file(f).revision(m2[f])
if cmp(t1, t2) == 0:
mark[f] = 1
n = m2[f]
del t1, t2
mpm@selenic.com
hg update: fix clobbering files when going backwards...
r296 # are files different?
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 if n != m2[f]:
mpm@selenic.com
unify checkout and resolve into update...
r254 a = ma.get(f, nullid)
mpm@selenic.com
hg update: fix clobbering files when going backwards...
r296 # are both different from the ancestor?
mpm@selenic.com
unify checkout and resolve into update...
r254 if n != a and m2[f] != a:
mpm@selenic.com
merge: Fix bug where we overwrote local when local was newer...
r273 self.ui.debug(" %s versions differ, resolve\n" % f)
mpm@selenic.com
add tracking of execute permissions...
r276 # merge executable bits
# "if we changed or they changed, change in merge"
a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
mode = ((a^b) | (a^c)) ^ a
merge[f] = (m1.get(f, nullid), m2[f], mode)
mpm@selenic.com
merge: update permissions even if file contents didn't change...
r277 s = 1
mpm@selenic.com
more merge fixes...
r305 # are we clobbering?
# is remote's version newer?
# or are we going back in time?
elif force or m2[f] != a or (p2 == pa and mw[f] == m1[f]):
mpm@selenic.com
merge: Fix bug where we overwrote local when local was newer...
r273 self.ui.debug(" remote %s is newer, get\n" % f)
mpm@selenic.com
unify checkout and resolve into update...
r254 get[f] = m2[f]
mpm@selenic.com
merge: update permissions even if file contents didn't change...
r277 s = 1
mpm@selenic.com
more merge fixes...
r305 else:
mark[f] = 1
mpm@selenic.com
Handle unknown files better on update...
r576 elif f in umap:
# this unknown file is the same as the checkout
get[f] = m2[f]
mpm@selenic.com
merge: update permissions even if file contents didn't change...
r277
if not s and mfw[f] != mf2[f]:
if force:
self.ui.debug(" updating permissions for %s\n" % f)
mpm@selenic.com
Permission handling for the other OS...
r441 util.set_exec(self.wjoin(f), mf2[f])
mpm@selenic.com
merge: update permissions even if file contents didn't change...
r277 else:
a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
mode = ((a^b) | (a^c)) ^ a
if mode != b:
self.ui.debug(" updating permissions for %s\n" % f)
mpm@selenic.com
Permission handling for the other OS...
r441 util.set_exec(self.wjoin(f), mode)
mpm@selenic.com
more merge fixes...
r305 mark[f] = 1
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 del m2[f]
elif f in ma:
maf46@burn.cl.cam.ac.uk
Fix zombie files in merge...
r616 if n != ma[f]:
r = "d"
if not force and (linear_path or allow):
mpm@selenic.com
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted...
r415 r = self.ui.prompt(
(" local changed %s which remote deleted\n" % f) +
"(k)eep or (d)elete?", "[kd]", "k")
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 if r == "d":
remove.append(f)
else:
self.ui.debug("other deleted %s\n" % f)
mpm@selenic.com
unify checkout and resolve into update...
r254 remove.append(f) # other deleted it
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 else:
mpm@selenic.com
unify checkout and resolve into update...
r254 if n == m1.get(f, nullid): # same as parent
mpm@selenic.com
hg merge: fix time asymmetry bug with deleting files on update to past...
r383 if p2 == pa: # going backwards?
self.ui.debug("remote deleted %s\n" % f)
remove.append(f)
else:
self.ui.debug("local created %s, keeping\n" % f)
mpm@selenic.com
unify checkout and resolve into update...
r254 else:
self.ui.debug("working dir created %s, keeping\n" % f)
mpm@selenic.com
Add changegroup support
r46
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 for f, n in m2.iteritems():
mpm@selenic.com
[PATCH] hg revert...
r588 if choose and not choose(f): continue
mpm@selenic.com
minor fixes for update()...
r256 if f[0] == "/": continue
maf46@burn.cl.cam.ac.uk
Fix zombie files in merge...
r616 if f in ma and n != ma[f]:
r = "k"
if not force and (linear_path or allow):
mpm@selenic.com
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted...
r415 r = self.ui.prompt(
("remote changed %s which local deleted\n" % f) +
"(k)eep or (d)elete?", "[kd]", "k")
maf46@burn.cl.cam.ac.uk
Fix zombie files in merge...
r616 if r == "k": get[f] = n
elif f not in ma:
mpm@selenic.com
unify checkout and resolve into update...
r254 self.ui.debug("remote created %s\n" % f)
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 get[f] = n
maf46@burn.cl.cam.ac.uk
Fix zombie files in merge...
r616 else:
Matt Mackall
Handle undeletion of files when checking out old revisions...
r680 if force or p2 == pa: # going backwards?
self.ui.debug("local deleted %s, recreating\n" % f)
Matt Mackall
Fix bug in reverting deleted files...
r650 get[f] = n
Matt Mackall
Handle undeletion of files when checking out old revisions...
r680 else:
self.ui.debug("local deleted %s\n" % f)
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232
del mw, m1, m2, ma
mpm@selenic.com
various merge improvements...
r275 if force:
for f in merge:
get[f] = merge[f][1]
merge = {}
mpm@selenic.com
Minor merge fixups...
r690 if linear_path or force:
mpm@selenic.com
unify checkout and resolve into update...
r254 # we don't need to do any magic, just jump to the new rev
mode = 'n'
p1, p2 = p2, nullid
else:
mpm@selenic.com
various merge improvements...
r275 if not allow:
mpm@selenic.com
more merge fixes...
r305 self.ui.status("this update spans a branch" +
" affecting the following files:\n")
fl = merge.keys() + get.keys()
fl.sort()
for f in fl:
cf = ""
if f in merge: cf = " (resolve)"
self.ui.status(" %s%s\n" % (f, cf))
self.ui.warn("aborting update spanning branches!\n")
self.ui.status("(use update -m to perform a branch merge)\n")
mpm@selenic.com
various merge improvements...
r275 return 1
mpm@selenic.com
unify checkout and resolve into update...
r254 # we have to remember what files we needed to get/change
# because any file that's different from either one of its
# parents must be in the changeset
mode = 'm'
mpm@selenic.com
[PATCH] hg revert...
r588 if moddirstate:
self.dirstate.update(mark.keys(), "m")
mpm@selenic.com
unify checkout and resolve into update...
r254
mpm@selenic.com
[PATCH] hg revert...
r588 if moddirstate:
self.dirstate.setparents(p1, p2)
mpm@selenic.com
merge: add count of new manifests, files, and revisions...
r191
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 # get the files we don't need to change
files = get.keys()
files.sort()
for f in files:
if f[0] == "/": continue
mpm@selenic.com
merge: Fix bug where we overwrote local when local was newer...
r273 self.ui.note("getting %s\n" % f)
mpm@selenic.com
add tracking of execute permissions...
r276 t = self.file(f).read(get[f])
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 try:
mpm@selenic.com
Add wopener for opening files in the working directory...
r291 self.wfile(f, "w").write(t)
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 except IOError:
Thomas Arendsen Hein
Fixed usage of removed variable 'wp'.
r297 os.makedirs(os.path.dirname(self.wjoin(f)))
mpm@selenic.com
Add wopener for opening files in the working directory...
r291 self.wfile(f, "w").write(t)
mpm@selenic.com
Permission handling for the other OS...
r441 util.set_exec(self.wjoin(f), mf2[f])
mpm@selenic.com
[PATCH] hg revert...
r588 if moddirstate:
self.dirstate.update([f], mode)
mpm@selenic.com
Add changegroup support
r46
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 # merge the tricky bits
files = merge.keys()
files.sort()
for f in files:
mpm@selenic.com
minor fixes for update()...
r256 self.ui.status("merging %s\n" % f)
mpm@selenic.com
add tracking of execute permissions...
r276 m, o, flag = merge[f]
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 self.merge3(f, m, o)
mpm@selenic.com
Permission handling for the other OS...
r441 util.set_exec(self.wjoin(f), flag)
mpm@selenic.com
[PATCH] hg revert...
r588 if moddirstate:
self.dirstate.update([f], 'm')
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232
Matt Mackall
Sort files for removal
r681 remove.sort()
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 for f in remove:
self.ui.note("removing %s\n" % f)
mpm@selenic.com
Minor merge fixups...
r690 try:
os.unlink(f)
except OSError, inst:
self.ui.warn("update failed to remove %s: %s!\n" % (f, inst))
mpm@selenic.com
Remove empty directories on update...
r578 # try removing directories that might now be empty
try: os.removedirs(os.path.dirname(f))
except: pass
mpm@selenic.com
[PATCH] hg revert...
r588 if moddirstate:
if mode == 'n':
self.dirstate.forget(remove)
else:
self.dirstate.update(remove, 'r')
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232
def merge3(self, fn, my, other):
"""perform a 3-way merge in the working directory"""
mpm@selenic.com
import and startup cleanups...
r249
mpm@selenic.com
Add updated merge3 code
r96 def temp(prefix, node):
pre = "%s~%s." % (os.path.basename(fn), prefix)
(fd, name) = tempfile.mkstemp("", pre)
mpm@selenic.com
[PATCH] file type fixes for the other 'OS'...
r417 f = os.fdopen(fd, "wb")
mpm@selenic.com
Add updated merge3 code
r96 f.write(fl.revision(node))
f.close()
return name
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 fl = self.file(fn)
mpm@selenic.com
Add updated merge3 code
r96 base = fl.ancestor(my, other)
mpm@selenic.com
root relative IO and valid commit states...
r244 a = self.wjoin(fn)
mpm@selenic.com
merge3: fix argument order...
r346 b = temp("base", base)
c = temp("other", other)
mpm@selenic.com
Add updated merge3 code
r96
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 self.ui.note("resolving %s\n" % fn)
self.ui.debug("file %s: other %s ancestor %s\n" %
(fn, short(other), short(base)))
mpm@selenic.com
Add updated merge3 code
r96
Thomas Arendsen Hein
merge program setting from hgrc wasn't used....
r703 cmd = (os.environ.get("HGMERGE") or self.ui.config("ui", "merge")
or "hgmerge")
mpm@selenic.com
Replace tkmerge with hgmerge...
r240 r = os.system("%s %s %s %s" % (cmd, a, b, c))
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 if r:
mpm@selenic.com
various merge improvements...
r275 self.ui.warn("merging %s failed!\n" % fn)
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232
os.unlink(b)
os.unlink(c)
mpm@selenic.com
Add updated merge3 code
r96
mpm@selenic.com
migrate verify...
r247 def verify(self):
filelinkrevs = {}
filenodes = {}
changesets = revisions = files = 0
errors = 0
mpm@selenic.com
various fixups for git import...
r302 seen = {}
mpm@selenic.com
migrate verify...
r247 self.ui.status("checking changesets\n")
for i in range(self.changelog.count()):
changesets += 1
n = self.changelog.node(i)
mpm@selenic.com
various fixups for git import...
r302 if n in seen:
self.ui.warn("duplicate changeset at revision %d\n" % i)
errors += 1
seen[n] = 1
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
migrate verify...
r247 for p in self.changelog.parents(n):
if p not in self.changelog.nodemap:
self.ui.warn("changeset %s has unknown parent %s\n" %
(short(n), short(p)))
errors += 1
try:
changes = self.changelog.read(n)
except Exception, inst:
self.ui.warn("unpacking changeset %s: %s\n" % (short(n), inst))
errors += 1
for f in changes[3]:
filelinkrevs.setdefault(f, []).append(i)
mpm@selenic.com
various fixups for git import...
r302 seen = {}
mpm@selenic.com
migrate verify...
r247 self.ui.status("checking manifests\n")
for i in range(self.manifest.count()):
n = self.manifest.node(i)
mpm@selenic.com
various fixups for git import...
r302 if n in seen:
self.ui.warn("duplicate manifest at revision %d\n" % i)
errors += 1
seen[n] = 1
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
migrate verify...
r247 for p in self.manifest.parents(n):
if p not in self.manifest.nodemap:
self.ui.warn("manifest %s has unknown parent %s\n" %
(short(n), short(p)))
errors += 1
try:
delta = mdiff.patchtext(self.manifest.delta(n))
except KeyboardInterrupt:
mpm@selenic.com
Remove all remaining print statements...
r582 self.ui.warn("aborted")
mpm@selenic.com
migrate verify...
r247 sys.exit(0)
except Exception, inst:
self.ui.warn("unpacking manifest %s: %s\n"
% (short(n), inst))
errors += 1
ff = [ l.split('\0') for l in delta.splitlines() ]
for f, fn in ff:
mpm@selenic.com
verify: don't die from new permission bits...
r284 filenodes.setdefault(f, {})[bin(fn[:40])] = 1
mpm@selenic.com
migrate verify...
r247
self.ui.status("crosschecking files in changesets and manifests\n")
for f in filenodes:
if f not in filelinkrevs:
self.ui.warn("file %s in manifest but not in changesets\n" % f)
errors += 1
for f in filelinkrevs:
if f not in filenodes:
self.ui.warn("file %s in changeset but not in manifest\n" % f)
errors += 1
self.ui.status("checking files\n")
ff = filenodes.keys()
ff.sort()
for f in ff:
if f == "/dev/null": continue
files += 1
fl = self.file(f)
nodes = { nullid: 1 }
mpm@selenic.com
various fixups for git import...
r302 seen = {}
mpm@selenic.com
migrate verify...
r247 for i in range(fl.count()):
revisions += 1
n = fl.node(i)
mpm@selenic.com
various fixups for git import...
r302 if n in seen:
self.ui.warn("%s: duplicate revision %d\n" % (f, i))
errors += 1
mpm@selenic.com
migrate verify...
r247 if n not in filenodes[f]:
self.ui.warn("%s: %d:%s not in manifests\n"
% (f, i, short(n)))
errors += 1
else:
del filenodes[f][n]
flr = fl.linkrev(n)
if flr not in filelinkrevs[f]:
self.ui.warn("%s:%s points to unexpected changeset %d\n"
% (f, short(n), fl.linkrev(n)))
errors += 1
else:
filelinkrevs[f].remove(flr)
# verify contents
try:
t = fl.read(n)
except Exception, inst:
self.ui.warn("unpacking file %s %s: %s\n"
% (f, short(n), inst))
errors += 1
# verify parents
(p1, p2) = fl.parents(n)
if p1 not in nodes:
self.ui.warn("file %s:%s unknown parent 1 %s" %
(f, short(n), short(p1)))
errors += 1
if p2 not in nodes:
self.ui.warn("file %s:%s unknown parent 2 %s" %
(f, short(n), short(p1)))
errors += 1
nodes[n] = 1
# cross-check
for node in filenodes[f]:
self.ui.warn("node %s in manifests not in %s\n"
% (hex(n), f))
errors += 1
self.ui.status("%d files, %d changesets, %d total revisions\n" %
(files, changesets, revisions))
if errors:
self.ui.warn("%d integrity errors encountered!\n" % errors)
return 1
Matt Mackall
Change remote repository to httprepository
r623 class httprepository:
mpm@selenic.com
Add hg:// protocol...
r60 def __init__(self, ui, path):
mpm@selenic.com
Change hg: protocol name to http: and http: to old-http:...
r176 self.url = path
mpm@selenic.com
Add hg:// protocol...
r60 self.ui = ui
mpm@selenic.com
Transparent proxy support...
r321 no_list = [ "localhost", "127.0.0.1" ]
host = ui.config("http_proxy", "host")
Thomas Arendsen Hein
Allow override of HTTP_PROXY, http_proxy and no_proxy; make no_proxy work....
r424 if host is None:
host = os.environ.get("http_proxy")
Thomas Arendsen Hein
Allow hgrc's proxy host and $http_proxy env var to start with http://...
r426 if host and host.startswith('http://'):
host = host[7:]
mpm@selenic.com
Transparent proxy support...
r321 user = ui.config("http_proxy", "user")
passwd = ui.config("http_proxy", "passwd")
no = ui.config("http_proxy", "no")
Thomas Arendsen Hein
Allow override of HTTP_PROXY, http_proxy and no_proxy; make no_proxy work....
r424 if no is None:
no = os.environ.get("no_proxy")
mpm@selenic.com
Transparent proxy support...
r321 if no:
no_list = no_list + no.split(",")
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
Transparent proxy support...
r321 no_proxy = 0
for h in no_list:
if (path.startswith("http://" + h + "/") or
path.startswith("http://" + h + ":") or
path == "http://" + h):
no_proxy = 1
# Note: urllib2 takes proxy values from the environment and those will
# take precedence
Thomas Arendsen Hein
Allow override of HTTP_PROXY, http_proxy and no_proxy; make no_proxy work....
r424 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]:
if os.environ.has_key(env):
del os.environ[env]
mpm@selenic.com
Transparent proxy support...
r321
proxy_handler = urllib2.BaseHandler()
if host and not no_proxy:
proxy_handler = urllib2.ProxyHandler({"http" : "http://" + host})
authinfo = None
if user and passwd:
passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
passmgr.add_password(None, host, user, passwd)
authinfo = urllib2.ProxyBasicAuthHandler(passmgr)
opener = urllib2.build_opener(proxy_handler, authinfo)
urllib2.install_opener(opener)
mpm@selenic.com
Add hg:// protocol...
r60
Matt Mackall
Add a repo method to report repo device...
r634 def dev(self):
return -1
mpm@selenic.com
Add hg:// protocol...
r60 def do_cmd(self, cmd, **args):
mpm@selenic.com
Add -q quiet option...
r83 self.ui.debug("sending %s command\n" % cmd)
mpm@selenic.com
Add hg:// protocol...
r60 q = {"cmd": cmd}
q.update(args)
qs = urllib.urlencode(q)
cu = "%s?%s" % (self.url, qs)
mpm@selenic.com
Transparent proxy support...
r321 return urllib2.urlopen(cu)
mpm@selenic.com
Add hg:// protocol...
r60
mpm@selenic.com
make pull work for multiple heads...
r222 def heads(self):
d = self.do_cmd("heads").read()
try:
return map(bin, d[:-1].split(" "))
except:
self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
raise
mpm@selenic.com
Add hg:// protocol...
r60 def branches(self, nodes):
n = " ".join(map(hex, nodes))
mpm@selenic.com
Fix up a bunch of bugs in the new merge code...
r65 d = self.do_cmd("branches", nodes=n).read()
mpm@selenic.com
merge: catch unexpected responses...
r217 try:
br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
return br
except:
self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
raise
mpm@selenic.com
Add hg:// protocol...
r60
def between(self, pairs):
n = "\n".join(["-".join(map(hex, p)) for p in pairs])
mpm@selenic.com
Fix up a bunch of bugs in the new merge code...
r65 d = self.do_cmd("between", pairs=n).read()
mpm@selenic.com
merge: catch unexpected responses...
r217 try:
p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
return p
except:
self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
raise
mpm@selenic.com
Add hg:// protocol...
r60
def changegroup(self, nodes):
n = " ".join(map(hex, nodes))
mpm@selenic.com
Fix up a bunch of bugs in the new merge code...
r65 f = self.do_cmd("changegroup", roots=n)
mpm@selenic.com
Changes to network protocol...
r192 bytes = 0
Matt Mackall
Protocol switch from using generators to stream-like objects....
r635
class zread:
def __init__(self, f):
self.zd = zlib.decompressobj()
self.f = f
self.buf = ""
def read(self, l):
while l > len(self.buf):
r = f.read(4096)
if r:
self.buf += self.zd.decompress(r)
else:
self.buf += self.zd.flush()
break
d, self.buf = self.buf[:l], self.buf[l:]
return d
return zread(f)
Matt Mackall
Add a scheme for handling remote locking...
r638 class remotelock:
def __init__(self, repo):
self.repo = repo
def release(self):
self.repo.unlock()
self.repo = None
def __del__(self):
if self.repo:
self.release()
mpm@selenic.com
Add hg:// protocol...
r60
Matt Mackall
Add an sshrepository class and hg serve --stdio
r624 class sshrepository:
def __init__(self, ui, path):
self.url = path
self.ui = ui
m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', path)
if not m:
raise RepoError("couldn't parse destination %s\n" % path)
self.user = m.group(2)
self.host = m.group(3)
self.port = m.group(5)
self.path = m.group(7)
args = self.user and ("%s@%s" % (self.user, self.host)) or self.host
args = self.port and ("%s -p %s") % (args, self.port) or args
path = self.path or ""
cmd = "ssh %s 'hg -R %s serve --stdio'"
cmd = cmd % (args, path)
Matt Mackall
Show remote client output with "remote:"
r646 self.pipeo, self.pipei, self.pipee = os.popen3(cmd)
def readerr(self):
while 1:
r,w,x = select.select([self.pipee], [], [], 0)
if not r: break
l = self.pipee.readline()
if not l: break
self.ui.status("remote: ", l)
Matt Mackall
Add an sshrepository class and hg serve --stdio
r624
def __del__(self):
self.pipeo.close()
self.pipei.close()
Matt Mackall
Attempt to read all remaining remote output at close...
r648 for l in self.pipee:
self.ui.status("remote: ", l)
Matt Mackall
Show remote client output with "remote:"
r646 self.pipee.close()
Matt Mackall
Add an sshrepository class and hg serve --stdio
r624
Matt Mackall
Add a repo method to report repo device...
r634 def dev(self):
return -1
Matt Mackall
Add an sshrepository class and hg serve --stdio
r624 def do_cmd(self, cmd, **args):
self.ui.debug("sending %s command\n" % cmd)
self.pipeo.write("%s\n" % cmd)
for k, v in args.items():
self.pipeo.write("%s %d\n" % (k, len(v)))
self.pipeo.write(v)
self.pipeo.flush()
return self.pipei
def call(self, cmd, **args):
r = self.do_cmd(cmd, **args)
Matt Mackall
Show remote client output with "remote:"
r646 l = r.readline()
self.readerr()
try:
l = int(l)
except:
raise RepoError("unexpected response '%s'" % l)
Matt Mackall
Add an sshrepository class and hg serve --stdio
r624 return r.read(l)
Matt Mackall
Add a scheme for handling remote locking...
r638 def lock(self):
self.call("lock")
return remotelock(self)
def unlock(self):
self.call("unlock")
Matt Mackall
Add an sshrepository class and hg serve --stdio
r624 def heads(self):
d = self.call("heads")
try:
return map(bin, d[:-1].split(" "))
except:
Matt Mackall
Show remote client output with "remote:"
r646 raise RepoError("unexpected response '%s'" % (d[:400] + "..."))
Matt Mackall
Add an sshrepository class and hg serve --stdio
r624
def branches(self, nodes):
n = " ".join(map(hex, nodes))
d = self.call("branches", nodes=n)
try:
br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
return br
except:
Matt Mackall
Show remote client output with "remote:"
r646 raise RepoError("unexpected response '%s'" % (d[:400] + "..."))
Matt Mackall
Add an sshrepository class and hg serve --stdio
r624
def between(self, pairs):
n = "\n".join(["-".join(map(hex, p)) for p in pairs])
d = self.call("between", pairs=n)
try:
p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
return p
except:
Matt Mackall
Show remote client output with "remote:"
r646 raise RepoError("unexpected response '%s'" % (d[:400] + "..."))
Matt Mackall
Add an sshrepository class and hg serve --stdio
r624
def changegroup(self, nodes):
n = " ".join(map(hex, nodes))
f = self.do_cmd("changegroup", roots=n)
Matt Mackall
Protocol switch from using generators to stream-like objects....
r635 return self.pipei
Matt Mackall
Add an sshrepository class and hg serve --stdio
r624
Matt Mackall
Add addchangegroup to the ssh protocol
r639 def addchangegroup(self, cg):
d = self.call("addchangegroup")
if d:
raise RepoError("push refused: %s", d)
while 1:
d = cg.read(4096)
if not d: break
self.pipeo.write(d)
Matt Mackall
Show remote client output with "remote:"
r646 self.readerr()
Matt Mackall
Add addchangegroup to the ssh protocol
r639
self.pipeo.flush()
Matt Mackall
Show remote client output with "remote:"
r646 self.readerr()
Matt Mackall
Add addchangegroup to the ssh protocol
r639 l = int(self.pipei.readline())
Matt Mackall
Show remote client output with "remote:"
r646 return self.pipei.read(l) != ""
Matt Mackall
Add addchangegroup to the ssh protocol
r639
mpm@selenic.com
Add hg:// protocol...
r60 def repository(ui, path=None, create=0):
Matt Mackall
Change remote repository to httprepository
r623 if path:
if path.startswith("http://"):
return httprepository(ui, path)
if path.startswith("hg://"):
return httprepository(ui, path.replace("hg://", "http://"))
if path.startswith("old-http://"):
return localrepository(ui, path.replace("old-http://", "http://"))
Matt Mackall
Add an sshrepository class and hg serve --stdio
r624 if path.startswith("ssh://"):
return sshrepository(ui, path)
mpm@selenic.com
Add hg:// protocol...
r60
Matt Mackall
Change remote repository to httprepository
r623 return localrepository(ui, path, create)