Commit 094b7bb2 authored by Julien Muchembled's avatar Julien Muchembled

EPR5VCS: handle some cases where git couldn't push because working copy wasn't up-to-date

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@44025 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 5ac1ea5d
......@@ -151,7 +151,7 @@
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: not (lambda vcs: vcs.getAheadCount() or vcs.getBehindCount())(here.getVcsTool())</string> </value>
<value> <string>python: not here.getVcsTool().getAheadCount()</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -36,9 +36,10 @@ from Products.ERP5VCS.WorkingCopy import \
WorkingCopy, NotAWorkingCopyError, Dir, File, selfcached
class GitError(EnvironmentError):
def __init__(self, err, out):
def __init__(self, err, out, returncode):
EnvironmentError.__init__(self, err)
self.stdout = out
self.returncode = returncode
class Git(WorkingCopy):
......@@ -58,7 +59,7 @@ class Git(WorkingCopy):
p = self._git(stdout=subprocess.PIPE, stderr=subprocess.PIPE, *args, **kw)
out, err = p.communicate()
if p.returncode:
raise GitError(err, out)
raise GitError(err, out, p.returncode)
if strip:
return out.strip()
return out
......@@ -223,6 +224,12 @@ class Git(WorkingCopy):
def commit(self, changelog, added=(), modified=(), removed=()):
context = self.aq_parent
request = context.REQUEST
push = request.get('push')
reset = 1
if push:
# if we can't push because we are not up-to-date, we'll either 'merge' or
# 'rebase' depending on we already have local commits or not
merge = self.getAheadCount() and 'merge' or 'rebase'
selected_set = set(added)
selected_set.update(modified)
......@@ -234,13 +241,42 @@ class Git(WorkingCopy):
if author:
args[1:1] = '--author', author
self.git(*(args + list(selected_set)))
self.clean()
try:
if request.get('push'):
if push:
src, remote = self._getBranch()
remote, dst = remote.split('/', 1)
self.git('push', '--porcelain', remote, '%s:%s' % (src, dst))
push_args = 'push', '--porcelain', remote, '%s:%s' % (src, dst)
try:
self.git(*push_args)
except GitError, e:
# first check why we could not push
status = [x for x in e.stdout.splitlines() if x[:1] == '!']
if (len(status) != 1 or
status[0].split()[2:] != ['[rejected]', '(non-fast-forward)']):
raise
self.git('fetch', '--prune', remote)
if not self.getBehindCount():
raise
# try to update our working copy
# TODO: find a solution if there are other local changes
# TODO: solve conflicts on */bt/revision automatically
try:
self.git(merge, '@{u}')
except GitError, e:
# XXX: how to know how it failed ?
try:
self.git(merge, '--abort')
except GitError:
pass
raise e
# no need to keep a merge commit if push fails again
if merge == 'merge':
reset += 1
# retry to push everything
self.git(*push_args)
except GitError, e:
self.git('reset', '--soft', '@{1}')
self.git('reset', '--soft', '@{%u}' % reset)
portal_status_message = str(e)
else:
head = self.git('rev-parse', '--short', 'HEAD')
......@@ -262,6 +298,11 @@ class Git(WorkingCopy):
message=message))
return log
def clean(self):
self.git('reset', '-q', '.') # WKRD: "git checkout HEAD ." is inefficient
self.git('checkout', '.') # because it deletes and recreates all files
self.git('clean', '-qfd')
def _clean(self):
# XXX unsafe if user doesn't configure files to exclude
self.git('clean', '-fd', cwd=self.toplevel)
......@@ -379,7 +379,9 @@ class BusinessTemplateWorkingCopy(BusinessTemplateFolder):
try:
file = open(path, 'r+b')
except IOError, e:
if e.errno != errno.ENOENT:
if e.errno == errno.EISDIR:
shutil.rmtree(path, ignore_errors=True)
elif e.errno != errno.ENOENT:
raise
file = open(path, 'wb')
else:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment