/// <summary> /// Calls Path.GetFullPath for each of the inputs. Preserves metadata. /// </summary> /// <returns>true on success, false on failure</returns> public override bool Execute() { List<ITaskItem> absolutePathsList = new List<ITaskItem>(); foreach (ITaskItem path in this.Paths) { try { // Only call Path.GetFullPath if the path is not rooted to avoid // going to disk when it is not necessary if (!Path.IsPathRooted(path.ItemSpec)) { if (path is ITaskItem2) { ((ITaskItem2)path).EvaluatedIncludeEscaped = ((ITaskItem2)path).GetMetadataValueEscaped("FullPath"); } else { path.ItemSpec = EscapingUtilities.Escape(path.GetMetadata("FullPath")); } } absolutePathsList.Add(path); } catch (ArgumentException e) { Log.LogErrorWithCodeFromResources("General.InvalidArgument", e.Message); } } this.AbsolutePaths = absolutePathsList.ToArray(); return !Log.HasLoggedErrors; }
public void Escape() { Assert.Equal("%2a", EscapingUtilities.Escape("*")); Assert.Equal("%3f", EscapingUtilities.Escape("?")); Assert.Equal("#%2a%3f%2a#%2a", EscapingUtilities.Escape("#*?*#*")); Assert.Equal("%25%2a%3f%2a%25%2a", EscapingUtilities.Escape("%*?*%*")); }
/// <summary> /// Set up our list of destination files. /// </summary> /// <returns>False if an error occurred, implying aborting the overall copy operation.</returns> private bool InitializeDestinationFiles() { if (DestinationFiles == null) { // If the caller passed in DestinationFolder, convert it to DestinationFiles DestinationFiles = new ITaskItem[SourceFiles.Length]; for (int i = 0; i < SourceFiles.Length; ++i) { // Build the correct path. string destinationFile; try { destinationFile = Path.Combine(DestinationFolder.ItemSpec, Path.GetFileName(SourceFiles[i].ItemSpec)); } catch (ArgumentException e) { Log.LogErrorWithCodeFromResources("Copy.Error", SourceFiles[i].ItemSpec, DestinationFolder.ItemSpec, e.Message); // Clear the outputs. DestinationFiles = Array.Empty <ITaskItem>(); return(false); } // Initialize the destinationFolder item. // ItemSpec is unescaped, and the TaskItem constructor expects an escaped input, so we need to // make sure to re-escape it here. DestinationFiles[i] = new TaskItem(EscapingUtilities.Escape(destinationFile)); // Copy meta-data from source to destinationFolder. SourceFiles[i].CopyMetadataTo(DestinationFiles[i]); } } return(true); }
/// <summary> /// Sets the value of the specified custom metadata. /// </summary> /// <owner>SumedhK</owner> /// <param name="metadataName"></param> /// <param name="metadataValue"></param> public void SetMetadata(string metadataName, string metadataValue) { ErrorUtilities.VerifyThrowArgumentLength(metadataName, "metadataName"); ErrorUtilities.VerifyThrowArgumentNull(metadataValue, "metadataValue"); item.SetMetadata(metadataName, EscapingUtilities.Escape(metadataValue)); }
/// <summary> /// Calls a method on the TaskLoggingHelper to parse a single line of text to /// see if there are any errors or warnings in canonical format. /// </summary> /// <remarks> /// Overridden to handle any custom regular expressions supplied. /// </remarks> protected override void LogEventsFromTextOutput(string singleLine, MessageImportance messageImportance) { if (OutputMatchesRegex(singleLine, ref _customErrorRegex)) { Log.LogError(singleLine); } else if (OutputMatchesRegex(singleLine, ref _customWarningRegex)) { Log.LogWarning(singleLine); } else if (_ignoreStandardErrorWarningFormat) { // Not detecting regular format errors and warnings, and it didn't // match any regexes either -- log as a regular message Log.LogMessage(messageImportance, singleLine, null); } else { // This is the normal code path: match standard format errors and warnings Log.LogMessageFromText(singleLine, messageImportance); } if (ConsoleToMSBuild) { string trimmedTextLine = singleLine.Trim(); if (trimmedTextLine.Length > 0) { // The lines read may be unescaped, so we need to escape them // before passing them to the TaskItem. _nonEmptyOutput.Add(new TaskItem(EscapingUtilities.Escape(trimmedTextLine))); } } }
/// <summary> /// Execute the task. /// </summary> /// <returns></returns> public override bool Execute() { ArrayList inPathList = new ArrayList(); ArrayList outOfPathList = new ArrayList(); string conePath; try { conePath = OpportunisticIntern.InternStringIfPossible(System.IO.Path.GetFullPath(_path.ItemSpec)); conePath = FileUtilities.EnsureTrailingSlash(conePath); } catch (Exception e) when(ExceptionHandling.IsIoRelatedException(e)) { Log.LogErrorWithCodeFromResources(null, "", 0, 0, 0, 0, "FindUnderPath.InvalidParameter", "Path", _path.ItemSpec, e.Message); return(false); } int conePathLength = conePath.Length; Log.LogMessageFromResources(MessageImportance.Low, "FindUnderPath.ComparisonPath", Path.ItemSpec); foreach (ITaskItem item in Files) { string fullPath; try { fullPath = OpportunisticIntern.InternStringIfPossible(System.IO.Path.GetFullPath(item.ItemSpec)); } catch (Exception e) when(ExceptionHandling.IsIoRelatedException(e)) { Log.LogErrorWithCodeFromResources(null, "", 0, 0, 0, 0, "FindUnderPath.InvalidParameter", "Files", item.ItemSpec, e.Message); return(false); } // Compare the left side of both strings to see if they're equal. if (String.Compare(conePath, 0, fullPath, 0, conePathLength, StringComparison.OrdinalIgnoreCase) == 0) { // If we should use the absolute path, update the item contents // Since ItemSpec, which fullPath comes from, is unescaped, re-escape when setting // item.ItemSpec, since the setter for ItemSpec expects an escaped value. if (_updateToAbsolutePaths) { item.ItemSpec = EscapingUtilities.Escape(fullPath); } inPathList.Add(item); } else { outOfPathList.Add(item); } } InPath = (ITaskItem[])inPathList.ToArray(typeof(ITaskItem)); OutOfPath = (ITaskItem[])outOfPathList.ToArray(typeof(ITaskItem)); return(true); }
private BuildResult MapBuildResult(string project, Microsoft.Build.Execution.BuildResult buildResult) { var escapedProject = EscapingUtilities.Escape(project); return new BuildResult { Project = project, Exception = buildResult.Exception, CircularDependency = buildResult.CircularDependency, ConfigurationId = buildResult.ConfigurationId, GlobalRequestId = buildResult.GlobalRequestId, NodeRequestId = buildResult.NodeRequestId, OverallResult = buildResult.OverallResult, ParentGlobalRequestId = buildResult.ParentGlobalRequestId, ResultsByTarget = new ResultsByTarget(buildResult.ResultsByTarget.ToDictionary(x => x.Key, x => new TargetResult { Name = x.Key, Exception = x.Value.Exception, ResultCode = x.Value.ResultCode, Items = x.Value.Items.Cast<ITaskItem2>().Select( y => new TaskItem( y.EvaluatedIncludeEscaped, escapedProject, ToGeneric(y.CloneCustomMetadataEscaped()))) .ToArray() })) }; }
/// <summary> /// Allows custom metadata on the item to be copied to another item. /// </summary> /// <remarks> /// RECOMMENDED GUIDELINES FOR METHOD IMPLEMENTATIONS: /// 1) this method should NOT copy over the item-spec /// 2) if a particular piece of metadata already exists on the destination item, it should NOT be overwritten /// 3) if there are pieces of metadata on the item that make no semantic sense on the destination item, they should NOT be copied /// </remarks> /// <param name="destinationItem">The item to copy metadata to.</param> public void CopyMetadataTo(ITaskItem destinationItem) { ErrorUtilities.VerifyThrowArgumentNull(destinationItem, nameof(destinationItem)); // 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 (_customEscapedMetadata != null) { foreach (KeyValuePair <string, string> entry in _customEscapedMetadata) { string value = destinationItem.GetMetadata(entry.Key); if (String.IsNullOrEmpty(value)) { destinationItem.SetMetadata(entry.Key, entry.Value); } } } if (String.IsNullOrEmpty(originalItemSpec)) { destinationItem.SetMetadata("OriginalItemSpec", EscapingUtilities.Escape(ItemSpec)); } }
/// <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); }
/// <summary> /// This sets an arbitrary attribute on the task element. These /// are attributes that the project author has placed on the task element /// that get passed in to the task. /// /// This optionally escapes the parameter value so it will be treated as a literal. /// </summary> /// <param name="parameterName"></param> /// <param name="parameterValue"></param> /// <param name="treatParameterValueAsLiteral"></param> /// <owner>RGoel</owner> public void SetParameterValue ( string parameterName, string parameterValue, bool treatParameterValueAsLiteral ) { this.SetParameterValue(parameterName, treatParameterValueAsLiteral ? EscapingUtilities.Escape(parameterValue) : parameterValue); }
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))); }
/// <summary> /// Creates a new ITaskItem with the contents of the old one. /// </summary> private ITaskItem CreateNewTaskItemFrom(ITaskItem copyFrom) { ITaskItem2 copyFromAsITaskItem2 = copyFrom as ITaskItem2; string escapedItemSpec = null; string escapedDefiningProject = null; Dictionary <string, string> escapedMetadata = null; if (copyFromAsITaskItem2 != null) { escapedItemSpec = copyFromAsITaskItem2.EvaluatedIncludeEscaped; escapedDefiningProject = copyFromAsITaskItem2.GetMetadataValueEscaped(FileUtilities.ItemSpecModifiers.DefiningProjectFullPath); IDictionary nonGenericEscapedMetadata = copyFromAsITaskItem2.CloneCustomMetadataEscaped(); if (nonGenericEscapedMetadata is Dictionary <string, string> ) { escapedMetadata = (Dictionary <string, string>)nonGenericEscapedMetadata; } else { escapedMetadata = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); foreach (object key in nonGenericEscapedMetadata.Keys) { escapedMetadata[(string)key] = (string)nonGenericEscapedMetadata[key] ?? String.Empty; } } } else { // If we don't have ITaskItem2 to fall back on, we have to make do with the fact that // CloneCustomMetadata, GetMetadata, & ItemSpec returns unescaped values, and // TaskParameterTaskItem's constructor expects escaped values, so escaping them all // is the closest approximation to correct we can get. escapedItemSpec = EscapingUtilities.Escape(copyFrom.ItemSpec); escapedDefiningProject = EscapingUtilities.EscapeWithCaching(copyFrom.GetMetadata(FileUtilities.ItemSpecModifiers.DefiningProjectFullPath)); IDictionary customMetadata = copyFrom.CloneCustomMetadata(); escapedMetadata = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); if (customMetadata != null && customMetadata.Count > 0) { foreach (string key in customMetadata.Keys) { escapedMetadata.Add(key, EscapingUtilities.Escape((string)customMetadata[key] ?? String.Empty)); } } } TaskParameterTaskItem taskItem = new TaskParameterTaskItem(escapedItemSpec, escapedDefiningProject, escapedMetadata); return(taskItem); }
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))); }
/// <summary> /// This constructor creates a new TaskItem, using the given ITaskItem. /// </summary> /// <param name="sourceItem">The item to copy.</param> public TaskItem ( ITaskItem sourceItem ) { ErrorUtilities.VerifyThrowArgumentNull(sourceItem, nameof(sourceItem)); // Attempt to preserve escaped state if (!(sourceItem is ITaskItem2 sourceItemAsITaskItem2)) { _itemSpec = EscapingUtilities.Escape(sourceItem.ItemSpec); _definingProject = EscapingUtilities.EscapeWithCaching(sourceItem.GetMetadata(FileUtilities.ItemSpecModifiers.DefiningProjectFullPath)); }
public override bool Execute() { if (PropertiesAndValues != null) { XElement root = UseAttributeForTargetFrameworkInfoPropertyNames ? new("TargetFramework", new XAttribute("Name", EscapingUtilities.Escape(RootElementName))) : new(RootElementName); foreach (ITaskItem item in PropertiesAndValues) { root.Add(new XElement(item.ItemSpec, item.GetMetadata("Value"))); } Result = root.ToString(); } return(!Log.HasLoggedErrors); }
/// <summary> /// Execute the task. /// </summary> /// <returns></returns> public override bool Execute() { bool success = true; if (File != null) { if (System.IO.File.Exists(File.ItemSpec)) { string[] textLines = null; try { textLines = System.IO.File.ReadAllLines(File.ItemSpec); ArrayList nonEmptyLines = new ArrayList(); char[] charsToTrim = new char[] { '\0', ' ', '\t' }; foreach (string textLine in textLines) { // A customer has given us a project with a FileList.txt file containing // a line full of '\0' characters. We don't know how these characters // got in there, but when we try to read the file back in, we fail // miserably. Here, we Trim to protect us from this situation. string trimmedTextLine = textLine.Trim(charsToTrim); if (trimmedTextLine.Length > 0) { // The lines were written to the file in unescaped form, so we need to escape them // before passing them to the TaskItem. nonEmptyLines.Add(new TaskItem(EscapingUtilities.Escape(trimmedTextLine))); } } Lines = (ITaskItem[])nonEmptyLines.ToArray(typeof(ITaskItem)); } catch (Exception e) // Catching Exception, but rethrowing unless it's a well-known exception. { if (ExceptionHandling.NotExpectedException(e)) { throw; } LogError(_file, e, ref success); } } } return(success); }
public void CopyMetadataTo(ITaskItem destinationItem) { ErrorUtilities.VerifyThrowArgumentNull(destinationItem, "destinationItem"); string metadata = destinationItem.GetMetadata("OriginalItemSpec"); ITaskItem2 item = destinationItem as ITaskItem2; if (this.metadata != null) { TaskItem item2 = destinationItem as TaskItem; if ((item2 != null) && (item2.metadata == null)) { item2.metadata = this.metadata.Clone(); } else { foreach (KeyValuePair <string, string> pair in this.metadata) { if (item != null) { if (string.IsNullOrEmpty(item.GetMetadataValueEscaped(pair.Key))) { item.SetMetadata(pair.Key, pair.Value); } } else if (string.IsNullOrEmpty(destinationItem.GetMetadata(pair.Key))) { destinationItem.SetMetadata(pair.Key, EscapingUtilities.Escape(pair.Value)); } } } } if (string.IsNullOrEmpty(metadata)) { if (item != null) { item.SetMetadata("OriginalItemSpec", ((ITaskItem2)this).EvaluatedIncludeEscaped); } else { destinationItem.SetMetadata("OriginalItemSpec", EscapingUtilities.Escape(this.ItemSpec)); } } }
public override bool Execute() { bool success = true; if (File != null) { if (FileSystems.Default.FileExists(File.ItemSpec)) { try { string[] textLines = System.IO.File.ReadAllLines(File.ItemSpec); var nonEmptyLines = new List <ITaskItem>(); char[] charsToTrim = { '\0', ' ', '\t' }; foreach (string textLine in textLines) { // A customer has given us a project with a FileList.txt file containing // a line full of '\0' characters. We don't know how these characters // got in there, but when we try to read the file back in, we fail // miserably. Here, we Trim to protect us from this situation. string trimmedTextLine = textLine.Trim(charsToTrim); if (trimmedTextLine.Length > 0) { // The lines were written to the file in unescaped form, so we need to escape them // before passing them to the TaskItem. nonEmptyLines.Add(new TaskItem(EscapingUtilities.Escape(trimmedTextLine))); } } Lines = nonEmptyLines.ToArray(); } catch (Exception e) when(ExceptionHandling.IsIoRelatedException(e)) { Log.LogErrorWithCodeFromResources("ReadLinesFromFile.ErrorOrWarning", File.ItemSpec, e.Message); success = false; } } } return(success); }
public static Dictionary <string, string> ParseEnvironmentVariables(TaskLoggingHelper logger, string inputFileName, bool escape) { var vars = new Dictionary <string, string> (); foreach (var line in File.ReadAllLines(inputFileName)) { var match = Regex.Match(line); if (!match.Success) { logger.LogError($"Failed to parse environment export: '{line}'."); return(null); } var name = match.Groups[1].Value; var value = escape ? EscapingUtilities.Escape(match.Groups[2].Value) : match.Groups[2].Value; vars.Add(name, value); } return(vars); }
/// <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); }
// Create a temporary file and run the task on it private static void RunTask(FindUnderPath t, out FileInfo testFile, out bool success) { string fileName = ObjectModelHelpers.CreateFileInTempProjectDirectory("file%3b.temp", "foo"); testFile = new FileInfo(fileName); t.Path = new TaskItem(ObjectModelHelpers.TempProjectDir); t.Files = new ITaskItem[] { new TaskItem(EscapingUtilities.Escape(testFile.Name)), new TaskItem(@"C:\SomeoneElsesProject\File2.txt") }; success = false; string currentDirectory = Directory.GetCurrentDirectory(); try { Directory.SetCurrentDirectory(ObjectModelHelpers.TempProjectDir); success = t.Execute(); } finally { Directory.SetCurrentDirectory(currentDirectory); } }
/// <summary> /// This constructor creates a new TaskItem, using the given ITaskItem. /// </summary> /// <param name="sourceItem">The item to copy.</param> public TaskItem ( ITaskItem sourceItem ) { ErrorUtilities.VerifyThrowArgumentNull(sourceItem, "sourceItem"); ITaskItem2 sourceItemAsITaskItem2 = sourceItem as ITaskItem2; // Attempt to preserve escaped state if (sourceItemAsITaskItem2 == null) { _itemSpec = EscapingUtilities.Escape(sourceItem.ItemSpec); _definingProject = EscapingUtilities.EscapeWithCaching(sourceItem.GetMetadata(FileUtilities.ItemSpecModifiers.DefiningProjectFullPath)); } else { _itemSpec = sourceItemAsITaskItem2.EvaluatedIncludeEscaped; _definingProject = sourceItemAsITaskItem2.GetMetadataValueEscaped(FileUtilities.ItemSpecModifiers.DefiningProjectFullPath); } sourceItem.CopyMetadataTo(this); }
/// <summary> /// If OutputFiles is null, we need to generate default output names /// to pass to resgen.exe (which would generate the names on its own, but /// then we wouldn't have access to them) /// </summary> private void GenerateOutputFileNames() { ErrorUtilities.VerifyThrow(!ResGen.IsNullOrEmpty(InputFiles), "If InputFiles is empty, the task should have returned before reaching this point"); ITaskItem[] inputFiles = InputFiles; ITaskItem[] outputFiles = new ITaskItem[inputFiles.Length]; // Set the default OutputFiles values for (int i = 0; i < inputFiles.Length; i++) { ITaskItem2 inputFileAsITaskItem2 = inputFiles[i] as ITaskItem2; if (inputFileAsITaskItem2 != null) { outputFiles[i] = new TaskItem(Path.ChangeExtension(inputFileAsITaskItem2.EvaluatedIncludeEscaped, ".resources")); } else { outputFiles[i] = new TaskItem(Path.ChangeExtension(EscapingUtilities.Escape(inputFiles[i].ItemSpec), ".resources")); } } Bag["OutputFiles"] = outputFiles; }
/// <summary> /// Sets the exact metadata value given to the metadata name requested. /// </summary> void ITaskItem2.SetMetadataValueLiteral(string metadataName, string metadataValue) { SetMetadata(metadataName, EscapingUtilities.Escape(metadataValue)); }
/// <summary> /// Write the given ITaskItem, using the given write translator /// </summary> private void WriteITaskItem(ITranslator translator, ITaskItem wrappedItem) { ErrorUtilities.VerifyThrow(translator.Mode == TranslationDirection.WriteToStream, "Cannot call this method when reading!"); if (!TranslateNullable(translator, wrappedItem)) { return; } string escapedItemSpec; string escapedDefiningProject; IDictionary wrappedMetadata; bool wrappedMetadataIsEscaped; ITaskItem2 wrappedItemAsITaskItem2 = wrappedItem as ITaskItem2; if (wrappedItemAsITaskItem2 != null) { escapedItemSpec = wrappedItemAsITaskItem2.EvaluatedIncludeEscaped; escapedDefiningProject = wrappedItemAsITaskItem2.GetMetadataValueEscaped(FileUtilities.ItemSpecModifiers.DefiningProjectFullPath); wrappedMetadata = wrappedItemAsITaskItem2.CloneCustomMetadataEscaped(); wrappedMetadataIsEscaped = true; } else { // We know that the ITaskItem constructor expects an escaped string, and that ITaskItem.ItemSpec // is expected to be unescaped, so make sure we give the constructor what it wants. escapedItemSpec = EscapingUtilities.Escape(wrappedItem.ItemSpec); escapedDefiningProject = EscapingUtilities.EscapeWithCaching(wrappedItem.GetMetadata(FileUtilities.ItemSpecModifiers.DefiningProjectFullPath)); wrappedMetadata = wrappedItem.CloneCustomMetadata(); wrappedMetadataIsEscaped = false; } Dictionary <string, string> escapedGenericWrappedMetadata = wrappedMetadata as Dictionary <string, string>; if (escapedGenericWrappedMetadata == null) { escapedGenericWrappedMetadata = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); foreach (object key in wrappedMetadata.Keys) { string value = (string)wrappedMetadata[key]; if (!wrappedMetadataIsEscaped) { value = (value == null) ? value : EscapingUtilities.Escape(value); } escapedGenericWrappedMetadata.Add((string)key, value); } } else if (!wrappedMetadataIsEscaped) { foreach (KeyValuePair <string, string> entry in escapedGenericWrappedMetadata) { escapedGenericWrappedMetadata[entry.Key] = entry.Value == null ? entry.Value : EscapingUtilities.Escape(entry.Value); } } translator.Translate(ref escapedItemSpec); translator.Translate(ref escapedDefiningProject); translator.TranslateDictionary(ref escapedGenericWrappedMetadata, StringComparer.OrdinalIgnoreCase); }
/// <summary> /// Used to load information about default MSBuild tasks i.e. tasks that do not need to be explicitly declared in projects /// with the <UsingTask> element. Default task information is read from special files, which are located in the same /// directory as the MSBuild binaries. /// </summary> /// <remarks> /// 1) a default tasks file needs the <Project> root tag in order to be well-formed /// 2) the XML declaration tag <?xml ...> is ignored /// 3) comment tags are always ignored regardless of their placement /// 4) the rest of the tags are expected to be <UsingTask> tags /// </remarks> private void RegisterDefaultTasks(BuildEventContext buildEventContext) { if (!defaultTasksRegistrationAttempted) { try { this.defaultTaskRegistry = new TaskRegistry(); string[] defaultTasksFiles = { }; try { defaultTasksFiles = getFiles(toolset.ToolsPath, defaultTasksFilePattern); if (defaultTasksFiles.Length == 0) { loggingServices.LogWarning(buildEventContext, new BuildEventFileInfo(/* this warning truly does not involve any file */ String.Empty), "DefaultTasksFileLoadFailureWarning", defaultTasksFilePattern, toolset.ToolsPath, String.Empty); } } // handle security problems when finding the default tasks files catch (UnauthorizedAccessException e) { loggingServices.LogWarning(buildEventContext, new BuildEventFileInfo(/* this warning truly does not involve any file */ String.Empty), "DefaultTasksFileLoadFailureWarning", defaultTasksFilePattern, toolset.ToolsPath, e.Message); } // handle problems when reading the default tasks files catch (Exception e) // Catching Exception, but rethrowing unless it's an IO related exception. { if (ExceptionHandling.NotExpectedException(e)) { throw; } loggingServices.LogWarning(buildEventContext, new BuildEventFileInfo(/* this warning truly does not involve any file */ String.Empty), "DefaultTasksFileLoadFailureWarning", defaultTasksFilePattern, toolset.ToolsPath, e.Message); } BuildPropertyGroup propertyBag = null; foreach (string defaultTasksFile in defaultTasksFiles) { try { XmlDocument defaultTasks = loadXmlFromPath(defaultTasksFile); // look for the first root tag that is not a comment or an XML declaration -- this should be the <Project> tag // NOTE: the XML parser will guarantee there is only one real root element in the file // but we need to find it amongst the other types of XmlNode at the root. foreach (XmlNode topLevelNode in defaultTasks.ChildNodes) { if (XmlUtilities.IsXmlRootElement(topLevelNode)) { ProjectErrorUtilities.VerifyThrowInvalidProject(topLevelNode.LocalName == XMakeElements.project, topLevelNode, "UnrecognizedElement", topLevelNode.Name); ProjectErrorUtilities.VerifyThrowInvalidProject((topLevelNode.Prefix.Length == 0) && (String.Equals(topLevelNode.NamespaceURI, XMakeAttributes.defaultXmlNamespace, StringComparison.OrdinalIgnoreCase)), topLevelNode, "ProjectMustBeInMSBuildXmlNamespace", XMakeAttributes.defaultXmlNamespace); // the <Project> tag can only the XML namespace -- no other attributes foreach (XmlAttribute projectAttribute in topLevelNode.Attributes) { ProjectXmlUtilities.VerifyThrowProjectInvalidAttribute(projectAttribute.Name == XMakeAttributes.xmlns, projectAttribute); } // look at all the child tags of the <Project> root tag we found foreach (XmlNode usingTaskNode in topLevelNode.ChildNodes) { if (usingTaskNode.NodeType != XmlNodeType.Comment) { ProjectErrorUtilities.VerifyThrowInvalidProject(usingTaskNode.Name == XMakeElements.usingTask, usingTaskNode, "UnrecognizedElement", usingTaskNode.Name); // Initialize the property bag if it hasn't been already. if (propertyBag == null) { // Set the value of the MSBuildBinPath/ToolsPath properties. BuildPropertyGroup reservedPropertyBag = new BuildPropertyGroup(); reservedPropertyBag.SetProperty( new BuildProperty(ReservedPropertyNames.binPath, EscapingUtilities.Escape(toolset.ToolsPath), PropertyType.ReservedProperty)); reservedPropertyBag.SetProperty( new BuildProperty(ReservedPropertyNames.toolsPath, EscapingUtilities.Escape(toolset.ToolsPath), PropertyType.ReservedProperty)); // Also set MSBuildAssemblyVersion so that the tasks file can tell between v4 and v12 MSBuild reservedPropertyBag.SetProperty( new BuildProperty(ReservedPropertyNames.assemblyVersion, Constants.AssemblyVersion, PropertyType.ReservedProperty)); propertyBag = new BuildPropertyGroup(); propertyBag.ImportInitialProperties(parentEngine.EnvironmentProperties, reservedPropertyBag, BuildProperties, parentEngine.GlobalProperties); } defaultTaskRegistry.RegisterTask(new UsingTask((XmlElement)usingTaskNode, true), new Expander(propertyBag), loggingServices, buildEventContext); } } break; } } } // handle security problems when loading the default tasks file catch (UnauthorizedAccessException e) { loggingServices.LogError(buildEventContext, new BuildEventFileInfo(defaultTasksFile), "DefaultTasksFileFailure", e.Message); break; } // handle problems when loading the default tasks file catch (IOException e) { loggingServices.LogError(buildEventContext, new BuildEventFileInfo(defaultTasksFile), "DefaultTasksFileFailure", e.Message); break; } // handle XML errors in the default tasks file catch (XmlException e) { ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(false, new BuildEventFileInfo(e), "DefaultTasksFileFailure", e.Message); } } } finally { defaultTasksRegistrationAttempted = true; } } }
internal static string Escape(this string unescapedString) { return(EscapingUtilities.Escape(unescapedString)); }
/// <summary> /// Execute the task. /// </summary> /// <returns></returns> public override bool Execute() { AssignedFiles = new ITaskItem[Files.Length]; if (Files.Length > 0) { // Compose a file in the root folder. // NOTE: at this point fullRootPath may or may not have a trailing // slash because Path.GetFullPath() does not add or remove it string fullRootPath = Path.GetFullPath(RootFolder); // Ensure trailing slash otherwise c:\bin appears to match part of c:\bin2\foo fullRootPath = FileUtilities.EnsureTrailingSlash(fullRootPath); string currentDirectory = Directory.GetCurrentDirectory(); // check if the root folder is the same as the current directory // NOTE: the path returned from Directory.GetCurrentDirectory() // does not have a trailing slash, but fullRootPath does bool isRootFolderSameAsCurrentDirectory = ((fullRootPath.Length - 1 /* exclude trailing slash */) == currentDirectory.Length) && (String.Compare( fullRootPath, 0, currentDirectory, 0, fullRootPath.Length - 1 /* don't compare trailing slash */, StringComparison.OrdinalIgnoreCase) == 0); for (int i = 0; i < Files.Length; ++i) { AssignedFiles[i] = new TaskItem(Files[i]); // If TargetPath is already set, it takes priority. // https://github.com/dotnet/msbuild/issues/2795 string targetPath = ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave16_10) ? Files[i].GetMetadata(ItemMetadataNames.targetPath) : null; // If TargetPath not already set, fall back to default behavior. if (string.IsNullOrEmpty(targetPath)) { targetPath = Files[i].GetMetadata(ItemMetadataNames.link); } if (string.IsNullOrEmpty(targetPath)) { if (// if the file path is relative !Path.IsPathRooted(Files[i].ItemSpec) && // if the file path doesn't contain any relative specifiers !Files[i].ItemSpec.Contains("." + Path.DirectorySeparatorChar) && // if the file path is already relative to the root folder isRootFolderSameAsCurrentDirectory) { // then just use the file path as-is // PERF NOTE: we do this to avoid calling Path.GetFullPath() below, // because that method consumes a lot of memory, esp. when we have // a lot of items coming through this task targetPath = Files[i].ItemSpec; } else { // PERF WARNING: Path.GetFullPath() is expensive in terms of memory; // we should avoid calling it whenever possible string itemSpecFullFileNamePath = Path.GetFullPath(Files[i].ItemSpec); if (String.Compare(fullRootPath, 0, itemSpecFullFileNamePath, 0, fullRootPath.Length, StringComparison.CurrentCultureIgnoreCase) == 0) { // The item spec file is in the "cone" of the RootFolder. Return the relative path from the cone root. targetPath = itemSpecFullFileNamePath.Substring(fullRootPath.Length); } else { // The item spec file is not in the "cone" of the RootFolder. Return the filename only. targetPath = Path.GetFileName(Files[i].ItemSpec); } } } AssignedFiles[i].SetMetadata(ItemMetadataNames.targetPath, EscapingUtilities.Escape(targetPath)); } } return(true); }
/// <summary> /// Execute the task. /// </summary> /// <returns></returns> public override bool Execute() { _assignedFiles = new TaskItem[Files.Length]; if (Files.Length > 0) { // Compose a file in the root folder. // NOTE: at this point fullRootPath may or may not have a trailing // slash because Path.GetFullPath() does not add or remove it string fullRootPath = Path.GetFullPath(this.RootFolder); // Ensure trailing slash otherwise c:\bin appears to match part of c:\bin2\foo fullRootPath = FileUtilities.EnsureTrailingSlash(fullRootPath); string currentDirectory = Directory.GetCurrentDirectory(); // check if the root folder is the same as the current directory // NOTE: the path returned from Directory.GetCurrentDirectory() // does not have a trailing slash, but fullRootPath does bool isRootFolderSameAsCurrentDirectory = ((fullRootPath.Length - 1 /* exclude trailing slash */) == currentDirectory.Length) && (String.Compare( fullRootPath, 0, currentDirectory, 0, (fullRootPath.Length - 1) /* don't compare trailing slash */, StringComparison.OrdinalIgnoreCase) == 0); for (int i = 0; i < Files.Length; ++i) { string link = Files[i].GetMetadata(ItemMetadataNames.link); AssignedFiles[i] = new TaskItem(Files[i]); // If file has a link, use that. string targetPath = link; if (link == null || link.Length == 0) { if (// if the file path is relative !Path.IsPathRooted(Files[i].ItemSpec) && // if the file path doesn't contain any relative specifiers !Files[i].ItemSpec.Contains(".\\") && // if the file path is already relative to the root folder isRootFolderSameAsCurrentDirectory) { // then just use the file path as-is // PERF NOTE: we do this to avoid calling Path.GetFullPath() below, // because that method consumes a lot of memory, esp. when we have // a lot of items coming through this task targetPath = Files[i].ItemSpec; } else { // PERF WARNING: Path.GetFullPath() is expensive in terms of memory; // we should avoid calling it whenever possible string itemSpecFullFileNamePath = Path.GetFullPath(Files[i].ItemSpec); if (String.Compare(fullRootPath, 0, itemSpecFullFileNamePath, 0, fullRootPath.Length, true, CultureInfo.CurrentCulture) == 0) { // The item spec file is in the "cone" of the RootFolder. Return the relative path from the cone root. targetPath = itemSpecFullFileNamePath.Substring(fullRootPath.Length); } else { // The item spec file is not in the "cone" of the RootFolder. Return the filename only. targetPath = Path.GetFileName(Files[i].ItemSpec); } } } AssignedFiles[i].SetMetadata(ItemMetadataNames.targetPath, EscapingUtilities.Escape(targetPath)); } } return(true); }
/// <summary> /// Adds a new item to the ItemGroup, optional treating the item Include as literal so that /// any special characters will be escaped before persisting it. /// </summary> public BuildItem AddNewItem(string itemName, string itemInclude, bool treatItemIncludeAsLiteral) { return(AddNewItem(itemName, treatItemIncludeAsLiteral ? EscapingUtilities.Escape(itemInclude) : itemInclude)); }