Use lstat instead of stat to avoid permissions issues when creating symlinks.

Also refactor symlink code slightly and add some more error checking.

Test: Manually.
Change-Id: I75119707cdf497e5690ac57abd814c8f18cab1f8
This commit is contained in:
Rupert Shuttleworth 2020-12-04 01:05:59 +00:00
parent 0ec64e5df7
commit ead7ef6e3b

View file

@ -189,6 +189,7 @@ func runBazel(ctx Context, config Config) {
// currently hardcoded as ninja_build.output_root.
bazelNinjaBuildOutputRoot := filepath.Join(outputBasePath, "..", "out")
ctx.Println("Creating output symlinks..")
symlinkOutdir(ctx, config, bazelNinjaBuildOutputRoot, ".")
}
@ -201,27 +202,39 @@ func symlinkOutdir(ctx Context, config Config, rootPath string, relativePath str
if err != nil {
ctx.Fatal(err)
}
for _, f := range files {
// The original Bazel file path
destPath := filepath.Join(destDir, f.Name())
// The desired Soong file path
srcPath := filepath.Join(config.OutDir(), relativePath, f.Name())
if statResult, err := os.Stat(srcPath); err == nil {
if statResult.Mode().IsDir() && f.IsDir() {
// Directory under OutDir already exists, so recurse on its contents.
destLstatResult, destLstatErr := os.Lstat(destPath)
if destLstatErr != nil {
ctx.Fatalf("Unable to Lstat dest %s: %s", destPath, destLstatErr)
}
srcLstatResult, srcLstatErr := os.Lstat(srcPath)
if srcLstatErr == nil {
if srcLstatResult.IsDir() && destLstatResult.IsDir() {
// src and dest are both existing dirs - recurse on the dest dir contents...
symlinkOutdir(ctx, config, rootPath, filepath.Join(relativePath, f.Name()))
} else if !statResult.Mode().IsDir() && !f.IsDir() {
// File exists both in source and destination, and it's not a directory
// in either location. Do nothing.
// This can arise for files which are generated under OutDir outside of
// soong_build, such as .bootstrap files.
} else {
// File is a directory in one location but not the other. Raise an error.
ctx.Fatalf("Could not link %s to %s due to conflict", srcPath, destPath)
// Ignore other pre-existing src files (could be pre-existing files, directories, symlinks, ...)
// This can arise for files which are generated under OutDir outside of soong_build, such as .bootstrap files.
// FIXME: This might cause a problem later e.g. if a symlink in the build graph changes...
}
} else if os.IsNotExist(err) {
// Create symlink srcPath -> fullDestPath.
os.Symlink(destPath, srcPath)
} else {
ctx.Fatalf("Unable to stat %s: %s", srcPath, err)
if !os.IsNotExist(srcLstatErr) {
ctx.Fatalf("Unable to Lstat src %s: %s", srcPath, srcLstatErr)
}
// src does not exist, so try to create a src -> dest symlink (i.e. a Soong path -> Bazel path symlink)
if symlinkErr := os.Symlink(destPath, srcPath); symlinkErr != nil {
ctx.Fatalf("Unable to create symlink %s -> %s due to error %s", srcPath, destPath, symlinkErr)
}
}
}
}