aboutsummaryrefslogtreecommitdiff
path: root/b4/__init__.py
diff options
context:
space:
mode:
authorKonstantin Ryabitsev <konstantin@linuxfoundation.org>2020-05-25 15:22:30 -0400
committerKonstantin Ryabitsev <konstantin@linuxfoundation.org>2020-05-25 15:22:30 -0400
commit59be08453137a3b9c6a25dc6787b5066a88a84cd (patch)
treedfc5acde52c5cd72895dcd9af7c46260f2a11e1a /b4/__init__.py
parent34bcb457865d0b58e08486b2ceb80e9067717e60 (diff)
downloadb4-59be08453137a3b9c6a25dc6787b5066a88a84cd.tar.gz
Add -3 to "b4 am" to prep for a 3way merge
The original code used for b4 diff was to prepare for a 3-way merge by making sure that all blob indexes exist in the local repo. Add this functionality to "b4 am" and document all the features added in the 0.5.0 branch. Signed-off-by: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
Diffstat (limited to 'b4/__init__.py')
-rw-r--r--b4/__init__.py115
1 files changed, 112 insertions, 3 deletions
diff --git a/b4/__init__.py b/b4/__init__.py
index b6f25fe..3cdad1c 100644
--- a/b4/__init__.py
+++ b/b4/__init__.py
@@ -587,7 +587,7 @@ class LoreSeries:
return mbx
- def check_applies_clean(self, topdir, when=None):
+ def check_applies_clean(self, gitdir, when=None):
# Go through indexes and see if this series should apply cleanly
mismatches = 0
seenfiles = set()
@@ -603,7 +603,7 @@ class LoreSeries:
if set(bh) == {'0'}:
# New file, will for sure apply clean
continue
- fullpath = os.path.join(topdir, fn)
+ fullpath = os.path.join(gitdir, fn)
if when is None:
if not os.path.exists(fullpath):
mismatches += 1
@@ -611,7 +611,7 @@ class LoreSeries:
cmdargs = ['hash-object', fullpath]
ecode, out = git_run_command(None, cmdargs)
else:
- gitdir = os.path.join(topdir, '.git')
+ gitdir = os.path.join(gitdir, '.git')
logger.debug('Checking hash on %s:%s', when, fn)
# XXX: We should probably pipe the two commands instead of reading into memory,
# so something to consider for the future
@@ -632,6 +632,115 @@ class LoreSeries:
return len(seenfiles), mismatches
+ def make_fake_am_range(self, gitdir):
+ start_commit = end_commit = None
+ # Do we have it in cache already?
+ cachedir = get_cache_dir()
+ # Use the msgid of the first non-None patch in the series
+ msgid = None
+ for lmsg in self.patches:
+ if lmsg is not None:
+ msgid = lmsg.msgid
+ break
+ if msgid is None:
+ logger.critical('Cannot operate on an empty series')
+ return None, None
+ cachefile = os.path.join(cachedir, '%s.fakeam' % urllib.parse.quote_plus(msgid))
+ if os.path.exists(cachefile):
+ stalecache = False
+ with open(cachefile, 'r') as fh:
+ cachedata = fh.read()
+ chunks = cachedata.strip().split()
+ if len(chunks) == 2:
+ start_commit, end_commit = chunks
+ else:
+ stalecache = True
+ if start_commit is not None and end_commit is not None:
+ # Make sure they are still there
+ ecode, out = git_run_command(gitdir, ['cat-file', '-e', start_commit])
+ if ecode > 0:
+ stalecache = True
+ else:
+ ecode, out = git_run_command(gitdir, ['cat-file', '-e', end_commit])
+ if ecode > 0:
+ stalecache = True
+ else:
+ logger.debug('Using previously generated range')
+ return start_commit, end_commit
+
+ if stalecache:
+ logger.debug('Stale cache for [v%s] %s', self.revision, self.subject)
+ os.unlink(cachefile)
+
+ logger.info('Preparing fake-am for v%s: %s', self.revision, self.subject)
+ with git_temp_worktree(gitdir):
+ # We are in a temporary chdir at this time, so writing to a known file should be safe
+ mbxf = '.__git-am__'
+ mbx = mailbox.mbox(mbxf)
+ # Logic largely borrowed from gj_tools
+ seenfiles = set()
+ for lmsg in self.patches[1:]:
+ logger.debug('Looking at %s', lmsg.full_subject)
+ lmsg.load_hashes()
+ if not len(lmsg.blob_indexes):
+ logger.critical('ERROR: some patches do not have indexes')
+ logger.critical(' unable to create a fake-am range')
+ return None, None
+ for fn, fi in lmsg.blob_indexes:
+ if fn in seenfiles:
+ # We already processed this file, so this blob won't match
+ continue
+ seenfiles.add(fn)
+ if set(fi) == {'0'}:
+ # New file creation, nothing to do here
+ logger.debug(' New file: %s', fn)
+ continue
+ # Try to grab full ref_id of this hash
+ ecode, out = git_run_command(gitdir, ['rev-parse', fi])
+ if ecode > 0:
+ logger.critical(' ERROR: Could not find matching blob for %s (%s)', fn, fi)
+ logger.critical(' If you know on which tree this patchset is based,')
+ logger.critical(' add it as a remote and perform "git remote update"')
+ logger.critical(' in order to fetch the missing objects.')
+ return None, None
+ logger.debug(' Found matching blob for: %s', fn)
+ fullref = out.strip()
+ gitargs = ['update-index', '--add', '--cacheinfo', f'0644,{fullref},{fn}']
+ ecode, out = git_run_command(None, gitargs)
+ if ecode > 0:
+ logger.critical(' ERROR: Could not run update-index for %s (%s)', fn, fullref)
+ return None, None
+ mbx.add(lmsg.msg.as_string(policy=emlpolicy).encode('utf-8'))
+
+ mbx.close()
+ ecode, out = git_run_command(None, ['write-tree'])
+ if ecode > 0:
+ logger.critical('ERROR: Could not write fake-am tree')
+ return None, None
+ treeid = out.strip()
+ # At this point we have a worktree with files that should cleanly receive a git am
+ gitargs = ['commit-tree', treeid + '^{tree}', '-F', '-']
+ ecode, out = git_run_command(None, gitargs, stdin='Initial fake commit'.encode('utf-8'))
+ if ecode > 0:
+ logger.critical('ERROR: Could not commit-tree')
+ return None, None
+ start_commit = out.strip()
+ git_run_command(None, ['reset', '--hard', start_commit])
+ ecode, out = git_run_command(None, ['am', mbxf])
+ if ecode > 0:
+ logger.critical('ERROR: Could not fake-am version %s', self.revision)
+ return None, None
+ ecode, out = git_run_command(None, ['rev-parse', 'HEAD'])
+ end_commit = out.strip()
+ logger.info(' range: %.12s..%.12s', start_commit, end_commit)
+
+ with open(cachefile, 'w') as fh:
+ logger.debug('Saving into cache: %s', cachefile)
+ logger.debug(' %s..%s', start_commit, end_commit)
+ fh.write(f'{start_commit} {end_commit}\n')
+
+ return start_commit, end_commit
+
def save_cover(self, outfile):
cover_msg = self.patches[0].get_am_message(add_trailers=False, trailer_order=None)
with open(outfile, 'w') as fh: