This commit is contained in:
Vadim Gelfer 2006-08-12 15:43:38 -07:00
commit 00af865078
43 changed files with 580 additions and 217 deletions

View File

@ -216,6 +216,6 @@ http://selenic.com/mailman/listinfo/mercurial[Mailing list]
COPYING
-------
Copyright \(C) 2005 Matt Mackall.
Copyright \(C) 2005, 2006 Matt Mackall.
Free use of this software is granted under the terms of the GNU General
Public License (GPL).

View File

@ -30,6 +30,6 @@ hg(1) - the command line interface to Mercurial SCM
COPYING
-------
Copyright \(C) 2005 Matt Mackall.
Copyright \(C) 2005, 2006 Matt Mackall.
Free use of this software is granted under the terms of the GNU General
Public License (GPL).

View File

@ -862,6 +862,6 @@ http://selenic.com/mailman/listinfo/mercurial[メーリングリスト]
著作権情報
-----
Copyright (C) 2005 Matt Mackall.
Copyright (C) 2005, 2006 Matt Mackall.
このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで
認められます。

View File

@ -32,6 +32,6 @@ hg(1) - Mercurial システムへのコマンドラインインターフェイ
著作権情報
----
Copyright (C) 2005 Matt Mackall.
Copyright (C) 2005, 2006 Matt Mackall.
このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで
認められます。

View File

@ -1,6 +1,6 @@
# Minimal support for git commands on an hg repository
#
# Copyright 2005 Chris Mason <mason@suse.com>
# Copyright 2005, 2006 Chris Mason <mason@suse.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.

View File

