public void ValidateCachingAbsentDirectoryProbes(bool sourceMount)
        {
            // Set up absent directory
            DirectoryArtifact absentDirectory;

            if (sourceMount)
            {
                // Source mounts (i.e. read only mounts) use the actual filesystem and check the existence of files/directories on disk
                absentDirectory = DirectoryArtifact.CreateWithZeroPartialSealId(CreateUniqueDirectory(ReadonlyRoot));
                Directory.Delete(ArtifactToString(absentDirectory)); // start with absent directory
            }
            else
            {
                // Output mounts (i.e. read/write mounts) use the graph filesystem and do not check the existence of files/directories on disk
                absentDirectory = CreateOutputDirectoryArtifact();
            }

            // Pip probes absent input and directory
            Process pip = CreateAndSchedulePipBuilder(new Operation[]
            {
                Operation.Probe(absentDirectory),
                Operation.WriteFile(CreateOutputFileArtifact())
            }).Process;

            RunScheduler().AssertScheduled(pip.PipId).AssertCacheMiss(pip.PipId);
            RunScheduler().AssertNotScheduled(pip.PipId);

            // Create /absentDirectory
            Directory.CreateDirectory(ArtifactToString(absentDirectory));

            // Source mounts check the existence of files/directories on disk (so cache miss)
            // Output mounts do not check the existence of files/directories on disk (so cache hit)
            if (sourceMount)
            {
                RunScheduler().AssertScheduled(pip.PipId).AssertCacheMiss(pip.PipId);
            }

            RunScheduler().AssertNotScheduled(pip.PipId);

            // Create /absentDirectory/newFile
            CreateSourceFile(ArtifactToString(absentDirectory));
            RunScheduler().AssertNotScheduled(pip.PipId);
        }
        public void IncrementalSchedulingIsRobustAgainstWildDirectoryMembershipChangeBeforePipExecution(bool changeMembershipBeforeThirdRun)
        {
            var directoryPath = CreateUniqueDirectory(ReadonlyRoot);

            FileArtifact      file                = CreateSourceFile(directoryPath);
            FileArtifact      inputA              = CreateSourceFile();
            FileArtifact      outputA             = CreateOutputFileArtifact();
            DirectoryArtifact enumeratedDirectory = DirectoryArtifact.CreateWithZeroPartialSealId(directoryPath);

            var builderA = CreatePipBuilder(new Operation[]
            {
                Operation.ReadFile(inputA),
                Operation.EnumerateDir(enumeratedDirectory, doNotInfer: true),
                Operation.WriteFile(outputA)
            });

            var pipA = SchedulePipBuilder(builderA);

            RunScheduler().AssertScheduled(pipA.Process.PipId);
            ModifyFile(inputA);

            // Due to inputA modification, pipA becomes dirty.
            RunScheduler(
                testHooks: new SchedulerTestHooks()
            {
                IncrementalSchedulingStateAfterJournalScanAction = _ =>
                {
                    // Change directory membership before pip execution.
                    CreateSourceFile(directoryPath);
                }
            }).AssertScheduled(pipA.Process.PipId);

            AssertVerboseEventLogged(StorageLogEventId.ConflictDirectoryMembershipFingerprint, count: 1);

            if (changeMembershipBeforeThirdRun)
            {
                // Change directory membership before third run.
                CreateSourceFile(directoryPath);
            }

            // Due to membership change, pipA becomes dirty.
            RunScheduler().AssertScheduled(pipA.Process.PipId);
        }
Exemple #3
0
        public void ValidateCreatingDirectoryRetracksDirectoriesNeededForTrackedChildAbsentPaths()
        {
            // Set up absent file
            AbsolutePath readOnlyRoot = AbsolutePath.Create(Context.PathTable, ReadonlyRoot);

            DirectoryArtifact dir = SealDirectory(readOnlyRoot, SealDirectoryKind.SourceAllDirectories);

            // Pip probes absent input and directory
            var ops = new Operation[]
            {
                ProbeOp(ReadonlyRoot),
                ProbeOp(ReadonlyRoot, @"dir1\a\dir1_a.txt"),
                ProbeOp(ReadonlyRoot, @"dir1\b\dir1_b.txt"),
                Operation.WriteFile(CreateOutputFileArtifact())
            };

            var builder = CreatePipBuilder(ops);

            builder.AddInputDirectory(dir);

            Process pip = SchedulePipBuilder(builder).Process;

            RunScheduler().AssertCacheMiss(pip.PipId);

            // Create probed file path which with a parent directory
            // which is also a parent of another absent path probe
            CreateDir(ReadonlyRoot, @"dir1");
            CreateDir(ReadonlyRoot, @"dir1\a");
            CreateFile(ReadonlyRoot, @"dir1\a\dir1_a.txt");

            RunScheduler().AssertCacheMiss(pip.PipId);

            // Now validate that creating a file at the location of
            // the other absent path probe invalidates the pip
            // In the original bug, the parent directory becomes untracked such that
            // changes to the directory go unnoticed
            CreateDir(ReadonlyRoot, @"dir1");
            CreateDir(ReadonlyRoot, @"dir1\b");
            CreateFile(ReadonlyRoot, @"dir1\b\dir1_b.txt");

            RunScheduler().AssertCacheMiss(pip.PipId);
        }
        /// <inheritdoc />
        protected override EvaluationResult DoEval(Context context, ModuleLiteral env, EvaluationStackFrame frame)
        {
            var evaluatedPathExpression = PathExpression.Eval(context, env, frame);

            if (evaluatedPathExpression.IsErrorValue)
            {
                return(EvaluationResult.Error);
            }

            try
            {
                var path = Converter.ExpectPath(evaluatedPathExpression, strict: true, context: new ConversionContext(pos: 1));
                return(EvaluationResult.Create(DirectoryArtifact.CreateWithZeroPartialSealId(path)));
            }
            catch (ConvertException e)
            {
                context.Errors.ReportUnexpectedValueTypeOnConversion(env, e, Location);
                return(EvaluationResult.Error);
            }
        }
