示例#1
0
 /// <summary>
 /// Adds the output files of the pip to the set
 /// </summary>
 protected static void AddOutputs(IPipFilterContext context, PipId pipId, HashSet <FileOrDirectoryArtifact> outputs)
 {
     if (MayHaveOutputs(context, pipId))
     {
         AddOutputs(context.HydratePip(pipId), outputs);
     }
 }
示例#2
0
        /// <inheritdoc/>
        public override IReadOnlySet <FileOrDirectoryArtifact> FilterOutputsCore(IPipFilterContext context, bool negate = false, IList <PipId> constrainingPips = null)
        {
            var matchingModulePipIds = ParallelProcessAllOutputs <PipId>(
                context,
                (pipId, localPips) =>
            {
                if (context.GetPipType(pipId) == PipType.Module)
                {
                    var modulePip = (ModulePip)context.HydratePip(pipId);
                    if (m_modules.Contains(modulePip.Identity))
                    {
                        localPips.Add(pipId);
                    }
                }
            });

            var dependenciesWithOutputs = GetDependenciesWithOutputsForModulePips(context, matchingModulePipIds);

            if (constrainingPips != null)
            {
                dependenciesWithOutputs.IntersectWith(constrainingPips);
            }

            return(ParallelProcessAllOutputs <FileOrDirectoryArtifact>(
                       context,
                       (pipId, localOutputs) => AddOutputs(context, pipId, localOutputs),
                       dependenciesWithOutputs.ToArray()));
        }
示例#3
0
        protected static ReadOnlyHashSet <T> ParallelProcessAllOutputs <T>(
            IPipFilterContext context,
            Action <PipId, HashSet <T> > action,
            IList <PipId> pips = null)
        {
            var outputs = new ReadOnlyHashSet <T>();

            pips = pips ?? context.AllPips;

            // Note: pips better be an IList<...> in order to get good Parallel.ForEach performance
            Parallel.ForEach(
                pips,
                () => new HashSet <T>(),
                (pipId, loopState, index, localOutputs) =>
            {
                action(pipId, localOutputs);
                return(localOutputs);
            },
                localOutputs =>
            {
                if (localOutputs.Count > 0)
                {
                    lock (outputs)
                    {
                        // Even though the 'outputs' variable is of type ReadOnlyHashSet
                        // we still can modify it.
                        outputs.UnionWith(localOutputs);
                    }
                }
            });

            return(outputs);
        }
示例#4
0
 /// <inheritdoc/>
 public override IReadOnlySet <FileOrDirectoryArtifact> FilterOutputsCore(IPipFilterContext context, bool negate = false, IList <PipId> constrainingPips = null)
 {
     return(ParallelProcessAllOutputs <FileOrDirectoryArtifact>(
                context,
                (pipId, localOutputs) => ForEachOutput(
                    localOutputs,
                    context,
                    pipId,
                    (localOutputs2, output) =>
     {
         if (output.IsFile)
         {
             if (PathMatches(output.Path, context.PathTable) ^ negate)
             {
                 localOutputs2.Add(output);
             }
         }
         else
         {
             // Directory can be non-output directory. See ForEachOutput.
             if (output.DirectoryArtifact.IsOutputDirectory())
             {
                 if (DirectoryPathMatches(output.Path, false, context.PathTable) ^ negate)
                 {
                     localOutputs2.Add(output);
                 }
             }
         }
     }),
                constrainingPips));
 }
示例#5
0
        /// <inheritdoc/>
        public override IReadOnlySet <FileOrDirectoryArtifact> FilterOutputsCore(
            IPipFilterContext context,
            bool negate = false,
            IList <PipId> constrainingPips = null)
        {
            var matchingValuePipIds = ParallelProcessAllOutputs <PipId>(
                context,
                (pipId, localPips) =>
            {
                if (context.GetPipType(pipId) == PipType.Value)
                {
                    ValuePip valuePip = (ValuePip)context.HydratePip(pipId);

                    // TODO: Consider not allowing matching of non-public values.
                    if (valuePip.Symbol == m_value ^ negate)
                    {
                        localPips.Add(pipId);
                    }
                }
            });

            HashSet <PipId> dependenciesWithOutputs =
                m_valueTransitive
                    ? GetDependenciesWithOutputsBehindValueAndSealDirectoryPips(context, matchingValuePipIds)
                    : GetDependenciesWithOutputsForValuePips(context, matchingValuePipIds);

            return(ParallelProcessAllOutputs <FileOrDirectoryArtifact>(
                       context,
                       (pipId, localOutputs) => AddOutputs(context, pipId, localOutputs),
                       dependenciesWithOutputs.ToArray()));
        }
示例#6
0
        /// <inheritdoc/>
        public override IReadOnlySet <FileOrDirectoryArtifact> FilterOutputsCore(IPipFilterContext context, bool negate = false, IList <PipId> constrainingPips = null)
        {
            var outputs = Inner.FilterOutputs(context, negate: false);

            HashSet <PipId> innerPipProducers = new HashSet <PipId>();

            foreach (var innerOutput in outputs)
            {
                innerPipProducers.Add(context.GetProducer(innerOutput));
            }

            var producersAndNeighbors = GetClosureWithOutputs(context, innerPipProducers, GetNeighborPips, ClosureMode);

            if (IncludesInnerMatches)
            {
                // Add producers
                producersAndNeighbors.UnionWith(innerPipProducers);
            }
            else
            {
                // Exclude inner matchs
                producersAndNeighbors.ExceptWith(innerPipProducers);
            }

            // When not negated the set of pips to process is
            // the intersection of the constraining pips and the producers and
            // neighbors set.
            if (!negate)
            {
                if (constrainingPips == null)
                {
                    // No constraining pips, so only consider the producers and neighbors
                    constrainingPips = producersAndNeighbors.ToList();
                }
                else
                {
                    // Has constraining pips, so intersect with the producers and neighbors
                    producersAndNeighbors.IntersectWith(constrainingPips);
                    constrainingPips = producersAndNeighbors.ToList();
                }
            }

            return(ParallelProcessAllOutputs <FileOrDirectoryArtifact>(
                       context,
                       action: (pipId, localOutputs) =>
            {
                if (producersAndNeighbors.Contains(pipId) ^ negate)
                {
                    ForEachOutput(
                        localOutputs,
                        context,
                        pipId,
                        (localOutputs2, output) => localOutputs2.Add(output));
                }
            },
                       pips: constrainingPips));
        }
示例#7
0
        /// <summary>
        /// Gets the pips that can have outputs in the transitive closure of a given set of value and seal directory pips
        /// </summary>
        protected static void AddTransitiveSpecDependencies(IPipFilterContext context, HashSet <PipId> specFileIds)
        {
            HashSet <PipId> closure = new HashSet <PipId>();
            var             stack   = new Stack <PipId>();

            foreach (var rootPipId in specFileIds)
            {
                closure.Add(rootPipId);
                stack.Push(rootPipId);
            }

            while (stack.Count > 0)
            {
                var pipId = stack.Pop();
                foreach (PipId dependency in context.GetDependencies(pipId))
                {
                    if (closure.Add(dependency))
                    {
                        stack.Push(dependency);
                    }
                }

                var pipType = context.GetPipType(pipId);
                if (pipType == PipType.Value)
                {
                    // For value pips, get the spec corresponding spec file pip
                    foreach (var dependent in context.GetDependents(pipId))
                    {
                        if (context.GetPipType(dependent) == PipType.SpecFile)
                        {
                            if (specFileIds.Add(dependent))
                            {
                                stack.Push(dependent);
                            }

                            break;
                        }
                    }
                }
                else if (!pipType.IsMetaPip())
                {
                    // Get the value pip for the pip and push to visit its dependencies and the corresponding spec file
                    foreach (var dependent in context.GetDependents(pipId))
                    {
                        if (context.GetPipType(dependent) == PipType.Value)
                        {
                            if (closure.Add(dependent))
                            {
                                stack.Push(dependent);
                            }

                            break;
                        }
                    }
                }
            }
        }
示例#8
0
        private bool MatchesDependencies(IPipFilterContext context, Process proc)
        {
            foreach (var item in proc.Dependencies)
            {
                if (PathMatches(item.Path, context.PathTable))
                {
                    return(true);
                }
            }

            return(false);
        }
示例#9
0
        /// <summary>
        /// Determines whether a pip could have outputs
        /// </summary>
        protected static bool MayHaveOutputs(IPipFilterContext context, PipId pipId)
        {
            switch (context.GetPipType(pipId))
            {
            case PipType.Process:
            case PipType.CopyFile:
            case PipType.SealDirectory:
            case PipType.WriteFile:
            case PipType.Ipc:
                return(true);
            }

            return(false);
        }
