diff options
Diffstat (limited to 'project.py')
| -rw-r--r-- | project.py | 146 |
1 files changed, 102 insertions, 44 deletions
| @@ -231,14 +231,40 @@ class _CopyFile: | |||
| 231 | except IOError: | 231 | except IOError: |
| 232 | _error('Cannot copy file %s to %s', src, dest) | 232 | _error('Cannot copy file %s to %s', src, dest) |
| 233 | 233 | ||
| 234 | class _LinkFile: | ||
| 235 | def __init__(self, src, dest, abssrc, absdest): | ||
| 236 | self.src = src | ||
| 237 | self.dest = dest | ||
| 238 | self.abs_src = abssrc | ||
| 239 | self.abs_dest = absdest | ||
| 240 | |||
| 241 | def _Link(self): | ||
| 242 | src = self.abs_src | ||
| 243 | dest = self.abs_dest | ||
| 244 | # link file if it does not exist or is out of date | ||
| 245 | if not os.path.islink(dest) or os.readlink(dest) != src: | ||
| 246 | try: | ||
| 247 | # remove existing file first, since it might be read-only | ||
| 248 | if os.path.exists(dest): | ||
| 249 | os.remove(dest) | ||
| 250 | else: | ||
| 251 | dest_dir = os.path.dirname(dest) | ||
| 252 | if not os.path.isdir(dest_dir): | ||
| 253 | os.makedirs(dest_dir) | ||
| 254 | os.symlink(src, dest) | ||
| 255 | except IOError: | ||
| 256 | _error('Cannot link file %s to %s', src, dest) | ||
| 257 | |||
| 234 | class RemoteSpec(object): | 258 | class RemoteSpec(object): |
| 235 | def __init__(self, | 259 | def __init__(self, |
| 236 | name, | 260 | name, |
| 237 | url = None, | 261 | url = None, |
| 238 | review = None): | 262 | review = None, |
| 263 | revision = None): | ||
| 239 | self.name = name | 264 | self.name = name |
| 240 | self.url = url | 265 | self.url = url |
| 241 | self.review = review | 266 | self.review = review |
| 267 | self.revision = revision | ||
| 242 | 268 | ||
| 243 | class RepoHook(object): | 269 | class RepoHook(object): |
| 244 | """A RepoHook contains information about a script to run as a hook. | 270 | """A RepoHook contains information about a script to run as a hook. |
| @@ -414,7 +440,8 @@ class RepoHook(object): | |||
| 414 | # and convert to a HookError w/ just the failing traceback. | 440 | # and convert to a HookError w/ just the failing traceback. |
| 415 | context = {} | 441 | context = {} |
| 416 | try: | 442 | try: |
| 417 | execfile(self._script_fullpath, context) | 443 | exec(compile(open(self._script_fullpath).read(), |
| 444 | self._script_fullpath, 'exec'), context) | ||
| 418 | except Exception: | 445 | except Exception: |
| 419 | raise HookError('%s\nFailed to import %s hook; see traceback above.' % ( | 446 | raise HookError('%s\nFailed to import %s hook; see traceback above.' % ( |
| 420 | traceback.format_exc(), self._hook_type)) | 447 | traceback.format_exc(), self._hook_type)) |
| @@ -555,6 +582,7 @@ class Project(object): | |||
| 555 | 582 | ||
| 556 | self.snapshots = {} | 583 | self.snapshots = {} |
| 557 | self.copyfiles = [] | 584 | self.copyfiles = [] |
| 585 | self.linkfiles = [] | ||
| 558 | self.annotations = [] | 586 | self.annotations = [] |
| 559 | self.config = GitConfig.ForRepository( | 587 | self.config = GitConfig.ForRepository( |
| 560 | gitdir = self.gitdir, | 588 | gitdir = self.gitdir, |
| @@ -1040,7 +1068,7 @@ class Project(object): | |||
| 1040 | except OSError as e: | 1068 | except OSError as e: |
| 1041 | print("warn: Cannot remove archive %s: " | 1069 | print("warn: Cannot remove archive %s: " |
| 1042 | "%s" % (tarpath, str(e)), file=sys.stderr) | 1070 | "%s" % (tarpath, str(e)), file=sys.stderr) |
| 1043 | self._CopyFiles() | 1071 | self._CopyAndLinkFiles() |
| 1044 | return True | 1072 | return True |
| 1045 | 1073 | ||
| 1046 | if is_new is None: | 1074 | if is_new is None: |
| @@ -1078,17 +1106,12 @@ class Project(object): | |||
| 1078 | elif self.manifest.default.sync_c: | 1106 | elif self.manifest.default.sync_c: |
| 1079 | current_branch_only = True | 1107 | current_branch_only = True |
| 1080 | 1108 | ||
| 1081 | is_sha1 = False | 1109 | has_sha1 = ID_RE.match(self.revisionExpr) and self._CheckForSha1() |
| 1082 | if ID_RE.match(self.revisionExpr) is not None: | 1110 | if (not has_sha1 #Need to fetch since we don't already have this revision |
| 1083 | is_sha1 = True | 1111 | and not self._RemoteFetch(initial=is_new, quiet=quiet, alt_dir=alt_dir, |
| 1084 | if is_sha1 and self._CheckForSha1(): | 1112 | current_branch_only=current_branch_only, |
| 1085 | # Don't need to fetch since we already have this revision | 1113 | no_tags=no_tags)): |
| 1086 | return True | 1114 | return False |
| 1087 | |||
| 1088 | if not self._RemoteFetch(initial=is_new, quiet=quiet, alt_dir=alt_dir, | ||
| 1089 | current_branch_only=current_branch_only, | ||
| 1090 | no_tags=no_tags): | ||
| 1091 | return False | ||
| 1092 | 1115 | ||
| 1093 | if self.worktree: | 1116 | if self.worktree: |
| 1094 | self._InitMRef() | 1117 | self._InitMRef() |
| @@ -1103,9 +1126,11 @@ class Project(object): | |||
| 1103 | def PostRepoUpgrade(self): | 1126 | def PostRepoUpgrade(self): |
| 1104 | self._InitHooks() | 1127 | self._InitHooks() |
| 1105 | 1128 | ||
| 1106 | def _CopyFiles(self): | 1129 | def _CopyAndLinkFiles(self): |
| 1107 | for copyfile in self.copyfiles: | 1130 | for copyfile in self.copyfiles: |
| 1108 | copyfile._Copy() | 1131 | copyfile._Copy() |
| 1132 | for linkfile in self.linkfiles: | ||
| 1133 | linkfile._Link() | ||
| 1109 | 1134 | ||
| 1110 | def GetCommitRevisionId(self): | 1135 | def GetCommitRevisionId(self): |
| 1111 | """Get revisionId of a commit. | 1136 | """Get revisionId of a commit. |
| @@ -1152,7 +1177,7 @@ class Project(object): | |||
| 1152 | 1177 | ||
| 1153 | def _doff(): | 1178 | def _doff(): |
| 1154 | self._FastForward(revid) | 1179 | self._FastForward(revid) |
| 1155 | self._CopyFiles() | 1180 | self._CopyAndLinkFiles() |
| 1156 | 1181 | ||
| 1157 | head = self.work_git.GetHead() | 1182 | head = self.work_git.GetHead() |
| 1158 | if head.startswith(R_HEADS): | 1183 | if head.startswith(R_HEADS): |
| @@ -1188,7 +1213,7 @@ class Project(object): | |||
| 1188 | except GitError as e: | 1213 | except GitError as e: |
| 1189 | syncbuf.fail(self, e) | 1214 | syncbuf.fail(self, e) |
| 1190 | return | 1215 | return |
| 1191 | self._CopyFiles() | 1216 | self._CopyAndLinkFiles() |
| 1192 | return | 1217 | return |
| 1193 | 1218 | ||
| 1194 | if head == revid: | 1219 | if head == revid: |
| @@ -1210,7 +1235,7 @@ class Project(object): | |||
| 1210 | except GitError as e: | 1235 | except GitError as e: |
| 1211 | syncbuf.fail(self, e) | 1236 | syncbuf.fail(self, e) |
| 1212 | return | 1237 | return |
| 1213 | self._CopyFiles() | 1238 | self._CopyAndLinkFiles() |
| 1214 | return | 1239 | return |
| 1215 | 1240 | ||
| 1216 | upstream_gain = self._revlist(not_rev(HEAD), revid) | 1241 | upstream_gain = self._revlist(not_rev(HEAD), revid) |
| @@ -1283,12 +1308,12 @@ class Project(object): | |||
| 1283 | if cnt_mine > 0 and self.rebase: | 1308 | if cnt_mine > 0 and self.rebase: |
| 1284 | def _dorebase(): | 1309 | def _dorebase(): |
| 1285 | self._Rebase(upstream = '%s^1' % last_mine, onto = revid) | 1310 | self._Rebase(upstream = '%s^1' % last_mine, onto = revid) |
| 1286 | self._CopyFiles() | 1311 | self._CopyAndLinkFiles() |
| 1287 | syncbuf.later2(self, _dorebase) | 1312 | syncbuf.later2(self, _dorebase) |
| 1288 | elif local_changes: | 1313 | elif local_changes: |
| 1289 | try: | 1314 | try: |
| 1290 | self._ResetHard(revid) | 1315 | self._ResetHard(revid) |
| 1291 | self._CopyFiles() | 1316 | self._CopyAndLinkFiles() |
| 1292 | except GitError as e: | 1317 | except GitError as e: |
| 1293 | syncbuf.fail(self, e) | 1318 | syncbuf.fail(self, e) |
| 1294 | return | 1319 | return |
| @@ -1301,6 +1326,12 @@ class Project(object): | |||
| 1301 | abssrc = os.path.join(self.worktree, src) | 1326 | abssrc = os.path.join(self.worktree, src) |
| 1302 | self.copyfiles.append(_CopyFile(src, dest, abssrc, absdest)) | 1327 | self.copyfiles.append(_CopyFile(src, dest, abssrc, absdest)) |
| 1303 | 1328 | ||
| 1329 | def AddLinkFile(self, src, dest, absdest): | ||
| 1330 | # dest should already be an absolute path, but src is project relative | ||
| 1331 | # make src an absolute path | ||
| 1332 | abssrc = os.path.join(self.worktree, src) | ||
| 1333 | self.linkfiles.append(_LinkFile(src, dest, abssrc, absdest)) | ||
| 1334 | |||
| 1304 | def AddAnnotation(self, name, value, keep): | 1335 | def AddAnnotation(self, name, value, keep): |
| 1305 | self.annotations.append(_Annotation(name, value, keep)) | 1336 | self.annotations.append(_Annotation(name, value, keep)) |
| 1306 | 1337 | ||
| @@ -1629,7 +1660,8 @@ class Project(object): | |||
| 1629 | 1660 | ||
| 1630 | remote = RemoteSpec(self.remote.name, | 1661 | remote = RemoteSpec(self.remote.name, |
| 1631 | url = url, | 1662 | url = url, |
| 1632 | review = self.remote.review) | 1663 | review = self.remote.review, |
| 1664 | revision = self.remote.revision) | ||
| 1633 | subproject = Project(manifest = self.manifest, | 1665 | subproject = Project(manifest = self.manifest, |
| 1634 | name = name, | 1666 | name = name, |
| 1635 | remote = remote, | 1667 | remote = remote, |
| @@ -1674,6 +1706,7 @@ class Project(object): | |||
| 1674 | if command.Wait() != 0: | 1706 | if command.Wait() != 0: |
| 1675 | raise GitError('git archive %s: %s' % (self.name, command.stderr)) | 1707 | raise GitError('git archive %s: %s' % (self.name, command.stderr)) |
| 1676 | 1708 | ||
| 1709 | |||
| 1677 | def _RemoteFetch(self, name=None, | 1710 | def _RemoteFetch(self, name=None, |
| 1678 | current_branch_only=False, | 1711 | current_branch_only=False, |
| 1679 | initial=False, | 1712 | initial=False, |
| @@ -1683,11 +1716,17 @@ class Project(object): | |||
| 1683 | 1716 | ||
| 1684 | is_sha1 = False | 1717 | is_sha1 = False |
| 1685 | tag_name = None | 1718 | tag_name = None |
| 1719 | depth = None | ||
| 1720 | |||
| 1721 | # The depth should not be used when fetching to a mirror because | ||
| 1722 | # it will result in a shallow repository that cannot be cloned or | ||
| 1723 | # fetched from. | ||
| 1724 | if not self.manifest.IsMirror: | ||
| 1725 | if self.clone_depth: | ||
| 1726 | depth = self.clone_depth | ||
| 1727 | else: | ||
| 1728 | depth = self.manifest.manifestProject.config.GetString('repo.depth') | ||
| 1686 | 1729 | ||
| 1687 | if self.clone_depth: | ||
| 1688 | depth = self.clone_depth | ||
| 1689 | else: | ||
| 1690 | depth = self.manifest.manifestProject.config.GetString('repo.depth') | ||
| 1691 | if depth: | 1730 | if depth: |
| 1692 | current_branch_only = True | 1731 | current_branch_only = True |
| 1693 | 1732 | ||
| @@ -1763,26 +1802,37 @@ class Project(object): | |||
| 1763 | cmd.append('--update-head-ok') | 1802 | cmd.append('--update-head-ok') |
| 1764 | cmd.append(name) | 1803 | cmd.append(name) |
| 1765 | 1804 | ||
| 1805 | # If using depth then we should not get all the tags since they may | ||
| 1806 | # be outside of the depth. | ||
| 1807 | if no_tags or depth: | ||
| 1808 | cmd.append('--no-tags') | ||
| 1809 | else: | ||
| 1810 | cmd.append('--tags') | ||
| 1811 | |||
| 1812 | spec = [] | ||
| 1766 | if not current_branch_only: | 1813 | if not current_branch_only: |
| 1767 | # Fetch whole repo | 1814 | # Fetch whole repo |
| 1768 | # If using depth then we should not get all the tags since they may | 1815 | spec.append(str((u'+refs/heads/*:') + remote.ToLocal('refs/heads/*'))) |
| 1769 | # be outside of the depth. | ||
| 1770 | if no_tags or depth: | ||
| 1771 | cmd.append('--no-tags') | ||
| 1772 | else: | ||
| 1773 | cmd.append('--tags') | ||
| 1774 | |||
| 1775 | cmd.append(str((u'+refs/heads/*:') + remote.ToLocal('refs/heads/*'))) | ||
| 1776 | elif tag_name is not None: | 1816 | elif tag_name is not None: |
| 1777 | cmd.append('tag') | 1817 | spec.append('tag') |
| 1778 | cmd.append(tag_name) | 1818 | spec.append(tag_name) |
| 1779 | else: | 1819 | else: |
| 1780 | branch = self.revisionExpr | 1820 | branch = self.revisionExpr |
| 1781 | if is_sha1: | 1821 | if is_sha1: |
| 1782 | branch = self.upstream | 1822 | branch = self.upstream |
| 1783 | if branch.startswith(R_HEADS): | 1823 | if branch.startswith(R_HEADS): |
| 1784 | branch = branch[len(R_HEADS):] | 1824 | branch = branch[len(R_HEADS):] |
| 1785 | cmd.append(str((u'+refs/heads/%s:' % branch) + remote.ToLocal('refs/heads/%s' % branch))) | 1825 | spec.append(str((u'+refs/heads/%s:' % branch) + remote.ToLocal('refs/heads/%s' % branch))) |
| 1826 | cmd.extend(spec) | ||
| 1827 | |||
| 1828 | shallowfetch = self.config.GetString('repo.shallowfetch') | ||
| 1829 | if shallowfetch and shallowfetch != ' '.join(spec): | ||
| 1830 | GitCommand(self, ['fetch', '--unshallow', name] + shallowfetch.split(), | ||
| 1831 | bare=True, ssh_proxy=ssh_proxy).Wait() | ||
| 1832 | if depth: | ||
| 1833 | self.config.SetString('repo.shallowfetch', ' '.join(spec)) | ||
| 1834 | else: | ||
| 1835 | self.config.SetString('repo.shallowfetch', None) | ||
| 1786 | 1836 | ||
| 1787 | ok = False | 1837 | ok = False |
| 1788 | for _i in range(2): | 1838 | for _i in range(2): |
| @@ -1801,7 +1851,7 @@ class Project(object): | |||
| 1801 | # Ensure that some refs exist. Otherwise, we probably aren't looking | 1851 | # Ensure that some refs exist. Otherwise, we probably aren't looking |
| 1802 | # at a real git repository and may have a bad url. | 1852 | # at a real git repository and may have a bad url. |
| 1803 | if not self.bare_ref.all: | 1853 | if not self.bare_ref.all: |
| 1804 | ok = False | 1854 | ok = False |
| 1805 | 1855 | ||
| 1806 | if alt_dir: | 1856 | if alt_dir: |
| 1807 | if old_packed != '': | 1857 | if old_packed != '': |
| @@ -2147,7 +2197,7 @@ class Project(object): | |||
| 2147 | symlink_dirs = ['hooks', 'objects', 'rr-cache', 'svn'] | 2197 | symlink_dirs = ['hooks', 'objects', 'rr-cache', 'svn'] |
| 2148 | if share_refs: | 2198 | if share_refs: |
| 2149 | # These objects can only be used by a single working tree. | 2199 | # These objects can only be used by a single working tree. |
| 2150 | symlink_files += ['config', 'packed-refs'] | 2200 | symlink_files += ['config', 'packed-refs', 'shallow'] |
| 2151 | symlink_dirs += ['logs', 'refs'] | 2201 | symlink_dirs += ['logs', 'refs'] |
| 2152 | to_symlink = symlink_files + symlink_dirs | 2202 | to_symlink = symlink_files + symlink_dirs |
| 2153 | 2203 | ||
| @@ -2167,6 +2217,14 @@ class Project(object): | |||
| 2167 | if name in symlink_dirs and not os.path.lexists(src): | 2217 | if name in symlink_dirs and not os.path.lexists(src): |
| 2168 | os.makedirs(src) | 2218 | os.makedirs(src) |
| 2169 | 2219 | ||
| 2220 | # If the source file doesn't exist, ensure the destination | ||
| 2221 | # file doesn't either. | ||
| 2222 | if name in symlink_files and not os.path.lexists(src): | ||
| 2223 | try: | ||
| 2224 | os.remove(dst) | ||
| 2225 | except OSError: | ||
| 2226 | pass | ||
| 2227 | |||
| 2170 | if name in to_symlink: | 2228 | if name in to_symlink: |
| 2171 | os.symlink(os.path.relpath(src, os.path.dirname(dst)), dst) | 2229 | os.symlink(os.path.relpath(src, os.path.dirname(dst)), dst) |
| 2172 | elif copy_all and not os.path.islink(dst): | 2230 | elif copy_all and not os.path.islink(dst): |
| @@ -2195,7 +2253,7 @@ class Project(object): | |||
| 2195 | if GitCommand(self, cmd).Wait() != 0: | 2253 | if GitCommand(self, cmd).Wait() != 0: |
| 2196 | raise GitError("cannot initialize work tree") | 2254 | raise GitError("cannot initialize work tree") |
| 2197 | 2255 | ||
| 2198 | self._CopyFiles() | 2256 | self._CopyAndLinkFiles() |
| 2199 | 2257 | ||
| 2200 | def _gitdir_path(self, path): | 2258 | def _gitdir_path(self, path): |
| 2201 | return os.path.realpath(os.path.join(self.gitdir, path)) | 2259 | return os.path.realpath(os.path.join(self.gitdir, path)) |
| @@ -2287,8 +2345,8 @@ class Project(object): | |||
| 2287 | out = iter(out[:-1].split('\0')) # pylint: disable=W1401 | 2345 | out = iter(out[:-1].split('\0')) # pylint: disable=W1401 |
| 2288 | while out: | 2346 | while out: |
| 2289 | try: | 2347 | try: |
| 2290 | info = out.next() | 2348 | info = next(out) |
| 2291 | path = out.next() | 2349 | path = next(out) |
| 2292 | except StopIteration: | 2350 | except StopIteration: |
| 2293 | break | 2351 | break |
| 2294 | 2352 | ||
| @@ -2314,7 +2372,7 @@ class Project(object): | |||
| 2314 | info = _Info(path, *info) | 2372 | info = _Info(path, *info) |
| 2315 | if info.status in ('R', 'C'): | 2373 | if info.status in ('R', 'C'): |
| 2316 | info.src_path = info.path | 2374 | info.src_path = info.path |
| 2317 | info.path = out.next() | 2375 | info.path = next(out) |
| 2318 | r[info.path] = info | 2376 | r[info.path] = info |
| 2319 | return r | 2377 | return r |
| 2320 | finally: | 2378 | finally: |
| @@ -2327,8 +2385,8 @@ class Project(object): | |||
| 2327 | path = os.path.join(self._project.worktree, '.git', HEAD) | 2385 | path = os.path.join(self._project.worktree, '.git', HEAD) |
| 2328 | try: | 2386 | try: |
| 2329 | fd = open(path, 'rb') | 2387 | fd = open(path, 'rb') |
| 2330 | except IOError: | 2388 | except IOError as e: |
| 2331 | raise NoManifestException(path) | 2389 | raise NoManifestException(path, str(e)) |
| 2332 | try: | 2390 | try: |
| 2333 | line = fd.read() | 2391 | line = fd.read() |
| 2334 | finally: | 2392 | finally: |