Exemple #5
0
            private static DirectoryArtifact GetSpecialFolder(PathTable pathTable, Environment.SpecialFolder specialFolder, params string[] subFolders)
            {
                // GetFolderPath will return empty paths for special folders that don't exist in the current user profile.
                // Return DirectoryArtifact.Invalid for those folders so they can be omitted from being untracked when
                // the system does not support them.
                if (AbsolutePath.TryCreate(pathTable, SpecialFolderUtilities.GetFolderPath(specialFolder), out var root))
                {
                    if (subFolders != null)
                    {
                        foreach (var subFolder in subFolders)
                        {
                            root = root.Combine(pathTable, subFolder);
                        }
                    }

                    return(DirectoryArtifact.CreateWithZeroPartialSealId(root));
                }

                return(DirectoryArtifact.Invalid);
            }
Exemple #6
0
        /// <summary>
        /// Associates a directory artifact with its constituent file artifacts. The contents must be set before the directory artifact may
        /// be used by a pip (see <see cref="ListSealedDirectoryContents"/>).
        /// </summary>
        public void SetSealedDirectoryContents(DirectoryArtifact directory, params FileArtifact[] artifactsInDirectory)
        {
            Contract.Requires(directory.IsValid);
            Contract.Requires(artifactsInDirectory != null);

            FileArtifact[] artifacts = artifactsInDirectory.ToArray();
            SortedReadOnlyArray <FileArtifact, OrdinalFileArtifactComparer> sortedArtifacts = SortedReadOnlyArray <FileArtifact, OrdinalFileArtifactComparer> .SortUnsafe(
                artifacts,
                OrdinalFileArtifactComparer.Instance);

            bool added = m_knownSealedDirectoryContents.TryAdd(directory, sortedArtifacts);

            Contract.Assume(added);

            foreach (FileArtifact artifact in artifacts)
            {
                Contract.Assume(artifact.Path.IsWithin(Context.PathTable, directory.Path));
                m_knownSealedArtifacts[artifact.Path] = artifact;
            }
        }
Exemple #7
0
        public void DirectoryEnumerationUnderWritableMount()
        {
            var sealDirectoryPath = CreateUniqueDirectory(ObjectRoot);
            var path = sealDirectoryPath.ToString(Context.PathTable);

            DirectoryArtifact dir = SealDirectory(sealDirectoryPath, SealDirectoryKind.Partial, CreateSourceFile(path));

            var ops = new Operation[]
            {
                Operation.EnumerateDir(dir),
                Operation.WriteFile(CreateOutputFileArtifact())
            };

            var     builder = CreatePipBuilder(ops);
            Process pip     = SchedulePipBuilder(builder).Process;

            var result = RunScheduler().AssertSuccess();

            result.AssertObservation(pip.PipId, new ObservedPathEntry(sealDirectoryPath, false, true, true, RegexDirectoryMembershipFilter.AllowAllRegex, false));
        }
Exemple #8
0
        /// <nodoc />
        public bool TrySealDirectory(
            AbsolutePath directoryRoot,
            SortedReadOnlyArray <FileArtifact, OrdinalFileArtifactComparer> contents,
            SealDirectoryKind kind,
            string[] tags,
            string description,
            string[] patterns,
            out DirectoryArtifact sealedDirectory,
            bool scrub = false)
        {
            Contract.Requires(directoryRoot.IsValid);
            Contract.Requires(contents.IsValid);

            PipData usage = PipDataBuilder.CreatePipData(Context.StringTable, string.Empty, PipDataFragmentEscaping.NoEscaping, description != null
                ? new PipDataAtom[] { description }
                : new PipDataAtom[] { "'", directoryRoot, "' [", contents.Length.ToString(CultureInfo.InvariantCulture), " files]" });

            var pip = new SealDirectory(
                directoryRoot,
                contents,
                kind,
                CreatePipProvenance(usage),
                ToStringIds(tags),
                ToStringIds(patterns),
                scrub);

            if (PipGraph != null)
            {
                sealedDirectory = PipGraph.AddSealDirectory(pip, GetValuePipId());
                if (!sealedDirectory.IsValid)
                {
                    return(false);
                }
            }
            else
            {
                sealedDirectory = DirectoryArtifact.CreateWithZeroPartialSealId(directoryRoot);
            }

            return(true);
        }
