Пример #1
0
        public void OutputsUnderSharedOpaqueAreProperlyMarkedEvenOnCacheReplay()
        {
            var file  = X("out/SharedOpaqueOutput.txt");
            var spec0 = ProduceFileUnderSharedOpaque(file);

            AddModule("Module0", ("spec0.dsc", spec0), placeInRoot: true);

            RunEngine(rememberAllChangedTrackedInputs: true);

            var objDir = Configuration.Layout.ObjectDirectory.ToString(Context.PathTable);

            var producedFile = Path.Combine(objDir, file);

            // Make sure the file was produced
            Assert.True(File.Exists(producedFile));

            // And that it has been marked as shared opaque output
            XAssert.IsTrue(SharedOpaqueOutputHelper.IsSharedOpaqueOutput(producedFile));

            File.Delete(producedFile);

            // Replay from cache this time
            RunEngine(rememberAllChangedTrackedInputs: true);

            IgnoreWarnings();
            // Make sure this is a cache replay
            AssertVerboseEventLogged(global::BuildXL.Scheduler.Tracing.LogEventId.ProcessPipCacheHit);
            // And check again that the file is still properly marked
            XAssert.IsTrue(SharedOpaqueOutputHelper.IsSharedOpaqueOutput(producedFile));
        }
        public void StaleSharedOpaqueOutputsAreNotPartOfTheFingerprint()
        {
            AbsolutePath      dirPath        = AbsolutePath.Create(Context.PathTable, Path.Combine(SourceRoot, "dir"));
            DirectoryArtifact dirToEnumerate = DirectoryArtifact.CreateWithZeroPartialSealId(dirPath);
            var    alienFile     = CreateSourceFile(root: dirPath);
            string alienFilePath = alienFile.Path.ToString(Context.PathTable);

            // Create a fake stale shared opaque output under the directory we will enumerate
            File.WriteAllText(alienFilePath, "some text");
            SharedOpaqueOutputHelper.EnforceFileIsSharedOpaqueOutput(alienFilePath);

            var builder = CreatePipBuilder(new Operation[]
            {
                Operation.EnumerateDir(dirToEnumerate, doNotInfer: true),
                Operation.WriteFile(CreateOutputFileArtifact()) // dummy output
            });

            // This makes sure we use the right file system, which is aware of alien files
            builder.Options |= global::BuildXL.Pips.Operations.Process.Options.AllowUndeclaredSourceReads;

            var pip = SchedulePipBuilder(builder);

            // Run once
            RunScheduler().AssertSuccess();
            // Delete the sharedOpaque under the enumerated directory. We should get a cache hit on re-run since
            // old outputs are ignored
            File.Delete(alienFile.Path.ToString(Context.PathTable));
            RunScheduler().AssertCacheHit(pip.Process.PipId);
        }
Пример #3
0
        public void AllowedRewrittenSourcesAreNotFlaggedAsSharedOpaques()
        {
            var objDir       = Configuration.Layout.ObjectDirectory.ToString(Context.PathTable);
            var file         = X("out/SharedOpaqueOutput.txt");
            var producedFile = Path.Combine(objDir, file);

            // Create the file beforehand so it introduces an allowed rewrite
            Directory.CreateDirectory(Directory.GetParent(producedFile).FullName);
            string originalContent  = "content";
            string rewrittenContent = "rewritten";

            File.WriteAllText(producedFile, originalContent);

            var spec0 = ProduceFileUnderSharedOpaque(file, allowSourceRewrites: true, allowUndeclaredReads: true, content: rewrittenContent);

            AddModule("Module0", ("spec0.dsc", spec0), placeInRoot: true);

            RunEngine(rememberAllChangedTrackedInputs: true);

            // Make sure the file was produced with rewritten content
            Assert.True(File.Exists(producedFile));
            Assert.Equal(rewrittenContent, File.ReadAllText(producedFile).Trim(' ', '\r', '\n'));

            // And that it has not been marked as shared opaque output
            XAssert.IsFalse(SharedOpaqueOutputHelper.IsSharedOpaqueOutput(producedFile));
            // We should place the file as a copy, not hardlinked to the cache, and therefore the file should be modifiable
            // This operation will throw otherwise
            File.AppendAllText(producedFile, " we should be able to modify the file");

            // Restore the file to its initial shape
            File.Delete(producedFile);
            File.WriteAllText(producedFile, originalContent);

            // Replay from cache this time
            RunEngine(rememberAllChangedTrackedInputs: true);

            // Make sure the file was produced with rewritten content
            Assert.True(File.Exists(producedFile));
            Assert.Equal(rewrittenContent, File.ReadAllText(producedFile).Trim(' ', '\r', '\n'));

            IgnoreWarnings();
            // Make sure this is a cache replay
            AssertVerboseEventLogged(global::BuildXL.Scheduler.Tracing.LogEventId.ProcessPipCacheHit);
            // And check again that the file is still not marked
            XAssert.IsFalse(SharedOpaqueOutputHelper.IsSharedOpaqueOutput(producedFile));
            // We should place the file as a copy, not hardlinked to the cache, and therefore the file should be modifiable
            // This operation will throw otherwise
            File.AppendAllText(producedFile, " we should be able to modify the file");
        }
