예제 #1
0
        public void DirectorySymlinksAreTraversed()
        {
            string rootDir           = Path.Combine(TemporaryDirectory, nameof(DirectorySymlinksAreTraversed));
            string fullTargetDirPath = Path.Combine(rootDir, "target-dir");

            Directory.CreateDirectory(fullTargetDirPath);

            var fileUnderTarget = Path.Combine(fullTargetDirPath, "file.txt");

            File.WriteAllText(fileUnderTarget, "content");

            string rootToScrub = Path.Combine(rootDir, "root-to-scrub");

            Directory.CreateDirectory(rootToScrub);

            string fullSymlinkPath = WriteSymlink(Path.Combine(rootToScrub, "directory symlink"), fullTargetDirPath, isTargetFile: false);

            XAssert.IsTrue(FileUtilities.FileExistsNoFollow(fullSymlinkPath));

            // Scrub starting on a root dir that contains a symlink directory. We should be able to find the file underneath and delete it
            // We consider all artifacts to be not part of the build, so symlink directories are followed and all files are deleted
            Scrubber.RemoveExtraneousFilesAndDirectories(
                isPathInBuild: path => false,
                pathsToScrub: new[] { rootDir },
                blockedPaths: CollectionUtilities.EmptyArray <string>(),
                nonDeletableRootDirectories: CollectionUtilities.EmptyArray <string>());

            XAssert.IsFalse(File.Exists(fileUnderTarget));
            XAssert.Equals(OperatingSystemHelper.IsMacOS, !Directory.Exists(fullSymlinkPath));
        }
예제 #2
0
        public void ScrubbingDirectoriesWithMounts()
        {
            string       rootDirectory             = Path.Combine(TemporaryDirectory, nameof(ScrubbingDirectoriesWithMounts));
            const string NonScrubbableMountName    = "NonScrubbable";
            string       nonScrubbableMountPath    = Path.Combine(rootDirectory, NonScrubbableMountName);
            const string ScrubbableMountName       = "Scrubbable";
            string       scrubbableMountPath       = Path.Combine(rootDirectory, ScrubbableMountName);
            const string NestedScrubbableMountName = "NestedScrubbable";
            string       nestedScrubbableMountPath = Path.Combine(scrubbableMountPath, NestedScrubbableMountName);

            MountPathExpander mountPathExpander =
                CreateMountPathExpander(
                    new TestMount(NonScrubbableMountName, nonScrubbableMountPath, MountFeatures.Writable | MountFeatures.Readable),
                    new TestMount(ScrubbableMountName, scrubbableMountPath, MountFeatures.Scrubbable),
                    new TestMount(NestedScrubbableMountName, nestedScrubbableMountPath, MountFeatures.Scrubbable));
            string f       = WriteFile(Path.Combine(nonScrubbableMountPath, "D", "f"));
            string g1      = WriteFile(Path.Combine(scrubbableMountPath, "D", "g1"));
            string g2      = WriteFile(Path.Combine(scrubbableMountPath, "D", "g2"));
            string h       = WriteFile(Path.Combine(scrubbableMountPath, "D", "E", "h"));
            string i       = WriteFile(Path.Combine(scrubbableMountPath, "D", "F", "i"));
            string j       = WriteFile(Path.Combine(nestedScrubbableMountPath, "D", "j"));
            var    inBuild = new HashSet <string>(OperatingSystemHelper.PathComparer)
            {
                Path.Combine(scrubbableMountPath, "D", "E"), g1
            };

            Scrubber.RemoveExtraneousFilesAndDirectories(
                path => inBuild.Contains(path),
                pathsToScrub: new[] { Path.Combine(nonScrubbableMountPath, "D"), scrubbableMountPath },
                blockedPaths: new string[0],
                nonDeletableRootDirectories: new string[0],
                mountPathExpander: mountPathExpander);

            // NonScrubbable\D produces a warning.
            AssertWarningEventLogged(global::BuildXL.Engine.Tracing.LogEventId.ScrubbingFailedBecauseDirectoryIsNotScrubbable);

            // f is in NonScrubbable.
            XAssert.IsTrue(File.Exists(f));

            // g1 & h (via Scrubbable\D\E) is in build.
            XAssert.IsTrue(File.Exists(g1));
            XAssert.IsTrue(File.Exists(h));

            // NestedScrubbable, although not in build, but is a mount root.
            XAssert.IsTrue(Directory.Exists(nestedScrubbableMountPath));

            // Scrubbed files/directories.
            XAssert.IsFalse(File.Exists(g2));
            XAssert.IsFalse(File.Exists(i));
            XAssert.IsFalse(Directory.Exists(Path.Combine(scrubbableMountPath, "D", "F")));
            XAssert.IsFalse(File.Exists(j));
            XAssert.IsFalse(Directory.Exists(Path.Combine(nestedScrubbableMountPath, "D")));
        }
