##// END OF EJS Templates
more merge fixes...
more merge fixes -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 more merge fixes Logic for getting a remote change should work going backwards and forwards Mark all the changes in the merge that we don't get or merge so we have the right list of files in the changeset manifest hash: 88be742f510a2c58b276172ae538f9533f5e7491 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.0 (GNU/Linux) iD8DBQFCqc+CywK+sNU5EO8RAjOKAJwNkC7phUO77IGW20R7MKyWBGP01gCgjxP6 K2CqUESHr2+0J96q3N74Siw= =zb2f -----END PGP SIGNATURE-----

File last commit:

r305:719812eb default
r305:719812eb default
Show More
hg.py
1298 lines | 41.2 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
implement demand loading hack...
r262 from revlog import *
from demandload import *
demandload(globals(), "re lock urllib urllib2 transaction time socket")
demandload(globals(), "tempfile byterange difflib")
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
mpm@selenic.com
add tracking of execute permissions...
r276 def is_exec(f):
return (os.stat(f).st_mode & 0100 != 0)
def set_exec(f, mode):
s = os.stat(f).st_mode
if (s & 0100 != 0) == mode:
return
Thomas Arendsen Hein
Turn on +x for every +r bit when making a file executable and obey umask.
r298 if mode:
mpm@selenic.com
Merge with TAH...
r299 # Turn on +x for every +r bit when making a file executable
# and obey umask.
Thomas Arendsen Hein
Turn on +x for every +r bit when making a file executable and obey umask.
r298 umask = os.umask(0)
os.umask(umask)
os.chmod(f, s | (s & 0444) >> 2 & ~umask)
else:
os.chmod(f, s & 0666)
mpm@selenic.com
add tracking of execute permissions...
r276
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 class filelog(revlog):
def __init__(self, opener, path):
mpm@selenic.com
Fix transaction handling bug by reverting fileopener change
r144 revlog.__init__(self, opener,
os.path.join("data", path + ".i"),
os.path.join("data", path + ".d"))
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
def read(self, node):
return self.revision(node)
def add(self, text, transaction, link, p1=None, p2=None):
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):
return [(rev, l) for l in text.splitlines(1)]
def strip(annotation):
return [e[1] for e in annotation]
def pair(parent, child):
mpm@selenic.com
Annotate was being too clever trying to work in place, and triggering...
r109 new = []
mpm@selenic.com
implement demand loading hack...
r262 sm = difflib.SequenceMatcher(None, strip(parent), strip(child))
mpm@selenic.com
Add basic annotation support...
r79 for o, m, n, s, t in sm.get_opcodes():
mpm@selenic.com
Annotate was being too clever trying to work in place, and triggering...
r109 if o == 'equal':
mpm@selenic.com
annotate: deal with merges...
r199 new += parent[m:n]
mpm@selenic.com
Annotate was being too clever trying to work in place, and triggering...
r109 else:
mpm@selenic.com
annotate: deal with merges...
r199 new += child[s:t]
return new
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
annotate: deal with merges...
r199 visit = needed.keys()
visit = [ (self.rev(n), n) for n in visit ]
visit.sort()
visit = [ p[1] for p in visit ]
hist = {}
for n in visit:
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
return hist[n]
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):
if self.mapcache and self.mapcache[0] == node:
mpm@selenic.com
Fix manifest merge swap bug...
r90 return self.mapcache[1].copy()
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):
if self.mapcache or self.mapcache[0] != node:
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
add tracking of execute permissions...
r276 def add(self, map, flags, transaction, link, p1=None, p2=None):
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 files = map.keys()
files.sort()
mpm@selenic.com
add tracking of execute permissions...
r276 self.addlist = ["%s\000%s%s\n" %
(f, hex(map[f]), flags[f] and "x" or '')
for f in files]
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 text = "".join(self.addlist)
n = self.addrevision(text, transaction, link, p1, p2)
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):
user = (user or
os.environ.get("HGUSER") or
mpm@selenic.com
From: Thomas Arendsen Hein <thomas@intevation.de>...
r55 os.environ.get("EMAIL") or
os.environ.get("LOGNAME", "unknown") + '@' + socket.getfqdn())
mpm@selenic.com
hg rawcommit command...
r203 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
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
def setparents(self, p1, p2 = nullid):
self.dirty = 1
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
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
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
change dircache into dirstate...
r220 def update(self, files, state):
''' current states:
n normal
mpm@selenic.com
add 'm' state to dirstates...
r231 m needs merging
mpm@selenic.com
change dircache into dirstate...
r220 r marked for removal
a marked for addition'''
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 if not files: return
self.read()
self.dirty = 1
for f in files:
mpm@selenic.com
change dircache into dirstate...
r220 if state == "r":
self.map[f] = ('r', 0, 0, 0)
else:
mpm@selenic.com
Remove invalid state from dirstate...
r253 s = os.stat(os.path.join(self.root, f))
self.map[f] = (state, s.st_mode, s.st_size, s.st_mtime)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
mpm@selenic.com
change dircache into dirstate...
r220 def forget(self, files):
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 if not files: return
self.read()
self.dirty = 1
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 = {}
self.dirty = 1
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
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
def copy(self):
self.read()
return self.map.copy()
# used to avoid circular references so destructors work
def opener(base):
p = base
def o(path, mode="r"):
mpm@selenic.com
Fix network pull of repo files with "%" in their base64 encoding.
r15 if p[:7] == "http://":
f = os.path.join(p, urllib.quote(path))
return httprangereader(f)
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:
file(f + ".tmp", "w").write(file(f).read())
os.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 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
if path and path[:7] == "http://":
self.remote = 1
self.path = path
else:
if not path:
p = os.getcwd()
while not os.path.isdir(os.path.join(p, ".hg")):
p = os.path.dirname(p)
if p == "/": raise "No repo found"
path = p
self.path = os.path.join(path, ".hg")
self.root = path
self.ui = ui
if create:
os.mkdir(self.path)
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)
self.ignorelist = None
mpm@selenic.com
Add tag support
r67 self.tags = 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 back links from file revisions to changeset revisions...
r0
def ignore(self, f):
if self.ignorelist is None:
self.ignorelist = []
try:
mpm@selenic.com
Add wopener for opening files in the working directory...
r291 l = self.wfile(".hgignore")
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 for pat in l:
mpm@selenic.com
Ignore empty ignore patterns
r9 if pat != "\n":
self.ignorelist.append(re.compile(pat[:-1]))
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 except IOError: pass
for pat in self.ignorelist:
if pat.search(f): return True
return False
mpm@selenic.com
Add tag support
r67 def lookup(self, key):
if self.tags is None:
self.tags = {}
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:
n, k = l.split(" ")
self.tags[k] = bin(n)
mpm@selenic.com
Add tag support
r67 except KeyError: pass
try:
return self.tags[key]
except KeyError:
return self.changelog.lookup(key)
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
mpm@selenic.com
Add wopener for opening files in the working directory...
r291 def wfile(self, f, mode='r'):
return self.wopener(f, mode)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 def transaction(self):
mpm@selenic.com
backup dirstate for undo...
r251 # save dirstate for undo
mpm@selenic.com
Fix empty repository transaction bug...
r263 try:
ds = self.opener("dirstate").read()
except IOError:
ds = ""
mpm@selenic.com
backup dirstate for undo...
r251 self.opener("undo.dirstate", "w").write(ds)
mpm@selenic.com
implement demand loading hack...
r262
return transaction.transaction(self.opener, self.join("journal"),
self.join("undo"))
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
mpm@selenic.com
hg undo: fixup working dir state...
r210 def recover(self):
mpm@selenic.com
fix repo locking...
r225 lock = self.lock()
mpm@selenic.com
hg undo: fixup working dir state...
r210 if os.path.exists(self.join("recover")):
self.ui.status("attempting to rollback interrupted transaction\n")
mpm@selenic.com
implement demand loading hack...
r262 return transaction.rollback(self.opener, self.join("recover"))
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")):
self.ui.status("attempting to rollback 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
os.rename(self.join("undo.dirstate"), self.join("dirstate"))
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
teach rawcommit about dirstate.parents()...
r228 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
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()
tm = is_exec(self.wjoin(f))
r = self.file(f)
mfm[f] = tm
mm[f] = r.add(t, tr, linkrev,
m1.get(f, nullid), m2.get(f, nullid))
mpm@selenic.com
hg rawcommit command...
r203 except IOError:
mpm@selenic.com
various fixups for git import...
r302 del mm[f]
del mfm[f]
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])
n = self.changelog.add(mnode, files, text, tr, p1, p2, user, date)
mpm@selenic.com
hg rawcommit command...
r203 tr.close()
mpm@selenic.com
teach rawcommit about dirstate.parents()...
r228 self.dirstate.setparents(p1, p2)
mpm@selenic.com
change dircache into dirstate...
r220 self.dirstate.clear()
mpm@selenic.com
various fixups for git import...
r302 self.dirstate.update(files, "n")
mpm@selenic.com
hg rawcommit command...
r203
mpm@selenic.com
teach commit about dirstate.parents()...
r229 def commit(self, files = None, text = ""):
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:
mpm@selenic.com
make diffdir default to dirstate.parents()...
r230 (c, a, d, u) = self.diffdir(self.root)
mpm@selenic.com
change dircache into dirstate...
r220 commit = c + a
remove = d
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
mpm@selenic.com
change dircache into dirstate...
r220 if not commit and not remove:
mpm@selenic.com
Bail on attempts to do an empty commit
r151 self.ui.status("nothing changed\n")
return
mpm@selenic.com
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
add tracking of execute permissions...
r276 fp = self.wjoin(f)
mf1[f] = is_exec(fp)
t = file(fp).read()
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 except IOError:
mpm@selenic.com
change dircache into dirstate...
r220 self.warn("trouble committing %s!\n" % f)
raise
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)
new[f] = r.add(t, 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)
for f in remove: del m1[f]
mpm@selenic.com
add tracking of execute permissions...
r276 mn = self.manifest.add(m1, mf1, tr, linkrev, c1[0], c2[0])
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
# add changeset
new = new.keys()
new.sort()
mpm@selenic.com
commit: edit text fixups...
r288 if not text:
edittext = "\n" + "HG: manifest hash %s\n" % hex(mn)
edittext += "".join(["HG: changed %s\n" % f for f in new])
edittext += "".join(["HG: removed %s\n" % f for f in remove])
edittext = self.ui.edit(edittext)
if not edittext.rstrip():
return 1
text = edittext
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
mpm@selenic.com
commit: edit text fixups...
r288 n = self.changelog.add(mn, new, text, tr, p1, p2)
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
mpm@selenic.com
make diffdir default to dirstate.parents()...
r230 def diffdir(self, path, changeset = None):
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 changed = []
mpm@selenic.com
change dircache into dirstate...
r220 added = []
unknown = []
mpm@selenic.com
Fix exception handling for reading current working version
r4 mf = {}
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
mpm@selenic.com
Make diffdir take a revision argument
r29 if changeset:
change = self.changelog.read(changeset)
mpm@selenic.com
Fix exception handling for reading current working version
r4 mf = self.manifest.read(change[0])
mpm@selenic.com
make diffdir default to dirstate.parents()...
r230 dc = dict.fromkeys(mf)
else:
changeset = self.dirstate.parents()[0]
change = self.changelog.read(changeset)
mf = self.manifest.read(change[0])
mpm@selenic.com
change dircache into dirstate...
r220 dc = self.dirstate.copy()
mpm@selenic.com
Make diffdir take a revision argument
r29
def fcmp(fn):
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)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 for dir, subdirs, files in os.walk(self.root):
d = dir[len(self.root)+1:]
if ".hg" in subdirs: subdirs.remove(".hg")
for f in files:
fn = os.path.join(d, f)
mpm@selenic.com
Diff in subdirectories from Jake Edge...
r64 try: s = os.stat(os.path.join(self.root, fn))
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 except: continue
if fn in dc:
c = dc[fn]
del dc[fn]
mpm@selenic.com
change dircache into dirstate...
r220 if not c:
mpm@selenic.com
Make diffdir take a revision argument
r29 if fcmp(fn):
changed.append(fn)
mpm@selenic.com
add 'm' state to dirstates...
r231 elif c[0] == 'm':
changed.append(fn)
mpm@selenic.com
change dircache into dirstate...
r220 elif c[0] == 'a':
added.append(fn)
elif c[0] == 'r':
unknown.append(fn)
mpm@selenic.com
add tracking of execute permissions...
r276 elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100:
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 changed.append(fn)
mpm@selenic.com
change dircache into dirstate...
r220 elif c[1] != s.st_mode or c[3] != s.st_mtime:
mpm@selenic.com
Make diffdir take a revision argument
r29 if fcmp(fn):
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 changed.append(fn)
else:
if self.ignore(fn): continue
mpm@selenic.com
change dircache into dirstate...
r220 unknown.append(fn)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
deleted = dc.keys()
deleted.sort()
mpm@selenic.com
change dircache into dirstate...
r220 return (changed, added, deleted, unknown)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
mpm@selenic.com
Add diffrevs function to compare two nodes
r32 def diffrevs(self, node1, node2):
mpm@selenic.com
Support for 0, 1, or 2 diff revs
r33 changed, added = [], []
mpm@selenic.com
Add diffrevs function to compare two nodes
r32
change = self.changelog.read(node1)
mf1 = self.manifest.read(change[0])
mpm@selenic.com
Support for 0, 1, or 2 diff revs
r33 change = self.changelog.read(node2)
mpm@selenic.com
Add diffrevs function to compare two nodes
r32 mf2 = self.manifest.read(change[0])
for fn in mf2:
if mf1.has_key(fn):
if mf1[fn] != mf2[fn]:
changed.append(fn)
del mf1[fn]
else:
added.append(fn)
deleted = mf1.keys()
deleted.sort()
return (changed, added, deleted)
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)
mpm@selenic.com
change dircache into dirstate...
r220 if not os.path.isfile(p):
self.ui.warn("%s does not exist!\n" % f)
elif self.dirstate.state(f) == 'n':
self.ui.warn("%s already tracked!\n" % f)
else:
self.dirstate.update([f], "a")
def forget(self, list):
for f in list:
if self.dirstate.state(f) not in 'ai':
self.ui.warn("%s not added!\n" % f)
else:
self.dirstate.forget([f])
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)
mpm@selenic.com
change dircache into dirstate...
r220 if os.path.isfile(p):
self.ui.warn("%s still exists!\n" % f)
elif f not in self.dirstate:
self.ui.warn("%s not tracked!\n" % f)
else:
self.dirstate.update([f], "r")
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0
mpm@selenic.com
make pull work for multiple heads...
r222 def heads(self):
return self.changelog.heads()
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 def branches(self, nodes):
if not nodes: nodes = [self.changelog.tip()]
b = []
for n in nodes:
t = n
while n:
p = self.changelog.parents(n)
if p[1] != nullid or p[0] == nullid:
b.append((t, n, p[0], p[1]))
break
n = p[0]
return b
def between(self, pairs):
r = []
for top, bottom in pairs:
n, l, i = top, [], 0
f = 1
while n != bottom:
p = self.changelog.parents(n)[0]
if i == f:
l.append(n)
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
def getchangegroup(self, remote):
mpm@selenic.com
Fix up a bunch of bugs in the new merge code...
r65 m = self.changelog.nodemap
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 search = []
fetch = []
mpm@selenic.com
Improve pruning of branches in outstanding changeset algorithm...
r148 seen = {}
seenbranch = {}
mpm@selenic.com
Changes to network protocol...
r192
mpm@selenic.com
merge: short-circuit search for merge into empty repo...
r190 # if we have an empty repo, fetch everything
if self.changelog.tip() == nullid:
mpm@selenic.com
make pull work for multiple heads...
r222 self.ui.status("requesting all changes\n")
mpm@selenic.com
merge: short-circuit search for merge into empty repo...
r190 return remote.changegroup([nullid])
# otherwise, assume we're closer to the tip than the root
mpm@selenic.com
make pull work for multiple heads...
r222 self.ui.status("searching for changes\n")
heads = remote.heads()
unknown = []
for h in heads:
if h not in m:
unknown.append(h)
mpm@selenic.com
Add changegroup support
r46
mpm@selenic.com
make pull work for multiple heads...
r222 if not unknown:
mpm@selenic.com
Changes to network protocol...
r192 self.ui.status("nothing to do!\n")
mpm@selenic.com
Add hg:// protocol...
r60 return None
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:
n = unknown.pop(0)
mpm@selenic.com
Improve pruning of branches in outstanding changeset algorithm...
r148 seen[n[0]] = 1
self.ui.debug("examining %s:%s\n" % (short(n[0]), short(n[1])))
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 if n == nullid: break
mpm@selenic.com
Improve pruning of branches in outstanding changeset algorithm...
r148 if n in seenbranch:
self.ui.debug("branch already found\n")
continue
mpm@selenic.com
Fix up a bunch of bugs in the new merge code...
r65 if n[1] and n[1] in m: # do we know the base?
mpm@selenic.com
Improve pruning of branches in outstanding changeset algorithm...
r148 self.ui.debug("found incomplete branch %s:%s\n"
% (short(n[0]), short(n[1])))
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 search.append(n) # schedule branch range for scanning
mpm@selenic.com
Improve pruning of branches in outstanding changeset algorithm...
r148 seenbranch[n] = 1
mpm@selenic.com
Add getchangegroup code to efficiently calculate and request a changegroup
r56 else:
mpm@selenic.com
Refactor merge code...
r94 if n[2] in m and n[3] in m:
if n[1] not in fetch:
self.ui.debug("found new changeset %s\n" %
short(n[1]))
fetch.append(n[1]) # earliest unknown
continue
mpm@selenic.com
Improve pruning of branches in outstanding changeset algorithm...
r148
r = []
for a in n[2:4]:
if a not in seen: r.append(a)
if r:
self.ui.debug("requesting %s\n" %
" ".join(map(short, r)))
for b in remote.branches(r):
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
Add getchangegroup code to efficiently calculate and request a changegroup
r56
while search:
n = search.pop(0)
l = remote.between([(n[0], n[1])])[0]
p = n[0]
f = 1
for i in l + [n[1]]:
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)
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
Fix up a bunch of bugs in the new merge code...
r65 for f in fetch:
if f in m:
mpm@selenic.com
Add -q quiet option...
r83 raise "already have", short(f[:4])
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
Add getchangegroup code to efficiently calculate and request a changegroup
r56 return remote.changegroup(fetch)
def changegroup(self, basenodes):
nodes = self.newer(basenodes)
mpm@selenic.com
Add changegroup support
r46 # 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 ]
mpm@selenic.com
Changes to network protocol...
r192 for y in self.changelog.group(linkmap): yield y
for y in self.manifest.group(linkmap): yield y
mpm@selenic.com
Add changegroup support
r46 for f in changed:
mpm@selenic.com
Changes to network protocol...
r192 yield struct.pack(">l", len(f) + 4) + f
mpm@selenic.com
Add changegroup support
r46 g = self.file(f).group(linkmap)
mpm@selenic.com
Changes to network protocol...
r192 for y in g:
yield y
mpm@selenic.com
Add changegroup support
r46
mpm@selenic.com
Fix up a bunch of bugs in the new merge code...
r65 def addchangegroup(self, generator):
mpm@selenic.com
make pull work for multiple heads...
r222
class genread:
def __init__(self, generator):
self.g = generator
self.buf = ""
def read(self, l):
while l > len(self.buf):
try:
self.buf += self.g.next()
except StopIteration:
break
d, self.buf = self.buf[:l], self.buf[l:]
return d
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)
if not generator: return
changesets = files = revisions = 0
mpm@selenic.com
fix repo locking...
r225
mpm@selenic.com
make pull work for multiple heads...
r222 source = genread(generator)
mpm@selenic.com
fix repo locking...
r225 lock = self.lock()
mpm@selenic.com
make pull work for multiple heads...
r222 tr = self.transaction()
# pull off the changeset group
self.ui.status("adding changesets\n")
co = self.changelog.tip()
mpm@selenic.com
fix bad assumption about uniqueness of file versions...
r224 cn = self.changelog.addgroup(getgroup(), csmap, tr, 1) # unique
mpm@selenic.com
make pull work for multiple heads...
r222 changesets = self.changelog.rev(cn) - self.changelog.rev(co)
# pull off the manifest group
self.ui.status("adding manifests\n")
mm = self.manifest.tip()
mo = self.manifest.addgroup(getgroup(), revmap, tr)
# process the files
self.ui.status("adding file revisions\n")
while 1:
f = getchunk()
if not f: break
self.ui.debug("adding %s revisions\n" % f)
fl = self.file(f)
o = fl.tip()
n = fl.addgroup(getgroup(), revmap, tr)
revisions += fl.rev(n) - fl.rev(o)
files += 1
self.ui.status(("modified %d files, added %d changesets" +
" and %d new revisions\n")
% (files, changesets, revisions))
tr.close()
return
mpm@selenic.com
various merge improvements...
r275 def update(self, node, allow=False, force=False):
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
Add changegroup support
r46 return
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
add tracking of execute permissions...
r276 mfa = self.manifest.readflags(m2n)
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232
(c, a, d, u) = self.diffdir(self.root)
# 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")
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
unify checkout and resolve into update...
r254 for f in a + c + u:
mw[f] = ""
mpm@selenic.com
add tracking of execute permissions...
r276 mfw[f] = is_exec(self.wjoin(f))
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
for f, n in mw.iteritems():
if f in m2:
mpm@selenic.com
merge: update permissions even if file contents didn't change...
r277 s = 0
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
unify checkout and resolve into update...
r254 merge[f] = (m1.get(f, nullid), m2[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
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)
set_exec(self.wjoin(f), mf2[f])
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)
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:
mpm@selenic.com
various merge improvements...
r275 if not force and n != ma[f]:
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 r = self.ui.prompt(
(" local changed %s which remote deleted\n" % f) +
"(k)eep or (d)elete?", "[kd]", "k")
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
self.ui.debug("remote deleted %s\n" % f)
remove.append(f)
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
minor fixes for update()...
r256 if f[0] == "/": continue
mpm@selenic.com
various merge improvements...
r275 if not force and f in ma and n != ma[f]:
r = self.ui.prompt(
("remote changed %s which local deleted\n" % f) +
"(k)eep or (d)elete?", "[kd]", "k")
if r == "d": remove.append(f)
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 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
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
more merge fixes...
r305 if pa == p1 or pa == p2:
mpm@selenic.com
unify checkout and resolve into update...
r254 # we don't need to do any magic, just jump to the new rev
mode = 'n'
p1, p2 = p2, nullid
else:
mpm@selenic.com
various merge improvements...
r275 if not allow:
mpm@selenic.com
more merge fixes...
r305 self.ui.status("this update spans a branch" +
" affecting the following files:\n")
fl = merge.keys() + get.keys()
fl.sort()
for f in fl:
cf = ""
if f in merge: cf = " (resolve)"
self.ui.status(" %s%s\n" % (f, cf))
self.ui.warn("aborting update spanning branches!\n")
self.ui.status("(use update -m to perform a branch merge)\n")
mpm@selenic.com
various merge improvements...
r275 return 1
mpm@selenic.com
unify checkout and resolve into update...
r254 # we have to remember what files we needed to get/change
# because any file that's different from either one of its
# parents must be in the changeset
mode = 'm'
mpm@selenic.com
more merge fixes...
r305 self.dirstate.update(mark.keys(), "m")
mpm@selenic.com
unify checkout and resolve into update...
r254
mpm@selenic.com
hg resolve: merge a given node into the working directory...
r232 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)
set_exec(self.wjoin(f), mf2[f])
mpm@selenic.com
unify checkout and resolve into update...
r254 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)
Thomas Arendsen Hein
Fixed usage of removed variable 'wp'.
r297 set_exec(self.wjoin(f), flag)
mpm@selenic.com
unify checkout and resolve into update...
r254 self.dirstate.update([f], 'm')
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
unify checkout and resolve into update...
r254 os.unlink(f)
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)
f = os.fdopen(fd, "w")
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
hg resolve: merge a given node into the working directory...
r232 b = temp("other", other)
c = temp("base", base)
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
mpm@selenic.com
Replace tkmerge with hgmerge...
r240 cmd = os.environ.get("HGMERGE", "hgmerge")
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
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
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:
print "aborted"
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)))
print len(filenodes[f].keys()), fl.count(), f
errors += 1
else:
del filenodes[f][n]
flr = fl.linkrev(n)
if flr not in filelinkrevs[f]:
self.ui.warn("%s:%s points to unexpected changeset %d\n"
% (f, short(n), fl.linkrev(n)))
errors += 1
else:
filelinkrevs[f].remove(flr)
# verify contents
try:
t = fl.read(n)
except Exception, inst:
self.ui.warn("unpacking file %s %s: %s\n"
% (f, short(n), inst))
errors += 1
# verify parents
(p1, p2) = fl.parents(n)
if p1 not in nodes:
self.ui.warn("file %s:%s unknown parent 1 %s" %
(f, short(n), short(p1)))
errors += 1
if p2 not in nodes:
self.ui.warn("file %s:%s unknown parent 2 %s" %
(f, short(n), short(p1)))
errors += 1
nodes[n] = 1
# cross-check
for node in filenodes[f]:
self.ui.warn("node %s in manifests not in %s\n"
% (hex(n), f))
errors += 1
self.ui.status("%d files, %d changesets, %d total revisions\n" %
(files, changesets, revisions))
if errors:
self.ui.warn("%d integrity errors encountered!\n" % errors)
return 1
mpm@selenic.com
Add hg:// protocol...
r60 class remoterepository:
def __init__(self, ui, path):
mpm@selenic.com
Change hg: protocol name to http: and http: to old-http:...
r176 self.url = path
mpm@selenic.com
Add hg:// protocol...
r60 self.ui = ui
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
Fix up a bunch of bugs in the new merge code...
r65 return urllib.urlopen(cu)
mpm@selenic.com
Add hg:// protocol...
r60
mpm@selenic.com
make pull work for multiple heads...
r222 def heads(self):
d = self.do_cmd("heads").read()
try:
return map(bin, d[:-1].split(" "))
except:
self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
raise
mpm@selenic.com
Add hg:// protocol...
r60 def branches(self, nodes):
n = " ".join(map(hex, nodes))
mpm@selenic.com
Fix up a bunch of bugs in the new merge code...
r65 d = self.do_cmd("branches", nodes=n).read()
mpm@selenic.com
merge: catch unexpected responses...
r217 try:
br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
return br
except:
self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
raise
mpm@selenic.com
Add hg:// protocol...
r60
def between(self, pairs):
n = "\n".join(["-".join(map(hex, p)) for p in pairs])
mpm@selenic.com
Fix up a bunch of bugs in the new merge code...
r65 d = self.do_cmd("between", pairs=n).read()
mpm@selenic.com
merge: catch unexpected responses...
r217 try:
p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
return p
except:
self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
raise
mpm@selenic.com
Add hg:// protocol...
r60
def changegroup(self, nodes):
n = " ".join(map(hex, nodes))
mpm@selenic.com
Fix up a bunch of bugs in the new merge code...
r65 zd = zlib.decompressobj()
f = self.do_cmd("changegroup", roots=n)
mpm@selenic.com
Changes to network protocol...
r192 bytes = 0
mpm@selenic.com
Fix up a bunch of bugs in the new merge code...
r65 while 1:
d = f.read(4096)
mpm@selenic.com
Changes to network protocol...
r192 bytes += len(d)
mpm@selenic.com
Fix up a bunch of bugs in the new merge code...
r65 if not d:
yield zd.flush()
break
yield zd.decompress(d)
mpm@selenic.com
Changes to network protocol...
r192 self.ui.note("%d bytes of data transfered\n" % bytes)
mpm@selenic.com
Add hg:// protocol...
r60
def repository(ui, path=None, create=0):
mpm@selenic.com
Change hg: protocol name to http: and http: to old-http:...
r176 if path and path[:7] == "http://":
return remoterepository(ui, path)
mpm@selenic.com
Add hg:// protocol...
r60 if path and path[:5] == "hg://":
mpm@selenic.com
Change hg: protocol name to http: and http: to old-http:...
r176 return remoterepository(ui, path.replace("hg://", "http://"))
if path and path[:11] == "old-http://":
return localrepository(ui, path.replace("old-http://", "http://"))
mpm@selenic.com
Add hg:// protocol...
r60 else:
return localrepository(ui, path, create)
mpm@selenic.com
Add back links from file revisions to changeset revisions...
r0 class httprangereader:
def __init__(self, url):
self.url = url
self.pos = 0
def seek(self, pos):
self.pos = pos
def read(self, bytes=None):
opener = urllib2.build_opener(byterange.HTTPRangeHandler())
urllib2.install_opener(opener)
req = urllib2.Request(self.url)
end = ''
if bytes: end = self.pos + bytes
req.add_header('Range', 'bytes=%d-%s' % (self.pos, end))
f = urllib2.urlopen(req)
return f.read()