Example #1
0
        /// <summary>
        /// Retrieves the list of dependencies this target needs to have built and moves the target to the next state.
        /// Never returns null.
        /// </summary>
        /// <returns>A collection of targets on which this target depends.</returns>
        internal List <TargetSpecification> GetDependencies(ProjectLoggingContext projectLoggingContext)
        {
            VerifyState(_state, TargetEntryState.Dependencies);

            // Resolve the target now, since from this point on we are going to be doing work with the actual instance.
            GetTargetInstance();

            // We first make sure no batching was attempted with the target's condition.
            // UNDONE: (Improvement) We want to allow this actually.  In order to do this we need to determine what the
            // batching buckets are, and if there are any which aren't empty, return our list of dependencies.
            // Only in the case where all bucket conditions fail do we want to skip the target entirely (and
            // this skip building the dependencies.)
            if (ExpressionShredder.ContainsMetadataExpressionOutsideTransform(_target.Condition))
            {
                ProjectErrorUtilities.ThrowInvalidProject(_target.ConditionLocation, "TargetConditionHasInvalidMetadataReference", _target.Name, _target.Condition);
            }

            // If condition is false (based on propertyBag), set this target's state to
            // "Skipped" since we won't actually build it.
            bool condition = ConditionEvaluator.EvaluateCondition
                             (
                _target.Condition,
                ParserOptions.AllowPropertiesAndItemLists,
                _expander,
                ExpanderOptions.ExpandPropertiesAndItems,
                _requestEntry.ProjectRootDirectory,
                _target.ConditionLocation,
                projectLoggingContext.LoggingService,
                projectLoggingContext.BuildEventContext
                             );

            if (!condition)
            {
                _targetResult = new TargetResult(new TaskItem[0] {
                }, new WorkUnitResult(WorkUnitResultCode.Skipped, WorkUnitActionCode.Continue, null));
                _state        = TargetEntryState.Completed;

                if (!projectLoggingContext.LoggingService.OnlyLogCriticalEvents)
                {
                    // Expand the expression for the Log.
                    string expanded = _expander.ExpandIntoStringAndUnescape(_target.Condition, ExpanderOptions.ExpandPropertiesAndItems, _target.ConditionLocation);

                    // By design: Not building dependencies. This is what NAnt does too.
                    // NOTE: In the original code, this was logged from the target logging context.  However, the target
                    // hadn't been "started" by then, so you'd get a target message outside the context of a started
                    // target.  In the Task builder (and original Task Engine), a Task Skipped message would be logged in
                    // the context of the target, not the task.  This should be the same, especially given that we
                    // wish to allow batching on the condition of a target.
                    projectLoggingContext.LogComment(MessageImportance.Low, "TargetSkippedFalseCondition", _target.Name, _target.Condition, expanded);
                }

                return(new List <TargetSpecification>());
            }

            IList <string>             dependencies      = _expander.ExpandIntoStringListLeaveEscaped(_target.DependsOnTargets, ExpanderOptions.ExpandPropertiesAndItems, _target.DependsOnTargetsLocation);
            List <TargetSpecification> dependencyTargets = new List <TargetSpecification>(dependencies.Count);

            foreach (string escapedDependency in dependencies)
            {
                string dependencyTargetName = EscapingUtilities.UnescapeAll(escapedDependency);
                dependencyTargets.Add(new TargetSpecification(dependencyTargetName, _target.DependsOnTargetsLocation));
            }

            _state = TargetEntryState.Execution;

            return(dependencyTargets);
        }
Example #2
0
        private List <ProjectItemInstance> FindItemsMatchingSpecification
        (
            ICollection <ProjectItemInstance> items,
            string specification,
            ElementLocation specificationLocation,
            Expander <ProjectPropertyInstance, ProjectItemInstance> expander
        )
        {
            if (items.Count == 0 || specification.Length == 0)
            {
                return(null);
            }

            // This is a hashtable whose key is the filename for the individual items
            // in the Exclude list, after wildcard expansion.
            HashSet <string> specificationsToFind = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            // Split by semicolons
            var specificationPieces = expander.ExpandIntoStringListLeaveEscaped(specification, ExpanderOptions.ExpandAll, specificationLocation);

            foreach (string piece in specificationPieces)
            {
                // Take each individual path or file expression, and expand any
                // wildcards.  Then loop through each file returned, and add it
                // to our hashtable.

                // Don't unescape wildcards just yet - if there were any escaped, the caller wants to treat them
                // as literals. Everything else is safe to unescape at this point, since we're only matching
                // against the file system.
                string[] fileList = EngineFileUtilities.GetFileListEscaped(Project.Directory, piece);

                foreach (string file in fileList)
                {
                    // Now unescape everything, because this is the end of the road for this filename.
                    // We're just going to compare it to the unescaped include path to filter out the
                    // file excludes.
                    specificationsToFind.Add(EscapingUtilities.UnescapeAll(file));
                }
            }

            if (specificationsToFind.Count == 0)
            {
                return(null);
            }

            // Now loop through our list and filter out any that match a
            // filename in the remove list.
            List <ProjectItemInstance> itemsRemoved = new List <ProjectItemInstance>();

            foreach (ProjectItemInstance item in items)
            {
                // Even if the case for the excluded files is different, they
                // will still get excluded, as expected.  However, if the excluded path
                // references the same file in a different way, such as by relative
                // path instead of absolute path, we will not realize that they refer
                // to the same file, and thus we will not exclude it.
                if (specificationsToFind.Contains(item.EvaluatedInclude))
                {
                    itemsRemoved.Add(item);
                }
            }

            return(itemsRemoved);
        }
