##// END OF EJS Templates
Add hg outgoing command
Add hg outgoing command

File last commit:

r919:1458d20d default
r920:270756aa default
Show More
hg.py
2213 lines | 72.1 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
Hack to fix missing '/' problem in URLs
r765 demandload(globals(), "tempfile httprangereader bdiff urlparse")
Bryan O'Sullivan
Fix walk code for files that do not exist anywhere, and unhandled types....
r884 demandload(globals(), "bisect errno select stat")
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,
mpm@selenic.com
Fix the directory and revlog collision problem...
r786 os.path.join("data", self.encodedir(path + ".i")),
os.path.join("data", self.encodedir(path + ".d")))
# This avoids a collision between a file named foo and a dir named
# foo.i or foo.d
def encodedir(self, path):
Thomas Arendsen Hein
Fixed encoding of directories ending in .d or .i:...
r856 return (path
.replace(".hg/", ".hg.hg/")
.replace(".i/", ".i.hg/")
.replace(".d/", ".d.hg/"))
mpm@selenic.com
Fix the directory and revlog collision problem...
r786
def decodedir(self, path):
Thomas Arendsen Hein
Fixed encoding of directories ending in .d or .i:...
r856 return (path
.replace(".d.hg/", ".d/")
.replace(".i.hg/", ".i/")
.replace(".hg.hg/", ".hg/"))
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
mpm@selenic.com
Fix some line wrapping...
r741 def add(self, map, flags, transaction, link, p1=None, p2=None,
changed=None):
mason@suse.com
Performance enhancements for manifest.add()...
r644 # 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 = ""
mpm@selenic.com
Fix some line wrapping...
r741 while i < len(delta) - 1 and start <= delta[i+1][2] \
and end >= delta[i+1][2]:
mason@suse.com
Performance enhancements for manifest.add()...
r644 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
mpm@selenic.com
Fix some line wrapping...
r741 if not changed or not self.listcache or not p1 or \
self.mapcache[0] != p1:
mason@suse.com
Performance enhancements for manifest.add()...
r644 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]
mpm@selenic.com
Fix some line wrapping...
r741 # bs will either be the index of the item or the insert point
mason@suse.com
Performance enhancements for manifest.add()...
r644 bs = bisect.bisect(addlist, f, bs)
if bs < len(addlist):
fn = addlist[bs][:addlist[bs].index('\0')]
else:
fn = None
if w[1] == 0:
mpm@selenic.com
Fix some line wrapping...
r741 l = "%s\000%s%s\n" % (f, hex(map[f]),
flags[f] and "x" or '')
mason@suse.com
Performance enhancements for manifest.add()...
r644 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)
Bryan O'Sullivan
Teach walk code about absolute paths....
r870 def getcwd(self):
cwd = os.getcwd()
if cwd == self.root: return ''
return cwd[len(self.root) + 1:]
Bryan O'Sullivan
Work on walk code.
r723 def ignore(self, f):
if not self.ignorefunc:
bigpat = []
try:
l = file(self.wjoin(".hgignore"))
for pat in l:
Thomas Arendsen Hein
Fix .hgignore parsing if last line has no EOL, ignore trailing white space....
r911 p = pat.rstrip()
if p:
Bryan O'Sullivan
Work on walk code.
r723 try:
Bryan O'Sullivan
Fix walk path handling on Windows
r886 re.compile(p)
Bryan O'Sullivan
Work on walk code.
r723 except:
self.ui.warn("ignoring invalid ignore"
+ " regular expression '%s'\n" % p)
else:
Bryan O'Sullivan
Fix walk path handling on Windows
r886 bigpat.append(p)
Bryan O'Sullivan
Work on walk code.
r723 except IOError: pass
Bryan O'Sullivan
An empty .hgignore file must cause us to ignore nothing, not everything!
r735 if bigpat:
s = "(?:%s)" % (")|(?:".join(bigpat))
r = re.compile(s)
self.ignorefunc = r.search
else:
self.ignorefunc = util.never
Bryan O'Sullivan
Work on walk code.
r723
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
Thomas Arendsen Hein
Fix 3-way-merge of original parent, workdir and new parent....
r862 def update(self, files, state, **kw):
mpm@selenic.com
change dircache into dirstate...
r220 ''' 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))
Thomas Arendsen Hein
Fix 3-way-merge of original parent, workdir and new parent....
r862 st_size = kw.get('st_size', s.st_size)
st_mtime = kw.get('st_mtime', s.st_mtime)
Thomas Arendsen Hein
Cleanup after previous changes:...
r865 self.map[f] = (state, s.st_mode, st_size, 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
mason@suse.com
dirstate walking optimizations...
r879 def filterfiles(self, files):
ret = {}
unknown = []
for x in files:
if x is '.':
return self.map.copy()
if x not in self.map:
unknown.append(x)
else:
ret[x] = self.map[x]
mpm@selenic.com
whitespace cleanup
r919
mason@suse.com
dirstate walking optimizations...
r879 if not unknown:
return ret
b = self.map.keys()
b.sort()
blen = len(b)
for x in unknown:
bs = bisect.bisect(b, x)
mpm@selenic.com
whitespace cleanup
r919 if bs != 0 and b[bs-1] == x:
mason@suse.com
dirstate walking optimizations...
r879 ret[x] = self.map[x]
continue
while bs < blen:
s = b[bs]
if len(s) > len(x) and s.startswith(x) and s[len(x)] == '/':
ret[s] = self.map[s]
else:
break
bs += 1
return ret
def walk(self, files = None, match = util.always, dc=None):
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 self.read()
mason@suse.com
dirstate walking optimizations...
r879
Bryan O'Sullivan
Work on walk code.
r723 # walk all files by default
mason@suse.com
dirstate walking optimizations...
r879 if not files:
files = [self.root]
if not dc:
dc = self.map.copy()
elif not dc:
dc = self.filterfiles(files)
mpm@selenic.com
whitespace cleanup
r919
Bryan O'Sullivan
Ensure that dirstate.walk only yields names once....
r821 known = {'.hg': 1}
def seen(fn):
if fn in known: return True
known[fn] = 1
Bryan O'Sullivan
Work on walk code.
r723 def traverse():
Bryan O'Sullivan
Fix walk code for files that do not exist anywhere, and unhandled types....
r884 for ff in util.unique(files):
f = os.path.join(self.root, ff)
try:
st = os.stat(f)
except OSError, inst:
if ff not in dc: self.ui.warn('%s: %s\n' % (
util.pathto(self.getcwd(), ff),
inst.strerror))
continue
if stat.S_ISDIR(st.st_mode):
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 for dir, subdirs, fl in os.walk(f):
d = dir[len(self.root) + 1:]
Bryan O'Sullivan
Fix walk path handling on Windows
r886 nd = util.normpath(d)
Bryan O'Sullivan
Fix bug involving "hg debugwalk -Ipattern" from repository root.
r892 if nd == '.': nd = ''
Bryan O'Sullivan
Ensure that dirstate.walk only yields names once....
r821 if seen(nd):
Bryan O'Sullivan
Work on walk code.
r723 subdirs[:] = []
continue
mwilli2@localhost.localdomain
.hgignore speedups patch incorporating Matt's feedback....
r669 for sd in subdirs:
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820 ds = os.path.join(nd, sd +'/')
Bryan O'Sullivan
Work on walk code.
r723 if self.ignore(ds) or not match(ds):
mwilli2@localhost.localdomain
.hgignore speedups patch incorporating Matt's feedback....
r669 subdirs.remove(sd)
Bryan O'Sullivan
Attempt to yield names in sorted order when walking....
r822 subdirs.sort()
fl.sort()
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
Bryan O'Sullivan
Fix walk code for files that do not exist anywhere, and unhandled types....
r884 elif stat.S_ISREG(st.st_mode):
yield 'f', ff
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 else:
Bryan O'Sullivan
Fix walk code for files that do not exist anywhere, and unhandled types....
r884 kind = 'unknown'
if stat.S_ISCHR(st.st_mode): kind = 'character device'
elif stat.S_ISBLK(st.st_mode): kind = 'block device'
elif stat.S_ISFIFO(st.st_mode): kind = 'fifo'
elif stat.S_ISLNK(st.st_mode): kind = 'symbolic link'
elif stat.S_ISSOCK(st.st_mode): kind = 'socket'
self.ui.warn('%s: unsupported file type (type is %s)\n' % (
util.pathto(self.getcwd(), ff),
kind))
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536
Bryan O'Sullivan
Attempt to yield names in sorted order when walking....
r822 ks = dc.keys()
ks.sort()
for k in ks:
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
mwilli2@localhost.localdomain
.hgignore speedups patch incorporating Matt's feedback....
r669
Bryan O'Sullivan
Add a source designator to the walk methods....
r726 for src, fn in util.unique(traverse()):
Bryan O'Sullivan
Fix walk path handling on Windows
r886 fn = util.normpath(fn)
Bryan O'Sullivan
Ensure that dirstate.walk only yields names once....
r821 if seen(fn): continue
mason@suse.com
dirstate walking optimizations...
r879 if fn not in dc and self.ignore(fn):
Bryan O'Sullivan
Work on walk code.
r723 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
Thomas Arendsen Hein
dirstate.changes() now distinguishes 'hg remove'd or just deleted files....
r861 def changes(self, files=None, match=util.always):
Bryan O'Sullivan
Work on walk code.
r723 self.read()
mason@suse.com
dirstate walking optimizations...
r879 if not files:
dc = self.map.copy()
else:
dc = self.filterfiles(files)
Thomas Arendsen Hein
dirstate.changes() now distinguishes 'hg remove'd or just deleted files....
r861 lookup, modified, added, unknown = [], [], [], []
removed, deleted = [], []
Bryan O'Sullivan
Work on walk code.
r723
mason@suse.com
dirstate walking optimizations...
r879 for src, fn in self.walk(files, match, dc=dc):
Thomas Arendsen Hein
dirstate.changes() now distinguishes 'hg remove'd or just deleted files....
r861 try:
s = os.stat(os.path.join(self.root, fn))
except OSError:
continue
if not stat.S_ISREG(s.st_mode):
continue
c = dc.get(fn)
if c:
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 del dc[fn]
if c[0] == 'm':
Thomas Arendsen Hein
dirstate.changes() now distinguishes 'hg remove'd or just deleted files....
r861 modified.append(fn)
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 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:
Thomas Arendsen Hein
dirstate.changes() now distinguishes 'hg remove'd or just deleted files....
r861 modified.append(fn)
elif c[3] != s.st_mtime:
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536 lookup.append(fn)
else:
Thomas Arendsen Hein
dirstate.changes() now distinguishes 'hg remove'd or just deleted files....
r861 unknown.append(fn)
mpm@selenic.com
Refactor diffrevs/diffdir into changes...
r536
Thomas Arendsen Hein
dirstate.changes() now distinguishes 'hg remove'd or just deleted files....
r861 for fn, c in [(fn, c) for fn, c in dc.items() if match(fn)]:
if c[0] == 'r':
removed.append(fn)
else:
deleted.append(fn)
return (lookup, modified, added, removed + deleted, 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):
Bryan O'Sullivan
Teach walk code about absolute paths....
r870 return self.dirstate.getcwd()
Bryan O'Sullivan
Add locate command....
r627
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
Fix undo after aborted commit bug...
r785 self.opener("journal.dirstate", "w").write(ds)
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
Fix undo after aborted commit bug...
r785 def after():
util.rename(self.join("journal"), self.join("undo"))
util.rename(self.join("journal.dirstate"),
self.join("undo.dirstate"))
return transaction.transaction(self.ui.warn, self.opener,
self.join("journal"), after)
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
Bryan O'Sullivan
Adapt commit to use file matching code....
r813 def commit(self, files = None, text = "", user = None, date = None,
mason@suse.com
Add force option to repo.commit, allowing commits where no files change
r900 match = util.always, force=False):
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
Adapt commit to use file matching code....
r813 (c, a, d, u) = self.changes(match = match)
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
mason@suse.com
Add force option to repo.commit, allowing commits where no files change
r900 if not commit and not remove and not force:
mpm@selenic.com
Bail on attempts to do an empty commit
r151 self.ui.status("nothing changed\n")
mason@suse.com
Change repo.comit to return None on error or the new revision number on...
r901 return None
mpm@selenic.com
Bail on attempts to do an empty commit
r151
mpm@selenic.com
Add initial hook support...
r487 if not self.hook("precommit"):
mason@suse.com
Change repo.comit to return None on error or the new revision number on...
r901 return None
mpm@selenic.com
Add initial hook support...
r487
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]
mpm@selenic.com
Fix some line wrapping...
r741 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():
mason@suse.com
Change repo.comit to return None on error or the new revision number on...
r901 return None
mpm@selenic.com
commit: edit text fixups...
r288 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 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)):
mason@suse.com
Change repo.comit to return None on error or the new revision number on...
r901 return None
return n
Matt Mackall
Move commit hook after commit completes...
r660
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]):
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820 if match(fn): 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
Fix some line wrapping...
r741
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):
mpm@selenic.com
Fix some line wrapping...
r741 self.ui.warn("%s not added: only files supported 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)
mpm@selenic.com
Fix copy in subdirectories...
r781 if not os.path.exists(p):
mpm@selenic.com
Add hg copy...
r363 self.ui.warn("%s does not exist!\n" % dest)
mpm@selenic.com
Fix copy in subdirectories...
r781 elif not os.path.isfile(p):
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()
mason@suse.com
Add searching for named branches...
r898 # branchlookup returns a dict giving a list of branches for
# each head. A branch is defined as the tag of a node or
# the branch of the node's parents. If a node has multiple
# branch tags, tags are eliminated if they are visible from other
# branch tags.
#
# So, for this graph: a->b->c->d->e
# \ /
# aa -----/
mpm@selenic.com
whitespace cleanup
r919 # a has tag 2.6.12
mason@suse.com
Add searching for named branches...
r898 # d has tag 2.6.13
# e would have branch tags for 2.6.12 and 2.6.13. Because the node
# for 2.6.12 can be reached from the node 2.6.13, that is eliminated
# from the list.
#
# It is possible that more than one head will have the same branch tag.
# callers need to check the result for multiple heads under the same
# branch tag if that is a problem for them (ie checkout of a specific
# branch).
#
# passing in a specific branch will limit the depth of the search
# through the parents. It won't limit the branches returned in the
# result though.
def branchlookup(self, heads=None, branch=None):
if not heads:
heads = self.heads()
headt = [ h for h in heads ]
chlog = self.changelog
branches = {}
merges = []
seenmerge = {}
# traverse the tree once for each head, recording in the branches
# dict which tags are visible from this head. The branches
# dict also records which tags are visible from each tag
# while we traverse.
while headt or merges:
if merges:
n, found = merges.pop()
visit = [n]
else:
h = headt.pop()
visit = [h]
found = [h]
seen = {}
while visit:
n = visit.pop()
if n in seen:
continue
pp = chlog.parents(n)
tags = self.nodetags(n)
if tags:
for x in tags:
if x == 'tip':
continue
for f in found:
branches.setdefault(f, {})[n] = 1
branches.setdefault(n, {})[n] = 1
break
if n not in found:
found.append(n)
if branch in tags:
continue
seen[n] = 1
if pp[1] != nullid and n not in seenmerge:
merges.append((pp[1], [x for x in found]))
seenmerge[n] = 1
if pp[0] != nullid:
visit.append(pp[0])
# traverse the branches dict, eliminating branch tags from each
# head that are visible from another branch tag for that head.
out = {}
viscache = {}
for h in heads:
def visible(node):
if node in viscache:
return viscache[node]
ret = {}
visit = [node]
while visit:
x = visit.pop()
if x in viscache:
ret.update(viscache[x])
elif x not in ret:
ret[x] = 1
if x in branches:
visit[len(visit):] = branches[x].keys()
viscache[node] = ret
return ret
if h not in branches:
continue
# O(n^2), but somewhat limited. This only searches the
# tags visible from a specific head, not all the tags in the
# whole repo.
for b in branches[h]:
vis = False
for bb in branches[h].keys():
if b != bb:
if b in visible(bb):
vis = True
break
if not vis:
l = out.setdefault(h, [])
l[len(l):] = self.nodetags(b)
return out
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
mpm@selenic.com
Warn on pushing unsynced repo or adding new heads...
r816 def findincoming(self, remote, base=None, heads=None):
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
Warn on pushing unsynced repo or adding new heads...
r816 if base == None:
base = {}
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")
mpm@selenic.com
Warn on pushing unsynced repo or adding new heads...
r816
if not heads:
heads = remote.heads()
mpm@selenic.com
make pull work for multiple heads...
r222 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
mpm@selenic.com
Warn on pushing unsynced repo or adding new heads...
r816 def findoutgoing(self, remote, base=None, heads=None):
if base == None:
base = {}
self.findincoming(remote, base, heads)
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)
mpm@selenic.com
Warn on pushing unsynced repo or adding new heads...
r816 def push(self, remote, force=False):
Matt Mackall
Add generic repo commands for pull and push
r622 lock = remote.lock()
mpm@selenic.com
Warn on pushing unsynced repo or adding new heads...
r816
base = {}
heads = remote.heads()
inc = self.findincoming(remote, base, heads)
if not force and inc:
self.ui.warn("abort: unsynced remote changes!\n")
self.ui.status("(did you forget to sync? use push -f to force)\n")
return 1
update = self.findoutgoing(remote, base)
Matt Mackall
Add generic repo commands for pull and push
r622 if not update:
self.ui.status("no changes found\n")
return 1
mpm@selenic.com
Warn on pushing unsynced repo or adding new heads...
r816 elif not force:
if len(heads) < len(self.changelog.heads()):
self.ui.warn("abort: push creates new remote branches!\n")
self.ui.status("(did you forget to merge?" +
" use push -f to force)\n")
return 1
Matt Mackall
Add generic repo commands for pull and push
r622
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 = ""
mason@suse.com
Allow the changegroup generator to completely load the buffer....
r903 def fillbuf(self):
self.buf += "".join(self.g)
mpm@selenic.com
make pull work for multiple heads...
r222 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
mpm@selenic.com
Make pull count jargon less confusing...
r772 self.ui.status("adding file changes\n")
mpm@selenic.com
make pull work for multiple heads...
r222 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
mpm@selenic.com
Make pull count jargon less confusing...
r772 self.ui.status(("added %d changesets" +
" with %d changes to %d files\n")
% (changesets, revisions, files))
mpm@selenic.com
make pull work for multiple heads...
r222
tr.close()
mpm@selenic.com
Add changegroup hook for push/pull
r780
if not self.hook("changegroup"):
return 1
mpm@selenic.com
make pull work for multiple heads...
r222 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")
mpm@selenic.com
add note about -C to update message
r788 self.ui.status("(use update -m to merge across branches" +
" or -C to lose changes)\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)
Thomas Arendsen Hein
Fix 3-way-merge of original parent, workdir and new parent....
r862 if moddirstate:
if mode == 'm':
# only update dirstate on branch merge, otherwise we
# could mark files with changes as unchanged
self.dirstate.update([f], mode)
elif p2 == nullid:
# update dirstate from parent1's manifest
m1n = self.changelog.read(p1)[0]
m1 = self.manifest.read(m1n)
Thomas Arendsen Hein
Cleanup after previous changes:...
r865 f_len = len(self.file(f).read(m1[f]))
Thomas Arendsen Hein
Fix 3-way-merge of original parent, workdir and new parent....
r862 self.dirstate.update([f], mode, st_size=f_len, st_mtime=0)
else:
self.ui.warn("Second parent without branch merge!?\n"
"Dirstate for file %s may be wrong.\n" % f)
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"
mpm@selenic.com
Fix verify error reporting bug...
r721 % (hex(node), f))
mpm@selenic.com
migrate verify...
r247 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
Hack to fix missing '/' problem in URLs
r765 # fix missing / after hostname
s = urlparse.urlsplit(path)
partial = s[2]
if not partial: partial = "/"
self.url = urlparse.urlunsplit((s[0], s[1], partial, '', ''))
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"]:
Edouard Gomez
Trap OSError when deleting env vars...
r859 try:
if os.environ.has_key(env):
del os.environ[env]
except OSError:
pass
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
Simplify content type checking
r752 resp = urllib2.urlopen(cu)
mpm@selenic.com
Check protocol versions...
r753 proto = resp.headers['content-type']
mpm@selenic.com
Simplify content type checking
r752
mpm@selenic.com
Check protocol versions...
r753 # accept old "text/plain" and "application/hg-changegroup" for now
if not proto.startswith('application/mercurial') and \
not proto.startswith('text/plain') and \
not proto.startswith('application/hg-changegroup'):
mpm@selenic.com
Simplify content type checking
r752 raise RepoError("'%s' does not appear to be an hg repository"
% self.url)
mpm@selenic.com
Check protocol versions...
r753 if proto.startswith('application/mercurial'):
version = proto[22:]
if float(version) > 0.1:
raise RepoError("'%s' uses newer protocol %s" %
(self.url, version))
mpm@selenic.com
Simplify content type checking
r752 return resp
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
Simplify content type checking
r752 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
Simplify content type checking
r752 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
Simplify content type checking
r752 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):
Muli Ben-Yehuda
When pulling from a non hg repository URL (e.g. http://www.kernel.org/hg)...
r751 r = self.f.read(4096)
Matt Mackall
Protocol switch from using generators to stream-like objects....
r635 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
mpm@selenic.com
Simplify content type checking
r752 return zread(f)
Matt Mackall
Protocol switch from using generators to stream-like objects....
r635
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
mpm@selenic.com
Make ssh URL parsing more robust
r817 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))', path)
Matt Mackall
Add an sshrepository class and hg serve --stdio
r624 if not m:
mpm@selenic.com
Make ssh URL parsing more robust
r817 raise RepoError("couldn't parse destination %s" % path)
Matt Mackall
Add an sshrepository class and hg serve --stdio
r624
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 ""
mpm@selenic.com
Make ssh URL parsing more robust
r817 if not path:
raise RepoError("no remote repository path specified")
Matt Mackall
Add an sshrepository class and hg serve --stdio
r624 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):
mpm@selenic.com
Make ssh URL parsing more robust
r817 try:
self.pipeo.close()
self.pipei.close()
for l in self.pipee:
self.ui.status("remote: ", l)
self.pipee.close()
except:
pass
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)