示例#10
0
 /// <inheritdoc/>
 public override IReadOnlySet <FileOrDirectoryArtifact> FilterOutputsCore(
     IPipFilterContext context,
     bool negate = false,
     IList <PipId> constrainingPips = null)
 {
     return(ParallelProcessAllOutputs <FileOrDirectoryArtifact>(
                context,
                (pipId, localOutputs) =>
     {
         if ((context.GetSemiStableHash(pipId) == m_semiStableHash) ^ negate)
         {
             AddOutputs(context, pipId, localOutputs);
         }
     },
                constrainingPips));
 }
示例#11
0
 /// <inheritdoc />
 public override IReadOnlySet <FileOrDirectoryArtifact> FilterOutputsCore(IPipFilterContext context, bool negate = false, IList <PipId> constrainingPips = null)
 {
     return(ParallelProcessAllOutputs <FileOrDirectoryArtifact>(
                context,
                (pipId, localOutputs) =>
     {
         if (MayHaveOutputs(context, pipId))
         {
             Pip pip = context.HydratePip(pipId);
             if (Matches(pip) ^ negate)
             {
                 AddOutputs(pip, localOutputs);
             }
         }
     },
                constrainingPips));
 }
示例#12
0
        /// <summary>
        /// Gets the pips that can have outputs which are direct dependencies of values of the given spec file pips.
        /// </summary>
        protected static HashSet <PipId> GetDependenciesWithOutputsForSpecFilePips(IPipFilterContext context, IEnumerable <PipId> specFilePipIds)
        {
            HashSet <PipId> valueDependencies = new HashSet <PipId>();

            foreach (var specFilePipId in specFilePipIds)
            {
                foreach (var dependency in context.GetDependencies(specFilePipId))
                {
                    if (context.GetPipType(dependency) == PipType.Value)
                    {
                        valueDependencies.Add(dependency);
                    }
                }
            }

            return(GetDependenciesWithOutputsForValuePips(context, valueDependencies));
        }
示例#13
0
        /// <summary>
        /// Gets the pips that can have outputs which are direct dependencies of the given value pips.
        /// </summary>
        protected static HashSet <PipId> GetDependenciesWithOutputsForValuePips(IPipFilterContext context, IEnumerable <PipId> valuePipIds)
        {
            HashSet <PipId> dependenciesWithOutputs = new HashSet <PipId>();

            foreach (var valuePipId in valuePipIds)
            {
                foreach (var dependency in context.GetDependencies(valuePipId))
                {
                    if (MayHaveOutputs(context, dependency))
                    {
                        dependenciesWithOutputs.Add(dependency);
                    }
                }
            }

            return(dependenciesWithOutputs);
        }
示例#14
0
        /// <summary>
        /// Gets the transitive dependent pips that can have outputs
        /// </summary>
        protected static HashSet <PipId> GetClosureWithOutputs(
            IPipFilterContext context,
            HashSet <PipId> pipIds,
            Func <IPipFilterContext, PipId, IEnumerable <PipId> > getPips,
            ClosureMode closureMode)
        {
            HashSet <PipId> closure = new HashSet <PipId>();

            if (closureMode == ClosureMode.TransitiveIncludingSelf)
            {
                var stack = new Stack <PipId>();
                foreach (var rootPipId in pipIds)
                {
                    stack.Push(rootPipId);
                }

                while (stack.Count > 0)
                {
                    var pipId = stack.Pop();
                    foreach (PipId neighbor in getPips(context, pipId))
                    {
                        if (MayHaveOutputs(context, neighbor) && closure.Add(neighbor))
                        {
                            stack.Push(neighbor);
                        }
                    }
                }
            }
            else
            {
                Contract.Assert(closureMode == ClosureMode.DirectExcludingSelf);
                foreach (var pipId in pipIds)
                {
                    foreach (PipId neighbor in getPips(context, pipId))
                    {
                        if (MayHaveOutputs(context, neighbor))
                        {
                            closure.Add(neighbor);
                        }
                    }
                }
            }

            return(closure);
        }
