Compare commits

..

6 Commits

Author SHA1 Message Date
ceea368e88 Correctly name projects when mirroring
A bug introduced by relative urls caused projects such as manifest.git
to be placed in the root directory instead of the directory they should
by in.

This fix creates and refers to a resolvedFetchUrl in the _XmlRemote
class in order to get a fetchUrl that is never relative.
2011-10-20 11:01:38 -07:00
b660539c4a Fix sync on Python 2.6.6
Python 2.6.6 has the same bug as Python 2.7, where HTTP
authentication just stops working, but does not have the
setter method to clear the retry counter. Work around by
setting the field directly if it exists.

Change-Id: I6a742e606bb7750dc66c33fc7c5d1310541db2c8
Signed-off-by: Shawn O. Pearce <sop@google.com>
2011-10-11 15:58:07 -07:00
752371d91b help: Fix help sync
help sync crashed as sync required the manifest to be configured to
create the option parser, as the default number of jobs is required.

Change-Id: Ie75e8d75ac0e38313e4aab451cbb24430e84def5
Signed-off-by: Shawn O. Pearce <sop@google.com>
2011-10-11 15:23:41 -07:00
1a68dc58eb upload: Honor REPO_HOST_PORT_INFO environment variable
REPO_HOST_PORT_INFO can be set to 'host:port' and be used
instead of the review URL given in the manifest.

Change-Id: I440bdecb2c2249fe5285ec5d0c28a937b4053450
Signed-off-by: Shawn O. Pearce <sop@google.com>
2011-10-11 14:12:46 -07:00
df5ee52050 Fix Python 2.4 support
Change-Id: I89521ae52fa564f0d849cc51e71fee65b3c47bab
Signed-off-by: Shawn O. Pearce <sop@google.com>
2011-10-11 14:06:11 -07:00
fab96c68e3 Work around Python 2.7 urllib2 bug
If the remote is using authenticated HTTP, but does not have
$GIT_URL/clone.bundle files in each repository, an initial sync
would fail around 8 projects in due to the library not resetting
the number of failures after getting a 404.

Work around this by updating the retry counter ourselves.

The urllib2 library is also not thread-safe. Make it somewhat
safer by wrapping the critical section with a lock.

Change-Id: I886e2750ef4793cbe2150c3b5396eb9f10974f7f
Signed-off-by: Shawn O. Pearce <sop@google.com>
2011-10-11 12:18:07 -07:00
6 changed files with 91 additions and 46 deletions

View File

@ -575,6 +575,16 @@ class Remote(object):
self._review_protocol = info[0] self._review_protocol = info[0]
self._review_host = info[1] self._review_host = info[1]
self._review_port = info[2] self._review_port = info[2]
elif 'REPO_HOST_PORT_INFO' in os.environ:
info = os.environ['REPO_HOST_PORT_INFO']
self._review_protocol = 'ssh'
self._review_host = info.split(" ")[0]
self._review_port = info.split(" ")[1]
REVIEW_CACHE[u] = (
self._review_protocol,
self._review_host,
self._review_port)
else: else:
try: try:
info = urllib2.urlopen(u).read() info = urllib2.urlopen(u).read()

20
main.py
View File

@ -273,6 +273,24 @@ class _UserAgentHandler(urllib2.BaseHandler):
req.add_header('User-Agent', _UserAgent()) req.add_header('User-Agent', _UserAgent())
return req return req
class _BasicAuthHandler(urllib2.HTTPBasicAuthHandler):
def http_error_auth_reqed(self, authreq, host, req, headers):
try:
old_add_header = req.add_header
def _add_header(name, val):
val = val.replace('\n', '')
old_add_header(name, val)
req.add_header = _add_header
return urllib2.AbstractBasicAuthHandler.http_error_auth_reqed(
self, authreq, host, req, headers)
except:
reset = getattr(self, 'reset_retry_count', None)
if reset is not None:
reset()
elif getattr(self, 'retried', None):
self.retried = 0
raise
def init_http(): def init_http():
handlers = [_UserAgentHandler()] handlers = [_UserAgentHandler()]
@ -287,7 +305,7 @@ def init_http():
pass pass
except IOError: except IOError:
pass pass
handlers.append(urllib2.HTTPBasicAuthHandler(mgr)) handlers.append(_BasicAuthHandler(mgr))
if 'http_proxy' in os.environ: if 'http_proxy' in os.environ:
url = os.environ['http_proxy'] url = os.environ['http_proxy']

View File