@ -1,7 +1,6 @@
# queue.py - patch queues for mercurial
#
# Copyright 2005 Chris Mason <mason@suse.com>
# Copyright 2005, 2006 Chris Mason <mason@suse.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
@ -31,9 +30,9 @@ refresh contents of top applied patch qrefresh
'''
from mercurial.demandload import *
demandload(globals(), "os sys re struct traceback errno bz2")
from mercurial.i18n import gettext as _
from mercurial import ui, hg, revlog, commands, util
demandload(globals(), "os sys re struct traceback errno bz2")
demandload(globals(), "mercurial:commands,hg,revlog,ui,util")
commands.norepo += " qclone qversion"
@ -561,7 +560,7 @@ class queue:
r = self.qrepo()
if r: r.add([patch])
if commitfiles:
self.refresh(repo, msg=None, short=True)
self.refresh(repo, short=True)
def strip(self, repo, rev, update=True, backup="all", wlock=None):
def limitheads(chlog, stop):
@ -888,7 +887,6 @@ class queue:
top = self.check_toppatch(repo)
qp = self.qparents(repo, rev)
changes = repo.changelog.read(qp)
mf1 = repo.manifest.readflags(changes[0])
mmap = repo.manifest.read(changes[0])
(c, a, r, d, u) = repo.changes(qp, top)
if d:
@ -897,7 +895,7 @@ class queue:
getfile(f, mmap[f])
for f in r:
getfile(f, mmap[f])
util.set_exec(repo.wjoin(f), mf1[f])
util.set_exec(repo.wjoin(f), mmap.execf[f])
repo.dirstate.update(c + r, 'n')
for f in a:
try: os.unlink(repo.wjoin(f))
@ -922,7 +920,7 @@ class queue:
qp = self.qparents(repo, top)
commands.dodiff(sys.stdout, self.ui, repo, qp, None, files)
def refresh(self, repo, msg=None, short=False):
def refresh(self, repo, msg='', short=False):
if len(self.applied) == 0:
self.ui.write("No patches applied\n")
return
@ -1988,4 +1986,3 @@ cmdtable = {
"qtop": (top, [], 'hg qtop'),
"qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'),
}

View File

@ -163,12 +163,12 @@ def archive(repo, dest, node, kind, decode=True, matchfn=None,
change = repo.changelog.read(node)
mn = change[0]
archiver = archivers[kind](dest, prefix, mtime or change[2][0])
mf = repo.manifest.read(mn).items()
mff = repo.manifest.readflags(mn)
mf.sort()
m = repo.manifest.read(mn)
items = m.items()
items.sort()
write('.hg_archival.txt', 0644,
'repo: %s\nnode: %s\n' % (hex(repo.changelog.node(0)), hex(node)))
for filename, filenode in mf:
write(filename, mff[filename] and 0755 or 0644,
for filename, filenode in items:
write(filename, m.execf(filename) and 0755 or 0644,
repo.file(filename).read(filenode))
archiver.done()

View File

@ -1,7 +1,7 @@
/*
bdiff.c - efficient binary diff extension for Mercurial
Copyright 2005 Matt Mackall <mpm@selenic.com>
Copyright 2005, 2006 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.

View File

@ -1,6 +1,6 @@
# changelog.py - changelog class for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 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.

View File

@ -1,6 +1,6 @@
# commands.py - command processing for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 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.
@ -10,9 +10,9 @@ from node import *
from i18n import gettext as _
demandload(globals(), "os re sys signal shutil imp urllib pdb")
demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
demandload(globals(), "fnmatch mdiff difflib random signal tempfile time")
demandload(globals(), "fnmatch mdiff difflib patch random signal tempfile time")
demandload(globals(), "traceback errno socket version struct atexit sets bz2")
demandload(globals(), "archival cStringIO changegroup email.Parser")
demandload(globals(), "archival cStringIO changegroup")
demandload(globals(), "hgweb.server sshserver")
class UnknownCommand(Exception):
@ -633,7 +633,7 @@ def show_version(ui):
ui.write(_("Mercurial Distributed SCM (version %s)\n")
% version.get_version())
ui.status(_(
"\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
"\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
"This is free software; see the source for copying conditions. "
"There is NO\nwarranty; "
"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
@ -1333,9 +1333,9 @@ def debugrebuildstate(ui, repo, rev=None):
rev = repo.lookup(rev)
change = repo.changelog.read(rev)
n = change[0]
files = repo.manifest.readflags(n)
files = repo.manifest.read(n)
wlock = repo.wlock()
repo.dirstate.rebuild(rev, files.iteritems())
repo.dirstate.rebuild(rev, files)
def debugcheckstate(ui, repo):
"""validate the correctness of the current dirstate"""
@ -1843,84 +1843,23 @@ def import_(ui, repo, patch1, *patches, **opts):
d = opts["base"]
strip = opts["strip"]
mailre = re.compile(r'(?:From |[\w-]+:)')
# attempt to detect the start of a patch
# (this heuristic is borrowed from quilt)
diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
'retrieving revision [0-9]+(\.[0-9]+)*$|' +
'(---|\*\*\*)[ \t])', re.MULTILINE)
wlock = repo.wlock()
lock = repo.lock()
for patch in patches:
pf = os.path.join(d, patch)
for p in patches:
pf = os.path.join(d, p)
message = None
user = None
date = None
hgpatch = False
p = email.Parser.Parser()
if pf == '-':
msg = p.parse(sys.stdin)
ui.status(_("applying patch from stdin\n"))
tmpname, message, user, date = patch.extract(ui, sys.stdin)
else:
msg = p.parse(file(pf))
ui.status(_("applying %s\n") % patch)
ui.status(_("applying %s\n") % p)
tmpname, message, user, date = patch.extract(ui, file(pf))
if tmpname is None:
raise util.Abort(_('no diffs found'))
fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
tmpfp = os.fdopen(fd, 'w')
try:
message = msg['Subject']
if message:
message = message.replace('\n\t', ' ')
ui.debug('Subject: %s\n' % message)
user = msg['From']
if user:
ui.debug('From: %s\n' % user)
diffs_seen = 0
ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
for part in msg.walk():
content_type = part.get_content_type()
ui.debug('Content-Type: %s\n' % content_type)
if content_type not in ok_types:
continue
payload = part.get_payload(decode=True)
m = diffre.search(payload)
if m:
ui.debug(_('found patch at byte %d\n') % m.start(0))
diffs_seen += 1
hgpatch = False
fp = cStringIO.StringIO()
if message:
fp.write(message)
fp.write('\n')
for line in payload[:m.start(0)].splitlines():
if line.startswith('# HG changeset patch'):
ui.debug(_('patch generated by hg export\n'))
hgpatch = True
# drop earlier commit message content
fp.seek(0)
fp.truncate()
elif hgpatch:
if line.startswith('# User '):
user = line[7:]
ui.debug('From: %s\n' % user)
elif line.startswith("# Date "):
date = line[7:]
if not line.startswith('# '):
fp.write(line)
fp.write('\n')
message = fp.getvalue()
if tmpfp:
tmpfp.write(payload)
if not payload.endswith('\n'):
tmpfp.write('\n')
elif not diffs_seen and message and content_type == 'text/plain':
message += '\n' + payload
if opts['message']:
# pickup the cmdline msg
message = opts['message']
@ -1932,17 +1871,45 @@ def import_(ui, repo, patch1, *patches, **opts):
message = None
ui.debug(_('message:\n%s\n') % message)
tmpfp.close()
if not diffs_seen:
raise util.Abort(_('no diffs found'))
files = util.patch(strip, tmpname, ui, cwd=repo.root)
files = patch.patch(strip, tmpname, ui, cwd=repo.root)
removes = []
if len(files) > 0:
cfiles = files
cfiles = files.keys()
copies = []
copts = {'after': False, 'force': False}
cwd = repo.getcwd()
if cwd:
cfiles = [util.pathto(cwd, f) for f in files]
cfiles = [util.pathto(cwd, f) for f in files.keys()]
for f in files:
ctype, gp = files[f]
if ctype == 'RENAME':
copies.append((gp.oldpath, gp.path, gp.copymod))
removes.append(gp.oldpath)
elif ctype == 'COPY':
copies.append((gp.oldpath, gp.path, gp.copymod))
elif ctype == 'DELETE':
removes.append(gp.path)
for src, dst, after in copies:
absdst = os.path.join(repo.root, dst)
if not after and os.path.exists(absdst):
raise util.Abort(_('patch creates existing file %s') % dst)
if cwd:
src, dst = [util.pathto(cwd, f) for f in (src, dst)]
copts['after'] = after
errs, copied = docopy(ui, repo, (src, dst), copts, wlock=wlock)
if errs:
raise util.Abort(errs)
if removes:
repo.remove(removes, True, wlock=wlock)
for f in files:
ctype, gp = files[f]
if gp and gp.mode:
x = gp.mode & 0100 != 0
dst = os.path.join(repo.root, gp.path)
util.set_exec(dst, x)
addremove_lock(ui, repo, cfiles, {}, wlock=wlock)
files = files.keys()
files.extend([r for r in removes if r not in files])
repo.commit(files, message, user, date, wlock=wlock, lock=lock)
finally:
os.unlink(tmpname)
@ -2178,12 +2145,12 @@ def manifest(ui, repo, rev=None):
else:
n = repo.manifest.tip()
m = repo.manifest.read(n)
mf = repo.manifest.readflags(n)
files = m.keys()
files.sort()
for f in files:
ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
ui.write("%40s %3s %s\n" % (hex(m[f]),
m.execf(f) and "755" or "644", f))
def merge(ui, repo, node=None, force=None, branch=None):
"""Merge working directory with another revision

View File

@ -1,6 +1,6 @@
# context.py - changeset and file context objects for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2006 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.

View File

@ -1,7 +1,7 @@
"""
dirstate.py - working directory tracking for mercurial
Copyright 2005 Matt Mackall <mpm@selenic.com>
Copyright 2005, 2006 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.
@ -238,8 +238,8 @@ class dirstate(object):
self.clear()
umask = os.umask(0)
os.umask(umask)
for f, mode in files:
if mode:
for f in files:
if files.execf(f):
self.map[f] = ('n', ~umask, -1, 0)
else:
self.map[f] = ('n', ~umask & 0666, -1, 0)

View File

@ -1,6 +1,6 @@
# filelog.py - file history class for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 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.

View File

@ -1,6 +1,7 @@
# hg.py - repository classes for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.

View File

@ -1,7 +1,7 @@
# hgweb/common.py - Utility functions needed by hgweb_mod and hgwebdir_mod
#
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 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.

View File

@ -1,7 +1,7 @@
# hgweb/hgweb_mod.py - Web interface for a repository.
#
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 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.
@ -398,7 +398,7 @@ class hgweb(object):
parent=self.siblings(fl.parents(n), fl.rev, file=f),
child=self.siblings(fl.children(n), fl.rev, file=f),
rename=self.renamelink(fl, n),
permissions=self.repo.manifest.readflags(mfn)[f])
permissions=self.repo.manifest.read(mfn).execf(f))
def fileannotate(self, f, node):
bcache = {}
@ -452,7 +452,7 @@ class hgweb(object):
rename=self.renamelink(fl, n),
parent=self.siblings(fl.parents(n), fl.rev, file=f),
child=self.siblings(fl.children(n), fl.rev, file=f),
permissions=self.repo.manifest.readflags(mfn)[f])
permissions=self.repo.manifest.read(mfn).execf(f))
def manifest(self, mnode, path):
man = self.repo.manifest
@ -462,7 +462,6 @@ class hgweb(object):
rev = man.rev(mn)
changerev = man.linkrev(mn)
node = self.repo.changelog.node(changerev)
mff = man.readflags(mn)
files = {}
@ -496,7 +495,7 @@ class hgweb(object):
"filenode": hex(fnode),
"parity": self.stripes(parity),
"basename": f,
"permissions": mff[full]}
"permissions": mf.execf(full)}
parity += 1
def dirlist(**map):

View File

@ -1,7 +1,7 @@
# hgweb/hgwebdir_mod.py - Web interface for a directory of repositories.
#
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 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.

View File

@ -1,7 +1,7 @@
# hgweb/request.py - An http request from either CGI or the standalone server.
#
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 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.

View File

@ -1,7 +1,7 @@
# hgweb/server.py - The standalone hg web server.
#
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 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.

View File

@ -1,6 +1,6 @@
# httprangereader.py - just what it says
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 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.

View File

@ -1,6 +1,7 @@
# httprepo.py - HTTP repository proxy classes for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.

View File

@ -1,7 +1,7 @@
"""
i18n.py - internationalization support for mercurial
Copyright 2005 Matt Mackall <mpm@selenic.com>
Copyright 2005, 2006 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.

View File

@ -1,6 +1,6 @@
# localrepo.py - read/write repository class for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 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.
@ -470,8 +470,7 @@ class localrepository(repo.repository):
p2 = p2 or self.dirstate.parents()[1] or nullid
c1 = self.changelog.read(p1)
c2 = self.changelog.read(p2)
m1 = self.manifest.read(c1[0])
mf1 = self.manifest.readflags(c1[0])
m1 = self.manifest.read(c1[0]).copy()
m2 = self.manifest.read(c2[0])
changed = []
@ -484,36 +483,32 @@ class localrepository(repo.repository):
wlock = self.wlock()
l = self.lock()
tr = self.transaction()
mm = m1.copy()
mfm = mf1.copy()
linkrev = self.changelog.count()
for f in files:
try:
t = self.wread(f)
tm = util.is_exec(self.wjoin(f), mfm.get(f, False))
m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f)))
r = self.file(f)
mfm[f] = tm
(entry, fp1, fp2) = self.checkfilemerge(f, t, r, m1, m2)
if entry:
mm[f] = entry
m1[f] = entry
continue
mm[f] = r.add(t, {}, tr, linkrev, fp1, fp2)
m1[f] = r.add(t, {}, tr, linkrev, fp1, fp2)
changed.append(f)
if update_dirstate:
self.dirstate.update([f], "n")
except IOError:
try:
del mm[f]
del mfm[f]
del m1[f]
if update_dirstate:
self.dirstate.forget([f])
except:
# deleted from p2?
pass
mnode = self.manifest.add(mm, mfm, tr, linkrev, c1[0], c2[0])
mnode = self.manifest.add(m1, tr, linkrev, c1[0], c2[0])
user = user or self.ui.username()
n = self.changelog.add(mnode, changed, text, tr, p1, p2, user, date)
tr.close()
@ -544,8 +539,7 @@ class localrepository(repo.repository):
p1, p2 = self.dirstate.parents()
c1 = self.changelog.read(p1)
c2 = self.changelog.read(p2)
m1 = self.manifest.read(c1[0])
mf1 = self.manifest.readflags(c1[0])
m1 = self.manifest.read(c1[0]).copy()
m2 = self.manifest.read(c2[0])
if not commit and not remove and not force and p2 == nullid:
@ -571,7 +565,7 @@ class localrepository(repo.repository):
for f in commit:
self.ui.note(f + "\n")
try:
mf1[f] = util.is_exec(self.wjoin(f), mf1.get(f, False))
m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f)))
t = self.wread(f)
except IOError:
self.ui.warn(_("trouble committing %s!\n") % f)
@ -598,12 +592,11 @@ class localrepository(repo.repository):
changed.append(f)
# update manifest
m1 = m1.copy()
m1.update(new)
for f in remove:
if f in m1:
del m1[f]
mn = self.manifest.add(m1, mf1, tr, linkrev, c1[0], c2[0],
mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0],
(new, remove))
# add changeset
@ -816,7 +809,6 @@ class localrepository(repo.repository):
def undelete(self, list, wlock=None):
p = self.dirstate.parents()[0]
mn = self.changelog.read(p)[0]
mf = self.manifest.readflags(mn)
m = self.manifest.read(mn)
if not wlock:
wlock = self.wlock()
@ -826,7 +818,7 @@ class localrepository(repo.repository):
else:
t = self.file(f).read(m[f])
self.wwrite(f, t)
util.set_exec(self.wjoin(f), mf[f])
util.set_exec(self.wjoin(f), m.execf(f))
self.dirstate.update([f], "n")
def copy(self, source, dest, wlock=None):

View File

@ -1,6 +1,6 @@
# lock.py - simple locking scheme for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 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.

View File

@ -1,6 +1,6 @@
# manifest.py - manifest revision class for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 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.
@ -10,6 +10,31 @@ from i18n import gettext as _
from demandload import *
demandload(globals(), "array bisect struct")
class manifestdict(dict):
def __init__(self, mapping=None, flags=None):
if mapping is None: mapping = {}
if flags is None: flags = {}
dict.__init__(self, mapping)
self._flags = flags
def flags(self, f):
return self._flags.get(f, "")
def execf(self, f):
"test for executable in manifest flags"
return "x" in self.flags(f)
def linkf(self, f):
"test for symlink in manifest flags"
return "l" in self.flags(f)
def rawset(self, f, entry):
self[f] = bin(entry[:40])
fl = entry[40:-1]
if fl: self._flags[f] = fl
def set(self, f, execf=False, linkf=False):
if linkf: self._flags[f] = "l"
elif execf: self._flags[f] = "x"
else: self._flags[f] = ""
def copy(self):
return manifestdict(dict.copy(self), dict.copy(self._flags))
class manifest(revlog):
def __init__(self, opener, defversion=REVLOGV0):
self.mapcache = None
@ -18,26 +43,18 @@ class manifest(revlog):
defversion)
def read(self, node):
if node == nullid: return {} # don't upset local cache
if node == nullid: return manifestdict() # don't upset local cache
if self.mapcache and self.mapcache[0] == node:
return self.mapcache[1]
text = self.revision(node)
map = {}
flag = {}
self.listcache = array.array('c', text)
lines = text.splitlines(1)
mapping = manifestdict()
for l in lines:
(f, n) = l.split('\0')
map[f] = bin(n[:40])
flag[f] = (n[40:-1] == "x")
self.mapcache = (node, map, flag)
return map
def readflags(self, node):
if node == nullid: return {} # don't upset local cache
if not self.mapcache or self.mapcache[0] != node:
self.read(node)
return self.mapcache[2]
mapping.rawset(f, n)
self.mapcache = (node, mapping)
return mapping
def diff(self, a, b):
return mdiff.textdiff(str(a), str(b))
@ -86,7 +103,7 @@ class manifest(revlog):
'''look up entry for a single file efficiently.
return (node, flag) pair if found, (None, None) if not.'''
if self.mapcache and node == self.mapcache[0]:
return self.mapcache[1].get(f), self.mapcache[2].get(f)
return self.mapcache[1].get(f), self.mapcache[1].flags(f)
text = self.revision(node)
start, end = self._search(text, f)
if start == end:
@ -95,7 +112,7 @@ class manifest(revlog):
f, n = l.split('\0')
return bin(n[:40]), n[40:-1] == 'x'
def add(self, map, flags, transaction, link, p1=None, p2=None,
def add(self, map, transaction, link, p1=None, p2=None,
changed=None):
# apply the changes collected during the bisect loop to our addlist
# return a delta suitable for addrevision
@ -123,9 +140,7 @@ class manifest(revlog):
# if this is changed to support newlines in filenames,
# be sure to check the templates/ dir again (especially *-raw.tmpl)
text = ["%s\000%s%s\n" %
(f, hex(map[f]), flags[f] and "x" or '')
for f in files]
text = ["%s\000%s%s\n" % (f, hex(map[f]), map.flags(f)) for f in files]
self.listcache = array.array('c', "".join(text))
cachedelta = None
else:
@ -151,8 +166,7 @@ class manifest(revlog):
# bs will either be the index of the item or the insert point
start, end = self._search(addbuf, f, start)
if w[1] == 0:
l = "%s\000%s%s\n" % (f, hex(map[f]),
flags[f] and "x" or '')
l = "%s\000%s%s\n" % (f, hex(map[f]), map.flags(f))
else:
l = ""
if start == end and w[1] == 1:
@ -183,6 +197,6 @@ class manifest(revlog):
n = self.addrevision(buffer(self.listcache), transaction, link, p1, \
p2, cachedelta)
self.mapcache = (n, map, flags)
self.mapcache = (n, map)
return n

View File

@ -1,6 +1,6 @@
# mdiff.py - diff and patch routines for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 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.

View File

@ -84,11 +84,8 @@ def update(repo, node, branchmerge=False, force=False, partial=None,
m2n = repo.changelog.read(p2)[0]
man = repo.manifest.ancestor(m1n, m2n)
m1 = repo.manifest.read(m1n)
mf1 = repo.manifest.readflags(m1n)
m2 = repo.manifest.read(m2n).copy()
mf2 = repo.manifest.readflags(m2n)
ma = repo.manifest.read(man)
mfa = repo.manifest.readflags(man)
if not forcemerge and not overwrite:
for f in unknown:
@ -113,12 +110,11 @@ def update(repo, node, branchmerge=False, force=False, partial=None,
# construct a working dir manifest
mw = m1.copy()
mfw = mf1.copy()
umap = dict.fromkeys(unknown)
for f in added + modified + unknown:
mw[f] = ""
mfw[f] = util.is_exec(repo.wjoin(f), mfw.get(f, False))
mw.set(f, util.is_exec(repo.wjoin(f), mw.execf(f)))
for f in deleted + removed:
if f in mw:
@ -155,28 +151,28 @@ def update(repo, node, branchmerge=False, force=False, partial=None,
repo.ui.debug(_(" %s versions differ, resolve\n") % f)
# merge executable bits
# "if we changed or they changed, change in merge"
a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
a, b, c = ma.execf(f), mw.execf(f), m2.execf(f)
mode = ((a^b) | (a^c)) ^ a
merge[f] = (m1.get(f, nullid), m2[f], mode)
merge[f] = (mode, m1.get(f, nullid), m2[f])
s = 1
# are we clobbering?
# is remote's version newer?
# or are we going back in time?
elif overwrite or m2[f] != a or (p2 == pa and mw[f] == m1[f]):
repo.ui.debug(_(" remote %s is newer, get\n") % f)
get[f] = m2[f]
get[f] = (m2.execf(f), m2[f])
s = 1
elif f in umap or f in added:
# this unknown file is the same as the checkout
# we need to reset the dirstate if the file was added
get[f] = m2[f]
get[f] = (m2.execf(f), m2[f])
if not s and mfw[f] != mf2[f]:
if not s and mw.execf(f) != m2.execf(f):
if overwrite:
repo.ui.debug(_(" updating permissions for %s\n") % f)
util.set_exec(repo.wjoin(f), mf2[f])
util.set_exec(repo.wjoin(f), m2.execf(f))
else:
a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
a, b, c = ma.execf(f), mw.execf(f), m2.execf(f)
mode = ((a^b) | (a^c)) ^ a
if mode != b:
repo.ui.debug(_(" updating permissions for %s\n")
@ -221,14 +217,14 @@ def update(repo, node, branchmerge=False, force=False, partial=None,
(_("remote changed %s which local deleted\n") % f) +
_("(k)eep or (d)elete?"), _("[kd]"), _("k"))
if r == _("k"):
get[f] = n
get[f] = (m2.execf(f), n)
elif f not in ma:
repo.ui.debug(_("remote created %s\n") % f)
get[f] = n
get[f] = (m2.execf(f), n)
else:
if overwrite or p2 == pa: # going backwards?
repo.ui.debug(_("local deleted %s, recreating\n") % f)
get[f] = n
get[f] = (m2.execf(f), n)
else:
repo.ui.debug(_("local deleted %s\n") % f)
@ -236,7 +232,7 @@ def update(repo, node, branchmerge=False, force=False, partial=None,
if overwrite:
for f in merge:
get[f] = merge[f][1]
get[f] = merge[f][:2]
merge = {}
if linear_path or overwrite:
@ -254,12 +250,13 @@ def update(repo, node, branchmerge=False, force=False, partial=None,
files = get.keys()
files.sort()
for f in files:
flag, node = get[f]
if f[0] == "/":
continue
repo.ui.note(_("getting %s\n") % f)
t = repo.file(f).read(get[f])
t = repo.file(f).read(node)
repo.wwrite(f, t)
util.set_exec(repo.wjoin(f), mf2[f])
util.set_exec(repo.wjoin(f), flag)
if not partial:
if branchmerge:
repo.dirstate.update([f], 'n', st_mtime=-1)
@ -272,7 +269,7 @@ def update(repo, node, branchmerge=False, force=False, partial=None,
files.sort()
for f in files:
repo.ui.status(_("merging %s\n") % f)
my, other, flag = merge[f]
flag, my, other = merge[f]
ret = merge3(repo, f, my, other, xp1, xp2)
if ret:
unresolved.append(f)

View File

@ -14,7 +14,7 @@
allocation of intermediate Python objects. Working memory is about 2x
the total number of hunks.
Copyright 2005 Matt Mackall <mpm@selenic.com>
Copyright 2005, 2006 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.

View File

@ -1,7 +1,7 @@
"""
node.py - basic nodeid manipulation for mercurial
Copyright 2005 Matt Mackall <mpm@selenic.com>
Copyright 2005, 2006 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.

View File

@ -2,7 +2,7 @@
# Used for the py2exe distutil.
# This module must be the first mercurial module imported in setup.py
#
# Copyright 2005 Volker Kleinfeld <Volker.Kleinfeld@gmx.de>
# Copyright 2005, 2006 Volker Kleinfeld <Volker.Kleinfeld@gmx.de>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.

251
mercurial/patch.py Normal file
View File

@ -0,0 +1,251 @@
# patch.py - patch file parsing routines
#
# Copyright 2006 Brendan Cully <brendan@kublai.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
from demandload import demandload
from i18n import gettext as _
demandload(globals(), "util")
demandload(globals(), "cStringIO email.Parser os re shutil tempfile")
def extract(ui, fileobj):
'''extract patch from data read from fileobj.
patch can be normal patch or contained in email message.
return tuple (filename, message, user, date). any item in returned
tuple can be None. if filename is None, fileobj did not contain
patch. caller must unlink filename when done.'''
# attempt to detect the start of a patch
# (this heuristic is borrowed from quilt)
diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
'retrieving revision [0-9]+(\.[0-9]+)*$|' +
'(---|\*\*\*)[ \t])', re.MULTILINE)
fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
tmpfp = os.fdopen(fd, 'w')
try:
hgpatch = False
msg = email.Parser.Parser().parse(fileobj)
message = msg['Subject']
user = msg['From']
# should try to parse msg['Date']
date = None
if message:
message = message.replace('\n\t', ' ')
ui.debug('Subject: %s\n' % message)
if user:
ui.debug('From: %s\n' % user)
diffs_seen = 0
ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
for part in msg.walk():
content_type = part.get_content_type()
ui.debug('Content-Type: %s\n' % content_type)
if content_type not in ok_types:
continue
payload = part.get_payload(decode=True)
m = diffre.search(payload)
if m:
ui.debug(_('found patch at byte %d\n') % m.start(0))
diffs_seen += 1
cfp = cStringIO.StringIO()
if message:
cfp.write(message)
cfp.write('\n')
for line in payload[:m.start(0)].splitlines():
if line.startswith('# HG changeset patch'):
ui.debug(_('patch generated by hg export\n'))
hgpatch = True
# drop earlier commit message content
cfp.seek(0)
cfp.truncate()
elif hgpatch:
if line.startswith('# User '):
user = line[7:]
ui.debug('From: %s\n' % user)
elif line.startswith("# Date "):
date = line[7:]
if not line.startswith('# '):
cfp.write(line)
cfp.write('\n')
message = cfp.getvalue()
if tmpfp:
tmpfp.write(payload)
if not payload.endswith('\n'):
tmpfp.write('\n')
elif not diffs_seen and message and content_type == 'text/plain':
message += '\n' + payload
except:
tmpfp.close()
os.unlink(tmpname)
raise
tmpfp.close()
if not diffs_seen:
os.unlink(tmpname)
return None, message, user, date
return tmpname, message, user, date
def readgitpatch(patchname):
"""extract git-style metadata about patches from <patchname>"""
class gitpatch:
"op is one of ADD, DELETE, RENAME, MODIFY or COPY"
def __init__(self, path):
self.path = path
self.oldpath = None
self.mode = None
self.op = 'MODIFY'
self.copymod = False
self.lineno = 0
# Filter patch for git information
gitre = re.compile('diff --git a/(.*) b/(.*)')
pf = file(patchname)
gp = None
gitpatches = []
# Can have a git patch with only metadata, causing patch to complain
dopatch = False
lineno = 0
for line in pf:
lineno += 1
if line.startswith('diff --git'):
m = gitre.match(line)
if m:
if gp:
gitpatches.append(gp)
src, dst = m.group(1,2)
gp = gitpatch(dst)
gp.lineno = lineno
elif gp:
if line.startswith('--- '):
if gp.op in ('COPY', 'RENAME'):
gp.copymod = True
dopatch = 'filter'
gitpatches.append(gp)
gp = None
if not dopatch:
dopatch = True
continue
if line.startswith('rename from '):
gp.op = 'RENAME'
gp.oldpath = line[12:].rstrip()
elif line.startswith('rename to '):
gp.path = line[10:].rstrip()
elif line.startswith('copy from '):
gp.op = 'COPY'
gp.oldpath = line[10:].rstrip()
elif line.startswith('copy to '):
gp.path = line[8:].rstrip()
elif line.startswith('deleted file'):
gp.op = 'DELETE'
elif line.startswith('new file mode '):
gp.op = 'ADD'
gp.mode = int(line.rstrip()[-3:], 8)
elif line.startswith('new mode '):
gp.mode = int(line.rstrip()[-3:], 8)
if gp:
gitpatches.append(gp)
if not gitpatches:
dopatch = True
return (dopatch, gitpatches)
def dogitpatch(patchname, gitpatches):
"""Preprocess git patch so that vanilla patch can handle it"""
pf = file(patchname)
pfline = 1
fd, patchname = tempfile.mkstemp(prefix='hg-patch-')
tmpfp = os.fdopen(fd, 'w')
try:
for i in range(len(gitpatches)):
p = gitpatches[i]
if not p.copymod:
continue
if os.path.exists(p.path):
raise util.Abort(_("cannot create %s: destination already exists") %
p.path)
(src, dst) = [os.path.join(os.getcwd(), n)
for n in (p.oldpath, p.path)]
targetdir = os.path.dirname(dst)
if not os.path.isdir(targetdir):
os.makedirs(targetdir)
try:
shutil.copyfile(src, dst)
shutil.copymode(src, dst)
except shutil.Error, inst:
raise util.Abort(str(inst))
# rewrite patch hunk
while pfline < p.lineno:
tmpfp.write(pf.readline())
pfline += 1
tmpfp.write('diff --git a/%s b/%s\n' % (p.path, p.path))
line = pf.readline()
pfline += 1
while not line.startswith('--- a/'):
tmpfp.write(line)
line = pf.readline()
pfline += 1
tmpfp.write('--- a/%s\n' % p.path)
line = pf.readline()
while line:
tmpfp.write(line)
line = pf.readline()
except:
tmpfp.close()
os.unlink(patchname)
raise
tmpfp.close()
return patchname
def patch(strip, patchname, ui, cwd=None):
"""apply the patch <patchname> to the working directory.
a list of patched files is returned"""
(dopatch, gitpatches) = readgitpatch(patchname)
files = {}
if dopatch:
if dopatch == 'filter':
patchname = dogitpatch(patchname, gitpatches)
patcher = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
args = []
if cwd:
args.append('-d %s' % util.shellquote(cwd))
fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
util.shellquote(patchname)))
if dopatch == 'filter':
False and os.unlink(patchname)
for line in fp:
line = line.rstrip()
ui.status("%s\n" % line)
if line.startswith('patching file '):
pf = util.parse_patch_output(line)
files.setdefault(pf, (None, None))
code = fp.close()
if code:
raise util.Abort(_("patch command failed: %s") %
util.explain_exit(code)[0])
for gp in gitpatches:
files[gp.path] = (gp.op, gp)
return files

View File

@ -1,6 +1,6 @@
# remoterepo - remote repositort proxy classes for mercurial
# remoterepo - remote repository proxy classes for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 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.

View File

@ -1,6 +1,7 @@
# repo.py - repository base classes for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.

View File

@ -4,7 +4,7 @@ revlog.py - storage back-end for mercurial
This provides efficient delta storage with O(1) retrieve and append
and O(changes) merge between branches
Copyright 2005 Matt Mackall <mpm@selenic.com>
Copyright 2005, 2006 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.

View File

@ -1,6 +1,6 @@
# sshrepo.py - ssh repository proxy class for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 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.

View File

@ -1,6 +1,7 @@
# sshserver.py - ssh protocol server support for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.

View File

@ -2,7 +2,7 @@
#
# This provides read-only repo access to repositories exported via static http
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 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.

View File

@ -6,7 +6,7 @@
# effectively log-structured, this should amount to simply truncating
# anything that isn't referenced in the changelog.
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 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.

View File

@ -1,6 +1,6 @@
# ui.py - user interface bits for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
# Copyright 2005, 2006 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.

View File

@ -2,6 +2,8 @@
util.py - Mercurial utility functions and platform specfic implementations
Copyright 2005 K. Thananchayan <thananck@yahoo.com>
Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
@ -93,27 +95,6 @@ def find_in_path(name, path, default=None):
return p_name
return default
def patch(strip, patchname, ui, cwd=None):
"""apply the patch <patchname> to the working directory.
a list of patched files is returned"""
patcher = find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
args = []
if cwd:
args.append('-d %s' % shellquote(cwd))
fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
shellquote(patchname)))
files = {}
for line in fp:
line = line.rstrip()
ui.status("%s\n" % line)
if line.startswith('patching file '):
pf = parse_patch_output(line)
files.setdefault(pf, 1)
code = fp.close()
if code:
raise Abort(_("patch command failed: %s") % explain_exit(code)[0])
return files.keys()
def binary(s):
"""return true if a string is binary data using diff's heuristic"""
if s and '\0' in s[:4096]:

View File

@ -1,4 +1,4 @@
# Copyright (C) 2005 by Intevation GmbH
# Copyright (C) 2005, 2006 by Intevation GmbH
# Author(s):
# Thomas Arendsen Hein <thomas@intevation.de>
#

122
tests/test-git-import Executable file
View File

@ -0,0 +1,122 @@
#!/bin/sh
hg init a
cd a
echo % new file
hg import -mnew - <<EOF
diff --git a/new b/new
new file mode 100644
index 0000000..7898192
--- /dev/null
+++ b/new
@@ -0,0 +1 @@
+a
EOF
echo % chmod +x
hg import -msetx - <<EOF
diff --git a/new b/new
old mode 100644
new mode 100755
EOF
test -x new || echo failed
echo % copy
hg import -mcopy - <<EOF
diff --git a/new b/copy
old mode 100755
new mode 100644
similarity index 100%
copy from new
copy to copy
diff --git a/new b/copyx
similarity index 100%
copy from new
copy to copyx
EOF
test -f copy -a ! -x copy || echo failed
test -x copyx || echo failed
cat copy
hg cat copy
echo % rename
hg import -mrename - <<EOF
diff --git a/copy b/rename
similarity index 100%
rename from copy
rename to rename
EOF
hg locate
echo % delete
hg import -mdelete - <<EOF
diff --git a/copyx b/copyx
deleted file mode 100755
index 7898192..0000000
--- a/copyx
+++ /dev/null
@@ -1 +0,0 @@
-a
EOF
hg locate
test -f copyx && echo failed || true
echo % regular diff
hg import -mregular - <<EOF
diff --git a/rename b/rename
index 7898192..72e1fe3 100644
--- a/rename
+++ b/rename
@@ -1 +1,5 @@
a
+a
+a
+a
+a
EOF
echo % copy and modify
hg import -mcopymod - <<EOF
diff --git a/rename b/copy2
similarity index 80%
copy from rename
copy to copy2
index 72e1fe3..b53c148 100644
--- a/rename
+++ b/copy2
@@ -1,5 +1,5 @@
a
a
-a
+b
a
a
EOF
hg cat copy2
echo % rename and modify
hg import -mrenamemod - <<EOF
diff --git a/copy2 b/rename2
similarity index 80%
rename from copy2
rename to rename2
index b53c148..8f81e29 100644
--- a/copy2
+++ b/rename2
@@ -1,5 +1,5 @@
a
a
b
-a
+c
a
EOF
hg locate copy2
hg cat rename2

39
tests/test-git-import.out Normal file
View File

@ -0,0 +1,39 @@
% new file
applying patch from stdin
patching file new
% chmod +x
applying patch from stdin
% copy
applying patch from stdin
a
a
% rename
applying patch from stdin
copyx
new
rename
% delete
applying patch from stdin
patching file copyx
new
rename
% regular diff
applying patch from stdin
patching file rename
% copy and modify
applying patch from stdin
patching file copy2
a
a
b
a
a
% rename and modify
applying patch from stdin
patching file rename2
copy2: No such file or directory
a
a
b
c
a