##// END OF EJS Templates
convert: introduce --full for converting all files...
convert: introduce --full for converting all files Convert will normally only process files that were changed in a source revision, apply the filemap, and record it has a change in the target repository. (If it ends up not really changing anything, nothing changes.) That means that _if_ the filemap is changed before continuing an incremental convert, the change will only kick in when the files it affects are modified in a source revision and thus processed. With --full, convert will make a full conversion every time and process all files in the source repo and remove target repo files that shouldn't be there. Filemap changes will thus kick in on the first converted revision, no matter what is changed. This flag should in most cases not make any difference but will make convert significantly slower. Other names has been considered for this feature, such as "resync", "sync", "checkunmodified", "all" or "allfiles", but I found that they were less obvious and required more explanation than "full" and were harder to describe consistently.

File last commit:

r22300:35ab037d default
r22300:35ab037d default
Show More
git.py
345 lines | 11.7 KiB | text/x-python | PythonLexer
Martin Geisler
convert: add copyright and license headers to back-ends
r8250 # git.py - git support for the convert extension
#
# Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
#
# This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Brendan Cully
Split convert extension into common and repository type modules
r4536
import os
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 import subprocess
YaNan Xu
convert: add support for converting git submodule (issue3528)...
r17929 from mercurial import util, config
Martin Geisler
clone, patch, convert: use hex(nullid) instead of '0'*40
r12144 from mercurial.node import hex, nullid
Martin Geisler
convert: mark strings for translation
r10939 from mercurial.i18n import _
Brendan Cully
Split convert extension into common and repository type modules
r4536
Patrick Mezard
convert: fail if an external required tool is not found
r5497 from common import NoRepo, commit, converter_source, checktool
Brendan Cully
Split convert extension into common and repository type modules
r4536
YaNan Xu
convert: add support for converting git submodule (issue3528)...
r17929 class submodule(object):
def __init__(self, path, node, url):
self.path = path
self.node = node
self.url = url
def hgsub(self):
return "%s = [git]%s" % (self.path, self.url)
def hgsubstate(self):
return "%s %s" % (self.node, self.path)
Brendan Cully
Split convert extension into common and repository type modules
r4536 class convert_git(converter_source):
Patrick Mezard
convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
r5217 # Windows does not support GIT_DIR= construct while other systems
# cannot remove environment variable. Just assume none have
# both issues.
Augie Fackler
hgext: replace uses of hasattr with util.safehasattr
r14945 if util.safehasattr(os, 'unsetenv'):
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 def gitopen(self, s, err=None):
Patrick Mezard
convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
r5217 prevgitdir = os.environ.get('GIT_DIR')
os.environ['GIT_DIR'] = self.path
try:
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 if err == subprocess.PIPE:
Edouard Gomez
convert: add bookmarks reading support to git backend
r13756 (stdin, stdout, stderr) = util.popen3(s)
return stdout
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 elif err == subprocess.STDOUT:
return self.popen_with_stderr(s)
Edouard Gomez
convert: add bookmarks reading support to git backend
r13756 else:
return util.popen(s, 'rb')
Patrick Mezard
convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
r5217 finally:
if prevgitdir is None:
del os.environ['GIT_DIR']
else:
os.environ['GIT_DIR'] = prevgitdir
David Schleimer
convert: drastically speed up git conversions...
r21630
def gitpipe(self, s):
prevgitdir = os.environ.get('GIT_DIR')
os.environ['GIT_DIR'] = self.path
try:
return util.popen3(s)
finally:
if prevgitdir is None:
del os.environ['GIT_DIR']
else:
os.environ['GIT_DIR'] = prevgitdir
Patrick Mezard
convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
r5217 else:
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 def gitopen(self, s, err=None):
if err == subprocess.PIPE:
Edouard Gomez
convert: add bookmarks reading support to git backend
r13756 (sin, so, se) = util.popen3('GIT_DIR=%s %s' % (self.path, s))
timeless
convert: fix error in git solaris code
r14177 return so
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 elif err == subprocess.STDOUT:
return self.popen_with_stderr(s)
Edouard Gomez
convert: add bookmarks reading support to git backend
r13756 else:
Mads Kiilerich
convert: fix git convert on solaris - it cannot remove environment variables
r14735 return util.popen('GIT_DIR=%s %s' % (self.path, s), 'rb')
Brendan Cully
convert: gitcmd wrapper for os.popen
r4767
David Schleimer
convert: drastically speed up git conversions...
r21630 def gitpipe(self, s):
return util.popen3('GIT_DIR=%s %s' % (self.path, s))
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 def popen_with_stderr(self, s):
p = subprocess.Popen(s, shell=True, bufsize=-1,
close_fds=util.closefds,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=False,
env=None)
return p.stdout
Patrick Mezard
convert/git: check status when reading the whole output
r10986 def gitread(self, s):
fh = self.gitopen(s)
data = fh.read()
return data, fh.close()
Brendan Cully
convert: add -r argument specifying latest revision to convert
r4760 def __init__(self, ui, path, rev=None):
Brendan Cully
convert: call superclass init from engine init functions
r4807 super(convert_git, self).__init__(ui, path, rev=rev)
Brendan Cully
Split convert extension into common and repository type modules
r4536 if os.path.isdir(path + "/.git"):
path += "/.git"
if not os.path.exists(path + "/objects"):
Martin Geisler
convert: mark strings for translation
r10939 raise NoRepo(_("%s does not look like a Git repository") % path)
Patrick Mezard
convert: fail if an external required tool is not found
r5497
Dhruva Krishnamurthy
convert: use git executable only, with subcommands...
r6837 checktool('git', 'git')
Patrick Mezard
convert: fail if an external required tool is not found
r5497
Brendan Cully
Split convert extension into common and repository type modules
r4536 self.path = path
YaNan Xu
convert: add support for converting git submodule (issue3528)...
r17929 self.submodules = []
Brendan Cully
Split convert extension into common and repository type modules
r4536
David Schleimer
convert: drastically speed up git conversions...
r21630 self.catfilepipe = self.gitpipe('git cat-file --batch')
def after(self):
for f in self.catfilepipe:
f.close()
Brendan Cully
Split convert extension into common and repository type modules
r4536 def getheads(self):
Brendan Cully
convert: import all branches from git repositories
r4768 if not self.rev:
Patrick Mezard
convert/git: check status when reading the whole output
r10986 heads, ret = self.gitread('git rev-parse --branches --remotes')
heads = heads.splitlines()
Brendan Cully
convert: import all branches from git repositories
r4768 else:
Patrick Mezard
convert/git: check status when reading the whole output
r10986 heads, ret = self.gitread("git rev-parse --verify %s" % self.rev)
heads = [heads[:-1]]
if ret:
raise util.Abort(_('cannot retrieve git heads'))
return heads
Brendan Cully
Split convert extension into common and repository type modules
r4536
def catfile(self, rev, type):
Martin Geisler
clone, patch, convert: use hex(nullid) instead of '0'*40
r12144 if rev == hex(nullid):
Brodie Rao
cleanup: "raise SomeException()" -> "raise SomeException"
r16687 raise IOError
David Schleimer
convert: drastically speed up git conversions...
r21630 self.catfilepipe[0].write(rev+'\n')
self.catfilepipe[0].flush()
info = self.catfilepipe[1].readline().split()
if info[1] != type:
Patrick Mezard
convert/git: check status when reading the whole output
r10986 raise util.Abort(_('cannot read %r object at %s') % (type, rev))
David Schleimer
convert: drastically speed up git conversions...
r21630 size = int(info[2])
data = self.catfilepipe[1].read(size)
if len(data) < size:
FUJIWARA Katsunori
convert: fix argument mismatch at formatting the abort message...
r21958 raise util.Abort(_('cannot read %r object at %s: unexpected size')
% (type, rev))
David Schleimer
convert: drastically speed up git conversions...
r21630 # read the trailing newline
self.catfilepipe[1].read(1)
Patrick Mezard
convert/git: check status when reading the whole output
r10986 return data
Brendan Cully
Split convert extension into common and repository type modules
r4536
def getfile(self, name, rev):
FUJIWARA Katsunori
convert: detect removal of ".gitmodules" at git source revisions correctly...
r21868 if rev == hex(nullid):
Mads Kiilerich
convert: use None value for missing files instead of overloading IOError...
r22296 return None, None
YaNan Xu
convert: add support for converting git submodule (issue3528)...
r17929 if name == '.hgsub':
data = '\n'.join([m.hgsub() for m in self.submoditer()])
mode = ''
elif name == '.hgsubstate':
data = '\n'.join([m.hgsubstate() for m in self.submoditer()])
mode = ''
else:
data = self.catfile(rev, "blob")
mode = self.modecache[(name, rev)]
Patrick Mezard
convert: merge sources getmode() into getfile()
r11134 return data, mode
Brendan Cully
Split convert extension into common and repository type modules
r4536
YaNan Xu
convert: add support for converting git submodule (issue3528)...
r17929 def submoditer(self):
null = hex(nullid)
for m in sorted(self.submodules, key=lambda p: p.path):
if m.node != null:
yield m
def parsegitmodules(self, content):
"""Parse the formatted .gitmodules file, example file format:
[submodule "sub"]\n
\tpath = sub\n
\turl = git://giturl\n
"""
self.submodules = []
c = config.config()
# Each item in .gitmodules starts with \t that cant be parsed
c.parse('.gitmodules', content.replace('\t',''))
for sec in c.sections():
s = c[sec]
if 'url' in s and 'path' in s:
self.submodules.append(submodule(s['path'], '', s['url']))
def retrievegitmodules(self, version):
modules, ret = self.gitread("git show %s:%s" % (version, '.gitmodules'))
if ret:
Bryan O'Sullivan
convert: fix a too-long line nag
r17930 raise util.Abort(_('cannot read submodules config file in %s') %
version)
YaNan Xu
convert: add support for converting git submodule (issue3528)...
r17929 self.parsegitmodules(modules)
for m in self.submodules:
node, ret = self.gitread("git rev-parse %s:%s" % (version, m.path))
if ret:
continue
m.node = node.strip()
Mads Kiilerich
convert: introduce --full for converting all files...
r22300 def getchanges(self, version, full):
if full:
raise util.Abort(_("convert from git do not support --full"))
Brendan Cully
Split convert extension into common and repository type modules
r4536 self.modecache = {}
Patrick Mezard
convert/git: rename gitcmd() into gitopen() for readability
r10985 fh = self.gitopen("git diff-tree -z --root -m -r %s" % version)
Brendan Cully
Split convert extension into common and repository type modules
r4536 changes = []
Benoit Boissinot
convert: use set instead of dict
r8456 seen = set()
Patrick Mezard
convert: fix non-ASCII filenames retrieval from git sources (issue 1360)
r7242 entry = None
YaNan Xu
convert: add support for converting git submodule (issue3528)...
r17929 subexists = False
FUJIWARA Katsunori
convert: detect removal of ".gitmodules" at git source revisions correctly...
r21868 subdeleted = False
Patrick Mezard
convert: fix non-ASCII filenames retrieval from git sources (issue 1360)
r7242 for l in fh.read().split('\x00'):
if not entry:
if not l.startswith(':'):
continue
entry = l
Alexis S. L. Carvalho
convert_git: avoid returning two entries for the same file in getchanges...
r5335 continue
Patrick Mezard
convert: fix non-ASCII filenames retrieval from git sources (issue 1360)
r7242 f = l
if f not in seen:
Benoit Boissinot
convert: use set instead of dict
r8456 seen.add(f)
Patrick Mezard
convert: fix non-ASCII filenames retrieval from git sources (issue 1360)
r7242 entry = entry.split()
h = entry[3]
p = (entry[1] == "100755")
s = (entry[1] == "120000")
YaNan Xu
convert: add support for converting git submodule (issue3528)...
r17929
if f == '.gitmodules':
subexists = True
FUJIWARA Katsunori
convert: detect removal of ".gitmodules" at git source revisions correctly...
r21868 if entry[4] == 'D':
subdeleted = True
changes.append(('.hgsub', hex(nullid)))
else:
changes.append(('.hgsub', ''))
YaNan Xu
convert: add support for converting git submodule (issue3528)...
r17929 elif entry[1] == '160000' or entry[0] == ':160000':
subexists = True
else:
self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
changes.append((f, h))
Patrick Mezard
convert: fix non-ASCII filenames retrieval from git sources (issue 1360)
r7242 entry = None
Patrick Mezard
convert/git: check status when reading output stream
r10987 if fh.close():
raise util.Abort(_('cannot read changes in %s') % version)
YaNan Xu
convert: add support for converting git submodule (issue3528)...
r17929
if subexists:
FUJIWARA Katsunori
convert: detect removal of ".gitmodules" at git source revisions correctly...
r21868 if subdeleted:
changes.append(('.hgsubstate', hex(nullid)))
else:
self.retrievegitmodules(version)
changes.append(('.hgsubstate', ''))
Brendan Cully
convert: look up copies in getchanges instead of getcommit...
r5121 return (changes, {})
Brendan Cully
Split convert extension into common and repository type modules
r4536
def getcommit(self, version):
c = self.catfile(version, "commit") # read the commit hash
end = c.find("\n\n")
Matt Mackall
many, many trivial check-code fixups
r10282 message = c[end + 2:]
Brendan Cully
convert: ove recode method into converter_source
r4759 message = self.recode(message)
Brendan Cully
Split convert extension into common and repository type modules
r4536 l = c[:end].splitlines()
parents = []
Richard Quirk
Add committer tag only when needed in git conversion...
r8271 author = committer = None
Brendan Cully
Split convert extension into common and repository type modules
r4536 for e in l[1:]:
n, v = e.split(" ", 1)
if n == "author":
p = v.split()
tm, tz = p[-2:]
author = " ".join(p[:-2])
if author[0] == "<": author = author[1:-1]
Brendan Cully
convert: ove recode method into converter_source
r4759 author = self.recode(author)
Brendan Cully
Split convert extension into common and repository type modules
r4536 if n == "committer":
p = v.split()
tm, tz = p[-2:]
committer = " ".join(p[:-2])
if committer[0] == "<": committer = committer[1:-1]
Brendan Cully
convert: ove recode method into converter_source
r4759 committer = self.recode(committer)
Matt Mackall
many, many trivial check-code fixups
r10282 if n == "parent":
parents.append(v)
Brendan Cully
Split convert extension into common and repository type modules
r4536
Richard Quirk
Add committer tag only when needed in git conversion...
r8271 if committer and committer != author:
message += "\ncommitter: %s\n" % committer
Brendan Cully
Split convert extension into common and repository type modules
r4536 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
date = tm + " " + str(tz)
Brendan Cully
convert: record the source revision in the changelog
r4873 c = commit(parents=parents, date=date, author=author, desc=message,
rev=version)
Brendan Cully
Split convert extension into common and repository type modules
r4536 return c
def gettags(self):
tags = {}
Edouard Gomez
convert: support non annotated tags in git backend...
r16259 alltags = {}
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 fh = self.gitopen('git ls-remote --tags "%s"' % self.path,
err=subprocess.STDOUT)
Brendan Cully
Split convert extension into common and repository type modules
r4536 prefix = 'refs/tags/'
Edouard Gomez
convert: support non annotated tags in git backend...
r16259
# Build complete list of tags, both annotated and bare ones
Brendan Cully
Split convert extension into common and repository type modules
r4536 for line in fh:
line = line.strip()
Augie Fackler
git convert: some versions of git use fatal: instead of error:...
r18572 if line.startswith("error:") or line.startswith("fatal:"):
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 raise util.Abort(_('cannot read tags from %s') % self.path)
Brendan Cully
Split convert extension into common and repository type modules
r4536 node, tag = line.split(None, 1)
if not tag.startswith(prefix):
continue
Edouard Gomez
convert: support non annotated tags in git backend...
r16259 alltags[tag[len(prefix):]] = node
Patrick Mezard
convert/git: check status when reading output stream
r10987 if fh.close():
raise util.Abort(_('cannot read tags from %s') % self.path)
Brendan Cully
Split convert extension into common and repository type modules
r4536
Edouard Gomez
convert: support non annotated tags in git backend...
r16259 # Filter out tag objects for annotated tag refs
for tag in alltags:
if tag.endswith('^{}'):
tags[tag[:-3]] = alltags[tag]
else:
if tag + '^{}' in alltags:
continue
else:
tags[tag] = alltags[tag]
Brendan Cully
Split convert extension into common and repository type modules
r4536 return tags
Alexis S. L. Carvalho
convert_git: add --filemap support
r5380
def getchangedfiles(self, version, i):
changes = []
if i is None:
Patrick Mezard
convert/git: rename gitcmd() into gitopen() for readability
r10985 fh = self.gitopen("git diff-tree --root -m -r %s" % version)
Alexis S. L. Carvalho
convert_git: add --filemap support
r5380 for l in fh:
if "\t" not in l:
continue
m, f = l[:-1].split("\t")
changes.append(f)
else:
Brodie Rao
cleanup: eradicate long lines
r16683 fh = self.gitopen('git diff-tree --name-only --root -r %s '
'"%s^%s" --' % (version, version, i + 1))
Alexis S. L. Carvalho
convert_git: add --filemap support
r5380 changes = [f.rstrip('\n') for f in fh]
Patrick Mezard
convert/git: check status when reading output stream
r10987 if fh.close():
raise util.Abort(_('cannot read changes in %s') % version)
Alexis S. L. Carvalho
convert_git: add --filemap support
r5380
return changes
Edouard Gomez
convert: add bookmarks reading support to git backend
r13756
def getbookmarks(self):
bookmarks = {}
# Interesting references in git are prefixed
prefix = 'refs/heads/'
prefixlen = len(prefix)
# factor two commands
gitcmd = { 'remote/': 'git ls-remote --heads origin',
'': 'git show-ref'}
# Origin heads
for reftype in gitcmd:
try:
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 fh = self.gitopen(gitcmd[reftype], err=subprocess.PIPE)
Edouard Gomez
convert: add bookmarks reading support to git backend
r13756 for line in fh:
line = line.strip()
rev, name = line.split(None, 1)
if not name.startswith(prefix):
continue
name = '%s%s' % (reftype, name[prefixlen:])
bookmarks[name] = rev
Brodie Rao
cleanup: replace naked excepts with except Exception: ...
r16689 except Exception:
Edouard Gomez
convert: add bookmarks reading support to git backend
r13756 pass
return bookmarks
Ben Goswami
splicemap: improve error handling when source is git (issue2084)...
r19121
Sean Farley
convert: add mapname parameter to checkrevformat...
r20373 def checkrevformat(self, revstr, mapname='splicemap'):
Ben Goswami
splicemap: improve error handling when source is git (issue2084)...
r19121 """ git revision string is a 40 byte hex """
Sean Farley
convert: add mapname parameter to checkrevformat...
r20373 self.checkhexformat(revstr, mapname)
Ben Goswami
splicemap: improve error handling when source is git (issue2084)...
r19121