diff options
Diffstat (limited to 'project.py')
| -rw-r--r-- | project.py | 145 |
1 files changed, 134 insertions, 11 deletions
| @@ -24,9 +24,11 @@ import urllib2 | |||
| 24 | 24 | ||
| 25 | from color import Coloring | 25 | from color import Coloring |
| 26 | from git_command import GitCommand | 26 | from git_command import GitCommand |
| 27 | from git_config import GitConfig, IsId | 27 | from git_config import GitConfig, IsId, GetSchemeFromUrl |
| 28 | from error import DownloadError | ||
| 28 | from error import GitError, HookError, ImportError, UploadError | 29 | from error import GitError, HookError, ImportError, UploadError |
| 29 | from error import ManifestInvalidRevisionError | 30 | from error import ManifestInvalidRevisionError |
| 31 | from progress import Progress | ||
| 30 | 32 | ||
| 31 | from git_refs import GitRefs, HEAD, R_HEADS, R_TAGS, R_PUB, R_M | 33 | from git_refs import GitRefs, HEAD, R_HEADS, R_TAGS, R_PUB, R_M |
| 32 | 34 | ||
| @@ -884,15 +886,13 @@ class Project(object): | |||
| 884 | 886 | ||
| 885 | ## Sync ## | 887 | ## Sync ## |
| 886 | 888 | ||
| 887 | def Sync_NetworkHalf(self, quiet=False): | 889 | def Sync_NetworkHalf(self, quiet=False, is_new=None): |
| 888 | """Perform only the network IO portion of the sync process. | 890 | """Perform only the network IO portion of the sync process. |
| 889 | Local working directory/branch state is not affected. | 891 | Local working directory/branch state is not affected. |
| 890 | """ | 892 | """ |
| 891 | is_new = not self.Exists | 893 | if is_new is None: |
| 894 | is_new = not self.Exists | ||
| 892 | if is_new: | 895 | if is_new: |
| 893 | if not quiet: | ||
| 894 | print >>sys.stderr | ||
| 895 | print >>sys.stderr, 'Initializing project %s ...' % self.name | ||
| 896 | self._InitGitDir() | 896 | self._InitGitDir() |
| 897 | 897 | ||
| 898 | self._InitRemote() | 898 | self._InitRemote() |
| @@ -1312,9 +1312,16 @@ class Project(object): | |||
| 1312 | name = self.remote.name | 1312 | name = self.remote.name |
| 1313 | 1313 | ||
| 1314 | ssh_proxy = False | 1314 | ssh_proxy = False |
| 1315 | if self.GetRemote(name).PreConnectFetch(): | 1315 | remote = self.GetRemote(name) |
| 1316 | if remote.PreConnectFetch(): | ||
| 1316 | ssh_proxy = True | 1317 | ssh_proxy = True |
| 1317 | 1318 | ||
| 1319 | bundle_dst = os.path.join(self.gitdir, 'clone.bundle') | ||
| 1320 | bundle_tmp = os.path.join(self.gitdir, 'clone.bundle.tmp') | ||
| 1321 | use_bundle = False | ||
| 1322 | if os.path.exists(bundle_dst) or os.path.exists(bundle_tmp): | ||
| 1323 | use_bundle = True | ||
| 1324 | |||
| 1318 | if initial: | 1325 | if initial: |
| 1319 | alt = os.path.join(self.gitdir, 'objects/info/alternates') | 1326 | alt = os.path.join(self.gitdir, 'objects/info/alternates') |
| 1320 | try: | 1327 | try: |
| @@ -1329,6 +1336,8 @@ class Project(object): | |||
| 1329 | ref_dir = None | 1336 | ref_dir = None |
| 1330 | 1337 | ||
| 1331 | if ref_dir and 'objects' == os.path.basename(ref_dir): | 1338 | if ref_dir and 'objects' == os.path.basename(ref_dir): |
| 1339 | if use_bundle: | ||
| 1340 | use_bundle = False | ||
| 1332 | ref_dir = os.path.dirname(ref_dir) | 1341 | ref_dir = os.path.dirname(ref_dir) |
| 1333 | packed_refs = os.path.join(self.gitdir, 'packed-refs') | 1342 | packed_refs = os.path.join(self.gitdir, 'packed-refs') |
| 1334 | remote = self.GetRemote(name) | 1343 | remote = self.GetRemote(name) |
| @@ -1368,6 +1377,7 @@ class Project(object): | |||
| 1368 | 1377 | ||
| 1369 | else: | 1378 | else: |
| 1370 | ref_dir = None | 1379 | ref_dir = None |
| 1380 | use_bundle = True | ||
| 1371 | 1381 | ||
| 1372 | cmd = ['fetch'] | 1382 | cmd = ['fetch'] |
| 1373 | 1383 | ||
| @@ -1376,15 +1386,37 @@ class Project(object): | |||
| 1376 | depth = self.manifest.manifestProject.config.GetString('repo.depth') | 1386 | depth = self.manifest.manifestProject.config.GetString('repo.depth') |
| 1377 | if depth and initial: | 1387 | if depth and initial: |
| 1378 | cmd.append('--depth=%s' % depth) | 1388 | cmd.append('--depth=%s' % depth) |
| 1389 | use_bundle = False | ||
| 1379 | 1390 | ||
| 1380 | if quiet: | 1391 | if quiet: |
| 1381 | cmd.append('--quiet') | 1392 | cmd.append('--quiet') |
| 1382 | if not self.worktree: | 1393 | if not self.worktree: |
| 1383 | cmd.append('--update-head-ok') | 1394 | cmd.append('--update-head-ok') |
| 1384 | cmd.append(name) | 1395 | |
| 1385 | if tag is not None: | 1396 | if use_bundle and not os.path.exists(bundle_dst): |
| 1386 | cmd.append('tag') | 1397 | bundle_url = remote.url + '/clone.bundle' |
| 1387 | cmd.append(tag) | 1398 | bundle_url = GitConfig.ForUser().UrlInsteadOf(bundle_url) |
| 1399 | if GetSchemeFromUrl(bundle_url) in ('http', 'https'): | ||
| 1400 | use_bundle = self._FetchBundle( | ||
| 1401 | bundle_url, | ||
| 1402 | bundle_tmp, | ||
| 1403 | bundle_dst, | ||
| 1404 | quiet=quiet) | ||
| 1405 | else: | ||
| 1406 | use_bundle = False | ||
| 1407 | |||
| 1408 | if use_bundle: | ||
| 1409 | if not quiet: | ||
| 1410 | cmd.append('--quiet') | ||
| 1411 | cmd.append(bundle_dst) | ||
| 1412 | for f in remote.fetch: | ||
| 1413 | cmd.append(str(f)) | ||
| 1414 | cmd.append('refs/tags/*:refs/tags/*') | ||
| 1415 | else: | ||
| 1416 | cmd.append(name) | ||
| 1417 | if tag is not None: | ||
| 1418 | cmd.append('tag') | ||
| 1419 | cmd.append(tag) | ||
| 1388 | 1420 | ||
| 1389 | ok = GitCommand(self, | 1421 | ok = GitCommand(self, |
| 1390 | cmd, | 1422 | cmd, |
| @@ -1399,8 +1431,99 @@ class Project(object): | |||
| 1399 | os.remove(packed_refs) | 1431 | os.remove(packed_refs) |
| 1400 | self.bare_git.pack_refs('--all', '--prune') | 1432 | self.bare_git.pack_refs('--all', '--prune') |
| 1401 | 1433 | ||
| 1434 | if os.path.exists(bundle_dst): | ||
| 1435 | os.remove(bundle_dst) | ||
| 1436 | if os.path.exists(bundle_tmp): | ||
| 1437 | os.remove(bundle_tmp) | ||
| 1438 | |||
| 1402 | return ok | 1439 | return ok |
| 1403 | 1440 | ||
| 1441 | def _FetchBundle(self, srcUrl, tmpPath, dstPath, quiet=False): | ||
| 1442 | keep = True | ||
| 1443 | done = False | ||
| 1444 | dest = open(tmpPath, 'a+b') | ||
| 1445 | try: | ||
| 1446 | dest.seek(0, os.SEEK_END) | ||
| 1447 | pos = dest.tell() | ||
| 1448 | |||
| 1449 | req = urllib2.Request(srcUrl) | ||
| 1450 | if pos > 0: | ||
| 1451 | req.add_header('Range', 'bytes=%d-' % pos) | ||
| 1452 | |||
| 1453 | try: | ||
| 1454 | r = urllib2.urlopen(req) | ||
| 1455 | except urllib2.HTTPError, e: | ||
| 1456 | if e.code == 404: | ||
| 1457 | keep = False | ||
| 1458 | return False | ||
| 1459 | elif e.info()['content-type'] == 'text/plain': | ||
| 1460 | try: | ||
| 1461 | msg = e.read() | ||
| 1462 | if len(msg) > 0 and msg[-1] == '\n': | ||
| 1463 | msg = msg[0:-1] | ||
| 1464 | msg = ' (%s)' % msg | ||
| 1465 | except: | ||
| 1466 | msg = '' | ||
| 1467 | else: | ||
| 1468 | try: | ||
| 1469 | from BaseHTTPServer import BaseHTTPRequestHandler | ||
| 1470 | res = BaseHTTPRequestHandler.responses[e.code] | ||
| 1471 | msg = ' (%s: %s)' % (res[0], res[1]) | ||
| 1472 | except: | ||
| 1473 | msg = '' | ||
| 1474 | raise DownloadError('HTTP %s%s' % (e.code, msg)) | ||
| 1475 | except urllib2.URLError, e: | ||
| 1476 | raise DownloadError('%s (%s)' % (e.reason, req.get_host())) | ||
| 1477 | |||
| 1478 | p = None | ||
| 1479 | try: | ||
| 1480 | size = r.headers['content-length'] | ||
| 1481 | unit = 1 << 10 | ||
| 1482 | |||
| 1483 | if size and not quiet: | ||
| 1484 | if size > 1024 * 1.3: | ||
| 1485 | unit = 1 << 20 | ||
| 1486 | desc = 'MB' | ||
| 1487 | else: | ||
| 1488 | desc = 'KB' | ||
| 1489 | p = Progress( | ||
| 1490 | 'Downloading %s' % self.relpath, | ||
| 1491 | int(size) / unit, | ||
| 1492 | units=desc) | ||
| 1493 | if pos > 0: | ||
| 1494 | p.update(pos / unit) | ||
| 1495 | |||
| 1496 | s = 0 | ||
| 1497 | while True: | ||
| 1498 | d = r.read(8192) | ||
| 1499 | if d == '': | ||
| 1500 | done = True | ||
| 1501 | return True | ||
| 1502 | dest.write(d) | ||
| 1503 | if p: | ||
| 1504 | s += len(d) | ||
| 1505 | if s >= unit: | ||
| 1506 | p.update(s / unit) | ||
| 1507 | s = s % unit | ||
| 1508 | if p: | ||
| 1509 | if s >= unit: | ||
| 1510 | p.update(s / unit) | ||
| 1511 | else: | ||
| 1512 | p.update(1) | ||
| 1513 | finally: | ||
| 1514 | r.close() | ||
| 1515 | if p: | ||
| 1516 | p.end() | ||
| 1517 | finally: | ||
| 1518 | dest.close() | ||
| 1519 | |||
| 1520 | if os.path.exists(dstPath): | ||
| 1521 | os.remove(dstPath) | ||
| 1522 | if done: | ||
| 1523 | os.rename(tmpPath, dstPath) | ||
| 1524 | elif not keep: | ||
| 1525 | os.remove(tmpPath) | ||
| 1526 | |||
| 1404 | def _Checkout(self, rev, quiet=False): | 1527 | def _Checkout(self, rev, quiet=False): |
| 1405 | cmd = ['checkout'] | 1528 | cmd = ['checkout'] |
| 1406 | if quiet: | 1529 | if quiet: |
