diff options
Diffstat (limited to 'project.py')
-rw-r--r-- | project.py | 96 |
1 files changed, 74 insertions, 22 deletions
@@ -16,6 +16,7 @@ from __future__ import print_function | |||
16 | import contextlib | 16 | import contextlib |
17 | import errno | 17 | import errno |
18 | import filecmp | 18 | import filecmp |
19 | import glob | ||
19 | import os | 20 | import os |
20 | import random | 21 | import random |
21 | import re | 22 | import re |
@@ -233,28 +234,60 @@ class _CopyFile(object): | |||
233 | _error('Cannot copy file %s to %s', src, dest) | 234 | _error('Cannot copy file %s to %s', src, dest) |
234 | 235 | ||
235 | class _LinkFile(object): | 236 | class _LinkFile(object): |
236 | def __init__(self, src, dest, abssrc, absdest): | 237 | def __init__(self, git_worktree, src, dest, relsrc, absdest): |
238 | self.git_worktree = git_worktree | ||
237 | self.src = src | 239 | self.src = src |
238 | self.dest = dest | 240 | self.dest = dest |
239 | self.abs_src = abssrc | 241 | self.src_rel_to_dest = relsrc |
240 | self.abs_dest = absdest | 242 | self.abs_dest = absdest |
241 | 243 | ||
242 | def _Link(self): | 244 | def __linkIt(self, relSrc, absDest): |
243 | src = self.abs_src | ||
244 | dest = self.abs_dest | ||
245 | # link file if it does not exist or is out of date | 245 | # link file if it does not exist or is out of date |
246 | if not os.path.islink(dest) or os.readlink(dest) != src: | 246 | if not os.path.islink(absDest) or (os.readlink(absDest) != relSrc): |
247 | try: | 247 | try: |
248 | # remove existing file first, since it might be read-only | 248 | # remove existing file first, since it might be read-only |
249 | if os.path.exists(dest): | 249 | if os.path.exists(absDest): |
250 | os.remove(dest) | 250 | os.remove(absDest) |
251 | else: | 251 | else: |
252 | dest_dir = os.path.dirname(dest) | 252 | dest_dir = os.path.dirname(absDest) |
253 | if not os.path.isdir(dest_dir): | 253 | if not os.path.isdir(dest_dir): |
254 | os.makedirs(dest_dir) | 254 | os.makedirs(dest_dir) |
255 | os.symlink(src, dest) | 255 | os.symlink(relSrc, absDest) |
256 | except IOError: | 256 | except IOError: |
257 | _error('Cannot link file %s to %s', src, dest) | 257 | _error('Cannot link file %s to %s', relSrc, absDest) |
258 | |||
259 | def _Link(self): | ||
260 | """Link the self.rel_src_to_dest and self.abs_dest. Handles wild cards | ||
261 | on the src linking all of the files in the source in to the destination | ||
262 | directory. | ||
263 | """ | ||
264 | # We use the absSrc to handle the situation where the current directory | ||
265 | # is not the root of the repo | ||
266 | absSrc = os.path.join(self.git_worktree, self.src) | ||
267 | if os.path.exists(absSrc): | ||
268 | # Entity exists so just a simple one to one link operation | ||
269 | self.__linkIt(self.src_rel_to_dest, self.abs_dest) | ||
270 | else: | ||
271 | # Entity doesn't exist assume there is a wild card | ||
272 | absDestDir = self.abs_dest | ||
273 | if os.path.exists(absDestDir) and not os.path.isdir(absDestDir): | ||
274 | _error('Link error: src with wildcard, %s must be a directory', | ||
275 | absDestDir) | ||
276 | else: | ||
277 | absSrcFiles = glob.glob(absSrc) | ||
278 | for absSrcFile in absSrcFiles: | ||
279 | # Create a releative path from source dir to destination dir | ||
280 | absSrcDir = os.path.dirname(absSrcFile) | ||
281 | relSrcDir = os.path.relpath(absSrcDir, absDestDir) | ||
282 | |||
283 | # Get the source file name | ||
284 | srcFile = os.path.basename(absSrcFile) | ||
285 | |||
286 | # Now form the final full paths to srcFile. They will be | ||
287 | # absolute for the desintaiton and relative for the srouce. | ||
288 | absDest = os.path.join(absDestDir, srcFile) | ||
289 | relSrc = os.path.join(relSrcDir, srcFile) | ||
290 | self.__linkIt(relSrc, absDest) | ||
258 | 291 | ||
259 | class RemoteSpec(object): | 292 | class RemoteSpec(object): |
260 | def __init__(self, | 293 | def __init__(self, |
@@ -535,7 +568,8 @@ class Project(object): | |||
535 | upstream=None, | 568 | upstream=None, |
536 | parent=None, | 569 | parent=None, |
537 | is_derived=False, | 570 | is_derived=False, |
538 | dest_branch=None): | 571 | dest_branch=None, |
572 | optimized_fetch=False): | ||
539 | """Init a Project object. | 573 | """Init a Project object. |
540 | 574 | ||
541 | Args: | 575 | Args: |
@@ -557,6 +591,8 @@ class Project(object): | |||
557 | is_derived: False if the project was explicitly defined in the manifest; | 591 | is_derived: False if the project was explicitly defined in the manifest; |
558 | True if the project is a discovered submodule. | 592 | True if the project is a discovered submodule. |
559 | dest_branch: The branch to which to push changes for review by default. | 593 | dest_branch: The branch to which to push changes for review by default. |
594 | optimized_fetch: If True, when a project is set to a sha1 revision, only | ||
595 | fetch from the remote if the sha1 is not present locally. | ||
560 | """ | 596 | """ |
561 | self.manifest = manifest | 597 | self.manifest = manifest |
562 | self.name = name | 598 | self.name = name |
@@ -585,6 +621,7 @@ class Project(object): | |||
585 | self.upstream = upstream | 621 | self.upstream = upstream |
586 | self.parent = parent | 622 | self.parent = parent |
587 | self.is_derived = is_derived | 623 | self.is_derived = is_derived |
624 | self.optimized_fetch = optimized_fetch | ||
588 | self.subprojects = [] | 625 | self.subprojects = [] |
589 | 626 | ||
590 | self.snapshots = {} | 627 | self.snapshots = {} |
@@ -1066,7 +1103,8 @@ class Project(object): | |||
1066 | current_branch_only=False, | 1103 | current_branch_only=False, |
1067 | clone_bundle=True, | 1104 | clone_bundle=True, |
1068 | no_tags=False, | 1105 | no_tags=False, |
1069 | archive=False): | 1106 | archive=False, |
1107 | optimized_fetch=False): | ||
1070 | """Perform only the network IO portion of the sync process. | 1108 | """Perform only the network IO portion of the sync process. |
1071 | Local working directory/branch state is not affected. | 1109 | Local working directory/branch state is not affected. |
1072 | """ | 1110 | """ |
@@ -1134,8 +1172,9 @@ class Project(object): | |||
1134 | elif self.manifest.default.sync_c: | 1172 | elif self.manifest.default.sync_c: |
1135 | current_branch_only = True | 1173 | current_branch_only = True |
1136 | 1174 | ||
1137 | has_sha1 = ID_RE.match(self.revisionExpr) and self._CheckForSha1() | 1175 | need_to_fetch = not (optimized_fetch and \ |
1138 | if (not has_sha1 #Need to fetch since we don't already have this revision | 1176 | (ID_RE.match(self.revisionExpr) and self._CheckForSha1())) |
1177 | if (need_to_fetch | ||
1139 | and not self._RemoteFetch(initial=is_new, quiet=quiet, alt_dir=alt_dir, | 1178 | and not self._RemoteFetch(initial=is_new, quiet=quiet, alt_dir=alt_dir, |
1140 | current_branch_only=current_branch_only, | 1179 | current_branch_only=current_branch_only, |
1141 | no_tags=no_tags)): | 1180 | no_tags=no_tags)): |
@@ -1358,9 +1397,10 @@ class Project(object): | |||
1358 | 1397 | ||
1359 | def AddLinkFile(self, src, dest, absdest): | 1398 | def AddLinkFile(self, src, dest, absdest): |
1360 | # dest should already be an absolute path, but src is project relative | 1399 | # dest should already be an absolute path, but src is project relative |
1361 | # make src an absolute path | 1400 | # make src relative path to dest |
1362 | abssrc = os.path.join(self.worktree, src) | 1401 | absdestdir = os.path.dirname(absdest) |
1363 | self.linkfiles.append(_LinkFile(src, dest, abssrc, absdest)) | 1402 | relsrc = os.path.relpath(os.path.join(self.worktree, src), absdestdir) |
1403 | self.linkfiles.append(_LinkFile(self.worktree, src, dest, relsrc, absdest)) | ||
1364 | 1404 | ||
1365 | def AddAnnotation(self, name, value, keep): | 1405 | def AddAnnotation(self, name, value, keep): |
1366 | self.annotations.append(_Annotation(name, value, keep)) | 1406 | self.annotations.append(_Annotation(name, value, keep)) |
@@ -1401,7 +1441,7 @@ class Project(object): | |||
1401 | branch = self.GetBranch(name) | 1441 | branch = self.GetBranch(name) |
1402 | branch.remote = self.GetRemote(self.remote.name) | 1442 | branch.remote = self.GetRemote(self.remote.name) |
1403 | branch.merge = self.revisionExpr | 1443 | branch.merge = self.revisionExpr |
1404 | if not branch.merge.startswith('refs/'): | 1444 | if not branch.merge.startswith('refs/') and not ID_RE.match(self.revisionExpr): |
1405 | branch.merge = R_HEADS + self.revisionExpr | 1445 | branch.merge = R_HEADS + self.revisionExpr |
1406 | revid = self.GetRevisionId(all_refs) | 1446 | revid = self.GetRevisionId(all_refs) |
1407 | 1447 | ||
@@ -1841,6 +1881,8 @@ class Project(object): | |||
1841 | cmd.append('--quiet') | 1881 | cmd.append('--quiet') |
1842 | if not self.worktree: | 1882 | if not self.worktree: |
1843 | cmd.append('--update-head-ok') | 1883 | cmd.append('--update-head-ok') |
1884 | if self.manifest.IsMirror: | ||
1885 | cmd.append('--prune') | ||
1844 | cmd.append(name) | 1886 | cmd.append(name) |
1845 | 1887 | ||
1846 | # If using depth then we should not get all the tags since they may | 1888 | # If using depth then we should not get all the tags since they may |
@@ -1860,7 +1902,7 @@ class Project(object): | |||
1860 | 1902 | ||
1861 | if not self.manifest.IsMirror: | 1903 | if not self.manifest.IsMirror: |
1862 | branch = self.revisionExpr | 1904 | branch = self.revisionExpr |
1863 | if is_sha1 and depth: | 1905 | if is_sha1 and depth and git_require((1, 8, 3)): |
1864 | # Shallow checkout of a specific commit, fetch from that commit and not | 1906 | # Shallow checkout of a specific commit, fetch from that commit and not |
1865 | # the heads only as the commit might be deeper in the history. | 1907 | # the heads only as the commit might be deeper in the history. |
1866 | spec.append(branch) | 1908 | spec.append(branch) |
@@ -1905,6 +1947,9 @@ class Project(object): | |||
1905 | # mode, we just tried sync'ing from the upstream field; it doesn't exist, thus | 1947 | # mode, we just tried sync'ing from the upstream field; it doesn't exist, thus |
1906 | # abort the optimization attempt and do a full sync. | 1948 | # abort the optimization attempt and do a full sync. |
1907 | break | 1949 | break |
1950 | elif ret < 0: | ||
1951 | # Git died with a signal, exit immediately | ||
1952 | break | ||
1908 | time.sleep(random.randint(30, 45)) | 1953 | time.sleep(random.randint(30, 45)) |
1909 | 1954 | ||
1910 | if initial: | 1955 | if initial: |
@@ -1920,8 +1965,15 @@ class Project(object): | |||
1920 | # got what we wanted, else trigger a second run of all | 1965 | # got what we wanted, else trigger a second run of all |
1921 | # refs. | 1966 | # refs. |
1922 | if not self._CheckForSha1(): | 1967 | if not self._CheckForSha1(): |
1923 | return self._RemoteFetch(name=name, current_branch_only=False, | 1968 | if not depth: |
1924 | initial=False, quiet=quiet, alt_dir=alt_dir) | 1969 | # Avoid infinite recursion when depth is True (since depth implies |
1970 | # current_branch_only) | ||
1971 | return self._RemoteFetch(name=name, current_branch_only=False, | ||
1972 | initial=False, quiet=quiet, alt_dir=alt_dir) | ||
1973 | if self.clone_depth: | ||
1974 | self.clone_depth = None | ||
1975 | return self._RemoteFetch(name=name, current_branch_only=current_branch_only, | ||
1976 | initial=False, quiet=quiet, alt_dir=alt_dir) | ||
1925 | 1977 | ||
1926 | return ok | 1978 | return ok |
1927 | 1979 | ||