eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/mercurial/statichttprepo.py
changeset 69 c6bca38c1cbf
equal deleted inserted replaced
68:5ff1fc726848 69:c6bca38c1cbf
       
     1 # statichttprepo.py - simple http repository class for mercurial
       
     2 #
       
     3 # This provides read-only repo access to repositories exported via static http
       
     4 #
       
     5 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
       
     6 #
       
     7 # This software may be used and distributed according to the terms of the
       
     8 # GNU General Public License version 2 or any later version.
       
     9 
       
    10 from i18n import _
       
    11 import changelog, byterange, url, error
       
    12 import localrepo, manifest, util, store
       
    13 import urllib, urllib2, errno
       
    14 
       
    15 class httprangereader(object):
       
    16     def __init__(self, url, opener):
       
    17         # we assume opener has HTTPRangeHandler
       
    18         self.url = url
       
    19         self.pos = 0
       
    20         self.opener = opener
       
    21         self.name = url
       
    22     def seek(self, pos):
       
    23         self.pos = pos
       
    24     def read(self, bytes=None):
       
    25         req = urllib2.Request(self.url)
       
    26         end = ''
       
    27         if bytes:
       
    28             end = self.pos + bytes - 1
       
    29         req.add_header('Range', 'bytes=%d-%s' % (self.pos, end))
       
    30 
       
    31         try:
       
    32             f = self.opener.open(req)
       
    33             data = f.read()
       
    34             if hasattr(f, 'getcode'):
       
    35                 # python 2.6+
       
    36                 code = f.getcode()
       
    37             elif hasattr(f, 'code'):
       
    38                 # undocumented attribute, seems to be set in 2.4 and 2.5
       
    39                 code = f.code
       
    40             else:
       
    41                 # Don't know how to check, hope for the best.
       
    42                 code = 206
       
    43         except urllib2.HTTPError, inst:
       
    44             num = inst.code == 404 and errno.ENOENT or None
       
    45             raise IOError(num, inst)
       
    46         except urllib2.URLError, inst:
       
    47             raise IOError(None, inst.reason[1])
       
    48 
       
    49         if code == 200:
       
    50             # HTTPRangeHandler does nothing if remote does not support
       
    51             # Range headers and returns the full entity. Let's slice it.
       
    52             if bytes:
       
    53                 data = data[self.pos:self.pos + bytes]
       
    54             else:
       
    55                 data = data[self.pos:]
       
    56         elif bytes:
       
    57             data = data[:bytes]
       
    58         self.pos += len(data)
       
    59         return data
       
    60     def __iter__(self):
       
    61         return iter(self.read().splitlines(1))
       
    62     def close(self):
       
    63         pass
       
    64 
       
    65 def build_opener(ui, authinfo):
       
    66     # urllib cannot handle URLs with embedded user or passwd
       
    67     urlopener = url.opener(ui, authinfo)
       
    68     urlopener.add_handler(byterange.HTTPRangeHandler())
       
    69 
       
    70     def opener(base):
       
    71         """return a function that opens files over http"""
       
    72         p = base
       
    73         def o(path, mode="r", atomictemp=None):
       
    74             if 'a' in mode or 'w' in mode:
       
    75                 raise IOError('Permission denied')
       
    76             f = "/".join((p, urllib.quote(path)))
       
    77             return httprangereader(f, urlopener)
       
    78         return o
       
    79 
       
    80     opener.options = {'nonlazy': 1}
       
    81     return opener
       
    82 
       
    83 class statichttprepository(localrepo.localrepository):
       
    84     def __init__(self, ui, path):
       
    85         self._url = path
       
    86         self.ui = ui
       
    87 
       
    88         self.root = path
       
    89         self.path, authinfo = url.getauthinfo(path.rstrip('/') + "/.hg")
       
    90 
       
    91         opener = build_opener(ui, authinfo)
       
    92         self.opener = opener(self.path)
       
    93 
       
    94         # find requirements
       
    95         try:
       
    96             requirements = self.opener("requires").read().splitlines()
       
    97         except IOError, inst:
       
    98             if inst.errno != errno.ENOENT:
       
    99                 raise
       
   100             # check if it is a non-empty old-style repository
       
   101             try:
       
   102                 self.opener("00changelog.i").read(1)
       
   103             except IOError, inst:
       
   104                 if inst.errno != errno.ENOENT:
       
   105                     raise
       
   106                 # we do not care about empty old-style repositories here
       
   107                 msg = _("'%s' does not appear to be an hg repository") % path
       
   108                 raise error.RepoError(msg)
       
   109             requirements = []
       
   110 
       
   111         # check them
       
   112         for r in requirements:
       
   113             if r not in self.supported:
       
   114                 raise error.RepoError(_("requirement '%s' not supported") % r)
       
   115 
       
   116         # setup store
       
   117         def pjoin(a, b):
       
   118             return a + '/' + b
       
   119         self.store = store.store(requirements, self.path, opener, pjoin)
       
   120         self.spath = self.store.path
       
   121         self.sopener = self.store.opener
       
   122         self.sjoin = self.store.join
       
   123 
       
   124         self.manifest = manifest.manifest(self.sopener)
       
   125         self.changelog = changelog.changelog(self.sopener)
       
   126         self._tags = None
       
   127         self.nodetagscache = None
       
   128         self._branchcache = None
       
   129         self._branchcachetip = None
       
   130         self.encodepats = None
       
   131         self.decodepats = None
       
   132         self.capabilities.remove("pushkey")
       
   133 
       
   134     def url(self):
       
   135         return self._url
       
   136 
       
   137     def local(self):
       
   138         return False
       
   139 
       
   140     def lock(self, wait=True):
       
   141         raise util.Abort(_('cannot lock static-http repository'))
       
   142 
       
   143 def instance(ui, path, create):
       
   144     if create:
       
   145         raise util.Abort(_('cannot create new static-http repository'))
       
   146     return statichttprepository(ui, path[7:])