Exemple #9
0
            /// <summary>
            /// Augments the processBuilder with the OS dependencies.
            /// </summary>
            /// <param name="processBuilder">builder to use</param>
            /// <param name="untrackInsteadSourceSeal">when true, directories that are meant to be source sealed are untracked instead</param>
            public bool ProcessDefaults(ProcessBuilder processBuilder, bool untrackInsteadSourceSeal = false)
            {
                if (processBuilder.Options.HasFlag(Process.Options.DependsOnCurrentOs))
                {
                    // process source seal directories: either source seal them or untrack them, depending on 'untrackInsteadSourceSeal'
                    if (untrackInsteadSourceSeal)
                    {
                        foreach (var sourceSealDirPath in m_sourceSealDirectoryPaths)
                        {
                            processBuilder.AddUntrackedDirectoryScope(DirectoryArtifact.CreateWithZeroPartialSealId(sourceSealDirPath));
                        }
                    }
                    else
                    {
                        var defaultSourceSealDirs = m_lazySourceSealDirectories.Value;
                        if (!defaultSourceSealDirs.IsValid)
                        {
                            return(false);
                        }

                        foreach (var inputDirectory in defaultSourceSealDirs.Directories)
                        {
                            processBuilder.AddInputDirectory(inputDirectory);
                        }
                    }

                    // add untracked files
                    foreach (var untrackedFile in m_untrackedFiles)
                    {
                        processBuilder.AddUntrackedFile(untrackedFile);
                    }

                    // add untracked directories
                    foreach (var untrackedDirectory in m_untrackedDirectories)
                    {
                        processBuilder.AddUntrackedDirectoryScope(untrackedDirectory);
                    }
                }

                return(true);
            }
        public void ReadingUnderAnExclusiveOpaqueIsBlocked()
        {
            var exclusiveOpaqueRoot = Path.Combine(ObjectRoot, "exclusiveOpaque");
            var source = CreateSourceFile(exclusiveOpaqueRoot);

            // Read the source file
            var reader = ScheduleProcessWithUndeclaredReads(source);

            // Create an exclusive opaque that produces the same file
            var builder = CreatePipBuilder(new List <Operation>()
            {
                Operation.WriteFile(source, doNotInfer: true)
            });
            var exclusiveOpaqueDirectoryArtifact = DirectoryArtifact.CreateWithZeroPartialSealId(Context.PathTable, exclusiveOpaqueRoot);

            builder.AddOutputDirectory(exclusiveOpaqueDirectoryArtifact, SealDirectoryKind.Opaque);
            var writer = SchedulePipBuilder(builder);

            // A violation should be detected when reading the produced output as a source file
            // Force an execution order to avoid write locks
            RunScheduler(constraintExecutionOrder: new[] { ((Pip)reader.Process, (Pip)writer.Process) }).AssertFailure();
        public void ExecutionUntrackTempFolder()
        {
            AbsolutePath tempDirectory = CreateUniqueDirectory(ObjectRoot);
            FileArtifact tempFile      = CreateOutputFileArtifact(tempDirectory);

            ProcessBuilder builder = CreatePipBuilder(new[]
            {
                Operation.ReadFile(CreateSourceFile()),
                Operation.WriteFile(CreateOutputFileArtifact()),
                Operation.WriteFile(tempFile, doNotInfer: true),
                Operation.ReadFile(tempFile, doNotInfer: true)
            });

            builder.Options |= Process.Options.RequiresAdmin;
            builder.SetTempDirectory(DirectoryArtifact.CreateWithZeroPartialSealId(tempDirectory));

            ProcessWithOutputs process = SchedulePipBuilder(builder);

            RunScheduler().AssertSuccess();
            RunScheduler().AssertCacheHit(process.Process.PipId);
        }
Exemple #12
0
            /// <summary>
            /// Creates a directory artifact which may be queried with <see cref="ListSealedDirectoryContents"/>,
            /// and whose members may be queried with <see cref="TryQuerySealedInputContent"/>.
            /// Each mentioned path must have been added explicitly with <see cref="AddAbsentPath"/> or <see cref="AddFile"/>
            /// </summary>
            public DirectoryArtifact SealDir(string root, params string[] contents)
            {
                var rootPath = Path(root);

                FileArtifact[] artifacts = new FileArtifact[contents.Length];
                for (int i = 0; i < contents.Length; i++)
                {
                    var path = Path(contents[i]);
                    if (!path.IsWithin(Context.PathTable, rootPath))
                    {
                        XAssert.Fail("Root {0} does not contain {1}", root, contents[i]);
                    }

                    artifacts[i] = FileArtifact.CreateSourceFile(path);
                }

                DirectoryArtifact newArtifact = DirectoryArtifact.CreateDirectoryArtifactForTesting(rootPath, m_nextDirectorySealId++);

                m_env.SetSealedDirectoryContents(newArtifact, artifacts);
                return(newArtifact);
            }
        internal static bool TryDeserializeDirectoryArtifact(string input, out DirectoryArtifact directoryArtifact)
        {
            var components = input.Split(':');

            if (components.Length != 3)
            {
                directoryArtifact = default;
                return(false);
            }

            if (!int.TryParse(components[0], out var pathId) ||
                !uint.TryParse(components[1], out var partialSealId) ||
                !int.TryParse(components[2], out var isSharedOpaque))
            {
                directoryArtifact = default;
                return(false);
            }

            directoryArtifact = new DirectoryArtifact(new AbsolutePath(pathId), partialSealId, isSharedOpaque == 1);
            return(true);
        }
Exemple #14
0
        /// <param name="topOnly">When true, the SourceSealedDirectory will be a topOnly. When false, it will be a recursive SourceSealedDirectory</param>
        /// <param name="probeOnly">When true, the source file will be probed without reading</param>
        /// <param name="alsoDeclareAsInput">When true, the file accessed under the SourceSealDirectory will also be declared as an input</param>
        public void ValidateCachingBehavior(bool topOnly, bool probeOnly, bool alsoDeclareAsInput = false)
        {
            // Create a very simple graph with a process that consumes files from a source sealed directory
            var source1 = topOnly ? CreateSourceFile(SourceRoot) : CreateSourceFile(Path.Combine(SourceRoot, "nested"));

            WriteSourceFile(source1);

            // Create a graph with a SealedSourceDirectory
            DirectoryArtifact dir = SealDirectory(SourceRootPath, topOnly ? SealDirectoryKind.SourceTopDirectoryOnly : SealDirectoryKind.SourceAllDirectories);

            // Set up test process
            var builder = CreatePipBuilder(new Operation[]
            {
                Operation.WriteFile(CreateOutputFileArtifact(ObjectRoot)),
                // don't take dependencies on files in SealedSourceDirectory
                probeOnly ? Operation.Probe(source1, doNotInfer: !alsoDeclareAsInput) :  Operation.ReadFile(source1, doNotInfer: !alsoDeclareAsInput)
            });

            builder.AddInputDirectory(dir);
            Process process = SchedulePipBuilder(builder).Process;

            // Perform builds:
            RunScheduler().AssertCacheMiss(process.PipId);
            RunScheduler().AssertCacheHit(process.PipId);

            // Modify an input file and make sure there's a cache miss
            WriteSourceFile(source1);

            if (probeOnly && !alsoDeclareAsInput)
            {
                // Files probes that are not declared as input do not cause cache misses when the content changes.
                RunScheduler().AssertCacheHit(process.PipId);
            }
            else
            {
                RunScheduler().AssertCacheMiss(process.PipId);
            }

            RunScheduler().AssertCacheHit(process.PipId);
        }
Exemple #15
0
        private EvaluationResult ComposeSharedOpaqueDirectories(Context context, ModuleLiteral env, EvaluationStackFrame args)
        {
            AbsolutePath root;
            ArrayLiteral contents;
            SealDirectoryContentFilter?contentFilter;

            if (args.Length > 0 && args[0].Value is ObjectLiteral)
            {
                var obj       = Args.AsObjectLiteral(args, 0);
                var directory = Converter.ExtractDirectory(obj, m_sealRoot, allowUndefined: false);
                root     = directory.Path;
                contents = Converter.ExtractArrayLiteral(obj, m_sealDirectories, allowUndefined: false);
                var filterObj = Converter.ExtractObjectLiteral(obj, m_sealDirectoryContentFilter, allowUndefined: true);
                contentFilter = GetContentFilterHelper(filterObj);
            }
            else
            {
                root     = Args.AsPath(args, 0, false);
                contents = Args.AsArrayLiteral(args, 1);
                var filterObj = Args.AsObjectLiteralOptional(args, 2);
                contentFilter = GetContentFilterHelper(filterObj);
            }

            var directories = new DirectoryArtifact[contents.Length];

            for (int i = 0; i < contents.Length; ++i)
            {
                directories[i] = Converter.ExpectSharedOpaqueDirectory(contents[i], context: new ConversionContext(pos: i, objectCtx: contents)).Root;
            }

            if (!context.GetPipConstructionHelper().TryComposeSharedOpaqueDirectory(root, directories, SealDirectoryCompositionActionKind.WidenDirectoryCone, contentFilter, description: null, tags: null, out var compositeSharedOpaque))
            {
                // Error should have been logged
                return(EvaluationResult.Error);
            }

            var result = new StaticDirectory(compositeSharedOpaque, SealDirectoryKind.SharedOpaque, s_emptySealContents.WithCompatibleComparer(OrdinalPathOnlyFileArtifactComparer.Instance));

            return(new EvaluationResult(result));
        }
Exemple #16
0
        /// <nodoc/>
        public bool TryComposeSharedOpaqueDirectory(
            AbsolutePath directoryRoot,
            IReadOnlyList <DirectoryArtifact> contents,
            [CanBeNull] string description,
            string[] tags,
            out DirectoryArtifact sharedOpaqueDirectory)
        {
            Contract.Requires(directoryRoot.IsValid);
            Contract.Requires(contents != null);

            if (PipGraph == null)
            {
                sharedOpaqueDirectory = DirectoryArtifact.CreateWithZeroPartialSealId(directoryRoot);
                return(true);
            }

            PipData usage = PipDataBuilder.CreatePipData(Context.StringTable, string.Empty, PipDataFragmentEscaping.NoEscaping, description != null
                ? new PipDataAtom[] { description }
                : new PipDataAtom[] { "'", directoryRoot, " [", contents.Count.ToString(CultureInfo.InvariantCulture), " shared opaque directories]" });

            sharedOpaqueDirectory = PipGraph.ReserveSharedOpaqueDirectory(directoryRoot);

            var pip = new CompositeSharedOpaqueSealDirectory(
                directoryRoot,
                contents,
                CreatePipProvenance(usage),
                ToStringIds(tags));

            // The seal directory is ready to be initialized, since the directory artifact has been reserved already
            pip.SetDirectoryArtifact(sharedOpaqueDirectory);

            sharedOpaqueDirectory = PipGraph.AddSealDirectory(pip, GetValuePipId());
            if (!sharedOpaqueDirectory.IsValid)
            {
                return(false);
            }

            return(true);
        }
Exemple #17
0
        /// <inheritdoc />
        protected override void AddWeakFingerprint(IFingerprinter fingerprinter, SealDirectory sealDirectory)
        {
            Contract.Requires(fingerprinter != null);
            Contract.Requires(sealDirectory != null);

            base.AddWeakFingerprint(fingerprinter, sealDirectory);

            // For non-composite shared opaque directories, contents and composed directories are always empty, and therefore the static fingerprint
            // is not strong enough, i.e. multiple shared opaques can share the same directory root. So in this case we need to add the fingerprint of the producer
            if (sealDirectory.Kind == SealDirectoryKind.SharedOpaque && !sealDirectory.IsComposite)
            {
                DirectoryArtifact directory = sealDirectory.Directory;
                fingerprinter.Add(directory, m_directoryProducerFingerprintLookup(directory).Hash);
            }

            if (!ExcludeSemiStableHashOnFingerprintingSealDirectory && !sealDirectory.Kind.IsDynamicKind())
            {
                // A statically sealed directory can exist as multiple different instances, e.g., one can have partially sealed directories with the same root and member set.
                // To distinguish those instances, we include the semi stable hash as part of the static fingerprint.
                fingerprinter.Add("SemiStableHash", sealDirectory.SemiStableHash);
            }
        }
Exemple #18
0
        public void ScheduleFullSealDirectoryWithOpaqueAsContentBehavior(bool includeOpaqueAsContent)
        {
            using (TestEnv env = TestEnv.CreateTestEnvWithPausedScheduler())
            {
                AbsolutePath directoryPath = env.Paths.CreateAbsolutePath(env.ObjectRoot, "seal");
                AbsolutePath sod           = env.Paths.CreateAbsolutePath(directoryPath, "sod");

                // A pip that produces an output directory under the seal root
                var pip = CreatePipBuilderWithTag(env, "test");
                pip.AddOutputDirectory(sod, SealDirectoryKind.SharedOpaque);
                var pipResult            = env.PipConstructionHelper.AddProcess(pip);
                var sharedOpaqueArtifact = pipResult.GetOpaqueDirectory(sod);

                FileArtifact a = ScheduleWriteOutputFileUnderDirectory(env, directoryPath, "a");

                // We should be able to schedule a seal directory with the produced file and optionally the opaque as content
                DirectoryArtifact sealDirectory = ScheduleSealDirectory(
                    env,
                    directoryPath,
                    new[] { a },
                    includeOpaqueAsContent? new[] { sharedOpaqueArtifact } : new DirectoryArtifact[] { });

                var graph = env.PipGraph.Build();
                if (includeOpaqueAsContent)
                {
                    // Everything should be good in this case
                    Assert.NotNull(graph);

                    // The fully seal directory should have a dependency on the opaque
                    Assert.True(graph.DataflowGraph.IsReachableFrom(graph.GetSealedDirectoryNode(sharedOpaqueArtifact), graph.GetSealedDirectoryNode(sealDirectory)));
                }
                else
                {
                    // We should fail at scheduling the graph because of a missing output directory
                    Assert.Null(graph);
                    AssertErrorEventLogged(LogEventId.InvalidGraphSinceFullySealedDirectoryIncompleteDueToMissingOutputDirectories);
                }
            }
        }
        private static EvaluationResult GetPathValues(Context context, EvaluationStackFrame args, Type type)
        {
            var    name      = Args.AsString(args, 0);
            var    separator = Args.AsString(args, 1);
            string strValue  = GetRawValue(context, name);

            var entry = context.TopStack;

            if (string.IsNullOrWhiteSpace(strValue))
            {
                return(EvaluationResult.Create(ArrayLiteral.CreateWithoutCopy(CollectionUtilities.EmptyArray <EvaluationResult>(), entry.InvocationLocation, entry.Path)));
            }

            var values       = separator.Length == 0 ? new[] { strValue } : strValue.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries);
            var pathsOrFiles = new List <EvaluationResult>();

            for (int i = 0; i < values.Length; ++i)
            {
                if (!string.IsNullOrWhiteSpace(values[i]))
                {
                    AbsolutePath path = ParsePath(context, name, values[i], 1);

                    EvaluationResult result =
                        type == typeof(AbsolutePath)      ? EvaluationResult.Create(path) :
                        type == typeof(FileArtifact)      ? EvaluationResult.Create(FileArtifact.CreateSourceFile(path)) :
                        type == typeof(DirectoryArtifact) ? EvaluationResult.Create(DirectoryArtifact.CreateWithZeroPartialSealId(path)) :
                        EvaluationResult.Undefined;

                    if (result.IsUndefined)
                    {
                        throw Contract.AssertFailure(I($"Cannot convert paths to typeof({type.Name})"));
                    }

                    pathsOrFiles.Add(result);
                }
            }

            return(EvaluationResult.Create(ArrayLiteral.CreateWithoutCopy(pathsOrFiles.ToArray(), entry.InvocationLocation, entry.Path)));
        }