示例#15
0
        /// <summary>
        /// Returns the set of output files or directories that match the filter.
        /// </summary>
        /// <remarks>
        /// NOTE: ALL FILTER OPERATION MUST BE IDEMPOTENT BECAUSE THE RESULTS ARE CACHED.
        /// </remarks>
        public IReadOnlySet <FileOrDirectoryArtifact> FilterOutputs(
            IPipFilterContext context,
            bool negate = false,
            IList <PipId> constrainingPips = null)
        {
            if (negate || constrainingPips != null)
            {
                return(FilterOutputsCore(context, negate, constrainingPips));
            }

            if (context.TryGetCachedOutputs(this, out IReadOnlySet <FileOrDirectoryArtifact> result))
            {
                return(result);
            }

            result = FilterOutputsCore(context);
            context.CacheOutputs(this, result);

            return(result);
        }
示例#16
0
        /// <inheritdoc/>
        public override IReadOnlySet <FileOrDirectoryArtifact> FilterOutputsCore(IPipFilterContext context, bool negate = false, IList <PipId> constrainingPips = null)
        {
            var matchingSpecFilePipIds = ParallelProcessAllOutputs <PipId>(
                context,
                (pipId, localPips) =>
            {
                if (context.GetPipType(pipId) == PipType.SpecFile)
                {
                    SpecFilePip specFilePip = (SpecFilePip)context.HydratePip(pipId);
                    if (PathMatches(specFilePip.SpecFile.Path, context.PathTable) ^ negate)
                    {
                        localPips.Add(pipId);
                    }
                }
            });

            if (m_specDependencies)
            {
                AddTransitiveSpecDependencies(context, matchingSpecFilePipIds);
            }

            HashSet <PipId> dependenciesWithOutputs =
                m_valueTransitive
                    ? GetDependenciesWithOutputsBehindValueAndSealDirectoryPips(context, matchingSpecFilePipIds)
                    : GetDependenciesWithOutputsForSpecFilePips(context, matchingSpecFilePipIds);

            if (constrainingPips != null)
            {
                dependenciesWithOutputs.IntersectWith(constrainingPips);
            }

            return(ParallelProcessAllOutputs <FileOrDirectoryArtifact>(
                       context,
                       (pipId, localOutputs) => AddOutputs(context, pipId, localOutputs),
                       dependenciesWithOutputs.ToArray()));
        }
示例#17
0
        /// <inheritdoc/>
        public override IReadOnlySet <FileOrDirectoryArtifact> FilterOutputsCore(IPipFilterContext context, bool negate = false, IList <PipId> constrainingPips = null)
        {
            // First we collect all matching seal directories
            HashSet <DirectoryArtifact> directories = ParallelProcessAllOutputs <DirectoryArtifact>(
                context,
                (pipId, localDirectories) =>
            {
                if (context.GetPipType(pipId) == PipType.SealDirectory)
                {
                    SealDirectory sd = (SealDirectory)context.HydratePip(pipId);
                    foreach (var item in sd.Contents)
                    {
                        if (PathMatches(item.Path, context.PathTable))
                        {
                            localDirectories.Add(sd.Directory);
                            break;
                        }
                    }

                    switch (sd.Kind)
                    {
                    case SealDirectoryKind.SourceAllDirectories:
                    case SealDirectoryKind.Opaque:
                    case SealDirectoryKind.SharedOpaque:
                        if (DirectoryPathMatches(sd.DirectoryRoot, false, context.PathTable))
                        {
                            localDirectories.Add(sd.Directory);
                        }
                        break;

                    case SealDirectoryKind.SourceTopDirectoryOnly:
                        if (DirectoryPathMatches(sd.DirectoryRoot, true, context.PathTable))
                        {
                            localDirectories.Add(sd.Directory);
                        }
                        break;
                    }
                }
            });

            // Now look at all pips, checking if their input match one of the files or matching DirectoryArtifacts
            return(ParallelProcessAllOutputs <FileOrDirectoryArtifact>(
                       context,
                       (pipId, localOutputs) =>
            {
                switch (context.GetPipType(pipId))
                {
                case PipType.CopyFile:
                    CopyFile cf = (CopyFile)context.HydratePip(pipId);
                    if (PathMatches(cf.Source, context.PathTable) ^ negate)
                    {
                        localOutputs.Add(FileOrDirectoryArtifact.Create(cf.Destination));
                    }

                    break;

                case PipType.Process:
                    Process proc = (Process)context.HydratePip(pipId);
                    bool processMatches =
                        PathMatches(proc.Executable, context.PathTable) ||
                        MatchesDependencies(context, proc) ||
                        MatchesDirectoryDependencies(proc, directories);
                    if (processMatches ^ negate)
                    {
                        // TODO: If only directory dependencies matched, only include outputs from those directories
                        foreach (var output in proc.FileOutputs)
                        {
                            localOutputs.Add(FileOrDirectoryArtifact.Create(output.ToFileArtifact()));
                        }

                        foreach (var output in proc.DirectoryOutputs)
                        {
                            localOutputs.Add(FileOrDirectoryArtifact.Create(output));
                        }
                    }

                    break;
                }
            },
                       constrainingPips));
        }
