public static FileSpecMatcherTester Parse(string currentDirectory, string fileSpec) { string unescapedFileSpec = EscapingUtilities.UnescapeAll(fileSpec); Regex regex = EngineFileUtilities.FilespecHasWildcards(fileSpec) ? CreateRegex(unescapedFileSpec, currentDirectory) : null; return(new FileSpecMatcherTester(currentDirectory, unescapedFileSpec, regex)); }
private (ITaskItem[] Element, bool NoLoggedErrors) TryExpandingWildcards(ITaskItem[] expand, string attributeType) { const string CreateItemTask = nameof(CreateItem); string fileSpec; FileMatcher.SearchAction searchAction; (expand, searchAction, fileSpec) = ExpandWildcards(expand); // Log potential drive enumeration glob anomalies when applicable. if (searchAction == FileMatcher.SearchAction.LogDriveEnumeratingWildcard) { Log.LogWarningWithCodeFromResources( "WildcardResultsInDriveEnumeration", EscapingUtilities.UnescapeAll(fileSpec), attributeType, CreateItemTask); } else if (searchAction == FileMatcher.SearchAction.FailOnDriveEnumeratingWildcard) { Log.LogErrorWithCodeFromResources( "WildcardResultsInDriveEnumeration", EscapingUtilities.UnescapeAll(fileSpec), attributeType, CreateItemTask); } return(expand, !Log.HasLoggedErrors); }
/// <summary> /// Given a build state try to find the parent target that caused this build state to /// come into being either via dependent, on error relationship or via IBuildEngine call /// </summary> internal TargetIdWrapper FindParentTarget ( EngineCallback engineCallback, ProjectBuildState buildContext, Target target, out BuildRequest parentRequest ) { // We need to find the parent target parentRequest = null; // Skip build states that have already been filled if (buildContext.CurrentBuildContextState == ProjectBuildState.BuildContextState.RequestFilled) { return(null); } // Check if the target was called due to a onerror or depends on call if (buildContext.ContainsBlockingTarget(target.Name)) { // Figure out the record for the parent target Project containingProject = target.ParentProject; Target parentTarget = containingProject.Targets[buildContext.GetParentTarget(target.Name)]; return(new TargetIdWrapper(parentTarget)); } else { // The build context must have formed due to IBuildEngine call ErrorUtilities.VerifyThrow( String.Compare(EscapingUtilities.UnescapeAll(buildContext.NameOfTargetInProgress), target.Name, StringComparison.OrdinalIgnoreCase) == 0, "The target should be the in progress target for the context"); // This target is called due to IBuildEngine or host request return(FindParentTargetForBuildRequest(engineCallback, buildContext.BuildRequest, out parentRequest)); } }
/// <summary> /// Copy the metadata (but not the ItemSpec or other built-in metadata) to destinationItem. If a particular metadata /// already exists on the destination item, then it is not overwritten -- the original value wins. /// </summary> /// <owner>JomoF</owner> /// <param name="destinationItem"></param> public void CopyMetadataTo ( ITaskItem destinationItem ) { ErrorUtilities.VerifyThrowArgumentNull(destinationItem, "destinationItem"); // Intentionally not _computed_ properties. These are slow and don't really // apply anyway. foreach (DictionaryEntry entry in item.GetAllCustomEvaluatedMetadata()) { string key = (string)entry.Key; string destinationValue = destinationItem.GetMetadata(key); if ((destinationValue == null) || (destinationValue.Length == 0)) { destinationItem.SetMetadata(key, EscapingUtilities.UnescapeAll((string)entry.Value)); } } // also copy the original item-spec under a "magic" metadata -- this is useful for tasks that forward metadata // between items, and need to know the source item where the metadata came from string originalItemSpec = destinationItem.GetMetadata("OriginalItemSpec"); if ((originalItemSpec == null) || (originalItemSpec.Length == 0)) { destinationItem.SetMetadata("OriginalItemSpec", ItemSpec); } }
/// <summary> /// Initializes a build request with a parent context. /// </summary> /// <param name="submissionId">The id of the build submission.</param> /// <param name="nodeRequestId">The id of the node issuing the request</param> /// <param name="configurationId">The configuration id to use.</param> /// <param name="escapedTargets">The targets to be built</param> /// <param name="hostServices">Host services if any. May be null.</param> /// <param name="parentBuildEventContext">The build event context of the parent project.</param> /// <param name="parentRequest">The parent build request, if any.</param> /// <param name="buildRequestDataFlags">Additional flags for the request.</param> /// <param name="requestedProjectState">Filter for desired build results.</param> public BuildRequest( int submissionId, int nodeRequestId, int configurationId, ICollection <string> escapedTargets, HostServices hostServices, BuildEventContext parentBuildEventContext, BuildRequest parentRequest, BuildRequestDataFlags buildRequestDataFlags = BuildRequestDataFlags.None, RequestedProjectState requestedProjectState = null) { ErrorUtilities.VerifyThrowArgumentNull(escapedTargets, "targets"); ErrorUtilities.VerifyThrowArgumentNull(parentBuildEventContext, "parentBuildEventContext"); _submissionId = submissionId; _configurationId = configurationId; // When targets come into a build request, we unescape them. _targets = new List <string>(escapedTargets.Count); foreach (string target in escapedTargets) { _targets.Add(EscapingUtilities.UnescapeAll(target)); } HostServices = hostServices; _buildEventContext = BuildEventContext.Invalid; _parentBuildEventContext = parentBuildEventContext; _globalRequestId = InvalidGlobalRequestId; _parentGlobalRequestId = parentRequest?.GlobalRequestId ?? InvalidGlobalRequestId; _nodeRequestId = nodeRequestId; _buildRequestDataFlags = buildRequestDataFlags; _requestedProjectState = requestedProjectState; }
public BuildRequest( int submissionId, int nodeRequestId, int configurationId, ICollection <string> escapedTargets, HostServices hostServices, BuildEventContext parentBuildEventContext, BuildRequest parentRequest, BuildRequestDataFlags buildRequestDataFlags = BuildRequestDataFlags.None, RequestedProjectState requestedProjectState = null, bool skipStaticGraphIsolationConstraints = false, int projectContextId = BuildEventContext.InvalidProjectContextId) : this(submissionId, nodeRequestId, configurationId, hostServices, buildRequestDataFlags, requestedProjectState, projectContextId) { ErrorUtilities.VerifyThrowArgumentNull(escapedTargets, "targets"); ErrorUtilities.VerifyThrowArgumentNull(parentBuildEventContext, nameof(parentBuildEventContext)); // When targets come into a build request, we unescape them. _targets = new List <string>(escapedTargets.Count); foreach (string target in escapedTargets) { _targets.Add(EscapingUtilities.UnescapeAll(target)); } _parentBuildEventContext = parentBuildEventContext; _parentGlobalRequestId = parentRequest?.GlobalRequestId ?? InvalidGlobalRequestId; _skipStaticGraphIsolationConstraints = skipStaticGraphIsolationConstraints; }
/// <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 not items match, returns null. /// </summary> internal static List <BuildItem> FindItemsMatchingSpecification(BuildItemGroup items, string specification, XmlAttribute attribute, Expander expander, string baseDirectory) { 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. The value in the hash table // is just an empty string. Hashtable specificationsToFind = new Hashtable(StringComparer.OrdinalIgnoreCase); // Split by semicolons List <string> specificationPieces = expander.ExpandAllIntoStringListLeaveEscaped(specification, attribute); 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(baseDirectory, 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[EscapingUtilities.UnescapeAll(file)] = String.Empty; } } if (specificationsToFind.Count == 0) { return(null); } // Now loop through our list and filter out any that match a // filename in the remove list. List <BuildItem> itemsRemoved = new List <BuildItem>(); foreach (BuildItem 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.ContainsKey(item.FinalItemSpec)) { itemsRemoved.Add(item); } } return(itemsRemoved); }
/// <summary> /// Used for the purposes of evaluating an item specification. Given a filespec that may include wildcard characters * and /// ?, we translate it into an actual list of files. If the input filespec doesn't contain any wildcard characters, and it /// doesn't appear to point to an actual file on disk, then we just give back the input string as an array of length one, /// assuming that it wasn't really intended to be a filename (as items are not required to necessarily represent files). /// Any wildcards passed in that are unescaped will be treated as real wildcards. /// The "include" of items passed back from the filesystem will be returned canonically escaped. /// The ordering of the list returned is deterministic (it is sorted). /// Will never throw IO exceptions: if there is no match, returns the input verbatim. /// </summary> /// <param name="directoryEscaped">The directory to evaluate, escaped.</param> /// <param name="filespecEscaped">The filespec to evaluate, escaped.</param> /// <param name="returnEscaped"><code>true</code> to return escaped specs.</param> /// <param name="excludeSpecsEscaped">The exclude specification, escaped.</param> /// <returns>Array of file paths.</returns> private static string[] GetFileList ( string directoryEscaped, string filespecEscaped, bool returnEscaped, IEnumerable <string> excludeSpecsEscaped = null ) { ErrorUtilities.VerifyThrowInternalLength(filespecEscaped, "filespecEscaped"); if (excludeSpecsEscaped == null) { excludeSpecsEscaped = Enumerable.Empty <string>(); } string[] fileList; if (FilespecHasWildcards(filespecEscaped)) { // Unescape before handing it to the filesystem. var directoryUnescaped = EscapingUtilities.UnescapeAll(directoryEscaped); var filespecUnescaped = EscapingUtilities.UnescapeAll(filespecEscaped); var excludeSpecsUnescaped = excludeSpecsEscaped.Where(IsValidExclude).Select(EscapingUtilities.UnescapeAll).ToList(); // Get the list of actual files which match the filespec. Put // the list into a string array. If the filespec started out // as a relative path, we will get back a bunch of relative paths. // If the filespec started out as an absolute path, we will get // back a bunch of absolute paths. fileList = FileMatcher.GetFiles(directoryUnescaped, filespecUnescaped, excludeSpecsUnescaped); ErrorUtilities.VerifyThrow(fileList != null, "We must have a list of files here, even if it's empty."); // Before actually returning the file list, we sort them alphabetically. This // provides a certain amount of extra determinism and reproducability. That is, // we're sure that the build will behave in exactly the same way every time, // and on every machine. Array.Sort(fileList, StringComparer.OrdinalIgnoreCase); if (returnEscaped) { // We must now go back and make sure all special characters are escaped because we always // store data in the engine in escaped form so it doesn't interfere with our parsing. // Note that this means that characters that were not escaped in the original filespec // may now be escaped, but that's not easy to avoid. for (int i = 0; i < fileList.Length; i++) { fileList[i] = EscapingUtilities.Escape(fileList[i]); } } } else { // Just return the original string. fileList = new string[] { returnEscaped?filespecEscaped : EscapingUtilities.UnescapeAll(filespecEscaped) }; } return(fileList); }
internal static string Unescape ( this string escapedString, out bool escapingWasNecessary ) { return(EscapingUtilities.UnescapeAll(escapedString, out escapingWasNecessary)); }
/// <summary> /// Retrieves one of the arbitrary metadata on the item. /// If not found, returns empty string. /// </summary> /// <comments> /// Returns the unescaped value of the metadata requested. /// </comments> /// <param name="metadataName">The name of the metadata to retrieve.</param> /// <returns>The metadata value.</returns> public string GetMetadata ( string metadataName ) { string metadataValue = (this as ITaskItem2).GetMetadataValueEscaped(metadataName); return(EscapingUtilities.UnescapeAll(metadataValue)); }
/// <summary> /// Get the value of any metadata in the item that has the specified /// name, otherwise returns null /// </summary> public string GetMetadataValue(string name) { if (Link != null) { return(Link.GetMetadataValue(name)); } string escapedValue = (this as IMetadataTable).GetEscapedValue(name); return((escapedValue == null) ? null : EscapingUtilities.UnescapeAll(escapedValue)); }
public void EscapeUnescape() { string text = "%2a"; Assert.Equal(text, EscapingUtilities.Escape(EscapingUtilities.UnescapeAll(text))); text = "%3f"; Assert.Equal(text, EscapingUtilities.Escape(EscapingUtilities.UnescapeAll(text))); text = "#%2a%3f%2a#%2a"; Assert.Equal(text, EscapingUtilities.Escape(EscapingUtilities.UnescapeAll(text))); }
public void UnescapeEscape() { string text = "*"; Assert.Equal(text, EscapingUtilities.UnescapeAll(EscapingUtilities.Escape(text))); text = "?"; Assert.Equal(text, EscapingUtilities.UnescapeAll(EscapingUtilities.Escape(text))); text = "#*?*#*"; Assert.Equal(text, EscapingUtilities.UnescapeAll(EscapingUtilities.Escape(text))); }
void ProcessItemSpec(OperationBuilder operationBuilder, string itemSpec, ElementLocation itemSpecLocation) { // Code corresponds to Evaluator.CreateItemsFromInclude // STEP 1: Expand properties in Include string evaluatedIncludeEscaped = _outerExpander.ExpandIntoStringLeaveEscaped(itemSpec, ExpanderOptions.ExpandProperties, itemSpecLocation); // STEP 2: Split Include on any semicolons, and take each split in turn if (evaluatedIncludeEscaped.Length > 0) { IList <string> includeSplitsEscaped = ExpressionShredder.SplitSemiColonSeparatedList(evaluatedIncludeEscaped); foreach (string includeSplitEscaped in includeSplitsEscaped) { // STEP 3: If expression is "@(x)" copy specified list with its metadata, otherwise just treat as string bool isItemListExpression; ProcessSingleItemVectorExpressionForInclude(includeSplitEscaped, operationBuilder, itemSpecLocation, out isItemListExpression); if (!isItemListExpression) { // The expression is not of the form "@(X)". Treat as string // Code corresponds to EngineFileUtilities.GetFileList bool containsEscapedWildcards = EscapingUtilities.ContainsEscapedWildcards(includeSplitEscaped); bool containsRealWildcards = FileMatcher.HasWildcards(includeSplitEscaped); if (containsEscapedWildcards && containsRealWildcards) { // Umm, this makes no sense. The item's Include has both escaped wildcards and // real wildcards. What does he want us to do? Go to the file system and find // files that literally have '*' in their filename? Well, that's not going to // happen because '*' is an illegal character to have in a filename. // Just return the original string. operationBuilder.Operations.Add(Tuple.Create(ItemOperationType.Value, (object)includeSplitEscaped)); } else if (!containsEscapedWildcards && containsRealWildcards) { // Unescape before handing it to the filesystem. string filespecUnescaped = EscapingUtilities.UnescapeAll(includeSplitEscaped); operationBuilder.Operations.Add(Tuple.Create(ItemOperationType.Glob, (object)filespecUnescaped)); } else { // No real wildcards means we just return the original string. Don't even bother // escaping ... it should already be escaped appropriately since it came directly // from the project file operationBuilder.Operations.Add(Tuple.Create(ItemOperationType.Value, (object)includeSplitEscaped)); } } } } }
public IDictionary CloneCustomMetadata() { CopyOnWriteDictionary <string, string> dictionary = new CopyOnWriteDictionary <string, string>(MSBuildNameIgnoreCaseComparer.Default); if (this.metadata != null) { foreach (KeyValuePair <string, string> pair in this.metadata) { dictionary.Add(pair.Key, EscapingUtilities.UnescapeAll(pair.Value)); } } return(dictionary); }
public IEnumerable <KeyValuePair <string, string> > EnumerateMetadata() { if (_customEscapedMetadata == null) { yield break; } foreach (var kvp in _customEscapedMetadata) { var unescaped = new KeyValuePair <string, string>(kvp.Key, EscapingUtilities.UnescapeAll(kvp.Value)); yield return(unescaped); } }
public static FileSpecMatcherTester Parse(string currentDirectory, string fileSpec) { string unescapedFileSpec = EscapingUtilities.UnescapeAll(fileSpec); string filenamePattern = null; Regex regex = null; if (EngineFileUtilities.FilespecHasWildcards(fileSpec)) { CreateRegexOrFilenamePattern(unescapedFileSpec, currentDirectory, out filenamePattern, out regex); } return(new FileSpecMatcherTester(currentDirectory, unescapedFileSpec, filenamePattern, regex)); }
/// <summary> /// Get the collection of custom metadata. This does not include built-in metadata. /// </summary> /// <remarks> /// RECOMMENDED GUIDELINES FOR METHOD IMPLEMENTATIONS: /// 1) this method should return a clone of the metadata /// 2) writing to this dictionary should not be reflected in the underlying item. /// </remarks> /// <returns>Dictionary of cloned metadata</returns> public IDictionary CloneCustomMetadata() { IDictionary <string, string> clonedMetadata = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); if (_customEscapedMetadata != null) { foreach (KeyValuePair <string, string> metadatum in _customEscapedMetadata) { clonedMetadata.Add(metadatum.Key, EscapingUtilities.UnescapeAll(metadatum.Value)); } } return((IDictionary)clonedMetadata); }
internal virtual void OutputProperties(List <DictionaryEntry> list) { // Write the banner setColor(ConsoleColor.Green); WriteLinePretty(currentIndentLevel, ResourceUtilities.FormatResourceString("PropertyListHeader")); // Write each property name and its value, one per line foreach (DictionaryEntry prop in list) { setColor(ConsoleColor.Gray); WritePretty(String.Format(CultureInfo.CurrentCulture, "{0,-30} = ", prop.Key)); setColor(ConsoleColor.DarkGray); WriteLinePretty(EscapingUtilities.UnescapeAll((string)prop.Value)); } resetColor(); }
/// <summary> /// Sets the given property in the given property group. /// </summary> private void SetProperty(ToolsetPropertyDefinition property, PropertyDictionary <ProjectPropertyInstance> propertyGroup, PropertyDictionary <ProjectPropertyInstance> globalProperties) { try { // Global properties cannot be overwritten if (globalProperties[property.Name] == null) { propertyGroup.Set(ProjectPropertyInstance.Create(property.Name, EscapingUtilities.UnescapeAll(property.Value), true /* may be reserved */, false /* not immutable */)); } } catch (ArgumentException ex) { InvalidToolsetDefinitionException.Throw(ex, "InvalidPropertyNameInToolset", property.Name, property.Source.LocationString, ex.Message); } }
public void Unescape() { Assert.Equal("", EscapingUtilities.UnescapeAll("")); Assert.Equal("foo", EscapingUtilities.UnescapeAll("foo")); Assert.Equal("foo space", EscapingUtilities.UnescapeAll("foo%20space")); Assert.Equal("foo2;", EscapingUtilities.UnescapeAll("foo2%3B")); Assert.Equal(";foo3", EscapingUtilities.UnescapeAll("%3bfoo3")); Assert.Equal(";", EscapingUtilities.UnescapeAll("%3b")); Assert.Equal(";;;;;", EscapingUtilities.UnescapeAll("%3b%3B;%3b%3B")); Assert.Equal("%3B", EscapingUtilities.UnescapeAll("%253B")); Assert.Equal("===%ZZ %%%===", EscapingUtilities.UnescapeAll("===%ZZ%20%%%===")); Assert.Equal("hello; escaping% how( are) you?", EscapingUtilities.UnescapeAll("hello%3B escaping%25 how%28 are%29 you%3f")); Assert.Equal("%*?*%*", EscapingUtilities.UnescapeAll("%25*?*%25*")); Assert.Equal("%*?*%*", EscapingUtilities.UnescapeAll("%25%2a%3f%2a%25%2a")); Assert.Equal("*Star*craft or *War*cr@ft??", EscapingUtilities.UnescapeAll("%2aStar%2Acraft%20or %2aWar%2Acr%40ft%3f%3F")); }
/// <summary> /// Retrieves the error targets for this target. /// </summary> /// <param name="projectLoggingContext">The project logging context.</param> /// <returns>A list of error targets.</returns> internal List <TargetSpecification> GetErrorTargets(ProjectLoggingContext projectLoggingContext) { VerifyState(_state, TargetEntryState.ErrorExecution); ErrorUtilities.VerifyThrow(_legacyCallTargetScopes == null, "We should have already left any legacy call target scopes."); List <TargetSpecification> allErrorTargets = new List <TargetSpecification>(_target.OnErrorChildren.Count); foreach (ProjectOnErrorInstance errorTargetInstance in _target.OnErrorChildren) { bool condition = ConditionEvaluator.EvaluateCondition ( errorTargetInstance.Condition, ParserOptions.AllowPropertiesAndItemLists, _expander, ExpanderOptions.ExpandPropertiesAndItems, _requestEntry.ProjectRootDirectory, errorTargetInstance.ConditionLocation, projectLoggingContext.LoggingService, projectLoggingContext.BuildEventContext ); if (condition) { IList <string> errorTargets = _expander.ExpandIntoStringListLeaveEscaped(errorTargetInstance.ExecuteTargets, ExpanderOptions.ExpandPropertiesAndItems, errorTargetInstance.ExecuteTargetsLocation); foreach (string escapedErrorTarget in errorTargets) { string errorTargetName = EscapingUtilities.UnescapeAll(escapedErrorTarget); allErrorTargets.Add(new TargetSpecification(errorTargetName, errorTargetInstance.ExecuteTargetsLocation)); } } } // If this target never executed (for instance, because one of its dependencies errored) then we need to // create a result for this target to report when it gets to the Completed state. if (null == _targetResult) { _targetResult = new TargetResult(new TaskItem[] { }, new WorkUnitResult(WorkUnitResultCode.Failed, WorkUnitActionCode.Stop, null)); } _state = TargetEntryState.Completed; return(allErrorTargets); }
/// <summary> /// Extract the value for "RecursiveDir", if any, from the Include. /// If there is none, returns an empty string. /// </summary> /// <remarks> /// Inputs to and outputs of this function are all escaped. /// </remarks> private static string GetRecursiveDirValue(string evaluatedIncludeBeforeWildcardExpansionEscaped, string evaluatedIncludeEscaped) { // If there were no wildcards, the two strings will be the same, and there is no recursivedir part. if (String.Equals(evaluatedIncludeBeforeWildcardExpansionEscaped, evaluatedIncludeEscaped, StringComparison.OrdinalIgnoreCase)) { return(String.Empty); } // we're going to the file system, so unescape the include value here: string evaluatedIncludeBeforeWildcardExpansion = EscapingUtilities.UnescapeAll(evaluatedIncludeBeforeWildcardExpansionEscaped); string evaluatedInclude = EscapingUtilities.UnescapeAll(evaluatedIncludeEscaped); FileMatcher.Result match = FileMatcher.Default.FileMatch(evaluatedIncludeBeforeWildcardExpansion, evaluatedInclude); if (match.isLegalFileSpec && match.isMatch) { return(EscapingUtilities.Escape(match.wildcardDirectoryPart)); } return(String.Empty); }
private IEnumerable <KeyValuePair <string, string> > EnumerateMetadataEager() { if (_customEscapedMetadata == null || _customEscapedMetadata.Count == 0) { #if TASKHOST // MSBuildTaskHost.dll compiles against .NET 3.5 which doesn't have Array.Empty() return(new KeyValuePair <string, string> [0]); #else return(Array.Empty <KeyValuePair <string, string> >()); #endif } var result = new KeyValuePair <string, string> [_customEscapedMetadata.Count]; int index = 0; foreach (var kvp in _customEscapedMetadata) { var unescaped = new KeyValuePair <string, string>(kvp.Key, EscapingUtilities.UnescapeAll(kvp.Value)); result[index++] = unescaped; } return(result); }
internal static Func <string, bool> GetFileSpecMatchTester(string filespec, string currentDirectory) { Debug.Assert(!string.IsNullOrEmpty(filespec)); var unescapedSpec = EscapingUtilities.UnescapeAll(filespec); var regex = FilespecHasWildcards(filespec) ? CreateRegex(unescapedSpec, currentDirectory) : null; return(fileToMatch => { Debug.Assert(!string.IsNullOrEmpty(fileToMatch)); // check if there is a regex matching the file if (regex != null) { var normalizedFileToMatch = FileUtilities.GetFullPathNoThrow(Path.Combine(currentDirectory, fileToMatch)); return regex.IsMatch(normalizedFileToMatch); } return FileUtilities.ComparePathsNoThrow(unescapedSpec, fileToMatch, currentDirectory); }); }
internal static Func <string, bool> GetMatchTester(string filespec, string currentDirectory) { var unescapedSpec = EscapingUtilities.UnescapeAll(filespec); Regex regex = null; // TODO: assumption on file system case sensitivity: https://github.com/Microsoft/msbuild/issues/781 if (FilespecHasWildcards(filespec)) { Regex regexFileMatch; bool isRecursive; bool isLegal; // TODO: If creating Regex's here ends up being expensive perf-wise, consider how to avoid it in common cases FileMatcher.GetFileSpecInfo( unescapedSpec, out regexFileMatch, out isRecursive, out isLegal, FileMatcher.s_defaultGetFileSystemEntries); // If the spec is not legal, it doesn't match anything regex = isLegal ? regexFileMatch : null; } return(file => { var unescapedFile = EscapingUtilities.UnescapeAll(file); // check if there is a regex matching the file if (regex != null) { return regex.IsMatch(unescapedFile); } return FileUtilities.ComparePathsNoThrow(unescapedSpec, unescapedFile, currentDirectory); }); }
/// <summary> /// Get the collection of metadata. This does not include built-in metadata. /// </summary> /// <remarks> /// RECOMMENDED GUIDELINES FOR METHOD IMPLEMENTATIONS: /// 1) this method should return a clone of the metadata /// 2) writing to this dictionary should not be reflected in the underlying item. /// </remarks> /// <owner>JomoF</owner> public IDictionary CloneCustomMetadata() { IDictionary backingItemMetadata = item.CloneCustomMetadata(); // Go through and escape the metadata as necessary. string[] keys = new string[backingItemMetadata.Count]; backingItemMetadata.Keys.CopyTo(keys, 0); foreach (string singleMetadataName in keys) { string singleMetadataValue = (string)backingItemMetadata[singleMetadataName]; bool unescapingWasNecessary; string singleMetadataValueUnescaped = EscapingUtilities.UnescapeAll(singleMetadataValue, out unescapingWasNecessary); // It's very important for perf not to touch this IDictionary unless we really need to. Touching // it in any way causes it to get cloned (in the implementation of CopyOnWriteHashtable). if (unescapingWasNecessary) { backingItemMetadata[singleMetadataName] = singleMetadataValueUnescaped; } } return(backingItemMetadata); }
/// <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); }
protected override ImmutableList <I> SelectItems(OrderedItemDataCollection.Builder listBuilder, ImmutableHashSet <string> globsToIgnore) { var itemsToAdd = ImmutableList.CreateBuilder <I>(); Lazy <Func <string, bool> > excludeTester = null; ImmutableList <string> .Builder excludePatterns = ImmutableList.CreateBuilder <string>(); if (_excludes != null) { // STEP 4: Evaluate, split, expand and subtract any Exclude foreach (string exclude in _excludes) { string excludeExpanded = _expander.ExpandIntoStringLeaveEscaped(exclude, ExpanderOptions.ExpandPropertiesAndItems, _itemElement.ExcludeLocation); var excludeSplits = ExpressionShredder.SplitSemiColonSeparatedList(excludeExpanded); excludePatterns.AddRange(excludeSplits); } if (excludePatterns.Count > 0) { excludeTester = new Lazy <Func <string, bool> >(() => EngineFileUtilities.GetFileSpecMatchTester(excludePatterns, _rootDirectory)); } } ISet <string> excludePatternsForGlobs = null; foreach (var fragment in _itemSpec.Fragments) { if (fragment is ItemSpec <P, I> .ItemExpressionFragment itemReferenceFragment) { // STEP 3: If expression is "@(x)" copy specified list with its metadata, otherwise just treat as string var itemsFromExpression = _expander.ExpandExpressionCaptureIntoItems( itemReferenceFragment.Capture, _evaluatorData, _itemFactory, ExpanderOptions.ExpandItems, includeNullEntries: false, isTransformExpression: out _, elementLocation: _itemElement.IncludeLocation); itemsToAdd.AddRange( excludeTester != null ? itemsFromExpression.Where(item => !excludeTester.Value(item.EvaluatedInclude)) : itemsFromExpression); } else if (fragment is ValueFragment valueFragment) { string value = valueFragment.TextFragment; if (excludeTester?.Value(EscapingUtilities.UnescapeAll(value)) != true) { var item = _itemFactory.CreateItem(value, value, _itemElement.ContainingProject.FullPath); itemsToAdd.Add(item); } } else if (fragment is GlobFragment globFragment) { // If this item is behind a false condition and represents a full drive/filesystem scan, expanding it is // almost certainly undesired. It should be skipped to avoid evaluation taking an excessive amount of time. bool skipGlob = !_conditionResult && globFragment.IsFullFileSystemScan && !Traits.Instance.EscapeHatches.AlwaysEvaluateDangerousGlobs; if (!skipGlob) { string glob = globFragment.TextFragment; if (excludePatternsForGlobs == null) { excludePatternsForGlobs = BuildExcludePatternsForGlobs(globsToIgnore, excludePatterns); } string[] includeSplitFilesEscaped; if (MSBuildEventSource.Log.IsEnabled()) { MSBuildEventSource.Log.ExpandGlobStart(_rootDirectory, glob, string.Join(", ", excludePatternsForGlobs)); } using (_lazyEvaluator._evaluationProfiler.TrackGlob(_rootDirectory, glob, excludePatternsForGlobs)) { includeSplitFilesEscaped = EngineFileUtilities.GetFileListEscaped( _rootDirectory, glob, excludePatternsForGlobs ); } if (MSBuildEventSource.Log.IsEnabled()) { MSBuildEventSource.Log.ExpandGlobStop(_rootDirectory, glob, string.Join(", ", excludePatternsForGlobs)); } foreach (string includeSplitFileEscaped in includeSplitFilesEscaped) { itemsToAdd.Add(_itemFactory.CreateItem(includeSplitFileEscaped, glob, _itemElement.ContainingProject.FullPath)); } } } else { throw new InvalidOperationException(fragment.GetType().ToString()); } } return(itemsToAdd.ToImmutable()); }
/// <summary> /// Parse a ProjectTargetElement /// </summary> private ProjectTargetElement ParseProjectTargetElement(XmlElementWithLocation element) { ProjectXmlUtilities.VerifyThrowProjectAttributes(element, s_validAttributesOnTarget); ProjectXmlUtilities.VerifyThrowProjectRequiredAttribute(element, XMakeAttributes.name); string targetName = ProjectXmlUtilities.GetAttributeValue(element, XMakeAttributes.name); // Orcas compat: all target names are automatically unescaped targetName = EscapingUtilities.UnescapeAll(targetName); int indexOfSpecialCharacter = targetName.IndexOfAny(XMakeElements.illegalTargetNameCharacters); if (indexOfSpecialCharacter >= 0) { ProjectErrorUtilities.ThrowInvalidProject(element.GetAttributeLocation(XMakeAttributes.name), "NameInvalid", targetName, targetName[indexOfSpecialCharacter]); } ProjectTargetElement target = new ProjectTargetElement(element, _project, _project); ProjectOnErrorElement onError = null; foreach (XmlElementWithLocation childElement in ProjectXmlUtilities.GetVerifyThrowProjectChildElements(element)) { ProjectElement child = null; switch (childElement.Name) { case XMakeElements.propertyGroup: if (onError != null) { ProjectErrorUtilities.ThrowInvalidProject(onError.Location, "NodeMustBeLastUnderElement", XMakeElements.onError, XMakeElements.target, childElement.Name); } child = ParseProjectPropertyGroupElement(childElement, target); break; case XMakeElements.itemGroup: if (onError != null) { ProjectErrorUtilities.ThrowInvalidProject(onError.Location, "NodeMustBeLastUnderElement", XMakeElements.onError, XMakeElements.target, childElement.Name); } child = ParseProjectItemGroupElement(childElement, target); break; case XMakeElements.onError: onError = ParseProjectOnErrorElement(childElement, target); child = onError; break; case XMakeElements.itemDefinitionGroup: ProjectErrorUtilities.ThrowInvalidProject(childElement.Location, "ItemDefinitionGroupNotLegalInsideTarget", childElement.Name); break; default: if (onError != null) { ProjectErrorUtilities.ThrowInvalidProject(onError.Location, "NodeMustBeLastUnderElement", XMakeElements.onError, XMakeElements.target, childElement.Name); } child = ParseProjectTaskElement(childElement, target); break; } target.AppendParentedChildNoChecks(child); } return(target); }