summaryrefslogtreecommitdiffstats
path: root/project.py
diff options
context:
space:
mode:
Diffstat (limited to 'project.py')
-rw-r--r--project.py118
1 files changed, 82 insertions, 36 deletions
diff --git a/project.py b/project.py
index dec21ab1..f9f1f75d 100644
--- a/project.py
+++ b/project.py
@@ -487,6 +487,7 @@ class Project(object):
487 name, 487 name,
488 remote, 488 remote,
489 gitdir, 489 gitdir,
490 objdir,
490 worktree, 491 worktree,
491 relpath, 492 relpath,
492 revisionExpr, 493 revisionExpr,
@@ -507,6 +508,7 @@ class Project(object):
507 name: The `name` attribute of manifest.xml's project element. 508 name: The `name` attribute of manifest.xml's project element.
508 remote: RemoteSpec object specifying its remote's properties. 509 remote: RemoteSpec object specifying its remote's properties.
509 gitdir: Absolute path of git directory. 510 gitdir: Absolute path of git directory.
511 objdir: Absolute path of directory to store git objects.
510 worktree: Absolute path of git working tree. 512 worktree: Absolute path of git working tree.
511 relpath: Relative path of git working tree to repo's top directory. 513 relpath: Relative path of git working tree to repo's top directory.
512 revisionExpr: The `revision` attribute of manifest.xml's project element. 514 revisionExpr: The `revision` attribute of manifest.xml's project element.
@@ -525,6 +527,7 @@ class Project(object):
525 self.name = name 527 self.name = name
526 self.remote = remote 528 self.remote = remote
527 self.gitdir = gitdir.replace('\\', '/') 529 self.gitdir = gitdir.replace('\\', '/')
530 self.objdir = objdir.replace('\\', '/')
528 if worktree: 531 if worktree:
529 self.worktree = worktree.replace('\\', '/') 532 self.worktree = worktree.replace('\\', '/')
530 else: 533 else:
@@ -557,11 +560,12 @@ class Project(object):
557 defaults = self.manifest.globalConfig) 560 defaults = self.manifest.globalConfig)
558 561
559 if self.worktree: 562 if self.worktree:
560 self.work_git = self._GitGetByExec(self, bare=False) 563 self.work_git = self._GitGetByExec(self, bare=False, gitdir=gitdir)
561 else: 564 else:
562 self.work_git = None 565 self.work_git = None
563 self.bare_git = self._GitGetByExec(self, bare=True) 566 self.bare_git = self._GitGetByExec(self, bare=True, gitdir=gitdir)
564 self.bare_ref = GitRefs(gitdir) 567 self.bare_ref = GitRefs(gitdir)
568 self.bare_objdir = self._GitGetByExec(self, bare=True, gitdir=objdir)
565 self.dest_branch = dest_branch 569 self.dest_branch = dest_branch
566 570
567 # This will be filled in if a project is later identified to be the 571 # This will be filled in if a project is later identified to be the
@@ -1069,6 +1073,7 @@ class Project(object):
1069 """Perform only the local IO portion of the sync process. 1073 """Perform only the local IO portion of the sync process.
1070 Network access is not required. 1074 Network access is not required.
1071 """ 1075 """
1076 self._InitWorkTree()
1072 all_refs = self.bare_ref.all 1077 all_refs = self.bare_ref.all
1073 self.CleanPublishedCache(all_refs) 1078 self.CleanPublishedCache(all_refs)
1074 revid = self.GetRevisionId(all_refs) 1079 revid = self.GetRevisionId(all_refs)
@@ -1077,7 +1082,6 @@ class Project(object):
1077 self._FastForward(revid) 1082 self._FastForward(revid)
1078 self._CopyFiles() 1083 self._CopyFiles()
1079 1084
1080 self._InitWorkTree()
1081 head = self.work_git.GetHead() 1085 head = self.work_git.GetHead()
1082 if head.startswith(R_HEADS): 1086 if head.startswith(R_HEADS):
1083 branch = head[len(R_HEADS):] 1087 branch = head[len(R_HEADS):]
@@ -1544,11 +1548,13 @@ class Project(object):
1544 return result 1548 return result
1545 for rev, path, url in self._GetSubmodules(): 1549 for rev, path, url in self._GetSubmodules():
1546 name = self.manifest.GetSubprojectName(self, path) 1550 name = self.manifest.GetSubprojectName(self, path)
1547 project = self.manifest.projects.get(name) 1551 relpath, worktree, gitdir, objdir = \
1552 self.manifest.GetSubprojectPaths(self, name, path)
1553 project = self.manifest.paths.get(relpath)
1548 if project: 1554 if project:
1549 result.extend(project.GetDerivedSubprojects()) 1555 result.extend(project.GetDerivedSubprojects())
1550 continue 1556 continue
1551 relpath, worktree, gitdir = self.manifest.GetSubprojectPaths(self, path) 1557
1552 remote = RemoteSpec(self.remote.name, 1558 remote = RemoteSpec(self.remote.name,
1553 url = url, 1559 url = url,
1554 review = self.remote.review) 1560 review = self.remote.review)
@@ -1556,6 +1562,7 @@ class Project(object):
1556 name = name, 1562 name = name,
1557 remote = remote, 1563 remote = remote,
1558 gitdir = gitdir, 1564 gitdir = gitdir,
1565 objdir = objdir,
1559 worktree = worktree, 1566 worktree = worktree,
1560 relpath = relpath, 1567 relpath = relpath,
1561 revisionExpr = self.revisionExpr, 1568 revisionExpr = self.revisionExpr,
@@ -1905,8 +1912,17 @@ class Project(object):
1905 1912
1906 def _InitGitDir(self, mirror_git=None): 1913 def _InitGitDir(self, mirror_git=None):
1907 if not os.path.exists(self.gitdir): 1914 if not os.path.exists(self.gitdir):
1908 os.makedirs(self.gitdir) 1915
1909 self.bare_git.init() 1916 # Initialize the bare repository, which contains all of the objects.
1917 if not os.path.exists(self.objdir):
1918 os.makedirs(self.objdir)
1919 self.bare_objdir.init()
1920
1921 # If we have a separate directory to hold refs, initialize it as well.
1922 if self.objdir != self.gitdir:
1923 os.makedirs(self.gitdir)
1924 self._ReferenceGitDir(self.objdir, self.gitdir, share_refs=False,
1925 copy_all=True)
1910 1926
1911 mp = self.manifest.manifestProject 1927 mp = self.manifest.manifestProject
1912 ref_dir = mp.config.GetString('repo.reference') or '' 1928 ref_dir = mp.config.GetString('repo.reference') or ''
@@ -2022,33 +2038,61 @@ class Project(object):
2022 msg = 'manifest set to %s' % self.revisionExpr 2038 msg = 'manifest set to %s' % self.revisionExpr
2023 self.bare_git.symbolic_ref('-m', msg, ref, dst) 2039 self.bare_git.symbolic_ref('-m', msg, ref, dst)
2024 2040
2041 def _ReferenceGitDir(self, gitdir, dotgit, share_refs, copy_all):
2042 """Update |dotgit| to reference |gitdir|, using symlinks where possible.
2043
2044 Args:
2045 gitdir: The bare git repository. Must already be initialized.
2046 dotgit: The repository you would like to initialize.
2047 share_refs: If true, |dotgit| will store its refs under |gitdir|.
2048 Only one work tree can store refs under a given |gitdir|.
2049 copy_all: If true, copy all remaining files from |gitdir| -> |dotgit|.
2050 This saves you the effort of initializing |dotgit| yourself.
2051 """
2052 # These objects can be shared between several working trees.
2053 symlink_files = ['description', 'info']
2054 symlink_dirs = ['hooks', 'objects', 'rr-cache', 'svn']
2055 if share_refs:
2056 # These objects can only be used by a single working tree.
2057 symlink_files += ['config', 'packed-refs']
2058 symlink_dirs += ['logs', 'refs']
2059 to_symlink = symlink_files + symlink_dirs
2060
2061 to_copy = []
2062 if copy_all:
2063 to_copy = os.listdir(gitdir)
2064
2065 for name in set(to_copy).union(to_symlink):
2066 try:
2067 src = os.path.realpath(os.path.join(gitdir, name))
2068 dst = os.path.realpath(os.path.join(dotgit, name))
2069
2070 if os.path.lexists(dst) and not os.path.islink(dst):
2071 raise GitError('cannot overwrite a local work tree')
2072
2073 # If the source dir doesn't exist, create an empty dir.
2074 if name in symlink_dirs and not os.path.lexists(src):
2075 os.makedirs(src)
2076
2077 if name in to_symlink:
2078 os.symlink(os.path.relpath(src, os.path.dirname(dst)), dst)
2079 elif copy_all and not os.path.islink(dst):
2080 if os.path.isdir(src):
2081 shutil.copytree(src, dst)
2082 elif os.path.isfile(src):
2083 shutil.copy(src, dst)
2084 except OSError as e:
2085 if e.errno == errno.EPERM:
2086 raise GitError('filesystem must support symlinks')
2087 else:
2088 raise
2089
2025 def _InitWorkTree(self): 2090 def _InitWorkTree(self):
2026 dotgit = os.path.join(self.worktree, '.git') 2091 dotgit = os.path.join(self.worktree, '.git')
2027 if not os.path.exists(dotgit): 2092 if not os.path.exists(dotgit):
2028 os.makedirs(dotgit) 2093 os.makedirs(dotgit)
2029 2094 self._ReferenceGitDir(self.gitdir, dotgit, share_refs=True,
2030 for name in ['config', 2095 copy_all=False)
2031 'description',
2032 'hooks',
2033 'info',
2034 'logs',
2035 'objects',
2036 'packed-refs',
2037 'refs',
2038 'rr-cache',
2039 'svn']:
2040 try:
2041 src = os.path.join(self.gitdir, name)
2042 dst = os.path.join(dotgit, name)
2043 if os.path.islink(dst) or not os.path.exists(dst):
2044 os.symlink(os.path.relpath(src, os.path.dirname(dst)), dst)
2045 else:
2046 raise GitError('cannot overwrite a local work tree')
2047 except OSError as e:
2048 if e.errno == errno.EPERM:
2049 raise GitError('filesystem must support symlinks')
2050 else:
2051 raise
2052 2096
2053 _lwrite(os.path.join(dotgit, HEAD), '%s\n' % self.GetRevisionId()) 2097 _lwrite(os.path.join(dotgit, HEAD), '%s\n' % self.GetRevisionId())
2054 2098
@@ -2058,14 +2102,10 @@ class Project(object):
2058 if GitCommand(self, cmd).Wait() != 0: 2102 if GitCommand(self, cmd).Wait() != 0:
2059 raise GitError("cannot initialize work tree") 2103 raise GitError("cannot initialize work tree")
2060 2104
2061 rr_cache = os.path.join(self.gitdir, 'rr-cache')
2062 if not os.path.exists(rr_cache):
2063 os.makedirs(rr_cache)
2064
2065 self._CopyFiles() 2105 self._CopyFiles()
2066 2106
2067 def _gitdir_path(self, path): 2107 def _gitdir_path(self, path):
2068 return os.path.join(self.gitdir, path) 2108 return os.path.realpath(os.path.join(self.gitdir, path))
2069 2109
2070 def _revlist(self, *args, **kw): 2110 def _revlist(self, *args, **kw):
2071 a = [] 2111 a = []
@@ -2078,9 +2118,10 @@ class Project(object):
2078 return self.bare_ref.all 2118 return self.bare_ref.all
2079 2119
2080 class _GitGetByExec(object): 2120 class _GitGetByExec(object):
2081 def __init__(self, project, bare): 2121 def __init__(self, project, bare, gitdir):
2082 self._project = project 2122 self._project = project
2083 self._bare = bare 2123 self._bare = bare
2124 self._gitdir = gitdir
2084 2125
2085 def LsOthers(self): 2126 def LsOthers(self):
2086 p = GitCommand(self._project, 2127 p = GitCommand(self._project,
@@ -2089,6 +2130,7 @@ class Project(object):
2089 '--others', 2130 '--others',
2090 '--exclude-standard'], 2131 '--exclude-standard'],
2091 bare = False, 2132 bare = False,
2133 gitdir=self._gitdir,
2092 capture_stdout = True, 2134 capture_stdout = True,
2093 capture_stderr = True) 2135 capture_stderr = True)
2094 if p.Wait() == 0: 2136 if p.Wait() == 0:
@@ -2104,6 +2146,7 @@ class Project(object):
2104 cmd.extend(args) 2146 cmd.extend(args)
2105 p = GitCommand(self._project, 2147 p = GitCommand(self._project,
2106 cmd, 2148 cmd,
2149 gitdir=self._gitdir,
2107 bare = False, 2150 bare = False,
2108 capture_stdout = True, 2151 capture_stdout = True,
2109 capture_stderr = True) 2152 capture_stderr = True)
@@ -2213,6 +2256,7 @@ class Project(object):
2213 p = GitCommand(self._project, 2256 p = GitCommand(self._project,
2214 cmdv, 2257 cmdv,
2215 bare = self._bare, 2258 bare = self._bare,
2259 gitdir=self._gitdir,
2216 capture_stdout = True, 2260 capture_stdout = True,
2217 capture_stderr = True) 2261 capture_stderr = True)
2218 r = [] 2262 r = []
@@ -2265,6 +2309,7 @@ class Project(object):
2265 p = GitCommand(self._project, 2309 p = GitCommand(self._project,
2266 cmdv, 2310 cmdv,
2267 bare = self._bare, 2311 bare = self._bare,
2312 gitdir=self._gitdir,
2268 capture_stdout = True, 2313 capture_stdout = True,
2269 capture_stderr = True) 2314 capture_stderr = True)
2270 if p.Wait() != 0: 2315 if p.Wait() != 0:
@@ -2398,6 +2443,7 @@ class MetaProject(Project):
2398 manifest = manifest, 2443 manifest = manifest,
2399 name = name, 2444 name = name,
2400 gitdir = gitdir, 2445 gitdir = gitdir,
2446 objdir = gitdir,
2401 worktree = worktree, 2447 worktree = worktree,
2402 remote = RemoteSpec('origin'), 2448 remote = RemoteSpec('origin'),
2403 relpath = '.repo/%s' % name, 2449 relpath = '.repo/%s' % name,