Exemple #20
0
        private EvaluationResult[] EnumerateFilesOrDirectories(
            Context context,
            string directoryPath,
            string searchPattern,
            bool isRecursive,
            bool enumerateDirectory)
        {
            var fileSystem = context.FrontEndContext.FileSystem;

            if (enumerateDirectory)
            {
                return(fileSystem
                       .EnumerateDirectories(AbsolutePath.Create(context.PathTable, directoryPath), searchPattern, isRecursive)
                       .Select(ap => EvaluationResult.Create(DirectoryArtifact.CreateWithZeroPartialSealId(ap)))
                       .ToArray());
            }

            return(fileSystem
                   .EnumerateFiles(AbsolutePath.Create(context.PathTable, directoryPath), searchPattern, isRecursive)
                   .Select(ap => EvaluationResult.Create(FileArtifact.CreateSourceFile(ap)))
                   .ToArray());
        }
Exemple #21
0
        private void AddAdditionalOutputDirectories(ProcessBuilder processBuilder, AbsolutePath projectFolder)
        {
            if (m_resolverSettings.AdditionalOutputDirectories == null)
            {
                return;
            }

            foreach (DiscriminatingUnion <AbsolutePath, RelativePath> directoryUnion in m_resolverSettings.AdditionalOutputDirectories)
            {
                object directory = directoryUnion.GetValue();
                if (directory is AbsolutePath absolutePath)
                {
                    processBuilder.AddOutputDirectory(DirectoryArtifact.CreateWithZeroPartialSealId(absolutePath), SealDirectoryKind.SharedOpaque);
                }
                else
                {
                    // The specified relative path is interpreted relative to the project directory folder
                    AbsolutePath absoluteDirectory = projectFolder.Combine(PathTable, (RelativePath)directory);
                    processBuilder.AddOutputDirectory(DirectoryArtifact.CreateWithZeroPartialSealId(absoluteDirectory), SealDirectoryKind.SharedOpaque);
                }
            }
        }
