diff options
Diffstat (limited to 'project.py')
-rw-r--r-- | project.py | 118 |
1 files changed, 82 insertions, 36 deletions
@@ -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, |