Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ead7ef6e authored by Rupert Shuttleworth's avatar Rupert Shuttleworth
Browse files

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
parent 0ec64e5d
Loading
Loading
Loading
Loading
+27 −14
Original line number Diff line number Diff line
@@ -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)
			}
		}
	}
}