Exemple #22
0
        public void TranslateGlobalUntrackedScope(bool translate, Process.Options requireGlobalDependencies)
        {
            DirectoryArtifact sourceDirectory       = DirectoryArtifact.CreateWithZeroPartialSealId(CreateUniqueDirectory(SourceRoot, prefix: "sourceDir"));
            DirectoryArtifact targetDirectory       = DirectoryArtifact.CreateWithZeroPartialSealId(CreateUniqueDirectory(SourceRoot, prefix: "targetDir"));
            FileArtifact      outputFileInTargetDir = CreateOutputFileArtifact(ArtifactToString(targetDirectory));
            FileArtifact      inputFileInTargetDir  = CreateSourceFile(ArtifactToString(targetDirectory));

            Configuration.Sandbox.GlobalUnsafeUntrackedScopes.Add(sourceDirectory);

            if (translate)
            {
                DirectoryTranslator = new DirectoryTranslator();
                DirectoryTranslator.AddTranslation(ArtifactToString(sourceDirectory), ArtifactToString(targetDirectory));
            }

            var ops = new Operation[]
            {
                Operation.ReadFile(inputFileInTargetDir, doNotInfer: true),
                Operation.WriteFile(outputFileInTargetDir)
            };

            var builder = CreatePipBuilder(ops);

            builder.Options |= requireGlobalDependencies;

            Process pip = SchedulePipBuilder(builder).Process;

            if (translate && ((requireGlobalDependencies & Process.Options.RequireGlobalDependencies) == Process.Options.RequireGlobalDependencies))
            {
                RunScheduler().AssertCacheMiss(pip.PipId);
                RunScheduler().AssertCacheHit(pip.PipId);
            }
            else
            {
                RunScheduler().AssertFailure();
                AssertWarningEventLogged(EventId.ProcessNotStoredToCacheDueToFileMonitoringViolations);
                AssertErrorEventLogged(EventId.FileMonitoringError);
            }
        }