示例#18
0
 /// <inheritdoc/>
 protected override IEnumerable <PipId> GetNeighborPips(IPipFilterContext context, PipId pip)
 {
     return(context.GetDependents(pip).Where(p => context.GetPipType(p) == BuildXL.Pips.Operations.PipType.CopyFile));
 }
示例#19
0
 /// <inheritdoc/>
 public override IReadOnlySet <FileOrDirectoryArtifact> FilterOutputsCore(IPipFilterContext context, bool negate = false, IList <PipId> constrainingPips = null)
 {
     Contract.Assert(false, "The empty filter should never be executed. It will always match so executing it is just wasted work.");
     throw new InvalidOperationException("The empty filter should never be executed. It will always match so executing it is just wasted work.");
 }
示例#20
0
 /// <inheritdoc/>
 public override IReadOnlySet <FileOrDirectoryArtifact> FilterOutputsCore(IPipFilterContext context, bool negate = false, IList <PipId> constrainingPips = null)
 {
     return(Inner.FilterOutputs(context, !negate, constrainingPips));
 }
示例#21
0
 /// <inheritdoc/>
 protected override IEnumerable <PipId> GetNeighborPips(IPipFilterContext context, PipId pip)
 {
     return(context.GetDependents(pip));
 }
示例#22
0
 /// <summary>
 /// To be implemented by specific filter types. Returns the set of output files or directories that match the filter.
 /// </summary>
 /// <returns>Collection of output files that match the filter</returns>
 public abstract IReadOnlySet <FileOrDirectoryArtifact> FilterOutputsCore(
     IPipFilterContext context,
     bool negate = false,
     IList <PipId> constrainingPips = null);
示例#23
0
 /// <summary>
 /// Gets the neighbor (dependents or dependencies) pips of the current pip
 /// </summary>
 protected abstract IEnumerable <PipId> GetNeighborPips(IPipFilterContext context, PipId pip);
示例#24
0
 /// <summary>
 /// Hydrates the pip and calls an action for each of the pip's outputs
 /// (<see cref="ForEachOutput{TState}(TState,IPipFilterContext,PipId,Action{TState,FileOrDirectoryArtifact})"/>.
 /// </summary>
 protected static void ForEachOutput <TState>(TState state, IPipFilterContext context, PipId pipId, Action <TState, FileOrDirectoryArtifact> outputAction)
 {
     ForEachOutput(state, context.HydratePip(pipId), outputAction);
 }
示例#25
0
        /// <summary>
        /// Gets the pips that can have outputs in the transitive closure of a given set of value and seal directory pips
        /// </summary>
        protected static HashSet <PipId> GetDependenciesWithOutputsBehindValueAndSealDirectoryPips(IPipFilterContext context, IReadOnlySet <PipId> rootPipIds)
        {
            HashSet <PipId> closure = new HashSet <PipId>();
            HashSet <PipId> dependenciesWithOutputs = new HashSet <PipId>();
            var             q = new Queue <PipId>();

            foreach (var rootPipId in rootPipIds)
            {
                closure.Add(rootPipId);
                q.Enqueue(rootPipId);
            }

            while (q.Count > 0)
            {
                var pipId = q.Dequeue();
                foreach (PipId dependency in context.GetDependencies(pipId))
                {
                    switch (context.GetPipType(dependency))
                    {
                    case PipType.Value:
                    case PipType.SealDirectory:
                        if (closure.Add(dependency))
                        {
                            q.Enqueue(dependency);
                        }

                        break;

                    case PipType.WriteFile:
                    case PipType.CopyFile:
                    case PipType.Process:
                    case PipType.Ipc:
                        dependenciesWithOutputs.Add(dependency);
                        break;
                    }
                }
            }

            return(dependenciesWithOutputs);
        }