@ -46,16 +46,20 @@ class _XmlRemote(object):
self.fetchUrl = fetch self.fetchUrl = fetch
self.manifestUrl = manifestUrl self.manifestUrl = manifestUrl
self.reviewUrl = review self.reviewUrl = review
self.resolvedFetchUrl = self._resolveFetchUrl()
def ToRemoteSpec(self, projectName): def _resolveFetchUrl(self):
url = self.fetchUrl.rstrip('/') + '/' + projectName + '.git' url = self.fetchUrl.rstrip('/')
manifestUrl = self.manifestUrl.rstrip('/') manifestUrl = self.manifestUrl.rstrip('/')
# urljoin will get confused if there is no scheme in the base url # urljoin will get confused if there is no scheme in the base url
# ie, if manifestUrl is of the form <hostname:port> # ie, if manifestUrl is of the form <hostname:port>
if manifestUrl.find(':') != manifestUrl.find('/') - 1: if manifestUrl.find(':') != manifestUrl.find('/') - 1:
manifestUrl = 'gopher://' + manifestUrl manifestUrl = 'gopher://' + manifestUrl
url = urlparse.urljoin(manifestUrl, url) url = urlparse.urljoin(manifestUrl, url)
url = re.sub(r'^gopher://', '', url) return re.sub(r'^gopher://', '', url)
def ToRemoteSpec(self, projectName):
url = self.resolvedFetchUrl + '/' + projectName
return RemoteSpec(self.name, url, self.reviewUrl) return RemoteSpec(self.name, url, self.reviewUrl)
class XmlManifest(object): class XmlManifest(object):
@ -368,7 +372,7 @@ class XmlManifest(object):
raise ManifestParseError, 'refusing to mirror %s' % m_url raise ManifestParseError, 'refusing to mirror %s' % m_url
if self._default and self._default.remote: if self._default and self._default.remote:
url = self._default.remote.fetchUrl url = self._default.remote.resolvedFetchUrl
if not url.endswith('/'): if not url.endswith('/'):
url += '/' url += '/'
if m_url.startswith(url): if m_url.startswith(url):

View File

@ -24,6 +24,16 @@ import sys
import time import time
import urllib2 import urllib2
try:
import threading as _threading
except ImportError:
import dummy_threading as _threading
try:
from os import SEEK_END
except ImportError:
SEEK_END = 2
from color import Coloring from color import Coloring
from git_command import GitCommand from git_command import GitCommand
from git_config import GitConfig, IsId, GetSchemeFromUrl from git_config import GitConfig, IsId, GetSchemeFromUrl
@ -34,6 +44,8 @@ from progress import Progress
from git_refs import GitRefs, HEAD, R_HEADS, R_TAGS, R_PUB, R_M from git_refs import GitRefs, HEAD, R_HEADS, R_TAGS, R_PUB, R_M
_urllib_lock = _threading.Lock()
def _lwrite(path, content): def _lwrite(path, content):
lock = '%s.lock' % path lock = '%s.lock' % path
@ -1455,43 +1467,47 @@ class Project(object):
done = False done = False
dest = open(tmpPath, 'a+b') dest = open(tmpPath, 'a+b')
try: try:
dest.seek(0, os.SEEK_END) dest.seek(0, SEEK_END)
pos = dest.tell() pos = dest.tell()
req = urllib2.Request(srcUrl) _urllib_lock.acquire()
if pos > 0:
req.add_header('Range', 'bytes=%d-' % pos)
try: try:
r = urllib2.urlopen(req) req = urllib2.Request(srcUrl)
except urllib2.HTTPError, e: if pos > 0:
def _content_type(): req.add_header('Range', 'bytes=%d-' % pos)
try:
return e.info()['content-type']
except:
return None
if e.code == 404: try:
keep = False r = urllib2.urlopen(req)
return False except urllib2.HTTPError, e:
elif _content_type() == 'text/plain': def _content_type():
try: try:
msg = e.read() return e.info()['content-type']
if len(msg) > 0 and msg[-1] == '\n': except:
msg = msg[0:-1] return None
msg = ' (%s)' % msg
except: if e.code == 404:
msg = '' keep = False
else: return False
try: elif _content_type() == 'text/plain':
from BaseHTTPServer import BaseHTTPRequestHandler try:
res = BaseHTTPRequestHandler.responses[e.code] msg = e.read()
msg = ' (%s: %s)' % (res[0], res[1]) if len(msg) > 0 and msg[-1] == '\n':
except: msg = msg[0:-1]
msg = '' msg = ' (%s)' % msg
raise DownloadError('HTTP %s%s' % (e.code, msg)) except:
except urllib2.URLError, e: msg = ''
raise DownloadError('%s: %s ' % (req.get_host(), str(e))) else:
try:
from BaseHTTPServer import BaseHTTPRequestHandler
res = BaseHTTPRequestHandler.responses[e.code]
msg = ' (%s: %s)' % (res[0], res[1])
except:
msg = ''
raise DownloadError('HTTP %s%s' % (e.code, msg))
except urllib2.URLError, e:
raise DownloadError('%s: %s ' % (req.get_host(), str(e)))
finally:
_urllib_lock.release()
p = None p = None
try: try:

View File

@ -165,6 +165,7 @@ See 'repo help --all' for a complete list of recognized commands.
print >>sys.stderr, "repo: '%s' is not a repo command." % name print >>sys.stderr, "repo: '%s' is not a repo command." % name
sys.exit(1) sys.exit(1)
cmd.manifest = self.manifest
self._PrintCommandHelp(cmd) self._PrintCommandHelp(cmd)
else: else:

View File

@ -195,15 +195,11 @@ later is required to fix a server side protocol bug.
fetched.add(project.gitdir) fetched.add(project.gitdir)
pm.update() pm.update()
except BaseException, e: except _FetchError:
# Notify the _Fetch() function about all errors.
err_event.set() err_event.set()
except:
# If we got our own _FetchError, we don't want a stack trace. err_event.set()
# However, if we got something else (something in Sync_NetworkHalf?), raise
# we'd like one (so re-raise after we've set err_event).
if not isinstance(e, _FetchError):
raise
finally: finally:
if did_lock: if did_lock:
lock.release() lock.release()