Exemple #23
0
        public void IncrementalPreserveOutputTool()
        {
            Configuration.Sandbox.UnsafeSandboxConfigurationMutable.PreserveOutputs = PreserveOutputsMode.Enabled;
            Configuration.IncrementalTools = new List <RelativePath>
            {
                RelativePath.Create(Context.StringTable, TestProcessToolName)
            };

            AbsolutePath readonlyRootPath;

            AbsolutePath.TryCreate(Context.PathTable, ReadonlyRoot, out readonlyRootPath);

            // Create /readonly/a.txt
            FileArtifact aTxtFile = CreateFileArtifactWithName("a.txt", ReadonlyRoot);

            WriteSourceFile(aTxtFile);

            DirectoryArtifact readonlyRootDir = SealDirectory(readonlyRootPath, SealDirectoryKind.SourceAllDirectories);

            var builder = CreatePipBuilder(new Operation[]
            {
                Operation.Probe(aTxtFile, doNotInfer: true),
                Operation.WriteFile(CreateOutputFileArtifact())
            });

            builder.AddInputDirectory(readonlyRootDir);

            builder.Options |= Process.Options.AllowPreserveOutputs;
            builder.Options |= Process.Options.IncrementalTool;

            var pip = SchedulePipBuilder(builder).Process;

            RunScheduler().AssertCacheMiss(pip.PipId);
            RunScheduler().AssertCacheHit(pip.PipId);

            WriteSourceFile(aTxtFile);
            RunScheduler().AssertCacheMiss(pip.PipId);
        }
