hgext/largefiles/remotestore.py
changeset 15168 cfccd3bee7b3
child 15188 8e115063950d
equal deleted inserted replaced
15167:8df4166b6f63 15168:cfccd3bee7b3
       
     1 # Copyright 2010-2011 Fog Creek Software
       
     2 # Copyright 2010-2011 Unity Technologies
       
     3 #
       
     4 # This software may be used and distributed according to the terms of the
       
     5 # GNU General Public License version 2 or any later version.
       
     6 
       
     7 '''Remote largefile store; the base class for servestore'''
       
     8 
       
     9 import urllib2
       
    10 import HTTPError
       
    11 
       
    12 from mercurial import util
       
    13 from mercurial.i18n import _
       
    14 
       
    15 import lfutil
       
    16 import basestore
       
    17 
       
    18 class remotestore(basestore.basestore):
       
    19     """A largefile store accessed over a network"""
       
    20     def __init__(self, ui, repo, url):
       
    21         super(remotestore, self).__init__(ui, repo, url)
       
    22 
       
    23     def put(self, source, hash):
       
    24         if self._verify(hash):
       
    25             return
       
    26         if self.sendfile(source, hash):
       
    27             raise util.Abort(
       
    28                 _('remotestore: could not put %s to remote store %s')
       
    29                 % (source, self.url))
       
    30         self.ui.debug(
       
    31             _('remotestore: put %s to remote store %s') % (source, self.url))
       
    32 
       
    33     def exists(self, hash):
       
    34         return self._verify(hash)
       
    35 
       
    36     def sendfile(self, filename, hash):
       
    37         self.ui.debug('remotestore: sendfile(%s, %s)\n' % (filename, hash))
       
    38         fd = None
       
    39         try:
       
    40             try:
       
    41                 fd = lfutil.httpsendfile(self.ui, filename)
       
    42             except IOError, e:
       
    43                 raise util.Abort(
       
    44                     _('remotestore: could not open file %s: %s')
       
    45                     % (filename, str(e)))
       
    46             return self._put(hash, fd)
       
    47         finally:
       
    48             if fd:
       
    49                 fd.close()
       
    50 
       
    51     def _getfile(self, tmpfile, filename, hash):
       
    52         # quit if the largefile isn't there
       
    53         stat = self._stat(hash)
       
    54         if stat:
       
    55             raise util.Abort(_('remotestore: largefile %s is %s') %
       
    56                              (hash, stat == 1 and 'invalid' or 'missing'))
       
    57 
       
    58         try:
       
    59             length, infile = self._get(hash)
       
    60         except HTTPError, e:
       
    61             # 401s get converted to util.Aborts; everything else is fine being
       
    62             # turned into a StoreError
       
    63             raise basestore.StoreError(filename, hash, self.url, str(e))
       
    64         except urllib2.URLError, e:
       
    65             # This usually indicates a connection problem, so don't
       
    66             # keep trying with the other files... they will probably
       
    67             # all fail too.
       
    68             raise util.Abort('%s: %s' % (self.url, str(e.reason)))
       
    69         except IOError, e:
       
    70             raise basestore.StoreError(filename, hash, self.url, str(e))
       
    71 
       
    72         # Mercurial does not close its SSH connections after writing a stream
       
    73         if length is not None:
       
    74             infile = lfutil.limitreader(infile, length)
       
    75         return lfutil.copyandhash(lfutil.blockstream(infile), tmpfile)
       
    76 
       
    77     def _verify(self, hash):
       
    78         return not self._stat(hash)
       
    79 
       
    80     def _verifyfile(self, cctx, cset, contents, standin, verified):
       
    81         filename = lfutil.splitstandin(standin)
       
    82         if not filename:
       
    83             return False
       
    84         fctx = cctx[standin]
       
    85         key = (filename, fctx.filenode())
       
    86         if key in verified:
       
    87             return False
       
    88 
       
    89         verified.add(key)
       
    90 
       
    91         stat = self._stat(hash)
       
    92         if not stat:
       
    93             return False
       
    94         elif stat == 1:
       
    95             self.ui.warn(
       
    96                 _('changeset %s: %s: contents differ\n')
       
    97                 % (cset, filename))
       
    98             return True # failed
       
    99         elif stat == 2:
       
   100             self.ui.warn(
       
   101                 _('changeset %s: %s missing\n')
       
   102                 % (cset, filename))
       
   103             return True # failed
       
   104         else:
       
   105             raise util.Abort(_('check failed, unexpected response'
       
   106                                'statlfile: %d') % stat)