Пример #4
0
        public void StaticOutputBecomingASharedOpaqueOutputIsProperlyMarkedAsSharedOpaqueOutput()
        {
            var file = X($"out/MyFile.txt");

            XAssert.PossiblySucceeded(FileUtilities.TryDeleteFile(file));

            var message = Guid.NewGuid().ToString();
            var spec0   = ProduceFileStatically(file, content: message);

            AddModule("Module0", ("spec0.dsc", spec0), placeInRoot: true);

            RunEngine(rememberAllChangedTrackedInputs: true);

            var objDir = Configuration.Layout.ObjectDirectory.ToString(Context.PathTable);

            var producedFile = Path.Combine(objDir, file);

            // Make sure the file was produced
            Assert.True(File.Exists(producedFile));

            // Since this is a statically declared file, it shouldn't be marked as a shared opaque output
            XAssert.IsFalse(SharedOpaqueOutputHelper.IsSharedOpaqueOutput(producedFile), "Statically declared file marked as shared opaque output: " + producedFile);

            // Delete the created file (since scrubbing is not on for this test, we have to simulate it)
            File.Delete(producedFile);

            // Overrite the spec so now the same file is generated as a shared opaque output
            spec0 = ProduceFileUnderSharedOpaque(file, content: message);
            File.WriteAllText(Path.Combine(Configuration.Layout.SourceDirectory.ToString(Context.PathTable), "spec0.dsc"), spec0);

            // Run the pip
            RunEngine(rememberAllChangedTrackedInputs: true);

            // Check the timestamp is the right one
            XAssert.IsTrue(SharedOpaqueOutputHelper.IsSharedOpaqueOutput(producedFile), "SOD file not marked on cache miss");

            // Delete the file
            File.Delete(producedFile);
            // Replay from cache. Since the file content is unchanged, the cache should have a blob
            // corresponding to the first pip, where the file was a statically declared output
            RunEngine(rememberAllChangedTrackedInputs: true);

            IgnoreWarnings();
            // Make sure this is a cache replay
            AssertVerboseEventLogged(global::BuildXL.Scheduler.Tracing.LogEventId.ProcessPipCacheHit);
            // Check the timestamp is the right one now
            XAssert.IsTrue(SharedOpaqueOutputHelper.IsSharedOpaqueOutput(producedFile), "SOD file not marked on cache replay");
        }
Пример #5
0
        private void AssertSharedOpaqueOputputsInNestedDestDirectory(AbsolutePath rootDirPath)
        {
            string root            = ToString(rootDirPath);
            var    expectedOutputs = new[]
            {
                X($"{root}/{NestedDirDest}/{FileNameInSrc}"),
                X($"{root}/{NestedDirDest}/{FileNameInDest}"),
            };

            foreach (var path in expectedOutputs)
            {
                XAssert.IsTrue(
                    SharedOpaqueOutputHelper.IsSharedOpaqueOutput(path),
                    $"Path '{path}' does not have magic shared opaque output timestamp");
            }
        }