Exemple #24
0
        private ObjectInfo DirectoryArtifactInfo(DirectoryArtifact d)
        {
            if (!d.IsValid)
            {
                return(new ObjectInfo("Invalid"));
            }

            var name = d.Path.GetName(PathTable).ToString(StringTable);
            var kind = d.IsSharedOpaque ? "shared opaque" : d.IsOutputDirectory() ? "exclusive opaque" : "source";

            return(new ObjectInfo(
                       preview: $"{name} [{kind}]",
                       properties: new[]
            {
                new Property("Path", d.Path.ToString(PathTable)),
                new Property("PartialSealId", d.PartialSealId),
                new Property("Kind", kind),
                d.IsOutputDirectory() ? new Property("Producer", () => PipGraph.GetProducer(d)) : null,
                new Property("Consumers", PipGraph.GetConsumingPips(d.Path).ToArray()),
                d.PartialSealId > 0 ? new Property("Members", () => PipGraph.ListSealedDirectoryContents(d)) : null
            }
                       .Where(p => p != null)));
        }
Exemple #25
0
        public void SetSealedSourceDirectory(DirectoryArtifact directory, bool allDirectories, params AbsolutePath[] dynamicallyAccessedPathInDirectory)
        {
            var directoryPath         = directory.Path;
            var sealedDiretoriesToUse = allDirectories ? m_knownSealedSourceDirectoriesAllDirectories : m_knownSealedSourceDirectoriesTopDirectoryOnly;

            sealedDiretoriesToUse.Add(directoryPath);

            foreach (AbsolutePath path in dynamicallyAccessedPathInDirectory)
            {
                if (allDirectories)
                {
                    Contract.Assume(path.IsWithin(Context.PathTable, directoryPath));
                }
                else
                {
                    Contract.Assume(
                        path.GetParent(Context.PathTable) == directoryPath,
                        "If not recursive all files must be directly under the folder.");
                }

                m_knownSealedArtifacts[path] = FileArtifact.CreateSourceFile(path);
            }
        }
Exemple #26
0
        private void SetUntrackedFilesAndDirectories(ProcessBuilder processBuilder)
        {
            // On some machines, the current user and public user desktop.ini are read by Powershell.exe.
            // Ignore accesses to the user profile and Public common user profile.
            processBuilder.AddUntrackedDirectoryScope(DirectoryArtifact.CreateWithZeroPartialSealId(PathTable, SpecialFolderUtilities.GetFolderPath(Environment.SpecialFolder.UserProfile)));

            if (Engine.TryGetBuildParameter("PUBLIC", m_frontEndName, out string publicDir))
            {
                processBuilder.AddUntrackedDirectoryScope(DirectoryArtifact.CreateWithZeroPartialSealId(AbsolutePath.Create(PathTable, publicDir)));
            }

            PipConstructionUtilities.UntrackUserConfigurableArtifacts(processBuilder, m_resolverSettings);

            // Git accesses should be ignored if .git directory is there
            var gitDirectory = Root.Combine(PathTable, ".git");

            if (Engine.DirectoryExists(gitDirectory))
            {
                processBuilder.AddUntrackedDirectoryScope(DirectoryArtifact.CreateWithZeroPartialSealId(gitDirectory));
                processBuilder.AddUntrackedFile(FileArtifact.CreateSourceFile(Root.Combine(PathTable, ".gitattributes")));
                processBuilder.AddUntrackedFile(FileArtifact.CreateSourceFile(Root.Combine(PathTable, ".gitignore")));
            }
        }
        public void CreatedDirectoriesUnderSharedOpaquesAreNotPartOfTheFingerprint()
        {
            string            dir            = Path.Combine(SourceRoot, "dir");
            AbsolutePath      dirPath        = AbsolutePath.Create(Context.PathTable, dir);
            DirectoryArtifact dirToEnumerate = DirectoryArtifact.CreateWithZeroPartialSealId(dirPath);

            Configuration.Logging.CacheMissAnalysisOption = CacheMissAnalysisOption.LocalMode();

            AbsolutePath nestedDirPath = dirPath.Combine(Context.PathTable, "nested");
            var          nestedDir     = DirectoryArtifact.CreateWithZeroPartialSealId(nestedDirPath);

            var operations = new List <Operation>
            {
                // Create a directory nested into the one that is going to be enumerated
                Operation.CreateDir(nestedDir, doNotInfer: true),
                Operation.EnumerateDir(dirToEnumerate, doNotInfer: true),
                Operation.WriteFile(CreateOutputFileArtifact()) // dummy output
            };

            var builder = CreatePipBuilder(operations);

            // This makes sure we use the right file system, which is aware of alien files
            builder.Options |= global::BuildXL.Pips.Operations.Process.Options.AllowUndeclaredSourceReads;
            // Define the shared opaque
            builder.AddOutputDirectory(dirPath, global::BuildXL.Pips.Operations.SealDirectoryKind.SharedOpaque);

            var pip = SchedulePipBuilder(builder);

            // Run once
            RunScheduler().AssertSuccess();

            // Simulate shared opaque scrubbing
            FileUtilities.DeleteDirectoryContents(nestedDirPath.ToString(Context.PathTable), deleteRootDirectory: true);

            // This should be a cache hit. Directories created by a pip are not part of the fingerprint
            RunScheduler().AssertCacheHit(pip.Process.PipId);
        }
        public void ValidateCachingBehaviorUntrackedMount(FileArtifact file, DirectoryArtifact dir, bool undefinedMount)
        {
            // Dynamically observed accesses on the file and directory
            Process pip = CreateAndSchedulePipBuilder(new Operation[]
            {
                Operation.ReadFile(file),
                Operation.EnumerateDir(dir),
                Operation.WriteFile(CreateOutputFileArtifact())
            }).Process;

            RunScheduler().AssertCacheMiss(pip.PipId);
            RunScheduler().AssertCacheHit(pip.PipId);

            // Create previously absent /file
            File.WriteAllText(ArtifactToString(file), "hello");
            RunScheduler().AssertCacheHit(pip.PipId);

            // Create previously absent /dir
            Directory.CreateDirectory(ArtifactToString(dir));

            if (undefinedMount)
            {
                //// TODO: Bug #1087986 - This is a miss for undefined mounts
                RunScheduler().AssertCacheMiss(pip.PipId);
            }
            RunScheduler().AssertCacheHit(pip.PipId);

            // Modify /file
            File.WriteAllText(ArtifactToString(file), "world");
            RunScheduler().AssertCacheHit(pip.PipId);

            // Modify /dir by creating /dir/undefinedNestedFile
            FileArtifact undefinedNestedFile = new FileArtifact(CreateUniqueSourcePath(SourceRootPrefix, ArtifactToString(dir)));

            File.Create(ArtifactToString(undefinedNestedFile));
            RunScheduler().AssertCacheHit(pip.PipId);
        }
