summaryrefslogtreecommitdiffstats
path: root/project.py
diff options
context:
space:
mode:
authorKevin Degi <kdegi@codeaurora.org>2014-10-16 16:02:58 -0600
committerKevin Degi <kdegi@codeaurora.org>2015-05-12 09:15:53 -0600
commit384b3c594831e79348a2eb98809ef9f3e34f6aa2 (patch)
tree12c9b77879b0937358a9a5fa96d2a1c562180066 /project.py
parent4ccad7554b958c701653c41a72442cccf301e71a (diff)
downloadgit-repo-384b3c594831e79348a2eb98809ef9f3e34f6aa2.tar.gz
Fail if gitdir does not point to objdir during sync
There are a set of cases that can cause the git directory in .repo/projects to point to a directory in .repo/project-objects that is not the one specified in the manifest. This results in a tree that is not sane, and so should cause a failure. In order to reproduce the failure case: 1) Sync to any manifest 2) Change the 'name' of a project to a different repository. Leave the 'path' the same. 3) Resync the modified project. The project-objects directory will not be created, and the projects directory will remain pointed at the old project-objects. Change-Id: Ie6711b1c773508850c5c9f748a27ff72d65e2bf2
Diffstat (limited to 'project.py')
-rw-r--r--project.py67
1 files changed, 47 insertions, 20 deletions
diff --git a/project.py b/project.py
index 6217aec8..003489aa 100644
--- a/project.py
+++ b/project.py
@@ -511,6 +511,12 @@ class RepoHook(object):
511 511
512 512
513class Project(object): 513class Project(object):
514 # These objects can be shared between several working trees.
515 shareable_files = ['description', 'info']
516 shareable_dirs = ['hooks', 'objects', 'rr-cache', 'svn']
517 # These objects can only be used by a single working tree.
518 working_tree_files = ['config', 'packed-refs', 'shallow']
519 working_tree_dirs = ['logs', 'refs']
514 def __init__(self, 520 def __init__(self,
515 manifest, 521 manifest,
516 name, 522 name,
@@ -608,7 +614,7 @@ class Project(object):
608 614
609 @property 615 @property
610 def Exists(self): 616 def Exists(self):
611 return os.path.isdir(self.gitdir) 617 return os.path.isdir(self.gitdir) and os.path.isdir(self.objdir)
612 618
613 @property 619 @property
614 def CurrentBranch(self): 620 def CurrentBranch(self):
@@ -1093,7 +1099,6 @@ class Project(object):
1093 "%s" % (tarpath, str(e)), file=sys.stderr) 1099 "%s" % (tarpath, str(e)), file=sys.stderr)
1094 self._CopyAndLinkFiles() 1100 self._CopyAndLinkFiles()
1095 return True 1101 return True
1096
1097 if is_new is None: 1102 if is_new is None:
1098 is_new = not self.Exists 1103 is_new = not self.Exists
1099 if is_new: 1104 if is_new:
@@ -2110,19 +2115,24 @@ class Project(object):
2110 raise GitError('%s merge %s ' % (self.name, head)) 2115 raise GitError('%s merge %s ' % (self.name, head))
2111 2116
2112 def _InitGitDir(self, mirror_git=None): 2117 def _InitGitDir(self, mirror_git=None):
2113 if not os.path.exists(self.gitdir): 2118 init_git_dir = not os.path.exists(self.gitdir)
2114 2119 init_obj_dir = not os.path.exists(self.objdir)
2115 # Initialize the bare repository, which contains all of the objects. 2120 # Initialize the bare repository, which contains all of the objects.
2116 if not os.path.exists(self.objdir): 2121 if init_obj_dir:
2117 os.makedirs(self.objdir) 2122 os.makedirs(self.objdir)
2118 self.bare_objdir.init() 2123 self.bare_objdir.init()
2119 2124
2120 # If we have a separate directory to hold refs, initialize it as well. 2125 # If we have a separate directory to hold refs, initialize it as well.
2121 if self.objdir != self.gitdir: 2126 if self.objdir != self.gitdir:
2127 if init_git_dir:
2122 os.makedirs(self.gitdir) 2128 os.makedirs(self.gitdir)
2129
2130 if init_obj_dir or init_git_dir:
2123 self._ReferenceGitDir(self.objdir, self.gitdir, share_refs=False, 2131 self._ReferenceGitDir(self.objdir, self.gitdir, share_refs=False,
2124 copy_all=True) 2132 copy_all=True)
2133 self._CheckDirReference(self.objdir, self.gitdir, share_refs=False)
2125 2134
2135 if init_git_dir:
2126 mp = self.manifest.manifestProject 2136 mp = self.manifest.manifestProject
2127 ref_dir = mp.config.GetString('repo.reference') or '' 2137 ref_dir = mp.config.GetString('repo.reference') or ''
2128 2138
@@ -2228,6 +2238,21 @@ class Project(object):
2228 msg = 'manifest set to %s' % self.revisionExpr 2238 msg = 'manifest set to %s' % self.revisionExpr
2229 self.bare_git.symbolic_ref('-m', msg, ref, dst) 2239 self.bare_git.symbolic_ref('-m', msg, ref, dst)
2230 2240
2241 def _CheckDirReference(self, srcdir, destdir, share_refs):
2242 symlink_files = self.shareable_files
2243 symlink_dirs = self.shareable_dirs
2244 if share_refs:
2245 symlink_files += self.working_tree_files
2246 symlink_dirs += self.working_tree_dirs
2247 to_symlink = symlink_files + symlink_dirs
2248 for name in set(to_symlink):
2249 dst = os.path.realpath(os.path.join(destdir, name))
2250 if os.path.lexists(dst):
2251 src = os.path.realpath(os.path.join(srcdir, name))
2252 # Fail if the links are pointing to the wrong place
2253 if src != dst:
2254 raise GitError('cannot overwrite a local work tree')
2255
2231 def _ReferenceGitDir(self, gitdir, dotgit, share_refs, copy_all): 2256 def _ReferenceGitDir(self, gitdir, dotgit, share_refs, copy_all):
2232 """Update |dotgit| to reference |gitdir|, using symlinks where possible. 2257 """Update |dotgit| to reference |gitdir|, using symlinks where possible.
2233 2258
@@ -2239,13 +2264,11 @@ class Project(object):
2239 copy_all: If true, copy all remaining files from |gitdir| -> |dotgit|. 2264 copy_all: If true, copy all remaining files from |gitdir| -> |dotgit|.
2240 This saves you the effort of initializing |dotgit| yourself. 2265 This saves you the effort of initializing |dotgit| yourself.
2241 """ 2266 """
2242 # These objects can be shared between several working trees. 2267 symlink_files = self.shareable_files
2243 symlink_files = ['description', 'info'] 2268 symlink_dirs = self.shareable_dirs
2244 symlink_dirs = ['hooks', 'objects', 'rr-cache', 'svn']
2245 if share_refs: 2269 if share_refs:
2246 # These objects can only be used by a single working tree. 2270 symlink_files += self.working_tree_files
2247 symlink_files += ['config', 'packed-refs', 'shallow'] 2271 symlink_dirs += self.working_tree_dirs
2248 symlink_dirs += ['logs', 'refs']
2249 to_symlink = symlink_files + symlink_dirs 2272 to_symlink = symlink_files + symlink_dirs
2250 2273
2251 to_copy = [] 2274 to_copy = []
@@ -2257,8 +2280,8 @@ class Project(object):
2257 src = os.path.realpath(os.path.join(gitdir, name)) 2280 src = os.path.realpath(os.path.join(gitdir, name))
2258 dst = os.path.realpath(os.path.join(dotgit, name)) 2281 dst = os.path.realpath(os.path.join(dotgit, name))
2259 2282
2260 if os.path.lexists(dst) and not os.path.islink(dst): 2283 if os.path.lexists(dst):
2261 raise GitError('cannot overwrite a local work tree') 2284 continue
2262 2285
2263 # If the source dir doesn't exist, create an empty dir. 2286 # If the source dir doesn't exist, create an empty dir.
2264 if name in symlink_dirs and not os.path.lexists(src): 2287 if name in symlink_dirs and not os.path.lexists(src):
@@ -2287,11 +2310,15 @@ class Project(object):
2287 2310
2288 def _InitWorkTree(self): 2311 def _InitWorkTree(self):
2289 dotgit = os.path.join(self.worktree, '.git') 2312 dotgit = os.path.join(self.worktree, '.git')
2290 if not os.path.exists(dotgit): 2313 init_dotgit = not os.path.exists(dotgit)
2314 if init_dotgit:
2291 os.makedirs(dotgit) 2315 os.makedirs(dotgit)
2292 self._ReferenceGitDir(self.gitdir, dotgit, share_refs=True, 2316 self._ReferenceGitDir(self.gitdir, dotgit, share_refs=True,
2293 copy_all=False) 2317 copy_all=False)
2294 2318
2319 self._CheckDirReference(self.gitdir, dotgit, share_refs=True)
2320
2321 if init_dotgit:
2295 _lwrite(os.path.join(dotgit, HEAD), '%s\n' % self.GetRevisionId()) 2322 _lwrite(os.path.join(dotgit, HEAD), '%s\n' % self.GetRevisionId())
2296 2323
2297 cmd = ['read-tree', '--reset', '-u'] 2324 cmd = ['read-tree', '--reset', '-u']