Mercurial > hg
view hgext/largefiles/remotestore.py @ 23529:38e55e55ae4d
largefiles: rewrite merge code using dictionary with entry per file
In overridecalculateupdates(), we currently only deal with conflicts
that result in a 'g' action for either the largefile or a standin. We
will soon want to deal cases with 'cd' and 'dc' actions here. It will
be easier to reason about such cases if we rewrite it using a dict
from filename to action.
A side-effect of this change is that the output can only have one
action per file (which should be a good change). Before this change,
when one of the tests in test-issue3084 received this input (the 'a'
in the input was a result of 'cd' conflict resolved in favor of the
modified file):
'g': [('.hglf/f', ('',), 'remote created')],
'a': [('f', None, 'prompt keep')],
and the user chose to keep the local largefile, it produced this
output:
'g': [('.hglf/f', ('',), 'remote created')],
'r': [('f', None, 'replaced by standin')],
'a': [('f', None, 'prompt keep')],
Although 'a' actions are processed after 'r' actions by
recordupdates(), it still worked because 'a' actions have no effect on
merges (only on updates). After this change, the output is:
'g': [('.hglf/f', ('',), 'remote created')],
'r': [('f', None, 'replaced by standin')],
Similarly, there are several tests in test-largefiles-update that get
inputs like:
'a': [('.hglf/large2', None, 'prompt keep')],
'g': [('large2', ('',), 'remote created')],
and when the user chooses to keep the local largefile, they produce
this output:
'a': [('.hglf/large2', None, 'prompt keep'),
('.hglf/large2', None, 'keep standin')],
'lfmr': [('large2', None, 'forget non-standin largefile')],
In this case, it was not a merge but an update, so the 'a' action does
have an effect. However, since dirstate.add() is idempotent, it still
has no obserable effect.
After this change, the output is:
'a': [('.hglf/large2', None, 'keep standin')],
'lfmr': [('large2', None, 'forget non-standin largefile')],
author | Martin von Zweigbergk <martinvonz@google.com> |
---|---|
date | Tue, 09 Dec 2014 22:03:53 -0800 |
parents | 70252bdfd39c |
children | bee00e0c2e45 |
line wrap: on
line source
# Copyright 2010-2011 Fog Creek Software # Copyright 2010-2011 Unity Technologies # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. '''remote largefile store; the base class for wirestore''' import urllib2 from mercurial import util, wireproto from mercurial.i18n import _ import lfutil import basestore class remotestore(basestore.basestore): '''a largefile store accessed over a network''' def __init__(self, ui, repo, url): super(remotestore, self).__init__(ui, repo, url) def put(self, source, hash): if self.sendfile(source, hash): raise util.Abort( _('remotestore: could not put %s to remote store %s') % (source, util.hidepassword(self.url))) self.ui.debug( _('remotestore: put %s to remote store %s\n') % (source, util.hidepassword(self.url))) def exists(self, hashes): return dict((h, s == 0) for (h, s) in # dict-from-generator self._stat(hashes).iteritems()) def sendfile(self, filename, hash): self.ui.debug('remotestore: sendfile(%s, %s)\n' % (filename, hash)) fd = None try: try: fd = lfutil.httpsendfile(self.ui, filename) except IOError, e: raise util.Abort( _('remotestore: could not open file %s: %s') % (filename, str(e))) return self._put(hash, fd) finally: if fd: fd.close() def _getfile(self, tmpfile, filename, hash): try: chunks = self._get(hash) except urllib2.HTTPError, e: # 401s get converted to util.Aborts; everything else is fine being # turned into a StoreError raise basestore.StoreError(filename, hash, self.url, str(e)) except urllib2.URLError, e: # This usually indicates a connection problem, so don't # keep trying with the other files... they will probably # all fail too. raise util.Abort('%s: %s' % (util.hidepassword(self.url), e.reason)) except IOError, e: raise basestore.StoreError(filename, hash, self.url, str(e)) return lfutil.copyandhash(chunks, tmpfile) def _verifyfile(self, cctx, cset, contents, standin, verified): filename = lfutil.splitstandin(standin) if not filename: return False fctx = cctx[standin] key = (filename, fctx.filenode()) if key in verified: return False verified.add(key) expecthash = fctx.data()[0:40] stat = self._stat([expecthash])[expecthash] if not stat: return False elif stat == 1: self.ui.warn( _('changeset %s: %s: contents differ\n') % (cset, filename)) return True # failed elif stat == 2: self.ui.warn( _('changeset %s: %s missing\n') % (cset, filename)) return True # failed else: raise RuntimeError('verify failed: unexpected response from ' 'statlfile (%r)' % stat) def batch(self): '''Support for remote batching.''' return wireproto.remotebatch(self)