예제 #3
0
        public void DoNotScrubDeclaredOutputDirectories()
        {
            string rootDirectory = Path.Combine(TemporaryDirectory, nameof(ScrubFilesAndDirectories));
            string a             = WriteFile(Path.Combine(rootDirectory, "1", "1", "out.txt"));
            var    inBuild       = new HashSet <string>(OperatingSystemHelper.PathComparer)
            {
                Path.GetDirectoryName(a)
            };

            Scrubber.RemoveExtraneousFilesAndDirectories(
                isPathInBuild: path => inBuild.Contains(path),
                pathsToScrub: new[] { Path.GetDirectoryName(a) },
                blockedPaths: new string[] { },
                nonDeletableRootDirectories: new string[0]);

            XAssert.IsTrue(File.Exists(a));
        }
예제 #4
0
        public void SymlinkDirectoriesDoNotIntroduceDuplicateWork()
        {
            // We are creating this layout
            //
            // root
            // -- real-dir
            //    -- symlink-dir -> real-dir
            //       --file.txt
            //
            // so there is in fact a cycle, where root/real-dir/symlink-dir/.../symlink-dir/... is a valid path
            // The fact that scrubbing finishes proves we are deduping work

            string rootDir       = Path.Combine(TemporaryDirectory, nameof(SymlinkDirectoriesDoNotIntroduceDuplicateWork));
            string realDirectory = Path.Combine(rootDir, "real-dir");

            Directory.CreateDirectory(realDirectory);

            string symlinkDirectory = WriteSymlink(Path.Combine(realDirectory, "symlink-dir"), rootDir, isTargetFile: false);

            XAssert.IsTrue(FileUtilities.FileExistsNoFollow(symlinkDirectory));

            var fileUnderSymlinkDir = Path.Combine(symlinkDirectory, "file.txt");

            File.WriteAllText(fileUnderSymlinkDir, "content");

            try
            {
                Scrubber.RemoveExtraneousFilesAndDirectories(
                    isPathInBuild: path => false,
                    pathsToScrub: new[] { rootDir },
                    blockedPaths: CollectionUtilities.EmptyArray <string>(),
                    nonDeletableRootDirectories: CollectionUtilities.EmptyArray <string>());

                XAssert.IsFalse(File.Exists(fileUnderSymlinkDir));
                XAssert.Equals(!OperatingSystemHelper.IsMacOS, Directory.Exists(realDirectory));
                XAssert.Equals(!OperatingSystemHelper.IsMacOS, Directory.Exists(symlinkDirectory));
            }
            finally
            {
                // On Windows, the temp directory cleaner has problems with cycles. So let's remove the symlink dir explicitly here
                if (!OperatingSystemHelper.IsMacOS)
                {
                    Directory.Delete(symlinkDirectory);
                }
            }
        }
예제 #5
0
        public void DontScrubBlockedPathsEvenIfAskedTo()
        {
            string rootDirectory = Path.Combine(TemporaryDirectory, nameof(ScrubFilesAndDirectories));
            string a             = WriteFile(Path.Combine(rootDirectory, "a", "b", "c", "out.txt"));

            var inBuild = new HashSet <string>(OperatingSystemHelper.PathComparer)
            {
            };

            Scrubber.RemoveExtraneousFilesAndDirectories(
                path => inBuild.Contains(path),
                pathsToScrub: new[] { rootDirectory },
                blockedPaths: new[] { rootDirectory },
                nonDeletableRootDirectories: new string[0]);

            // The file should still exist since it is under a blocked path
            XAssert.IsTrue(File.Exists(a));
        }
