mirror of
https://gerrit.googlesource.com/git-repo
synced 2025-06-30 20:17:08 +00:00
Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
cc14fa9820 | |||
3ce2a6b46b | |||
841be34968 | |||
ee1c2f5717 | |||
6a1f737380 | |||
e9311273dd | |||
605a9a487b | |||
2a32f6afa6 | |||
498fe90b45 | |||
53d6f4d17e | |||
9d8f914fe8 | |||
ceea368e88 | |||
b660539c4a | |||
752371d91b | |||
1a68dc58eb | |||
df5ee52050 | |||
fab96c68e3 | |||
bf1fbb20ab | |||
29472463ba | |||
c325dc35f6 | |||
f322b9abb4 | |||
db728cd866 | |||
c4657969eb | |||
7b947de1ee |
9
error.py
9
error.py
@ -57,6 +57,15 @@ class UploadError(Exception):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.reason
|
return self.reason
|
||||||
|
|
||||||
|
class DownloadError(Exception):
|
||||||
|
"""Cannot download a repository.
|
||||||
|
"""
|
||||||
|
def __init__(self, reason):
|
||||||
|
self.reason = reason
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.reason
|
||||||
|
|
||||||
class NoSuchProjectError(Exception):
|
class NoSuchProjectError(Exception):
|
||||||
"""A specified project does not exist in the work tree.
|
"""A specified project does not exist in the work tree.
|
||||||
"""
|
"""
|
||||||
|
@ -221,26 +221,10 @@ class GitCommand(object):
|
|||||||
self.stdin = p.stdin
|
self.stdin = p.stdin
|
||||||
|
|
||||||
def Wait(self):
|
def Wait(self):
|
||||||
p = self.process
|
|
||||||
|
|
||||||
if p.stdin:
|
|
||||||
p.stdin.close()
|
|
||||||
self.stdin = None
|
|
||||||
|
|
||||||
if p.stdout:
|
|
||||||
self.stdout = p.stdout.read()
|
|
||||||
p.stdout.close()
|
|
||||||
else:
|
|
||||||
p.stdout = None
|
|
||||||
|
|
||||||
if p.stderr:
|
|
||||||
self.stderr = p.stderr.read()
|
|
||||||
p.stderr.close()
|
|
||||||
else:
|
|
||||||
p.stderr = None
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
rc = p.wait()
|
p = self.process
|
||||||
|
(self.stdout, self.stderr) = p.communicate()
|
||||||
|
rc = p.returncode
|
||||||
finally:
|
finally:
|
||||||
_remove_ssh_client(p)
|
_remove_ssh_client(p)
|
||||||
return rc
|
return rc
|
||||||
|
@ -26,7 +26,6 @@ import time
|
|||||||
import urllib2
|
import urllib2
|
||||||
|
|
||||||
from signal import SIGTERM
|
from signal import SIGTERM
|
||||||
from urllib2 import urlopen, HTTPError
|
|
||||||
from error import GitError, UploadError
|
from error import GitError, UploadError
|
||||||
from trace import Trace
|
from trace import Trace
|
||||||
|
|
||||||
@ -491,6 +490,12 @@ def close_ssh():
|
|||||||
URI_SCP = re.compile(r'^([^@:]*@?[^:/]{1,}):')
|
URI_SCP = re.compile(r'^([^@:]*@?[^:/]{1,}):')
|
||||||
URI_ALL = re.compile(r'^([a-z][a-z+]*)://([^@/]*@?[^/]*)/')
|
URI_ALL = re.compile(r'^([a-z][a-z+]*)://([^@/]*@?[^/]*)/')
|
||||||
|
|
||||||
|
def GetSchemeFromUrl(url):
|
||||||
|
m = URI_ALL.match(url)
|
||||||
|
if m:
|
||||||
|
return m.group(1)
|
||||||
|
return None
|
||||||
|
|
||||||
def _preconnect(url):
|
def _preconnect(url):
|
||||||
m = URI_ALL.match(url)
|
m = URI_ALL.match(url)
|
||||||
if m:
|
if m:
|
||||||
@ -570,9 +575,19 @@ 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 = urlopen(u).read()
|
info = urllib2.urlopen(u).read()
|
||||||
if info == 'NOT_AVAILABLE':
|
if info == 'NOT_AVAILABLE':
|
||||||
raise UploadError('%s: SSH disabled' % self.review)
|
raise UploadError('%s: SSH disabled' % self.review)
|
||||||
if '<' in info:
|
if '<' in info:
|
||||||
@ -584,15 +599,15 @@ class Remote(object):
|
|||||||
self._review_protocol = 'ssh'
|
self._review_protocol = 'ssh'
|
||||||
self._review_host = info.split(" ")[0]
|
self._review_host = info.split(" ")[0]
|
||||||
self._review_port = info.split(" ")[1]
|
self._review_port = info.split(" ")[1]
|
||||||
except urllib2.URLError, e:
|
except urllib2.HTTPError, e:
|
||||||
raise UploadError('%s: %s' % (self.review, e.reason[1]))
|
|
||||||
except HTTPError, e:
|
|
||||||
if e.code == 404:
|
if e.code == 404:
|
||||||
self._review_protocol = 'http-post'
|
self._review_protocol = 'http-post'
|
||||||
self._review_host = None
|
self._review_host = None
|
||||||
self._review_port = None
|
self._review_port = None
|
||||||
else:
|
else:
|
||||||
raise UploadError('Upload over ssh unavailable')
|
raise UploadError('Upload over SSH unavailable')
|
||||||
|
except urllib2.URLError, e:
|
||||||
|
raise UploadError('%s: %s' % (self.review, str(e)))
|
||||||
|
|
||||||
REVIEW_CACHE[u] = (
|
REVIEW_CACHE[u] = (
|
||||||
self._review_protocol,
|
self._review_protocol,
|
||||||
|
12
git_refs.py
12
git_refs.py
@ -139,13 +139,15 @@ class GitRefs(object):
|
|||||||
def _ReadLoose1(self, path, name):
|
def _ReadLoose1(self, path, name):
|
||||||
try:
|
try:
|
||||||
fd = open(path, 'rb')
|
fd = open(path, 'rb')
|
||||||
mtime = os.path.getmtime(path)
|
except:
|
||||||
except OSError:
|
|
||||||
return
|
|
||||||
except IOError:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
id = fd.readline()
|
try:
|
||||||
|
mtime = os.path.getmtime(path)
|
||||||
|
id = fd.readline()
|
||||||
|
except:
|
||||||
|
return
|
||||||
finally:
|
finally:
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
|
51
main.py
51
main.py
@ -37,6 +37,7 @@ from command import InteractiveCommand
|
|||||||
from command import MirrorSafeCommand
|
from command import MirrorSafeCommand
|
||||||
from command import PagedCommand
|
from command import PagedCommand
|
||||||
from editor import Editor
|
from editor import Editor
|
||||||
|
from error import DownloadError
|
||||||
from error import ManifestInvalidRevisionError
|
from error import ManifestInvalidRevisionError
|
||||||
from error import NoSuchProjectError
|
from error import NoSuchProjectError
|
||||||
from error import RepoChangedException
|
from error import RepoChangedException
|
||||||
@ -72,6 +73,7 @@ class _Repo(object):
|
|||||||
all_commands['branch'] = all_commands['branches']
|
all_commands['branch'] = all_commands['branches']
|
||||||
|
|
||||||
def _Run(self, argv):
|
def _Run(self, argv):
|
||||||
|
result = 0
|
||||||
name = None
|
name = None
|
||||||
glob = []
|
glob = []
|
||||||
|
|
||||||
@ -95,7 +97,7 @@ class _Repo(object):
|
|||||||
name = 'version'
|
name = 'version'
|
||||||
else:
|
else:
|
||||||
print >>sys.stderr, 'fatal: invalid usage of --version'
|
print >>sys.stderr, 'fatal: invalid usage of --version'
|
||||||
sys.exit(1)
|
return 1
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cmd = self.commands[name]
|
cmd = self.commands[name]
|
||||||
@ -103,7 +105,7 @@ class _Repo(object):
|
|||||||
print >>sys.stderr,\
|
print >>sys.stderr,\
|
||||||
"repo: '%s' is not a repo command. See 'repo help'."\
|
"repo: '%s' is not a repo command. See 'repo help'."\
|
||||||
% name
|
% name
|
||||||
sys.exit(1)
|
return 1
|
||||||
|
|
||||||
cmd.repodir = self.repodir
|
cmd.repodir = self.repodir
|
||||||
cmd.manifest = XmlManifest(cmd.repodir)
|
cmd.manifest = XmlManifest(cmd.repodir)
|
||||||
@ -113,7 +115,7 @@ class _Repo(object):
|
|||||||
print >>sys.stderr, \
|
print >>sys.stderr, \
|
||||||
"fatal: '%s' requires a working directory"\
|
"fatal: '%s' requires a working directory"\
|
||||||
% name
|
% name
|
||||||
sys.exit(1)
|
return 1
|
||||||
|
|
||||||
copts, cargs = cmd.OptionParser.parse_args(argv)
|
copts, cargs = cmd.OptionParser.parse_args(argv)
|
||||||
|
|
||||||
@ -131,7 +133,7 @@ class _Repo(object):
|
|||||||
try:
|
try:
|
||||||
start = time.time()
|
start = time.time()
|
||||||
try:
|
try:
|
||||||
cmd.Execute(copts, cargs)
|
result = cmd.Execute(copts, cargs)
|
||||||
finally:
|
finally:
|
||||||
elapsed = time.time() - start
|
elapsed = time.time() - start
|
||||||
hours, remainder = divmod(elapsed, 3600)
|
hours, remainder = divmod(elapsed, 3600)
|
||||||
@ -143,15 +145,20 @@ class _Repo(object):
|
|||||||
else:
|
else:
|
||||||
print >>sys.stderr, 'real\t%dh%dm%.3fs' \
|
print >>sys.stderr, 'real\t%dh%dm%.3fs' \
|
||||||
% (hours, minutes, seconds)
|
% (hours, minutes, seconds)
|
||||||
|
except DownloadError, e:
|
||||||
|
print >>sys.stderr, 'error: %s' % str(e)
|
||||||
|
return 1
|
||||||
except ManifestInvalidRevisionError, e:
|
except ManifestInvalidRevisionError, e:
|
||||||
print >>sys.stderr, 'error: %s' % str(e)
|
print >>sys.stderr, 'error: %s' % str(e)
|
||||||
sys.exit(1)
|
return 1
|
||||||
except NoSuchProjectError, e:
|
except NoSuchProjectError, e:
|
||||||
if e.name:
|
if e.name:
|
||||||
print >>sys.stderr, 'error: project %s not found' % e.name
|
print >>sys.stderr, 'error: project %s not found' % e.name
|
||||||
else:
|
else:
|
||||||
print >>sys.stderr, 'error: no project in current directory'
|
print >>sys.stderr, 'error: no project in current directory'
|
||||||
sys.exit(1)
|
return 1
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
def _MyRepoPath():
|
def _MyRepoPath():
|
||||||
return os.path.dirname(__file__)
|
return os.path.dirname(__file__)
|
||||||
@ -269,6 +276,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()]
|
||||||
|
|
||||||
@ -281,7 +306,9 @@ def init_http():
|
|||||||
mgr.add_password(None, 'https://%s/' % host, p[0], p[2])
|
mgr.add_password(None, 'https://%s/' % host, p[0], p[2])
|
||||||
except netrc.NetrcParseError:
|
except netrc.NetrcParseError:
|
||||||
pass
|
pass
|
||||||
handlers.append(urllib2.HTTPBasicAuthHandler(mgr))
|
except IOError:
|
||||||
|
pass
|
||||||
|
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']
|
||||||
@ -292,6 +319,8 @@ def init_http():
|
|||||||
urllib2.install_opener(urllib2.build_opener(*handlers))
|
urllib2.install_opener(urllib2.build_opener(*handlers))
|
||||||
|
|
||||||
def _Main(argv):
|
def _Main(argv):
|
||||||
|
result = 0
|
||||||
|
|
||||||
opt = optparse.OptionParser(usage="repo wrapperinfo -- ...")
|
opt = optparse.OptionParser(usage="repo wrapperinfo -- ...")
|
||||||
opt.add_option("--repo-dir", dest="repodir",
|
opt.add_option("--repo-dir", dest="repodir",
|
||||||
help="path to .repo/")
|
help="path to .repo/")
|
||||||
@ -310,11 +339,11 @@ def _Main(argv):
|
|||||||
try:
|
try:
|
||||||
init_ssh()
|
init_ssh()
|
||||||
init_http()
|
init_http()
|
||||||
repo._Run(argv)
|
result = repo._Run(argv) or 0
|
||||||
finally:
|
finally:
|
||||||
close_ssh()
|
close_ssh()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
sys.exit(1)
|
result = 1
|
||||||
except RepoChangedException, rce:
|
except RepoChangedException, rce:
|
||||||
# If repo changed, re-exec ourselves.
|
# If repo changed, re-exec ourselves.
|
||||||
#
|
#
|
||||||
@ -325,7 +354,9 @@ def _Main(argv):
|
|||||||
except OSError, e:
|
except OSError, e:
|
||||||
print >>sys.stderr, 'fatal: cannot restart repo after upgrade'
|
print >>sys.stderr, 'fatal: cannot restart repo after upgrade'
|
||||||
print >>sys.stderr, 'fatal: %s' % e
|
print >>sys.stderr, 'fatal: %s' % e
|
||||||
sys.exit(128)
|
result = 128
|
||||||
|
|
||||||
|
sys.exit(result)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
_Main(sys.argv[1:])
|
_Main(sys.argv[1:])
|
||||||
|
@ -14,7 +14,9 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import urlparse
|
||||||
import xml.dom.minidom
|
import xml.dom.minidom
|
||||||
|
|
||||||
from git_config import GitConfig, IsId
|
from git_config import GitConfig, IsId
|
||||||
@ -24,6 +26,9 @@ from error import ManifestParseError
|
|||||||
MANIFEST_FILE_NAME = 'manifest.xml'
|
MANIFEST_FILE_NAME = 'manifest.xml'
|
||||||
LOCAL_MANIFEST_NAME = 'local_manifest.xml'
|
LOCAL_MANIFEST_NAME = 'local_manifest.xml'
|
||||||
|
|
||||||
|
urlparse.uses_relative.extend(['ssh', 'git'])
|
||||||
|
urlparse.uses_netloc.extend(['ssh', 'git'])
|
||||||
|
|
||||||
class _Default(object):
|
class _Default(object):
|
||||||
"""Project defaults within the manifest."""
|
"""Project defaults within the manifest."""
|
||||||
|
|
||||||
@ -35,16 +40,26 @@ class _XmlRemote(object):
|
|||||||
def __init__(self,
|
def __init__(self,
|
||||||
name,
|
name,
|
||||||
fetch=None,
|
fetch=None,
|
||||||
|
manifestUrl=None,
|
||||||
review=None):
|
review=None):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.fetchUrl = fetch
|
self.fetchUrl = fetch
|
||||||
|
self.manifestUrl = manifestUrl
|
||||||
self.reviewUrl = review
|
self.reviewUrl = review
|
||||||
|
self.resolvedFetchUrl = self._resolveFetchUrl()
|
||||||
|
|
||||||
|
def _resolveFetchUrl(self):
|
||||||
|
url = self.fetchUrl.rstrip('/')
|
||||||
|
manifestUrl = self.manifestUrl.rstrip('/')
|
||||||
|
# urljoin will get confused if there is no scheme in the base url
|
||||||
|
# ie, if manifestUrl is of the form <hostname:port>
|
||||||
|
if manifestUrl.find(':') != manifestUrl.find('/') - 1:
|
||||||
|
manifestUrl = 'gopher://' + manifestUrl
|
||||||
|
url = urlparse.urljoin(manifestUrl, url)
|
||||||
|
return re.sub(r'^gopher://', '', url)
|
||||||
|
|
||||||
def ToRemoteSpec(self, projectName):
|
def ToRemoteSpec(self, projectName):
|
||||||
url = self.fetchUrl
|
url = self.resolvedFetchUrl.rstrip('/') + '/' + projectName
|
||||||
while url.endswith('/'):
|
|
||||||
url = url[:-1]
|
|
||||||
url += '/%s.git' % projectName
|
|
||||||
return RemoteSpec(self.name, url, self.reviewUrl)
|
return RemoteSpec(self.name, url, self.reviewUrl)
|
||||||
|
|
||||||
class XmlManifest(object):
|
class XmlManifest(object):
|
||||||
@ -213,7 +228,11 @@ class XmlManifest(object):
|
|||||||
@property
|
@property
|
||||||
def manifest_server(self):
|
def manifest_server(self):
|
||||||
self._Load()
|
self._Load()
|
||||||
return self._manifest_server
|
|
||||||
|
if self._manifest_server:
|
||||||
|
return self._manifest_server
|
||||||
|
|
||||||
|
return self.manifestProject.config.GetString('repo.manifest-server')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def IsMirror(self):
|
def IsMirror(self):
|
||||||
@ -357,7 +376,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):
|
||||||
@ -366,7 +385,8 @@ class XmlManifest(object):
|
|||||||
|
|
||||||
if name is None:
|
if name is None:
|
||||||
s = m_url.rindex('/') + 1
|
s = m_url.rindex('/') + 1
|
||||||
remote = _XmlRemote('origin', m_url[:s])
|
manifestUrl = self.manifestProject.config.GetString('remote.origin.url')
|
||||||
|
remote = _XmlRemote('origin', m_url[:s], manifestUrl)
|
||||||
name = m_url[s:]
|
name = m_url[s:]
|
||||||
|
|
||||||
if name.endswith('.git'):
|
if name.endswith('.git'):
|
||||||
@ -394,7 +414,8 @@ class XmlManifest(object):
|
|||||||
review = node.getAttribute('review')
|
review = node.getAttribute('review')
|
||||||
if review == '':
|
if review == '':
|
||||||
review = None
|
review = None
|
||||||
return _XmlRemote(name, fetch, review)
|
manifestUrl = self.manifestProject.config.GetString('remote.origin.url')
|
||||||
|
return _XmlRemote(name, fetch, manifestUrl, review)
|
||||||
|
|
||||||
def _ParseDefault(self, node):
|
def _ParseDefault(self, node):
|
||||||
"""
|
"""
|
||||||
|
274
project.py
274
project.py
@ -16,20 +16,36 @@ import traceback
|
|||||||
import errno
|
import errno
|
||||||
import filecmp
|
import filecmp
|
||||||
import os
|
import os
|
||||||
|
import random
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import stat
|
import stat
|
||||||
import sys
|
import sys
|
||||||
|
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
|
from git_config import GitConfig, IsId, GetSchemeFromUrl, ID_RE
|
||||||
|
from error import DownloadError
|
||||||
from error import GitError, HookError, ImportError, UploadError
|
from error import GitError, HookError, ImportError, UploadError
|
||||||
from error import ManifestInvalidRevisionError
|
from error import ManifestInvalidRevisionError
|
||||||
|
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
|
||||||
|
|
||||||
@ -884,32 +900,35 @@ class Project(object):
|
|||||||
|
|
||||||
## Sync ##
|
## Sync ##
|
||||||
|
|
||||||
def Sync_NetworkHalf(self, quiet=False):
|
def Sync_NetworkHalf(self, quiet=False, is_new=None, current_branch_only=False):
|
||||||
"""Perform only the network IO portion of the sync process.
|
"""Perform only the network IO portion of the sync process.
|
||||||
Local working directory/branch state is not affected.
|
Local working directory/branch state is not affected.
|
||||||
"""
|
"""
|
||||||
is_new = not self.Exists
|
if is_new is None:
|
||||||
|
is_new = not self.Exists
|
||||||
if is_new:
|
if is_new:
|
||||||
if not quiet:
|
|
||||||
print >>sys.stderr
|
|
||||||
print >>sys.stderr, 'Initializing project %s ...' % self.name
|
|
||||||
self._InitGitDir()
|
self._InitGitDir()
|
||||||
|
|
||||||
self._InitRemote()
|
self._InitRemote()
|
||||||
if not self._RemoteFetch(initial=is_new, quiet=quiet):
|
|
||||||
return False
|
|
||||||
|
|
||||||
#Check that the requested ref was found after fetch
|
if is_new:
|
||||||
#
|
alt = os.path.join(self.gitdir, 'objects/info/alternates')
|
||||||
try:
|
try:
|
||||||
self.GetRevisionId()
|
fd = open(alt, 'rb')
|
||||||
except ManifestInvalidRevisionError:
|
try:
|
||||||
# if the ref is a tag. We can try fetching
|
alt_dir = fd.readline().rstrip()
|
||||||
# the tag manually as a last resort
|
finally:
|
||||||
#
|
fd.close()
|
||||||
rev = self.revisionExpr
|
except IOError:
|
||||||
if rev.startswith(R_TAGS):
|
alt_dir = None
|
||||||
self._RemoteFetch(None, rev[len(R_TAGS):], quiet=quiet)
|
else:
|
||||||
|
alt_dir = None
|
||||||
|
|
||||||
|
if alt_dir is None and self._ApplyCloneBundle(initial=is_new, quiet=quiet):
|
||||||
|
is_new = False
|
||||||
|
|
||||||
|
if not self._RemoteFetch(initial=is_new, quiet=quiet, alt_dir=alt_dir,
|
||||||
|
current_branch_only=current_branch_only):
|
||||||
|
return False
|
||||||
|
|
||||||
if self.worktree:
|
if self.worktree:
|
||||||
self._InitMRef()
|
self._InitMRef()
|
||||||
@ -997,7 +1016,7 @@ class Project(object):
|
|||||||
|
|
||||||
if not branch.LocalMerge:
|
if not branch.LocalMerge:
|
||||||
# The current branch has no tracking configuration.
|
# The current branch has no tracking configuration.
|
||||||
# Jump off it to a deatched HEAD.
|
# Jump off it to a detached HEAD.
|
||||||
#
|
#
|
||||||
syncbuf.info(self,
|
syncbuf.info(self,
|
||||||
"leaving %s; does not track upstream",
|
"leaving %s; does not track upstream",
|
||||||
@ -1305,31 +1324,41 @@ class Project(object):
|
|||||||
|
|
||||||
## Direct Git Commands ##
|
## Direct Git Commands ##
|
||||||
|
|
||||||
def _RemoteFetch(self, name=None, tag=None,
|
def _RemoteFetch(self, name=None,
|
||||||
|
current_branch_only=False,
|
||||||
initial=False,
|
initial=False,
|
||||||
quiet=False):
|
quiet=False,
|
||||||
|
alt_dir=None):
|
||||||
|
|
||||||
|
is_sha1 = False
|
||||||
|
tag_name = None
|
||||||
|
|
||||||
|
if current_branch_only:
|
||||||
|
if ID_RE.match(self.revisionExpr) is not None:
|
||||||
|
is_sha1 = True
|
||||||
|
elif self.revisionExpr.startswith(R_TAGS):
|
||||||
|
# this is a tag and its sha1 value should never change
|
||||||
|
tag_name = self.revisionExpr[len(R_TAGS):]
|
||||||
|
|
||||||
|
if is_sha1 or tag_name is not None:
|
||||||
|
try:
|
||||||
|
self.GetRevisionId()
|
||||||
|
return True
|
||||||
|
except ManifestInvalidRevisionError:
|
||||||
|
# There is no such persistent revision. We have to fetch it.
|
||||||
|
pass
|
||||||
|
|
||||||
if not name:
|
if not name:
|
||||||
name = self.remote.name
|
name = self.remote.name
|
||||||
|
|
||||||
ssh_proxy = False
|
ssh_proxy = False
|
||||||
if self.GetRemote(name).PreConnectFetch():
|
remote = self.GetRemote(name)
|
||||||
|
if remote.PreConnectFetch():
|
||||||
ssh_proxy = True
|
ssh_proxy = True
|
||||||
|
|
||||||
if initial:
|
if initial:
|
||||||
alt = os.path.join(self.gitdir, 'objects/info/alternates')
|
if alt_dir and 'objects' == os.path.basename(alt_dir):
|
||||||
try:
|
ref_dir = os.path.dirname(alt_dir)
|
||||||
fd = open(alt, 'rb')
|
|
||||||
try:
|
|
||||||
ref_dir = fd.readline()
|
|
||||||
if ref_dir and ref_dir.endswith('\n'):
|
|
||||||
ref_dir = ref_dir[:-1]
|
|
||||||
finally:
|
|
||||||
fd.close()
|
|
||||||
except IOError, e:
|
|
||||||
ref_dir = None
|
|
||||||
|
|
||||||
if ref_dir and 'objects' == os.path.basename(ref_dir):
|
|
||||||
ref_dir = os.path.dirname(ref_dir)
|
|
||||||
packed_refs = os.path.join(self.gitdir, 'packed-refs')
|
packed_refs = os.path.join(self.gitdir, 'packed-refs')
|
||||||
remote = self.GetRemote(name)
|
remote = self.GetRemote(name)
|
||||||
|
|
||||||
@ -1365,9 +1394,8 @@ class Project(object):
|
|||||||
old_packed += line
|
old_packed += line
|
||||||
|
|
||||||
_lwrite(packed_refs, tmp_packed)
|
_lwrite(packed_refs, tmp_packed)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
ref_dir = None
|
alt_dir = None
|
||||||
|
|
||||||
cmd = ['fetch']
|
cmd = ['fetch']
|
||||||
|
|
||||||
@ -1382,25 +1410,173 @@ class Project(object):
|
|||||||
if not self.worktree:
|
if not self.worktree:
|
||||||
cmd.append('--update-head-ok')
|
cmd.append('--update-head-ok')
|
||||||
cmd.append(name)
|
cmd.append(name)
|
||||||
if tag is not None:
|
|
||||||
cmd.append('tag')
|
|
||||||
cmd.append(tag)
|
|
||||||
|
|
||||||
ok = GitCommand(self,
|
if not current_branch_only or is_sha1:
|
||||||
cmd,
|
# Fetch whole repo
|
||||||
bare = True,
|
cmd.append('--tags')
|
||||||
ssh_proxy = ssh_proxy).Wait() == 0
|
cmd.append((u'+refs/heads/*:') + remote.ToLocal('refs/heads/*'))
|
||||||
|
elif tag_name is not None:
|
||||||
|
cmd.append('tag')
|
||||||
|
cmd.append(tag_name)
|
||||||
|
else:
|
||||||
|
branch = self.revisionExpr
|
||||||
|
if branch.startswith(R_HEADS):
|
||||||
|
branch = branch[len(R_HEADS):]
|
||||||
|
cmd.append((u'+refs/heads/%s:' % branch) + remote.ToLocal('refs/heads/%s' % branch))
|
||||||
|
|
||||||
|
ok = False
|
||||||
|
for i in range(2):
|
||||||
|
if GitCommand(self, cmd, bare=True, ssh_proxy=ssh_proxy).Wait() == 0:
|
||||||
|
ok = True
|
||||||
|
break
|
||||||
|
time.sleep(random.randint(30, 45))
|
||||||
|
|
||||||
if initial:
|
if initial:
|
||||||
if ref_dir:
|
if alt_dir:
|
||||||
if old_packed != '':
|
if old_packed != '':
|
||||||
_lwrite(packed_refs, old_packed)
|
_lwrite(packed_refs, old_packed)
|
||||||
else:
|
else:
|
||||||
os.remove(packed_refs)
|
os.remove(packed_refs)
|
||||||
self.bare_git.pack_refs('--all', '--prune')
|
self.bare_git.pack_refs('--all', '--prune')
|
||||||
|
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
|
def _ApplyCloneBundle(self, initial=False, quiet=False):
|
||||||
|
if initial and self.manifest.manifestProject.config.GetString('repo.depth'):
|
||||||
|
return False
|
||||||
|
|
||||||
|
remote = self.GetRemote(self.remote.name)
|
||||||
|
bundle_url = remote.url + '/clone.bundle'
|
||||||
|
bundle_url = GitConfig.ForUser().UrlInsteadOf(bundle_url)
|
||||||
|
if GetSchemeFromUrl(bundle_url) not in ('http', 'https'):
|
||||||
|
return False
|
||||||
|
|
||||||
|
bundle_dst = os.path.join(self.gitdir, 'clone.bundle')
|
||||||
|
bundle_tmp = os.path.join(self.gitdir, 'clone.bundle.tmp')
|
||||||
|
|
||||||
|
exist_dst = os.path.exists(bundle_dst)
|
||||||
|
exist_tmp = os.path.exists(bundle_tmp)
|
||||||
|
|
||||||
|
if not initial and not exist_dst and not exist_tmp:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not exist_dst:
|
||||||
|
exist_dst = self._FetchBundle(bundle_url, bundle_tmp, bundle_dst, quiet)
|
||||||
|
if not exist_dst:
|
||||||
|
return False
|
||||||
|
|
||||||
|
cmd = ['fetch']
|
||||||
|
if quiet:
|
||||||
|
cmd.append('--quiet')
|
||||||
|
if not self.worktree:
|
||||||
|
cmd.append('--update-head-ok')
|
||||||
|
cmd.append(bundle_dst)
|
||||||
|
for f in remote.fetch:
|
||||||
|
cmd.append(str(f))
|
||||||
|
cmd.append('refs/tags/*:refs/tags/*')
|
||||||
|
|
||||||
|
ok = GitCommand(self, cmd, bare=True).Wait() == 0
|
||||||
|
if os.path.exists(bundle_dst):
|
||||||
|
os.remove(bundle_dst)
|
||||||
|
if os.path.exists(bundle_tmp):
|
||||||
|
os.remove(bundle_tmp)
|
||||||
|
return ok
|
||||||
|
|
||||||
|
def _FetchBundle(self, srcUrl, tmpPath, dstPath, quiet):
|
||||||
|
keep = True
|
||||||
|
done = False
|
||||||
|
dest = open(tmpPath, 'a+b')
|
||||||
|
try:
|
||||||
|
dest.seek(0, SEEK_END)
|
||||||
|
pos = dest.tell()
|
||||||
|
|
||||||
|
_urllib_lock.acquire()
|
||||||
|
try:
|
||||||
|
req = urllib2.Request(srcUrl)
|
||||||
|
if pos > 0:
|
||||||
|
req.add_header('Range', 'bytes=%d-' % pos)
|
||||||
|
|
||||||
|
try:
|
||||||
|
r = urllib2.urlopen(req)
|
||||||
|
except urllib2.HTTPError, e:
|
||||||
|
def _content_type():
|
||||||
|
try:
|
||||||
|
return e.info()['content-type']
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if e.code == 404:
|
||||||
|
keep = False
|
||||||
|
return False
|
||||||
|
elif _content_type() == 'text/plain':
|
||||||
|
try:
|
||||||
|
msg = e.read()
|
||||||
|
if len(msg) > 0 and msg[-1] == '\n':
|
||||||
|
msg = msg[0:-1]
|
||||||
|
msg = ' (%s)' % msg
|
||||||
|
except:
|
||||||
|
msg = ''
|
||||||
|
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
|
||||||
|
try:
|
||||||
|
size = r.headers['content-length']
|
||||||
|
unit = 1 << 10
|
||||||
|
|
||||||
|
if size and not quiet:
|
||||||
|
if size > 1024 * 1.3:
|
||||||
|
unit = 1 << 20
|
||||||
|
desc = 'MB'
|
||||||
|
else:
|
||||||
|
desc = 'KB'
|
||||||
|
p = Progress(
|
||||||
|
'Downloading %s' % self.relpath,
|
||||||
|
int(size) / unit,
|
||||||
|
units=desc)
|
||||||
|
if pos > 0:
|
||||||
|
p.update(pos / unit)
|
||||||
|
|
||||||
|
s = 0
|
||||||
|
while True:
|
||||||
|
d = r.read(8192)
|
||||||
|
if d == '':
|
||||||
|
done = True
|
||||||
|
return True
|
||||||
|
dest.write(d)
|
||||||
|
if p:
|
||||||
|
s += len(d)
|
||||||
|
if s >= unit:
|
||||||
|
p.update(s / unit)
|
||||||
|
s = s % unit
|
||||||
|
if p:
|
||||||
|
if s >= unit:
|
||||||
|
p.update(s / unit)
|
||||||
|
else:
|
||||||
|
p.update(1)
|
||||||
|
finally:
|
||||||
|
r.close()
|
||||||
|
if p:
|
||||||
|
p.end()
|
||||||
|
finally:
|
||||||
|
dest.close()
|
||||||
|
|
||||||
|
if os.path.exists(dstPath):
|
||||||
|
os.remove(dstPath)
|
||||||
|
if done:
|
||||||
|
os.rename(tmpPath, dstPath)
|
||||||
|
elif not keep:
|
||||||
|
os.remove(tmpPath)
|
||||||
|
|
||||||
def _Checkout(self, rev, quiet=False):
|
def _Checkout(self, rev, quiet=False):
|
||||||
cmd = ['checkout']
|
cmd = ['checkout']
|
||||||
if quiet:
|
if quiet:
|
||||||
|
110
repo
110
repo
@ -28,7 +28,7 @@ if __name__ == '__main__':
|
|||||||
del magic
|
del magic
|
||||||
|
|
||||||
# increment this whenever we make important changes to this script
|
# increment this whenever we make important changes to this script
|
||||||
VERSION = (1, 12)
|
VERSION = (1, 14)
|
||||||
|
|
||||||
# increment this if the MAINTAINER_KEYS block is modified
|
# increment this if the MAINTAINER_KEYS block is modified
|
||||||
KEYRING_VERSION = (1,0)
|
KEYRING_VERSION = (1,0)
|
||||||
@ -91,6 +91,7 @@ import re
|
|||||||
import readline
|
import readline
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import urllib2
|
||||||
|
|
||||||
home_dot_repo = os.path.expanduser('~/.repoconfig')
|
home_dot_repo = os.path.expanduser('~/.repoconfig')
|
||||||
gpg_dir = os.path.join(home_dot_repo, 'gnupg')
|
gpg_dir = os.path.join(home_dot_repo, 'gnupg')
|
||||||
@ -138,6 +139,11 @@ group.add_option('--no-repo-verify',
|
|||||||
dest='no_repo_verify', action='store_true',
|
dest='no_repo_verify', action='store_true',
|
||||||
help='do not verify repo source code')
|
help='do not verify repo source code')
|
||||||
|
|
||||||
|
# Other
|
||||||
|
group = init_optparse.add_option_group('Other options')
|
||||||
|
group.add_option('--config-name',
|
||||||
|
dest='config_name', action="store_true", default=False,
|
||||||
|
help='Always prompt for name/e-mail')
|
||||||
|
|
||||||
class CloneFailure(Exception):
|
class CloneFailure(Exception):
|
||||||
"""Indicate the remote clone of repo itself failed.
|
"""Indicate the remote clone of repo itself failed.
|
||||||
@ -148,7 +154,7 @@ def _Init(args):
|
|||||||
"""Installs repo by cloning it over the network.
|
"""Installs repo by cloning it over the network.
|
||||||
"""
|
"""
|
||||||
opt, args = init_optparse.parse_args(args)
|
opt, args = init_optparse.parse_args(args)
|
||||||
if args or not opt.manifest_url:
|
if args:
|
||||||
init_optparse.print_usage()
|
init_optparse.print_usage()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
@ -187,10 +193,6 @@ def _Init(args):
|
|||||||
else:
|
else:
|
||||||
can_verify = True
|
can_verify = True
|
||||||
|
|
||||||
if not opt.quiet:
|
|
||||||
print >>sys.stderr, 'Getting repo ...'
|
|
||||||
print >>sys.stderr, ' from %s' % url
|
|
||||||
|
|
||||||
dst = os.path.abspath(os.path.join(repodir, S_repo))
|
dst = os.path.abspath(os.path.join(repodir, S_repo))
|
||||||
_Clone(url, dst, opt.quiet)
|
_Clone(url, dst, opt.quiet)
|
||||||
|
|
||||||
@ -300,15 +302,42 @@ def _SetConfig(local, name, value):
|
|||||||
raise CloneFailure()
|
raise CloneFailure()
|
||||||
|
|
||||||
|
|
||||||
def _Fetch(local, quiet, *args):
|
def _InitHttp():
|
||||||
|
handlers = []
|
||||||
|
|
||||||
|
mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
|
||||||
|
try:
|
||||||
|
import netrc
|
||||||
|
n = netrc.netrc()
|
||||||
|
for host in n.hosts:
|
||||||
|
p = n.hosts[host]
|
||||||
|
mgr.add_password(None, 'http://%s/' % host, p[0], p[2])
|
||||||
|
mgr.add_password(None, 'https://%s/' % host, p[0], p[2])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
handlers.append(urllib2.HTTPBasicAuthHandler(mgr))
|
||||||
|
|
||||||
|
if 'http_proxy' in os.environ:
|
||||||
|
url = os.environ['http_proxy']
|
||||||
|
handlers.append(urllib2.ProxyHandler({'http': url, 'https': url}))
|
||||||
|
if 'REPO_CURL_VERBOSE' in os.environ:
|
||||||
|
handlers.append(urllib2.HTTPHandler(debuglevel=1))
|
||||||
|
handlers.append(urllib2.HTTPSHandler(debuglevel=1))
|
||||||
|
urllib2.install_opener(urllib2.build_opener(*handlers))
|
||||||
|
|
||||||
|
def _Fetch(url, local, src, quiet):
|
||||||
|
if not quiet:
|
||||||
|
print >>sys.stderr, 'Get %s' % url
|
||||||
|
|
||||||
cmd = [GIT, 'fetch']
|
cmd = [GIT, 'fetch']
|
||||||
if quiet:
|
if quiet:
|
||||||
cmd.append('--quiet')
|
cmd.append('--quiet')
|
||||||
err = subprocess.PIPE
|
err = subprocess.PIPE
|
||||||
else:
|
else:
|
||||||
err = None
|
err = None
|
||||||
cmd.extend(args)
|
cmd.append(src)
|
||||||
cmd.append('origin')
|
cmd.append('+refs/heads/*:refs/remotes/origin/*')
|
||||||
|
cmd.append('refs/tags/*:refs/tags/*')
|
||||||
|
|
||||||
proc = subprocess.Popen(cmd, cwd = local, stderr = err)
|
proc = subprocess.Popen(cmd, cwd = local, stderr = err)
|
||||||
if err:
|
if err:
|
||||||
@ -317,6 +346,62 @@ def _Fetch(local, quiet, *args):
|
|||||||
if proc.wait() != 0:
|
if proc.wait() != 0:
|
||||||
raise CloneFailure()
|
raise CloneFailure()
|
||||||
|
|
||||||
|
def _DownloadBundle(url, local, quiet):
|
||||||
|
if not url.endswith('/'):
|
||||||
|
url += '/'
|
||||||
|
url += 'clone.bundle'
|
||||||
|
|
||||||
|
proc = subprocess.Popen(
|
||||||
|
[GIT, 'config', '--get-regexp', 'url.*.insteadof'],
|
||||||
|
cwd = local,
|
||||||
|
stdout = subprocess.PIPE)
|
||||||
|
for line in proc.stdout:
|
||||||
|
m = re.compile(r'^url\.(.*)\.insteadof (.*)$').match(line)
|
||||||
|
if m:
|
||||||
|
new_url = m.group(1)
|
||||||
|
old_url = m.group(2)
|
||||||
|
if url.startswith(old_url):
|
||||||
|
url = new_url + url[len(old_url):]
|
||||||
|
break
|
||||||
|
proc.stdout.close()
|
||||||
|
proc.wait()
|
||||||
|
|
||||||
|
if not url.startswith('http:') and not url.startswith('https:'):
|
||||||
|
return False
|
||||||
|
|
||||||
|
dest = open(os.path.join(local, '.git', 'clone.bundle'), 'w+b')
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
r = urllib2.urlopen(url)
|
||||||
|
except urllib2.HTTPError, e:
|
||||||
|
if e.code == 404:
|
||||||
|
return False
|
||||||
|
print >>sys.stderr, 'fatal: Cannot get %s' % url
|
||||||
|
print >>sys.stderr, 'fatal: HTTP error %s' % e.code
|
||||||
|
raise CloneFailure()
|
||||||
|
except urllib2.URLError, e:
|
||||||
|
print >>sys.stderr, 'fatal: Cannot get %s' % url
|
||||||
|
print >>sys.stderr, 'fatal: error %s' % e.reason
|
||||||
|
raise CloneFailure()
|
||||||
|
try:
|
||||||
|
if not quiet:
|
||||||
|
print >>sys.stderr, 'Get %s' % url
|
||||||
|
while True:
|
||||||
|
buf = r.read(8192)
|
||||||
|
if buf == '':
|
||||||
|
return True
|
||||||
|
dest.write(buf)
|
||||||
|
finally:
|
||||||
|
r.close()
|
||||||
|
finally:
|
||||||
|
dest.close()
|
||||||
|
|
||||||
|
def _ImportBundle(local):
|
||||||
|
path = os.path.join(local, '.git', 'clone.bundle')
|
||||||
|
try:
|
||||||
|
_Fetch(local, local, path, True)
|
||||||
|
finally:
|
||||||
|
os.remove(path)
|
||||||
|
|
||||||
def _Clone(url, local, quiet):
|
def _Clone(url, local, quiet):
|
||||||
"""Clones a git repository to a new subdirectory of repodir
|
"""Clones a git repository to a new subdirectory of repodir
|
||||||
@ -344,11 +429,14 @@ def _Clone(url, local, quiet):
|
|||||||
print >>sys.stderr, 'fatal: could not create %s' % local
|
print >>sys.stderr, 'fatal: could not create %s' % local
|
||||||
raise CloneFailure()
|
raise CloneFailure()
|
||||||
|
|
||||||
|
_InitHttp()
|
||||||
_SetConfig(local, 'remote.origin.url', url)
|
_SetConfig(local, 'remote.origin.url', url)
|
||||||
_SetConfig(local, 'remote.origin.fetch',
|
_SetConfig(local, 'remote.origin.fetch',
|
||||||
'+refs/heads/*:refs/remotes/origin/*')
|
'+refs/heads/*:refs/remotes/origin/*')
|
||||||
_Fetch(local, quiet)
|
if _DownloadBundle(url, local, quiet):
|
||||||
_Fetch(local, quiet, '--tags')
|
_ImportBundle(local)
|
||||||
|
else:
|
||||||
|
_Fetch(url, local, 'origin', quiet)
|
||||||
|
|
||||||
|
|
||||||
def _Verify(cwd, branch, quiet):
|
def _Verify(cwd, branch, quiet):
|
||||||
|
@ -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:
|
||||||
|
@ -21,7 +21,9 @@ from color import Coloring
|
|||||||
from command import InteractiveCommand, MirrorSafeCommand
|
from command import InteractiveCommand, MirrorSafeCommand
|
||||||
from error import ManifestParseError
|
from error import ManifestParseError
|
||||||
from project import SyncBuffer
|
from project import SyncBuffer
|
||||||
|
from git_config import GitConfig
|
||||||
from git_command import git_require, MIN_GIT_VERSION
|
from git_command import git_require, MIN_GIT_VERSION
|
||||||
|
from git_config import GitConfig
|
||||||
|
|
||||||
class Init(InteractiveCommand, MirrorSafeCommand):
|
class Init(InteractiveCommand, MirrorSafeCommand):
|
||||||
common = True
|
common = True
|
||||||
@ -35,6 +37,20 @@ The latest repo source code and manifest collection is downloaded
|
|||||||
from the server and is installed in the .repo/ directory in the
|
from the server and is installed in the .repo/ directory in the
|
||||||
current working directory.
|
current working directory.
|
||||||
|
|
||||||
|
The optional -u argument can be used to specify a URL to the
|
||||||
|
manifest project. It is also possible to have a git configuration
|
||||||
|
section as below to use 'identifier' as argument to -u:
|
||||||
|
|
||||||
|
[repo-manifest "identifier"]
|
||||||
|
url = ...
|
||||||
|
server = ...
|
||||||
|
reference = ...
|
||||||
|
|
||||||
|
Only the url is required - the others are optional.
|
||||||
|
|
||||||
|
If no -u argument is specified, the 'repo-manifest' section named
|
||||||
|
'default' will be used if present.
|
||||||
|
|
||||||
The optional -b argument can be used to select the manifest branch
|
The optional -b argument can be used to select the manifest branch
|
||||||
to checkout and use. If no branch is specified, master is assumed.
|
to checkout and use. If no branch is specified, master is assumed.
|
||||||
|
|
||||||
@ -68,7 +84,7 @@ to update the working directory files.
|
|||||||
# Manifest
|
# Manifest
|
||||||
g = p.add_option_group('Manifest options')
|
g = p.add_option_group('Manifest options')
|
||||||
g.add_option('-u', '--manifest-url',
|
g.add_option('-u', '--manifest-url',
|
||||||
dest='manifest_url',
|
dest='manifest_url', default='default',
|
||||||
help='manifest repository location', metavar='URL')
|
help='manifest repository location', metavar='URL')
|
||||||
g.add_option('-b', '--manifest-branch',
|
g.add_option('-b', '--manifest-branch',
|
||||||
dest='manifest_branch',
|
dest='manifest_branch',
|
||||||
@ -98,18 +114,39 @@ to update the working directory files.
|
|||||||
dest='no_repo_verify', action='store_true',
|
dest='no_repo_verify', action='store_true',
|
||||||
help='do not verify repo source code')
|
help='do not verify repo source code')
|
||||||
|
|
||||||
|
# Other
|
||||||
|
g = p.add_option_group('Other options')
|
||||||
|
g.add_option('--config-name',
|
||||||
|
dest='config_name', action="store_true", default=False,
|
||||||
|
help='Always prompt for name/e-mail')
|
||||||
|
|
||||||
def _SyncManifest(self, opt):
|
def _SyncManifest(self, opt):
|
||||||
m = self.manifest.manifestProject
|
m = self.manifest.manifestProject
|
||||||
is_new = not m.Exists
|
is_new = not m.Exists
|
||||||
|
manifest_server = None
|
||||||
|
|
||||||
|
# The manifest url may point out a manifest section in the config
|
||||||
|
key = 'repo-manifest.%s.' % opt.manifest_url
|
||||||
|
if GitConfig.ForUser().GetString(key + 'url'):
|
||||||
|
opt.manifest_url = GitConfig.ForUser().GetString(key + 'url')
|
||||||
|
|
||||||
|
# Also copy other options to the manifest config if not specified already.
|
||||||
|
if not opt.reference:
|
||||||
|
opt.reference = GitConfig.ForUser().GetString(key + 'reference')
|
||||||
|
manifest_server = GitConfig.ForUser().GetString(key + 'server')
|
||||||
|
|
||||||
if is_new:
|
if is_new:
|
||||||
if not opt.manifest_url:
|
if not opt.manifest_url or opt.manifest_url == 'default':
|
||||||
print >>sys.stderr, 'fatal: manifest url (-u) is required.'
|
print >>sys.stderr, """\
|
||||||
|
fatal: missing manifest url (-u) and no default found.
|
||||||
|
|
||||||
|
tip: The global git configuration key 'repo-manifest.default.url' can
|
||||||
|
be used to specify a default url."""
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if not opt.quiet:
|
if not opt.quiet:
|
||||||
print >>sys.stderr, 'Getting manifest ...'
|
print >>sys.stderr, 'Get %s' \
|
||||||
print >>sys.stderr, ' from %s' % opt.manifest_url
|
% GitConfig.ForUser().UrlInsteadOf(opt.manifest_url)
|
||||||
m._InitGitDir()
|
m._InitGitDir()
|
||||||
|
|
||||||
if opt.manifest_branch:
|
if opt.manifest_branch:
|
||||||
@ -128,6 +165,9 @@ to update the working directory files.
|
|||||||
r.ResetFetch()
|
r.ResetFetch()
|
||||||
r.Save()
|
r.Save()
|
||||||
|
|
||||||
|
if manifest_server:
|
||||||
|
m.config.SetString('repo.manifest-server', manifest_server)
|
||||||
|
|
||||||
if opt.reference:
|
if opt.reference:
|
||||||
m.config.SetString('repo.reference', opt.reference)
|
m.config.SetString('repo.reference', opt.reference)
|
||||||
|
|
||||||
@ -138,7 +178,7 @@ to update the working directory files.
|
|||||||
print >>sys.stderr, 'fatal: --mirror not supported on existing client'
|
print >>sys.stderr, 'fatal: --mirror not supported on existing client'
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if not m.Sync_NetworkHalf():
|
if not m.Sync_NetworkHalf(is_new=is_new):
|
||||||
r = m.GetRemote(m.remote.name)
|
r = m.GetRemote(m.remote.name)
|
||||||
print >>sys.stderr, 'fatal: cannot obtain manifest %s' % r.url
|
print >>sys.stderr, 'fatal: cannot obtain manifest %s' % r.url
|
||||||
|
|
||||||
@ -178,6 +218,24 @@ to update the working directory files.
|
|||||||
return value
|
return value
|
||||||
return a
|
return a
|
||||||
|
|
||||||
|
def _ShouldConfigureUser(self):
|
||||||
|
gc = self.manifest.globalConfig
|
||||||
|
mp = self.manifest.manifestProject
|
||||||
|
|
||||||
|
# If we don't have local settings, get from global.
|
||||||
|
if not mp.config.Has('user.name') or not mp.config.Has('user.email'):
|
||||||
|
if not gc.Has('user.name') or not gc.Has('user.email'):
|
||||||
|
return True
|
||||||
|
|
||||||
|
mp.config.SetString('user.name', gc.GetString('user.name'))
|
||||||
|
mp.config.SetString('user.email', gc.GetString('user.email'))
|
||||||
|
|
||||||
|
print ''
|
||||||
|
print 'Your identity is: %s <%s>' % (mp.config.GetString('user.name'),
|
||||||
|
mp.config.GetString('user.email'))
|
||||||
|
print 'If you want to change this, please re-run \'repo init\' with --config-name'
|
||||||
|
return False
|
||||||
|
|
||||||
def _ConfigureUser(self):
|
def _ConfigureUser(self):
|
||||||
mp = self.manifest.manifestProject
|
mp = self.manifest.manifestProject
|
||||||
|
|
||||||
@ -188,7 +246,7 @@ to update the working directory files.
|
|||||||
|
|
||||||
print ''
|
print ''
|
||||||
print 'Your identity is: %s <%s>' % (name, email)
|
print 'Your identity is: %s <%s>' % (name, email)
|
||||||
sys.stdout.write('is this correct [y/n]? ')
|
sys.stdout.write('is this correct [y/N]? ')
|
||||||
a = sys.stdin.readline().strip()
|
a = sys.stdin.readline().strip()
|
||||||
if a in ('yes', 'y', 't', 'true'):
|
if a in ('yes', 'y', 't', 'true'):
|
||||||
break
|
break
|
||||||
@ -230,7 +288,7 @@ to update the working directory files.
|
|||||||
out.printer(fg='black', attr=c)(' %-6s ', c)
|
out.printer(fg='black', attr=c)(' %-6s ', c)
|
||||||
out.nl()
|
out.nl()
|
||||||
|
|
||||||
sys.stdout.write('Enable color display in this user account (y/n)? ')
|
sys.stdout.write('Enable color display in this user account (y/N)? ')
|
||||||
a = sys.stdin.readline().strip().lower()
|
a = sys.stdin.readline().strip().lower()
|
||||||
if a in ('y', 'yes', 't', 'true', 'on'):
|
if a in ('y', 'yes', 't', 'true', 'on'):
|
||||||
gc.SetString('color.ui', 'auto')
|
gc.SetString('color.ui', 'auto')
|
||||||
@ -260,7 +318,8 @@ to update the working directory files.
|
|||||||
self._LinkManifest(opt.manifest_name)
|
self._LinkManifest(opt.manifest_name)
|
||||||
|
|
||||||
if os.isatty(0) and os.isatty(1) and not self.manifest.IsMirror:
|
if os.isatty(0) and os.isatty(1) and not self.manifest.IsMirror:
|
||||||
self._ConfigureUser()
|
if opt.config_name or self._ShouldConfigureUser():
|
||||||
|
self._ConfigureUser()
|
||||||
self._ConfigureColor()
|
self._ConfigureColor()
|
||||||
|
|
||||||
self._ConfigureDepth(opt)
|
self._ConfigureDepth(opt)
|
||||||
|
@ -131,12 +131,14 @@ later is required to fix a server side protocol bug.
|
|||||||
p.add_option('-d','--detach',
|
p.add_option('-d','--detach',
|
||||||
dest='detach_head', action='store_true',
|
dest='detach_head', action='store_true',
|
||||||
help='detach projects back to manifest revision')
|
help='detach projects back to manifest revision')
|
||||||
|
p.add_option('-c','--current-branch',
|
||||||
|
dest='current_branch_only', action='store_true',
|
||||||
|
help='fetch only current branch from server')
|
||||||
p.add_option('-q','--quiet',
|
p.add_option('-q','--quiet',
|
||||||
dest='quiet', action='store_true',
|
dest='quiet', action='store_true',
|
||||||
help='be more quiet')
|
help='be more quiet')
|
||||||
p.add_option('-j','--jobs',
|
p.add_option('-j','--jobs',
|
||||||
dest='jobs', action='store', type='int',
|
dest='jobs', action='store', type='int',
|
||||||
default=self.jobs,
|
|
||||||
help="projects to fetch simultaneously (default %d)" % self.jobs)
|
help="projects to fetch simultaneously (default %d)" % self.jobs)
|
||||||
if show_smart:
|
if show_smart:
|
||||||
p.add_option('-s', '--smart-sync',
|
p.add_option('-s', '--smart-sync',
|
||||||
@ -180,7 +182,8 @@ later is required to fix a server side protocol bug.
|
|||||||
# - We always make sure we unlock the lock if we locked it.
|
# - We always make sure we unlock the lock if we locked it.
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
success = project.Sync_NetworkHalf(quiet=opt.quiet)
|
success = project.Sync_NetworkHalf(quiet=opt.quiet,
|
||||||
|
current_branch_only=opt.current_branch_only)
|
||||||
|
|
||||||
# Lock around all the rest of the code, since printing, updating a set
|
# Lock around all the rest of the code, since printing, updating a set
|
||||||
# and Progress.update() are not thread safe.
|
# and Progress.update() are not thread safe.
|
||||||
@ -196,15 +199,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()
|
||||||
@ -217,7 +216,8 @@ later is required to fix a server side protocol bug.
|
|||||||
if self.jobs == 1:
|
if self.jobs == 1:
|
||||||
for project in projects:
|
for project in projects:
|
||||||
pm.update()
|
pm.update()
|
||||||
if project.Sync_NetworkHalf(quiet=opt.quiet):
|
if project.Sync_NetworkHalf(quiet=opt.quiet,
|
||||||
|
current_branch_only=opt.current_branch_only):
|
||||||
fetched.add(project.gitdir)
|
fetched.add(project.gitdir)
|
||||||
else:
|
else:
|
||||||
print >>sys.stderr, 'error: Cannot fetch %s' % project.name
|
print >>sys.stderr, 'error: Cannot fetch %s' % project.name
|
||||||
@ -393,7 +393,8 @@ uncommitted changes are present' % project.relpath
|
|||||||
_PostRepoUpgrade(self.manifest)
|
_PostRepoUpgrade(self.manifest)
|
||||||
|
|
||||||
if not opt.local_only:
|
if not opt.local_only:
|
||||||
mp.Sync_NetworkHalf(quiet=opt.quiet)
|
mp.Sync_NetworkHalf(quiet=opt.quiet,
|
||||||
|
current_branch_only=opt.current_branch_only)
|
||||||
|
|
||||||
if mp.HasChanges:
|
if mp.HasChanges:
|
||||||
syncbuf = SyncBuffer(mp.config)
|
syncbuf = SyncBuffer(mp.config)
|
||||||
@ -401,6 +402,8 @@ uncommitted changes are present' % project.relpath
|
|||||||
if not syncbuf.Finish():
|
if not syncbuf.Finish():
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
self.manifest._Unload()
|
self.manifest._Unload()
|
||||||
|
if opt.jobs is None:
|
||||||
|
self.jobs = self.manifest.default.sync_j
|
||||||
all = self.GetProjects(args, missing_ok=True)
|
all = self.GetProjects(args, missing_ok=True)
|
||||||
|
|
||||||
if not opt.local_only:
|
if not opt.local_only:
|
||||||
|
@ -73,7 +73,7 @@ Configuration
|
|||||||
|
|
||||||
review.URL.autoupload:
|
review.URL.autoupload:
|
||||||
|
|
||||||
To disable the "Upload ... (y/n)?" prompt, you can set a per-project
|
To disable the "Upload ... (y/N)?" prompt, you can set a per-project
|
||||||
or global Git configuration option. If review.URL.autoupload is set
|
or global Git configuration option. If review.URL.autoupload is set
|
||||||
to "true" then repo will assume you always answer "y" at the prompt,
|
to "true" then repo will assume you always answer "y" at the prompt,
|
||||||
and will not prompt you further. If it is set to "false" then repo
|
and will not prompt you further. If it is set to "false" then repo
|
||||||
@ -162,7 +162,7 @@ Gerrit Code Review: http://code.google.com/p/gerrit/
|
|||||||
date = branch.date
|
date = branch.date
|
||||||
list = branch.commits
|
list = branch.commits
|
||||||
|
|
||||||
print 'Upload project %s/:' % project.relpath
|
print 'Upload project %s/ to remote branch %s:' % (project.relpath, project.revisionExpr)
|
||||||
print ' branch %s (%2d commit%s, %s):' % (
|
print ' branch %s (%2d commit%s, %s):' % (
|
||||||
name,
|
name,
|
||||||
len(list),
|
len(list),
|
||||||
@ -171,7 +171,7 @@ Gerrit Code Review: http://code.google.com/p/gerrit/
|
|||||||
for commit in list:
|
for commit in list:
|
||||||
print ' %s' % commit
|
print ' %s' % commit
|
||||||
|
|
||||||
sys.stdout.write('to %s (y/n)? ' % remote.review)
|
sys.stdout.write('to %s (y/N)? ' % remote.review)
|
||||||
answer = sys.stdin.readline().strip()
|
answer = sys.stdin.readline().strip()
|
||||||
answer = answer in ('y', 'Y', 'yes', '1', 'true', 't')
|
answer = answer in ('y', 'Y', 'yes', '1', 'true', 't')
|
||||||
|
|
||||||
@ -202,11 +202,12 @@ Gerrit Code Review: http://code.google.com/p/gerrit/
|
|||||||
|
|
||||||
if b:
|
if b:
|
||||||
script.append('#')
|
script.append('#')
|
||||||
script.append('# branch %s (%2d commit%s, %s):' % (
|
script.append('# branch %s (%2d commit%s, %s) to remote branch %s:' % (
|
||||||
name,
|
name,
|
||||||
len(list),
|
len(list),
|
||||||
len(list) != 1 and 's' or '',
|
len(list) != 1 and 's' or '',
|
||||||
date))
|
date,
|
||||||
|
project.revisionExpr))
|
||||||
for commit in list:
|
for commit in list:
|
||||||
script.append('# %s' % commit)
|
script.append('# %s' % commit)
|
||||||
b[name] = branch
|
b[name] = branch
|
||||||
@ -215,6 +216,11 @@ Gerrit Code Review: http://code.google.com/p/gerrit/
|
|||||||
branches[project.name] = b
|
branches[project.name] = b
|
||||||
script.append('')
|
script.append('')
|
||||||
|
|
||||||
|
script = [ x.encode('utf-8')
|
||||||
|
if issubclass(type(x), unicode)
|
||||||
|
else x
|
||||||
|
for x in script ]
|
||||||
|
|
||||||
script = Editor.EditString("\n".join(script)).split("\n")
|
script = Editor.EditString("\n".join(script)).split("\n")
|
||||||
|
|
||||||
project_re = re.compile(r'^#?\s*project\s*([^\s]+)/:$')
|
project_re = re.compile(r'^#?\s*project\s*([^\s]+)/:$')
|
||||||
@ -294,7 +300,7 @@ Gerrit Code Review: http://code.google.com/p/gerrit/
|
|||||||
|
|
||||||
# if they want to auto upload, let's not ask because it could be automated
|
# if they want to auto upload, let's not ask because it could be automated
|
||||||
if answer is None:
|
if answer is None:
|
||||||
sys.stdout.write('Uncommitted changes in ' + branch.project.name + ' (did you forget to amend?). Continue uploading? (y/n) ')
|
sys.stdout.write('Uncommitted changes in ' + branch.project.name + ' (did you forget to amend?). Continue uploading? (y/N) ')
|
||||||
a = sys.stdin.readline().strip().lower()
|
a = sys.stdin.readline().strip().lower()
|
||||||
if a not in ('y', 'yes', 't', 'true', 'on'):
|
if a not in ('y', 'yes', 't', 'true', 'on'):
|
||||||
print >>sys.stderr, "skipping upload"
|
print >>sys.stderr, "skipping upload"
|
||||||
|
Reference in New Issue
Block a user