p4fastimport: fix sync commit - complete workflow

Differential Revision: https://phabricator.intern.facebook.com/D5966213
This commit is contained in:
Zhihui Huang 2017-10-10 10:14:00 -07:00
parent e4f962c4d2
commit a6d5ff8f57
4 changed files with 152 additions and 102 deletions

View File

@ -346,37 +346,22 @@ def p4syncimport(ui, repo, client, **opts):
scmutil.checknewlabel(repo, opts['bookmark'], 'bookmark')
if len(repo) == 0:
raise error.Abort(_('p4 blob commit does not support empty repo yet.'))
raise error.Abort(_('p4 sync commit does not support empty repo yet.'))
p1ctx, startcl, __ = startfrom(ui, repo, opts)
p1ctx, __, __ = startfrom(ui, repo, opts)
# Fail if the specified client does not exist
if not p4.exists_client(client):
raise error.Abort(_('p4 client %s does not exist.') % client)
# Return all the changelists touching files in a given client view.
ui.note(_('loading changelist numbers.\n'))
changelists = sorted(p4.parse_changes(
client, startcl=startcl, endcl=startcl))
ui.note(_('%d changelists to import.\n') % len(changelists))
if len(changelists) == 0:
return
# Get a list of files that we will have to import
basepath = opts.get('path')
startcl, endcl = startcl, startcl
ui.note(_('loading list of files.\n'))
filelist = getfilelist(ui, p4.parse_filelist(client, startcl, endcl))
ui.note(_('%d files to import.\n') % len(filelist))
latestcl = p4.get_latest_cl(client)
if latestcl is None:
raise error.Abort(_('Cannot find latest p4 changelist number.'))
importset = importer.ImportSet(repo, client, changelists,
filelist, basepath)
p4filelogs = []
for i, f in enumerate(importset.filelogs()):
ui.debug('reading filelog %s\n' % f.depotfile)
ui.progress(_('reading filelog'), i, unit=_('filelogs'),
total=len(filelist))
p4filelogs.append(f)
ui.progress(_('reading filelog'), None)
ui.note(_('Latest change list number %s\n') % latestcl)
p4filelogs = p4.get_filelogs_at_cl(client, latestcl)
p4filelogs = sorted(p4filelogs)
# sync import.
with repo.wlock(), repo.lock():
@ -384,12 +369,12 @@ def p4syncimport(ui, repo, client, **opts):
count = 0
fileinfo = {}
largefileslist = []
p4filelogs = sorted(p4filelogs)
tr = repo.transaction('syncimport')
try:
for p4fl in p4filelogs:
bfi = importer.BlobFileImporter(ui, repo, importset, p4fl)
# Create filelog.
bfi = importer.SyncFileImporter(
ui, repo, client, latestcl, p4fl)
# Create hg filelog
fileflags, largefiles, oldtiprev, newtiprev = bfi.create(tr)
fileinfo[p4fl.depotfile] = {
'flags': fileflags,
@ -399,8 +384,8 @@ def p4syncimport(ui, repo, client, **opts):
largefileslist.extend(largefiles)
count += 1
# Generate manifest and changelog
clog = importer.BlobChangeManifestImporter(ui, repo, importset,
p1ctx=p1ctx)
clog = importer.SyncChangeManifestImporter(
ui, repo, client, latestcl, p1ctx=p1ctx)
revisions = []
for cl, hgnode in clog.creategen(tr, fileinfo):
revisions.append((cl, hex(hgnode)))
@ -411,12 +396,11 @@ def p4syncimport(ui, repo, client, **opts):
if ui.config('p4fastimport', 'lfsmetadata', None) is not None:
ui.note(_('writing lfs metadata to sqlite\n'))
writelfsmetadata(largefiles, revisions,
writelfsmetadata(largefileslist, revisions,
ui.config('p4fastimport', 'lfsmetadata', None))
tr.close()
ui.note(_('%d revision(s), %d file(s) imported.\n') % (
len(changelists), count))
ui.note(_('1 revision, %d file(s) imported.\n') % count)
finally:
tr.release()

View File

@ -22,6 +22,9 @@ KEYWORD_REGEX = "\$(Id|Header|DateTime|" + \
"Date|Change|File|" + \
"Revision|Author).*?\$"
#TODO: make p4 user configurable
P4_ADMIN_USER = 'p4admin'
def relpath(client, depotfile):
where = p4.parse_where(client, depotfile)
filename = where['clientFile'].replace('//%s/' % client, '')
@ -147,7 +150,48 @@ class ChangeManifestImporter(object):
user=username, date=date,
extra={'p4changelist': cl})
class BlobChangeManifestImporter(ChangeManifestImporter):
class SyncChangeManifestImporter(ChangeManifestImporter):
def __init__(self, ui, repo, client, cl, p1ctx):
self._ui = ui
self._repo = repo
self._client = client
self._cl = cl
self._p1ctx = p1ctx
def creategen(self, tr, fileinfo):
mrevlog = self._repo.manifestlog._revlog
clog = self._repo.changelog
cp1 = self._p1ctx.node()
cp2 = nullid
p1 = self._repo[cp1]
mp1 = p1.manifestnode()
mp2 = nullid
mf = manifest.manifestdict()
changed = []
for info in fileinfo.values():
localname = info['localname']
baserev = info['baserev']
mf[localname] = self._repo.file(localname).node(baserev)
changed.append(localname)
linkrev = len(self._repo)
oldmp1 = mp1
mp1 = mrevlog.addrevision(mf.text(mrevlog._usemanifestv2), tr,
linkrev, mp1, mp2)
self._ui.debug('changelist %d: writing manifest. '
'node: %s p1: %s p2: %s linkrev: %d\n' % (
self._cl, short(mp1), short(oldmp1), short(mp2), linkrev))
desc = 'p4fastimport synchronizing client view'
username = P4_ADMIN_USER
self._ui.debug('changelist %d: writing changelog: %s\n' % (
self._cl, desc))
cp1 = self.writechangelog(
clog, mp1, changed, desc, tr, cp1, cp2,
username, None, self._cl)
yield self._cl, cp1
def writechangelog(
self, clog, mp1, changed, desc, tr, cp1, cp2, username, date, cl):
return clog.add(
@ -378,61 +422,65 @@ class FileImporter(object):
newlen = len(hgfilelog)
return fileflags, largefiles, origlen, newlen
class BlobFileImporter(FileImporter):
class SyncFileImporter(FileImporter):
def __init__(self, ui, repo, client, cl, p4filelog):
self._ui = ui
self._repo = repo
self._client = client
self._cl = cl
self._p4filelog = p4filelog
@util.propertycache
def relpath(self):
return relpath(self._client, self._p4filelog.depotfile)
def create(self, tr):
assert tr is not None
p4fi = P4FileImporter(self._p4filelog)
revs = set()
for c in self._importset.changelists:
if c.cl in p4fi.revisions and not self._p4filelog.isdeleted(c.cl):
revs.add(c)
fileflags = collections.defaultdict(dict)
lastlinkrev = 0
hgfilelog = self.hgfilelog()
origlen = len(hgfilelog)
largefiles = []
lfsext = self.findlfs()
for c in sorted(revs):
linkrev = self._importset.linkrev(c.cl)
fparent1, fparent2 = nullid, nullid
linkrev = len(self._repo)
fparent1, fparent2 = nullid, nullid
localfile = self.relpath
hgfilelog = self._repo.file(localfile)
if len(hgfilelog) > 0:
fparent1 = hgfilelog.tip()
assert linkrev >= lastlinkrev
lastlinkrev = linkrev
# Only read files from p4 for a sync commit
text, src = p4.get_file(self._p4filelog.depotfile, clnum=self._cl), 'p4'
if text is None:
raise error.Abort('error generating file content %d %s' % (
self._cl, localfile))
if len(hgfilelog) > 0:
fparent1 = hgfilelog.tip()
meta = {}
if self._p4filelog.isexec(self._cl):
fileflags[self._cl] = 'x'
else:
fileflags[self._cl] = ''
text = None
# Only read files from p4 for a blob commit
text, src = p4fi.content(c.cl), 'p4'
if text is None:
raise error.Abort('error generating file content %d %s' % (
c.cl, self.relpath))
if self._p4filelog.issymlink(self._cl):
fileflags[self._cl] = 'l'
else:
fileflags[self._cl] = ''
meta = {}
fileflags[c.cl] = ' '
if self._p4filelog.isexec(c.cl):
fileflags[c.cl] = 'x'
if self._p4filelog.issymlink(c.cl):
fileflags[c.cl] = 'l'
if self._p4filelog.iskeyworded(c.cl):
text = re.sub(KEYWORD_REGEX, r'$\1$', text)
if self._p4filelog.iskeyworded(self._cl):
text = re.sub(KEYWORD_REGEX, r'$\1$', text)
node = hgfilelog.add(text, meta, tr, linkrev, fparent1, fparent2)
self._ui.debug(
'writing filelog: %s, p1 %s, linkrev %d, %d bytes, src: %s, '
'path: %s\n' % (short(node), short(fparent1), linkrev,
len(text), src, self.relpath))
origlen = len(hgfilelog)
node = hgfilelog.add(text, meta, tr, linkrev, fparent1, fparent2)
self._ui.debug(
'writing filelog: %s, p1 %s, linkrev %d, %d bytes, src: %s, '
'path: %s\n' % (short(node), short(fparent1), linkrev,
len(text), src, self.relpath))
if lfsext and lfsext.wrapper._islfs(hgfilelog, node):
lfspointer = lfsext.pointer.deserialize(
hgfilelog.revision(node, raw=True))
oid = lfspointer.oid()
largefiles.append((c.cl, self.depotfile, oid))
self._ui.debug('largefile: %s, oid: %s\n' % (self.relpath, oid))
largefiles = []
if lfsext and lfsext.wrapper._islfs(hgfilelog, node):
lfspointer = lfsext.pointer.deserialize(
hgfilelog.revision(node, raw=True))
oid = lfspointer.oid()
largefiles.append((self._cl, self._p4filelog.depotfile, oid))
self._ui.debug('largefile: %s, oid: %s\n' % (self.relpath, oid))
newlen = len(hgfilelog)
return fileflags, largefiles, origlen, newlen

View File

@ -37,7 +37,7 @@ populate the depot
edit //depot/Main/largefile#2
Change 2 submitted.
Blob Commit
Sync Commit
$ cd $hgwd
$ hg init --config 'format.usefncache=False'
@ -75,19 +75,18 @@ Blob Commit
$ cd $hgwd
$ hg p4syncimport --debug -P $P4ROOT hg-p4-import
incremental import from changelist: 3, node: * (glob)
loading changelist numbers.
1 changelists to import.
loading list of files.
1 files to import.
reading filelog * (glob)
Latest change list number 3
running a sync import.
writing filelog: fc4d9d827df8, p1 a80d06849b33, linkrev 2, 4 bytes, src: *, path: Main/a (glob)
writing filelog: cf38a89d2b54, p1 000000000000, linkrev 2, 23 bytes, src: *, path: Main/anotherlargefile (glob)
largefile: Main/anotherlargefile, oid: 9703972eff7a4df07317eda436ab7ef827ed16ea28c62abdcd7de269745c610c
changelist 3: writing manifest. node: edf0e5bc6eac p1: c14352bb3510 p2: 000000000000 linkrev: 2
changelist 3: writing changelog: third
writing filelog: fa4df9fc788c, p1 9f14f96519e1, linkrev 2, 88 bytes, src: *, path: Main/largefile (glob)
largefile: Main/largefile, oid: b0d5c1968efbabbff9d94160f284cd7b52686ca3c46cfffdd351de07384fce9c
changelist 3: writing manifest. node: a6a6dbeefd0a p1: c14352bb3510 p2: 000000000000 linkrev: 2
changelist 3: writing changelog: p4fastimport synchronizing client view
writing lfs metadata to sqlite
updating the branch cache
1 revision(s), 1 file(s) imported.
1 revision, 3 file(s) imported.
Verify
(waiting for https://patchwork.mercurial-scm.org/patch/20582/)
@ -98,7 +97,7 @@ Verify
checking manifests
crosschecking files in changesets and manifests
checking files
3 files, 3 changesets, 5 total revisions
3 files, 3 changesets, 7 total revisions
$ test -d .hg/store/lfs/objects
[1]
@ -106,6 +105,7 @@ Verify
1|1|*|37a7b43abd9e105a0e6b22088b140735a02f288767fe7a6f4f436cb46b064ca9|//depot/Main/largefile (glob)
2|2|*|b0d5c1968efbabbff9d94160f284cd7b52686ca3c46cfffdd351de07384fce9c|//depot/Main/largefile (glob)
3|3|*|9703972eff7a4df07317eda436ab7ef827ed16ea28c62abdcd7de269745c610c|//depot/Main/anotherlargefile (glob)
4|3|*|b0d5c1968efbabbff9d94160f284cd7b52686ca3c46cfffdd351de07384fce9c|//depot/Main/largefile (glob)
End Test

View File

@ -25,7 +25,7 @@ Populate the Depot
edit //depot/Main/a#2
Change 2 submitted.
Sync import
Fast Import
$ cd $hgwd
$ hg init --config 'format.usefncache=False'
@ -60,35 +60,54 @@ Sync import
//depot/Main/c#1 - opened for add
//depot/Main/d/e#1 - opened for add
//depot/Main/d/f/g#1 - opened for add
$ p4 delete Main/a
//depot/Main/a#2 - opened for delete
$ p4 submit -d third
Submitting change 3.
Locking 4 files ...
Locking 5 files ...
delete //depot/Main/a#3
edit //depot/Main/b#2
add //depot/Main/c#1
add //depot/Main/d/e#1
add //depot/Main/d/f/g#1
Change 3 submitted.
Sync Import
$ cd $hgwd
$ cd $hgwd
$ hg p4syncimport --bookmark master --debug -P $P4ROOT hg-p4-import
incremental import from changelist: 3, node: * (glob)
loading changelist numbers.
1 changelists to import.
loading list of files.
4 files to import.
reading filelog * (glob)
reading filelog * (glob)
reading filelog * (glob)
reading filelog * (glob)
Latest change list number 3
running a sync import.
writing filelog: 861f64b39056, p1 1e88685f5dde, linkrev 2, 4 bytes, src: *, path: Main/b (glob)
writing filelog: 149da44f2a4e, p1 000000000000, linkrev 2, 2 bytes, src: *, path: Main/c (glob)
writing filelog: 6b67ccefd5ce, p1 000000000000, linkrev 2, 2 bytes, src: *, path: Main/d/e (glob)
writing filelog: 0973eb1b2ecc, p1 000000000000, linkrev 2, 2 bytes, *: p4, path: Main/d/f/g (glob)
changelist 3: writing manifest. node: 2f8836be616d p1: 5c8695bebd8f p2: 000000000000 linkrev: 2
changelist 3: writing changelog: third
writing filelog: 0973eb1b2ecc, p1 000000000000, linkrev 2, 2 bytes, src: *, path: Main/d/f/g (glob)
changelist 3: writing manifest. node: f0ca72fbd536 p1: 5c8695bebd8f p2: 000000000000 linkrev: 2
changelist 3: writing changelog: p4fastimport synchronizing client view
writing bookmark
updating the branch cache
1 revision(s), 4 file(s) imported.
1 revision, 4 file(s) imported.
Sync Import without New Changes
$ hg p4syncimport --bookmark master --debug -P $P4ROOT hg-p4-import
incremental import from changelist: 4, node: * (glob)
Latest change list number 3
running a sync import.
writing filelog: 0a738da2fcb2, p1 861f64b39056, linkrev 3, 4 bytes, src: *, path: Main/b (glob)
writing filelog: 825765709d02, p1 149da44f2a4e, linkrev 3, 2 bytes, src: *, path: Main/c (glob)
writing filelog: c3bd1155d122, p1 6b67ccefd5ce, linkrev 3, 2 bytes, src: *, path: Main/d/e (glob)
writing filelog: 7fd4bac0fb3a, p1 0973eb1b2ecc, linkrev 3, 2 bytes, src: *, path: Main/d/f/g (glob)
changelist 3: writing manifest. node: c11fdd72fcbf p1: f0ca72fbd536 p2: 000000000000 linkrev: 3
changelist 3: writing changelog: p4fastimport synchronizing client view
writing bookmark
updating the branch cache
1 revision, 4 file(s) imported.
Fast Import after Sync Import
$ hg p4fastimport --bookmark master --debug -P $P4ROOT hg-p4-import
incremental import from changelist: 4, node: * (glob)
loading changelist numbers.
@ -101,14 +120,13 @@ Verify
checking manifests
crosschecking files in changesets and manifests
checking files
5 files, 3 changesets, 7 total revisions
5 files, 4 changesets, 11 total revisions
$ hg update master
5 files updated, 0 files merged, 0 files removed, 0 files unresolved
4 files updated, 0 files merged, 0 files removed, 0 files unresolved
(activating bookmark master)
$ hg manifest -r master
Main/a
Main/b
Main/c
Main/d/e