Пример #6
0
        public void SkipFlaggingSharedOpaquesIsHonored()
        {
            // Set up PipA  => sharedOpaqueDirectory => PipB
            string       sharedOpaqueDir      = Path.Combine(ObjectRoot, "partialDir");
            AbsolutePath sharedOpaqueDirPath  = AbsolutePath.Create(Context.PathTable, sharedOpaqueDir);
            FileArtifact outputInSharedOpaque = CreateOutputFileArtifact(sharedOpaqueDir);
            FileArtifact source = CreateSourceFile();

            var pipA = CreateAndScheduleSharedOpaqueProducer(sharedOpaqueDir, fileToProduceStatically: FileArtifact.Invalid, sourceFileToRead: source, new KeyValuePair <FileArtifact, string>(outputInSharedOpaque, null));

            var builderB = CreatePipBuilder(new Operation[]
            {
                Operation.ReadFile(outputInSharedOpaque, doNotInfer: true),
                Operation.WriteFile(CreateOutputFileArtifact())
            });

            builderB.AddInputDirectory(pipA.ProcessOutputs.GetOpaqueDirectory(sharedOpaqueDirPath));
            var pipB = SchedulePipBuilder(builderB);

            // B should be able to consume the file in the opaque directory. Second build should have both cached
            RunScheduler().AssertCacheMiss(pipA.Process.PipId, pipB.Process.PipId);

            // The output shouldn't be flagged as a shared opaque
            XAssert.IsFalse(SharedOpaqueOutputHelper.IsSharedOpaqueOutput(outputInSharedOpaque.Path.ToString(Context.PathTable)));

            RunScheduler().AssertCacheHit(pipA.Process.PipId, pipB.Process.PipId);

            // The output shouldn't be flagged as a shared opaque
            XAssert.IsFalse(SharedOpaqueOutputHelper.IsSharedOpaqueOutput(outputInSharedOpaque.Path.ToString(Context.PathTable)));

            // Make sure we can replay the file in the opaque directory
            File.Delete(ArtifactToString(outputInSharedOpaque));
            RunScheduler().AssertCacheHit(pipA.Process.PipId, pipB.Process.PipId);
            XAssert.IsTrue(File.Exists(ArtifactToString(outputInSharedOpaque)));

            // The output shouldn't be flagged as a shared opaque
            XAssert.IsFalse(SharedOpaqueOutputHelper.IsSharedOpaqueOutput(outputInSharedOpaque.Path.ToString(Context.PathTable)));

            // Modify the input and make sure both are rerun
            File.WriteAllText(ArtifactToString(source), "New content");
            RunScheduler().AssertCacheMiss(pipA.Process.PipId, pipB.Process.PipId);
            RunScheduler().AssertCacheHit(pipA.Process.PipId, pipB.Process.PipId);

            // The output shouldn't be flagged as a shared opaque
            XAssert.IsFalse(SharedOpaqueOutputHelper.IsSharedOpaqueOutput(outputInSharedOpaque.Path.ToString(Context.PathTable)));
        }
Пример #7
0
        public void SharedOpaqueOutputsOnFailingPipMustBeProperlyMarked()
        {
            var file         = X("out/MyFile.txt");
            var objDir       = Configuration.Layout.ObjectDirectory.ToString(Context.PathTable);
            var producedFile = Path.Combine(objDir, file);

            var spec0 = ProduceFileUnderSharedOpaque(file, failOnExit: true);

            AddModule("Module0", ("spec0.dsc", spec0), placeInRoot: true);

            // Run the pip
            RunEngine(rememberAllChangedTrackedInputs: true, expectSuccess: false);

            AssertErrorEventLogged(LogEventId.PipProcessError);

            // Check the timestamp is the right one
            XAssert.IsTrue(SharedOpaqueOutputHelper.IsSharedOpaqueOutput(producedFile), "SOD file not marked on pip failure");
        }
Пример #8
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));
        }