@@ -9,21 +9,36 @@ from i18n import _
from node import hex
import errno
import util, scmutil, changegroup
import discovery, phases, obsolete, bookmarks
+
+class pushoperation(object):
+ """A object that represent a single push operation
+
+ It purpose is to carry push related state and very common operation.
+
+ A new should be created at the begining of each push and discarded
+ afterward.
+ """
+
+ def __init__(self, repo):
+ # repo we push from
+ self.repo = repo
+
def push(repo, remote, force=False, revs=None, newbranch=False):
'''Push outgoing changesets (limited by revs) from a local
repository to remote. Return an integer:
- None means nothing to push
- 0 means HTTP error
- 1 means we pushed and remote head count is unchanged *or*
we have outgoing changesets but refused to push
- other values as described by addchangegroup()
'''
+ pushop = pushoperation(repo)
if remote.local():
- missing = set(repo.requirements) - remote.local().supported
+ missing = set(pushop.repo.requirements) - remote.local().supported
if missing:
msg = _("required features are not"
" supported in the destination:"
" %s") % (', '.join(sorted(missing)))
raise util.Abort(msg)
@@ -36,38 +51,38 @@ def push(repo, remote, force=False, revs
# unbundle assumes local user cannot lock remote repo (new ssh
# servers, http servers).
if not remote.canpush():
raise util.Abort(_("destination does not support push"))
- unfi = repo.unfiltered()
+ unfi = pushop.repo.unfiltered()
def localphasemove(nodes, phase=phases.public):
"""move <nodes> to <phase> in the local source repo"""
if locallock is not None:
- phases.advanceboundary(repo, phase, nodes)
+ phases.advanceboundary(pushop.repo, phase, nodes)
else:
# repo is not locked, do not change any phases!
# Informs the user that phases should have been moved when
# applicable.
- actualmoves = [n for n in nodes if phase < repo[n].phase()]
+ actualmoves = [n for n in nodes if phase < pushop.repo[n].phase()]
phasestr = phases.phasenames[phase]
if actualmoves:
- repo.ui.status(_('cannot lock source repo, skipping local'
- ' %s phase update\n') % phasestr)
+ pushop.repo.ui.status(_('cannot lock source repo, skipping '
+ 'local %s phase update\n') % phasestr)
# get local lock as we might write phase data
locallock = None
try:
- locallock = repo.lock()
+ locallock = pushop.repo.lock()
except IOError, err:
if err.errno != errno.EACCES:
raise
# source repo cannot be locked.
# We do not abort the push, but just disable the local phase
# synchronisation.
msg = 'cannot lock source repository: %s\n' % err
- repo.ui.debug(msg)
+ pushop.repo.ui.debug(msg)
try:
- repo.checkpush(force, revs)
+ pushop.repo.checkpush(force, revs)
lock = None
unbundle = remote.capable('unbundle')
if not unbundle:
lock = remote.lock()
try:
@@ -107,29 +122,29 @@ def push(repo, remote, force=False, revs
raise util.Abort(mso % ctx)
elif ctx.troubled():
raise util.Abort(_(mst)
% (ctx.troubles()[0],
ctx))
- newbm = repo.ui.configlist('bookmarks', 'pushing')
+ newbm = pushop.repo.ui.configlist('bookmarks', 'pushing')
discovery.checkheads(unfi, remote, outgoing,
remoteheads, newbranch,
bool(inc), newbm)
# TODO: get bundlecaps from remote
bundlecaps = None
# create a changegroup from local
if revs is None and not (outgoing.excluded
- or repo.changelog.filteredrevs):
+ or pushop.repo.changelog.filteredrevs):
# push everything,
# use the fast path, no race possible on push
- bundler = changegroup.bundle10(repo, bundlecaps)
- cg = repo._changegroupsubset(outgoing,
- bundler,
- 'push',
- fastpath=True)
+ bundler = changegroup.bundle10(pushop.repo, bundlecaps)
+ cg = pushop.repo._changegroupsubset(outgoing,
+ bundler,
+ 'push',
+ fastpath=True)
else:
- cg = repo.getlocalbundle('push', outgoing, bundlecaps)
+ cg = pushop.repo.getlocalbundle('push', outgoing, bundlecaps)
# apply changegroup to remote
if unbundle:
# local repo finds heads on server, finds out what
# revs it must push. once revs transferred, if server
@@ -141,11 +156,11 @@ def push(repo, remote, force=False, revs
# http: return remote's addchangegroup() or 0 for error
ret = remote.unbundle(cg, remoteheads, 'push')
else:
# we return an integer indicating remote head count
# change
- ret = remote.addchangegroup(cg, 'push', repo.url())
+ ret = remote.addchangegroup(cg, 'push', pushop.repo.url())
if ret:
# push succeed, synchronize target of the push
cheads = outgoing.missingheads
elif revs is None:
@@ -165,21 +180,21 @@ def push(repo, remote, force=False, revs
# missing = ((commonheads::missingheads) - commonheads)
#
# We can pick:
# * missingheads part of common (::commonheads)
common = set(outgoing.common)
- nm = repo.changelog.nodemap
+ nm = pushop.repo.changelog.nodemap
cheads = [node for node in revs if nm[node] in common]
# and
# * commonheads parents on missing
revset = unfi.set('%ln and parents(roots(%ln))',
outgoing.commonheads,
outgoing.missing)
cheads.extend(c.node() for c in revset)
# even when we don't push, exchanging phase data is useful
remotephases = remote.listkeys('phases')
- if (repo.ui.configbool('ui', '_usedassubrepo', False)
+ if (pushop.repo.ui.configbool('ui', '_usedassubrepo', False)
and remotephases # server supports phases
and ret is None # nothing was pushed
and remotephases.get('publishing', False)):
# When:
# - this is a subrepo push
@@ -193,11 +208,12 @@ def push(repo, remote, force=False, revs
remotephases = {'publishing': 'True'}
if not remotephases: # old server or public only repo
localphasemove(cheads)
# don't push any phase data as there is nothing to push
else:
- ana = phases.analyzeremotephases(repo, cheads, remotephases)
+ ana = phases.analyzeremotephases(pushop.repo, cheads,
+ remotephases)
pheads, droots = ana
### Apply remote phase on local
if remotephases.get('publishing', False):
localphasemove(cheads)
else: # publish = False
@@ -214,18 +230,18 @@ def push(repo, remote, force=False, revs
r = remote.pushkey('phases',
newremotehead.hex(),
str(phases.draft),
str(phases.public))
if not r:
- repo.ui.warn(_('updating %s to public failed!\n')
+ pushop.repo.ui.warn(_('updating %s to public failed!\n')
% newremotehead)
- repo.ui.debug('try to push obsolete markers to remote\n')
- obsolete.syncpush(repo, remote)
+ pushop.repo.ui.debug('try to push obsolete markers to remote\n')
+ obsolete.syncpush(pushop.repo, remote)
finally:
if lock is not None:
lock.release()
finally:
if locallock is not None:
locallock.release()
- bookmarks.updateremote(repo.ui, unfi, remote, revs)
+ bookmarks.updateremote(pushop.repo.ui, unfi, remote, revs)
return ret