From ed4f2113d22e7cc8ccc13c15ad6d5b18926d95d7 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 11 Feb 2020 23:06:29 -0500 Subject: project: make syncing a little more self-healing We have a few files that we optionally symlink from the work tree .git/ to the .repo/projects/ path. If they don't exist when we first initialize, then we skip creating symlinks. If the files are created later on under the work tree .git/, repo gets upset. This can happen with the packed-refs file: if we don't have any packed refs initially, we don't symlink it. But if git tries to pack refs later on and creates the file, the project gets wedged. We could create an empty file initially and then symlink it, but for some files, it's not clear we want to always do that (e.g. the .git/shallow setting). Instead, lets make handling of these paths more dynamic. If they show up later on in the work tree .git/ only, we'll take care of relocating & symlinking. This also makes repo a little more robust and autorecovers incase a path goes missing in one of the dirs. Ideally we wouldn't monkey around at all here, but considering the only option we give to users currently is to blow things away with --force-sync, this seems a bit better. Bug: https://crbug.com/gerrit/12324 Change-Id: Ia6960f1896ac6d890c762d7d053684a1c6ab2c87 Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/254632 Reviewed-by: David Pursehouse Tested-by: Mike Frysinger --- project.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'project.py') diff --git a/project.py b/project.py index 3643762e..382650fb 100644 --- a/project.py +++ b/project.py @@ -2760,9 +2760,31 @@ class Project(object): symlink_dirs += self.working_tree_dirs to_symlink = symlink_files + symlink_dirs for name in set(to_symlink): - dst = platform_utils.realpath(os.path.join(destdir, name)) + # Try to self-heal a bit in simple cases. + dst_path = os.path.join(destdir, name) + src_path = os.path.join(srcdir, name) + + if name in self.working_tree_dirs: + # If the dir is missing under .repo/projects/, create it. + if not os.path.exists(src_path): + os.makedirs(src_path) + + elif name in self.working_tree_files: + # If it's a file under the checkout .git/ and the .repo/projects/ has + # nothing, move the file under the .repo/projects/ tree. + if not os.path.exists(src_path) and os.path.isfile(dst_path): + platform_utils.rename(dst_path, src_path) + + # If the path exists under the .repo/projects/ and there's no symlink + # under the checkout .git/, recreate the symlink. + if name in self.working_tree_dirs or name in self.working_tree_files: + if os.path.exists(src_path) and not os.path.exists(dst_path): + platform_utils.symlink( + os.path.relpath(src_path, os.path.dirname(dst_path)), dst_path) + + dst = platform_utils.realpath(dst_path) if os.path.lexists(dst): - src = platform_utils.realpath(os.path.join(srcdir, name)) + src = platform_utils.realpath(src_path) # Fail if the links are pointing to the wrong place if src != dst: _error('%s is different in %s vs %s', name, destdir, srcdir) -- cgit v1.2.3-54-g00ecf