PageRenderTime 46ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/mercurial/statichttprepo.py

https://bitbucket.org/mirror/mercurial/
Python | 164 lines | 125 code | 23 blank | 16 comment | 18 complexity | 18ba4b909addd1920d82038c3dd8de00 MD5 | raw file
Possible License(s): GPL-2.0
  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. from i18n import _
  10. import changelog, byterange, url, error
  11. import localrepo, manifest, util, scmutil, store
  12. import urllib, urllib2, errno, os
  13. class httprangereader(object):
  14. def __init__(self, url, opener):
  15. # we assume opener has HTTPRangeHandler
  16. self.url = url
  17. self.pos = 0
  18. self.opener = opener
  19. self.name = url
  20. def seek(self, pos):
  21. self.pos = pos
  22. def read(self, bytes=None):
  23. req = urllib2.Request(self.url)
  24. end = ''
  25. if bytes:
  26. end = self.pos + bytes - 1
  27. if self.pos or end:
  28. req.add_header('Range', 'bytes=%d-%s' % (self.pos, end))
  29. try:
  30. f = self.opener.open(req)
  31. data = f.read()
  32. # Python 2.6+ defines a getcode() function, and 2.4 and
  33. # 2.5 appear to always have an undocumented code attribute
  34. # set. If we can't read either of those, fall back to 206
  35. # and hope for the best.
  36. code = getattr(f, 'getcode', lambda : getattr(f, 'code', 206))()
  37. except urllib2.HTTPError, inst:
  38. num = inst.code == 404 and errno.ENOENT or None
  39. raise IOError(num, inst)
  40. except urllib2.URLError, inst:
  41. raise IOError(None, inst.reason[1])
  42. if code == 200:
  43. # HTTPRangeHandler does nothing if remote does not support
  44. # Range headers and returns the full entity. Let's slice it.
  45. if bytes:
  46. data = data[self.pos:self.pos + bytes]
  47. else:
  48. data = data[self.pos:]
  49. elif bytes:
  50. data = data[:bytes]
  51. self.pos += len(data)
  52. return data
  53. def readlines(self):
  54. return self.read().splitlines(True)
  55. def __iter__(self):
  56. return iter(self.readlines())
  57. def close(self):
  58. pass
  59. def build_opener(ui, authinfo):
  60. # urllib cannot handle URLs with embedded user or passwd
  61. urlopener = url.opener(ui, authinfo)
  62. urlopener.add_handler(byterange.HTTPRangeHandler())
  63. class statichttpvfs(scmutil.abstractvfs):
  64. def __init__(self, base):
  65. self.base = base
  66. def __call__(self, path, mode="r", atomictemp=None):
  67. if mode not in ('r', 'rb'):
  68. raise IOError('Permission denied')
  69. f = "/".join((self.base, urllib.quote(path)))
  70. return httprangereader(f, urlopener)
  71. def join(self, path):
  72. if path:
  73. return os.path.join(self.base, path)
  74. else:
  75. return self.base
  76. return statichttpvfs
  77. class statichttppeer(localrepo.localpeer):
  78. def local(self):
  79. return None
  80. def canpush(self):
  81. return False
  82. class statichttprepository(localrepo.localrepository):
  83. supported = localrepo.localrepository._basesupported
  84. def __init__(self, ui, path):
  85. self._url = path
  86. self.ui = ui
  87. self.root = path
  88. u = util.url(path.rstrip('/') + "/.hg")
  89. self.path, authinfo = u.authinfo()
  90. opener = build_opener(ui, authinfo)
  91. self.opener = opener(self.path)
  92. self.vfs = self.opener
  93. self._phasedefaults = []
  94. try:
  95. requirements = scmutil.readrequires(self.opener, self.supported)
  96. except IOError, inst:
  97. if inst.errno != errno.ENOENT:
  98. raise
  99. requirements = set()
  100. # check if it is a non-empty old-style repository
  101. try:
  102. fp = self.opener("00changelog.i")
  103. fp.read(1)
  104. fp.close()
  105. except IOError, inst:
  106. if inst.errno != errno.ENOENT:
  107. raise
  108. # we do not care about empty old-style repositories here
  109. msg = _("'%s' does not appear to be an hg repository") % path
  110. raise error.RepoError(msg)
  111. # setup store
  112. self.store = store.store(requirements, self.path, opener)
  113. self.spath = self.store.path
  114. self.sopener = self.store.opener
  115. self.svfs = self.sopener
  116. self.sjoin = self.store.join
  117. self._filecache = {}
  118. self.requirements = requirements
  119. self.manifest = manifest.manifest(self.sopener)
  120. self.changelog = changelog.changelog(self.sopener)
  121. self._tags = None
  122. self.nodetagscache = None
  123. self._branchcaches = {}
  124. self.encodepats = None
  125. self.decodepats = None
  126. def _restrictcapabilities(self, caps):
  127. caps = super(statichttprepository, self)._restrictcapabilities(caps)
  128. return caps.difference(["pushkey"])
  129. def url(self):
  130. return self._url
  131. def local(self):
  132. return False
  133. def peer(self):
  134. return statichttppeer(self)
  135. def lock(self, wait=True):
  136. raise util.Abort(_('cannot lock static-http repository'))
  137. def instance(ui, path, create):
  138. if create:
  139. raise util.Abort(_('cannot create new static-http repository'))
  140. return statichttprepository(ui, path[7:])