Exemple #29
0
        public void EnumeratingDirectoryUnderSharedOpaqueUsesMinimalGraphFileSystem()
        {
            // Enable minimal lazy output materialization to ensure files are not placed on disk after cache hit
            Configuration.Schedule.RequiredOutputMaterialization = RequiredOutputMaterialization.Minimal;

            // Enumeration path is sub path of shared opaque to ensure enumerating pip doesn't explicitly
            // mention the path in its dependencies
            var enumerationPath = Path.Combine(SharedOpaqueDirectoryRoot, "enum");

            // Create a pip that writes a file under a shared opaque
            var fileToWrite          = CreateOutputFileArtifact(enumerationPath);
            var sharedOpaqueProducer = CreateAndScheduleSharedOpaqueProducer(enumerationPath, filesToProduce: fileToWrite);

            // Create a pip which enumerates the shared opaque
            var enumeratingPipBuilder = CreatePipBuilder(new[]
            {
                Operation.EnumerateDir(DirectoryArtifact.CreateWithZeroPartialSealId(Context.PathTable, enumerationPath), doNotInfer: true),
                Operation.WriteFile(CreateOutputFileArtifact()) // dummy output
            });

            // Mark the pip with allow undeclared source reads to test regression of directory enumeration behavior in this case
            enumeratingPipBuilder.Options |= Process.Options.AllowUndeclaredSourceReads;

            enumeratingPipBuilder.AddInputDirectory(sharedOpaqueProducer.ProcessOutputs.GetOutputDirectories().Single().Root);

            var enumeratingPip = SchedulePipBuilder(enumeratingPipBuilder);

            RunScheduler().AssertSuccess();

            // After deleting the enumerated directory contents we should still get a hit even though the
            // state of the file system has changed since we are using the minimal graph file system
            FileUtilities.DeleteDirectoryContents(enumerationPath);
            RunScheduler().AssertCacheHit(enumeratingPip.Process.PipId, sharedOpaqueProducer.Process.PipId);

            AssertTrue(Directory.GetFiles(enumerationPath, "*.*", SearchOption.AllDirectories).Length == 0, "Enumerated directory should be empty due to lazy materialization");
        }
            public void AddRealPath(string fullPath, PathExistence existence)
            {
                if (existence == PathExistence.Nonexistent)
                {
                    return;
                }

                var path = AbsolutePath.Create(m_pathTable, fullPath);

                FileOrDirectoryArtifact member = FileOrDirectoryArtifact.Invalid;

                while (path.IsValid)
                {
                    if (existence == PathExistence.ExistsAsFile)
                    {
                        m_files.Add(path);
                        member = new FileArtifact(path);
                    }
                    else
                    {
                        var members = m_directories.GetOrAdd(path, p => new HashSet <FileOrDirectoryArtifact>());
                        if (member.IsValid)
                        {
                            if (!members.Add(member))
                            {
                                return;
                            }
                        }

                        member = DirectoryArtifact.CreateWithZeroPartialSealId(path);
                    }

                    existence = PathExistence.ExistsAsDirectory;
                    path      = path.GetParent(m_pathTable);
                }
            }