summaryrefslogtreecommitdiffstats
path: root/project.py
diff options
context:
space:
mode:
Diffstat (limited to 'project.py')
-rw-r--r--project.py96
1 files changed, 74 insertions, 22 deletions
diff --git a/project.py b/project.py
index 003489aa..d0d3b6eb 100644
--- a/project.py
+++ b/project.py
@@ -16,6 +16,7 @@ from __future__ import print_function
16import contextlib 16import contextlib
17import errno 17import errno
18import filecmp 18import filecmp
19import glob
19import os 20import os
20import random 21import random
21import re 22import 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
235class _LinkFile(object): 236class _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
259class RemoteSpec(object): 292class 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