Example #3
0
        public void ExpandAllIntoStringListLeaveEscapedComplex()
        {
            ReadOnlyLookup lookup;
            StringMetadataTable itemMetadata;
            CreateComplexPropertiesItemsMetadata(out lookup, out itemMetadata);

            Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(lookup, lookup, itemMetadata);

            string value = "@(Resource->'%(Filename)') ; @(Content) ; @(NonExistent) ; $(NonExistent) ; %(NonExistent) ; " +
                "$(OutputPath) ; $(TargetPath) ; %(Language)_%(Culture)";

            IList<string> expanded = expander.ExpandIntoStringListLeaveEscaped(value, ExpanderOptions.ExpandAll, MockElementLocation.Instance);

            Assert.Equal(9, expanded.Count);
            Assert.Equal(@"string$(p)", expanded[0]);
            Assert.Equal(@"dialogs%253b", expanded[1]);
            Assert.Equal(@"splash.bmp", expanded[2]);
            Assert.Equal(@"\jk", expanded[3]);
            Assert.Equal(@"l\mno%253bpqr\stu", expanded[4]);
            Assert.Equal(@"subdir1\", expanded[5]);
            Assert.Equal(@"subdir2\", expanded[6]);
            Assert.Equal(@"english_abc%253bdef", expanded[7]);
            Assert.Equal(@"ghi", expanded[8]);
        }
        /// <summary>
        /// Returns a list of all items in the provided item group whose itemspecs match the specification, after it is split and any wildcards are expanded.
        /// If no items match, returns null.
        /// </summary>
        /// <param name="items">The items to match</param>
        /// <param name="specification">The specification to match against the items.</param>
        /// <param name="specificationLocation">The specification to match against the provided items</param>
        /// <param name="expander">The expander to use</param>
        /// <returns>A list of matching items</returns>
        private List<ProjectItemInstance> FindItemsMatchingSpecification
            (
            ICollection<ProjectItemInstance> items,
            string specification,
            ElementLocation specificationLocation,
            Expander<ProjectPropertyInstance, ProjectItemInstance> expander
            )
        {
            if (items.Count == 0 || specification.Length == 0)
            {
                return null;
            }

            // This is a hashtable whose key is the filename for the individual items
            // in the Exclude list, after wildcard expansion.
            HashSet<string> specificationsToFind = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

            // Split by semicolons
            IList<string> specificationPieces = expander.ExpandIntoStringListLeaveEscaped(specification, ExpanderOptions.ExpandAll, specificationLocation);

            foreach (string piece in specificationPieces)
            {
                // Take each individual path or file expression, and expand any
                // wildcards.  Then loop through each file returned, and add it
                // to our hashtable.

                // Don't unescape wildcards just yet - if there were any escaped, the caller wants to treat them
                // as literals. Everything else is safe to unescape at this point, since we're only matching
                // against the file system.
                string[] fileList = EngineFileUtilities.GetFileListEscaped(Project.Directory, piece);

                foreach (string file in fileList)
                {
                    // Now unescape everything, because this is the end of the road for this filename.
                    // We're just going to compare it to the unescaped include path to filter out the
                    // file excludes.
                    specificationsToFind.Add(EscapingUtilities.UnescapeAll(file));
                }
            }

            if (specificationsToFind.Count == 0)
            {
                return null;
            }

            // Now loop through our list and filter out any that match a
            // filename in the remove list.
            List<ProjectItemInstance> itemsRemoved = new List<ProjectItemInstance>();

            foreach (ProjectItemInstance item in items)
            {
                // Even if the case for the excluded files is different, they
                // will still get excluded, as expected.  However, if the excluded path
                // references the same file in a different way, such as by relative
                // path instead of absolute path, we will not realize that they refer
                // to the same file, and thus we will not exclude it.
                if (specificationsToFind.Contains(item.EvaluatedInclude))
                {
                    itemsRemoved.Add(item);
                }
            }

            return itemsRemoved;
        }