예제 #6
0
        public void ScrubFilesAndDirectories()
        {
            // Create a layout with various paths. We will clean at the root dir.
            // Some files will be in the build, some out, and some paths excluded
            string rootDirectory = Path.Combine(TemporaryDirectory, nameof(ScrubFilesAndDirectories));
            string a             = WriteFile(Path.Combine(rootDirectory, "1", "1", "out.txt"));
            string b             = WriteFile(Path.Combine(rootDirectory, "1", "out.txt"));
            string c             = WriteFile(Path.Combine(rootDirectory, "2", "1", "in.txt"));
            string d             = WriteFile(Path.Combine(rootDirectory, "2", "2", "in.txt"));
            string e             = WriteFile(Path.Combine(rootDirectory, "2", "2", "out.txt"));
            string f             = WriteFile(Path.Combine(rootDirectory, "3", "out.txt"));
            string g             = WriteFile(Path.Combine(rootDirectory, "4", "out.txt"));
            string h             = WriteFile(Path.Combine(rootDirectory, "5", "6", "out.txt"));
            string i             = WriteFile(Path.Combine(rootDirectory, "5", "out.txt"));

            var inBuild = new HashSet <string>(OperatingSystemHelper.PathComparer)
            {
                c, d, Path.GetDirectoryName(f)
            };

            Scrubber.RemoveExtraneousFilesAndDirectories(
                pathsToScrub: new[] { rootDirectory },
                isPathInBuild: path => inBuild.Contains(path),
                blockedPaths: new[] { Path.Combine(rootDirectory, "1"), Path.Combine(rootDirectory, "5", "6") },
                nonDeletableRootDirectories: new string[0]);

            // Files in the "1" directory should still exist even though they were not in the build, since that directory was excluded.
            XAssert.IsTrue(File.Exists(a));
            XAssert.IsTrue(File.Exists(b));

            // The files that were in the build should still exist.
            XAssert.IsTrue(File.Exists(c));
            XAssert.IsTrue(File.Exists(d));
            XAssert.IsTrue(File.Exists(f));

            // File in the blocked path still exists.
            XAssert.IsTrue(File.Exists(h));

            // The file outside of the build should not exist.
            XAssert.IsFalse(File.Exists(e));
            XAssert.IsFalse(Directory.Exists(Path.GetDirectoryName(g)));
            XAssert.IsFalse(File.Exists(i));
        }
예제 #7
0
        public void DirectorySymlinksUnderSharedOpaquesArePreservedIfNonEmpty()
        {
            string rootDir           = Path.Combine(TemporaryDirectory, nameof(DirectorySymlinksUnderSharedOpaquesArePreservedIfNonEmpty));
            string fullTargetDirPath = Path.Combine(rootDir, "target-dir");

            Directory.CreateDirectory(fullTargetDirPath);
            XAssert.IsTrue(Directory.Exists(fullTargetDirPath));

            var fileUnderTarget = Path.Combine(fullTargetDirPath, "file.txt");

            File.WriteAllText(fileUnderTarget, "content");

            string fullSymlinkPath = WriteSymlink(Path.Combine(rootDir, "directory symlink"), fullTargetDirPath, isTargetFile: false);

            XAssert.IsTrue(FileUtilities.FileExistsNoFollow(fullSymlinkPath));

            if (OperatingSystemHelper.IsMacOS)
            {
                SharedOpaqueOutputHelper.EnforceFileIsSharedOpaqueOutput(fullSymlinkPath);
                XAssert.IsTrue(SharedOpaqueOutputHelper.IsSharedOpaqueOutput(fullSymlinkPath));
            }

            // This is somewhat subtle. On Windows, IsSharedOpaqueOutput will say yes for any directory, including symlink directories. This means they won't be
            // considered part of the build and therefore should be traversed.
            // So if the symlink is traversed, fileUnderTarget will be found, which is not a shared opaque output. So the file won't be deleted. And
            // so nor the symlink directory. If the symlink directory wasn't traversed, then it would be deleted.
            Scrubber.RemoveExtraneousFilesAndDirectories(
                isPathInBuild: path => !SharedOpaqueOutputHelper.IsSharedOpaqueOutput(path),
                pathsToScrub: new[] { rootDir },
                blockedPaths: CollectionUtilities.EmptyArray <string>(),
                nonDeletableRootDirectories: CollectionUtilities.EmptyArray <string>());

            XAssert.FileExists(fileUnderTarget);

            // On Mac:
            //   - any symlink is a file, any file under shared opaque dir gets scrubber ==> fullSymlinkPath should be scrubbed
            //
            // On Windows:
            //   - directories under shared opaques are always removed unless they have files underneath that shouldn't be
            //     removed. This test verifies this behavior also applies to symlink directories
            XAssert.AreEqual(!OperatingSystemHelper.IsMacOS, Directory.Exists(fullSymlinkPath));
        }