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)); } } } } }
/// <summary> /// Expands the given unexpanded property expression using the properties in the /// given expander. /// </summary> private string ExpandPropertyLeaveEscaped(ToolsetPropertyDefinition property, Expander <ProjectPropertyInstance, ProjectItemInstance> expander) { try { return(expander.ExpandIntoStringLeaveEscaped(property.Value, ExpanderOptions.ExpandProperties, property.Source)); } catch (InvalidProjectFileException ex) { InvalidToolsetDefinitionException.Throw(ex, "ErrorEvaluatingToolsetPropertyExpression", property.Value, property.Source.LocationString, ex.BaseMessage); } return(string.Empty); }
private static IEnumerable <string> GetExpandedMetadataValuesAndConditions(ICollection <ProjectMetadataElement> metadata, Expander <P, I> expander) { // Since we're just attempting to expand properties in order to find referenced items and not expanding metadata, // unexpected errors may occur when evaluating property functions on unexpanded metadata. Just ignore them if that happens. // See: https://github.com/dotnet/msbuild/issues/3460 const ExpanderOptions expanderOptions = ExpanderOptions.ExpandProperties | ExpanderOptions.LeavePropertiesUnexpandedOnError; // Expand properties here, because a property may have a value which is an item reference (ie "@(Bar)"), and // if so we need to add the right item reference. foreach (var metadatumElement in metadata) { yield return(expander.ExpandIntoStringLeaveEscaped( metadatumElement.Value, expanderOptions, metadatumElement.Location)); yield return(expander.ExpandIntoStringLeaveEscaped( metadatumElement.Condition, expanderOptions, metadatumElement.ConditionLocation)); } }
private IncludeOperation BuildIncludeOperation(string rootDirectory, ProjectItemElement itemElement, bool conditionResult) { IncludeOperationBuilder operationBuilder = new IncludeOperationBuilder(itemElement, conditionResult); operationBuilder.ElementOrder = _nextElementOrder++; operationBuilder.RootDirectory = rootDirectory; operationBuilder.ConditionResult = conditionResult; // Process include ProcessItemSpec(itemElement.Include, itemElement.IncludeLocation, operationBuilder); // Code corresponds to Evaluator.EvaluateItemElement // Process exclude (STEP 4: Evaluate, split, expand and subtract any Exclude) if (itemElement.Exclude.Length > 0) { // Expand properties here, because a property may have a value which is an item reference (ie "@(Bar)"), and // if so we need to add the right item reference string evaluatedExclude = _expander.ExpandIntoStringLeaveEscaped(itemElement.Exclude, ExpanderOptions.ExpandProperties, itemElement.ExcludeLocation); if (evaluatedExclude.Length > 0) { IList <string> excludeSplits = ExpressionShredder.SplitSemiColonSeparatedList(evaluatedExclude); operationBuilder.Excludes.AddRange(excludeSplits); foreach (var excludeSplit in excludeSplits) { AddItemReferences(excludeSplit, operationBuilder, itemElement.ExcludeLocation); } } } // Process Metadata (STEP 5: Evaluate each metadata XML and apply them to each item we have so far) ProcessMetadataElements(itemElement, operationBuilder); return(new IncludeOperation(operationBuilder, this)); }
/// <summary> /// See <see cref="GetMetadataValue(string)">GetMetadataValue</see> for a more detailed explanation. /// Returns the escaped value of the metadatum requested. /// </summary> string IItem.GetMetadataValueEscaped(string name) { ErrorUtilities.VerifyThrowArgumentLength(name, "name"); string value = null; if (_directMetadata != null) { ProjectMetadata metadatum = _directMetadata[name]; if (metadatum != null) { value = metadatum.EvaluatedValueEscaped; } } if (value == null) { value = GetBuiltInMetadataEscaped(name); } if (value == null) { ProjectMetadata metadatum = GetItemDefinitionMetadata(name); if (null != metadatum && Expander <ProjectProperty, ProjectItem> .ExpressionMayContainExpandableExpressions(metadatum.EvaluatedValueEscaped)) { Expander <ProjectProperty, ProjectItem> expander = new Expander <ProjectProperty, ProjectItem>(null, null, new BuiltInMetadataTable(this), FileSystems.Default); value = expander.ExpandIntoStringLeaveEscaped(metadatum.EvaluatedValueEscaped, ExpanderOptions.ExpandBuiltInMetadata, metadatum.Location); } else if (null != metadatum) { return(metadatum.EvaluatedValueEscaped); } } return(value ?? String.Empty); }
public void PropertyFunctionDoesTaskHostExist_Error() { Assert.Throws<InvalidProjectFileException>(() => { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::DoesTaskHostExist('ASDF', 'CurrentArchitecture'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); // We should have failed before now Assert.True(false); } ); }
public void PropertyFunctionValueOrDefault() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::ValueOrDefault('', '42'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal("42", result); result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::ValueOrDefault('42', '43'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal("42", result); }
public void PropertyFunctionStaticMethodGetCultureInfo() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped(@"$([System.Globalization.CultureInfo]::GetCultureInfo(`en-US`).ToString())", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal(System.Globalization.CultureInfo.GetCultureInfo("en-US").ToString(), result); }
public void PropertyFunctionStaticMethodEnumArgument() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped(@"$([System.Environment]::GetFolderPath(SpecialFolder.System))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal(System.Environment.GetFolderPath(Environment.SpecialFolder.System), result); }
public void PropertyFunctionStaticMethodRegex1() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); pg.Set(ProjectPropertyInstance.Create("File", @"foo\file.txt")); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); // Support enum combines as Enum.Parse expects them string result = expander.ExpandIntoStringLeaveEscaped(@"$([System.Text.RegularExpressions.Regex]::IsMatch(`-42`, `^-?\d+(\.\d{2})?$`, `RegexOptions.IgnoreCase,RegexOptions.Singleline`))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal(@"True", result); // We support the C# style enum combining syntax too result = expander.ExpandIntoStringLeaveEscaped(@"$([System.Text.RegularExpressions.Regex]::IsMatch(`-42`, `^-?\d+(\.\d{2})?$`, System.Text.RegularExpressions.RegexOptions.IgnoreCase|RegexOptions.Singleline))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal(@"True", result); result = expander.ExpandIntoStringLeaveEscaped(@"$([System.Text.RegularExpressions.Regex]::IsMatch(`100 GBP`, `^-?\d+(\.\d{2})?$`))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal(@"False", result); }
public void PropertyFunctionGetRegistryValueFromView2() { try { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); pg.Set(ProjectPropertyInstance.Create("SomeProperty", "Value")); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); RegistryKey key = Registry.CurrentUser.CreateSubKey(@"Software\Microsoft\MSBuild_test"); key.SetValue(String.Empty, "%TEMP%", RegistryValueKind.ExpandString); string result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\Software\Microsoft\MSBuild_test', null, null, Microsoft.Win32.RegistryView.Default))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal(Environment.GetEnvironmentVariable("TEMP"), result); } finally { Registry.CurrentUser.DeleteSubKey(@"Software\Microsoft\MSBuild_test"); } } /// <summary>
protected void DecorateItemsWithMetadata(ImmutableList <I> items, ImmutableList <ProjectMetadataElement> metadata) { if (metadata.Count > 0) { //////////////////////////////////////////////////// // UNDONE: Implement batching here. // // We want to allow built-in metadata in metadata values here. // For example, so that an Idl file can specify that its Tlb output should be named %(Filename).tlb. // // In other words, we want batching. However, we won't need to go to the trouble of using the regular batching code! // That's because that code is all about grouping into buckets of similar items. In this context, we're not // invoking a task, and it's fine to process each item individually, which will always give the correct results. // // For the CTP, to make the minimal change, we will not do this quite correctly. // // We will do this: // -- check whether any metadata values or their conditions contain any bare built-in metadata expressions, // or whether they contain any custom metadata && the Include involved an @(itemlist) expression. // -- if either case is found, we go ahead and evaluate all the metadata separately for each item. // -- otherwise we can do the old thing (evaluating all metadata once then applying to all items) // // This algorithm gives the correct results except when: // -- batchable expressions exist on the include, exclude, or condition on the item element itself // // It means that 99% of cases still go through the old code, which is best for the CTP. // When we ultimately implement this correctly, we should make sure we optimize for the case of very many items // and little metadata, none of which varies between items. // Do not expand properties as they have been already expanded by the lazy evaluator upon item operation construction. // Prior to lazy evaluation ExpanderOptions.ExpandAll was used. const ExpanderOptions metadataExpansionOptions = ExpanderOptions.ExpandAll; List <string> values = new List <string>(metadata.Count * 2); foreach (var metadataElement in metadata) { values.Add(metadataElement.Value); values.Add(metadataElement.Condition); } ItemsAndMetadataPair itemsAndMetadataFound = ExpressionShredder.GetReferencedItemNamesAndMetadata(values); bool needToProcessItemsIndividually = false; if (itemsAndMetadataFound.Metadata != null && itemsAndMetadataFound.Metadata.Values.Count > 0) { // If there is bare metadata of any kind, and the Include involved an item list, we should // run items individually, as even non-built-in metadata might differ between items if (_referencedItemLists.Count >= 0) { needToProcessItemsIndividually = true; } else { // If there is bare built-in metadata, we must always run items individually, as that almost // always differs between items. // UNDONE: When batching is implemented for real, we need to make sure that // item definition metadata is included in all metadata operations during evaluation if (itemsAndMetadataFound.Metadata.Values.Count > 0) { needToProcessItemsIndividually = true; } } } if (needToProcessItemsIndividually) { foreach (I item in items) { _expander.Metadata = item; foreach (var metadataElement in metadata) { #if FEATURE_MSBUILD_DEBUGGER //if (DebuggerManager.DebuggingEnabled) //{ // DebuggerManager.PulseState(metadataElementElement.Location, _itemPassLocals); //} #endif if (!EvaluateCondition(metadataElement.Condition, metadataElement, metadataExpansionOptions, ParserOptions.AllowAll, _expander, _lazyEvaluator)) { continue; } string evaluatedValue = _expander.ExpandIntoStringLeaveEscaped(metadataElement.Value, metadataExpansionOptions, metadataElement.Location); item.SetMetadata(metadataElement, FileUtilities.MaybeAdjustFilePath(evaluatedValue, metadataElement.ContainingProject.DirectoryPath)); } } // End of legal area for metadata expressions. _expander.Metadata = null; } // End of pseudo batching //////////////////////////////////////////////////// // Start of old code else { // Metadata expressions are allowed here. // Temporarily gather and expand these in a table so they can reference other metadata elements above. EvaluatorMetadataTable metadataTable = new EvaluatorMetadataTable(_itemType); _expander.Metadata = metadataTable; // Also keep a list of everything so we can get the predecessor objects correct. List <Pair <ProjectMetadataElement, string> > metadataList = new List <Pair <ProjectMetadataElement, string> >(metadata.Count); foreach (var metadataElement in metadata) { // Because of the checking above, it should be safe to expand metadata in conditions; the condition // will be true for either all the items or none if (!EvaluateCondition(metadataElement.Condition, metadataElement, metadataExpansionOptions, ParserOptions.AllowAll, _expander, _lazyEvaluator)) { continue; } #if FEATURE_MSBUILD_DEBUGGER //if (DebuggerManager.DebuggingEnabled) //{ // DebuggerManager.PulseState(metadataElementElement.Location, _itemPassLocals); //} #endif string evaluatedValue = _expander.ExpandIntoStringLeaveEscaped(metadataElement.Value, metadataExpansionOptions, metadataElement.Location); evaluatedValue = FileUtilities.MaybeAdjustFilePath(evaluatedValue, metadataElement.ContainingProject.DirectoryPath); metadataTable.SetValue(metadataElement, evaluatedValue); metadataList.Add(new Pair <ProjectMetadataElement, string>(metadataElement, evaluatedValue)); } // Apply those metadata to each item // Note that several items could share the same metadata objects // Set all the items at once to make a potential copy-on-write optimization possible. // This is valuable in the case where one item element evaluates to // many items (either by semicolon or wildcards) // and that item also has the same piece/s of metadata for each item. _itemFactory.SetMetadata(metadataList, items); // End of legal area for metadata expressions. _expander.Metadata = null; } } }
private List <ProjectItemInstance> ExpandItemIntoItems ( ProjectItemGroupTaskItemInstance originalItem, Expander <ProjectPropertyInstance, ProjectItemInstance> expander, ISet <string> keepMetadata, ISet <string> removeMetadata ) { // todo this is duplicated logic with the item computation logic from evaluation (in LazyIncludeOperation.SelectItems) ProjectErrorUtilities.VerifyThrowInvalidProject(!(keepMetadata != null && removeMetadata != null), originalItem.KeepMetadataLocation, "KeepAndRemoveMetadataMutuallyExclusive"); List <ProjectItemInstance> items = new List <ProjectItemInstance>(); // Expand properties and metadata in Include string evaluatedInclude = expander.ExpandIntoStringLeaveEscaped(originalItem.Include, ExpanderOptions.ExpandPropertiesAndMetadata, originalItem.IncludeLocation); if (evaluatedInclude.Length == 0) { return(items); } // Compute exclude fragments, without expanding wildcards var excludes = ImmutableList <string> .Empty.ToBuilder(); if (originalItem.Exclude.Length > 0) { string evaluatedExclude = expander.ExpandIntoStringLeaveEscaped(originalItem.Exclude, ExpanderOptions.ExpandAll, originalItem.ExcludeLocation); if (evaluatedExclude.Length > 0) { var excludeSplits = ExpressionShredder.SplitSemiColonSeparatedList(evaluatedExclude); foreach (string excludeSplit in excludeSplits) { excludes.Add(excludeSplit); } } } // Split Include on any semicolons, and take each split in turn var includeSplits = ExpressionShredder.SplitSemiColonSeparatedList(evaluatedInclude); ProjectItemInstanceFactory itemFactory = new ProjectItemInstanceFactory(this.Project, originalItem.ItemType); foreach (string includeSplit in includeSplits) { // If expression is "@(x)" copy specified list with its metadata, otherwise just treat as string bool throwaway; IList <ProjectItemInstance> itemsFromSplit = expander.ExpandSingleItemVectorExpressionIntoItems(includeSplit, itemFactory, ExpanderOptions.ExpandItems, false /* do not include null expansion results */, out throwaway, originalItem.IncludeLocation); if (itemsFromSplit != null) { // Expression is in form "@(X)", so add these items directly. foreach (ProjectItemInstance item in itemsFromSplit) { items.Add(item); } } else { // The expression is not of the form "@(X)". Treat as string // Pass the non wildcard expanded excludes here to fix https://github.com/dotnet/msbuild/issues/2621 string[] includeSplitFiles = EngineFileUtilities.GetFileListEscaped( Project.Directory, includeSplit, excludes); foreach (string includeSplitFile in includeSplitFiles) { items.Add(new ProjectItemInstance( Project, originalItem.ItemType, includeSplitFile, includeSplit /* before wildcard expansion */, null, null, originalItem.Location.File)); } } } // Evaluate, split, expand and subtract any Exclude HashSet <string> excludesUnescapedForComparison = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (string excludeSplit in excludes) { string[] excludeSplitFiles = EngineFileUtilities.GetFileListUnescaped(Project.Directory, excludeSplit); foreach (string excludeSplitFile in excludeSplitFiles) { excludesUnescapedForComparison.Add(excludeSplitFile); } } List <ProjectItemInstance> remainingItems = new List <ProjectItemInstance>(); for (int i = 0; i < items.Count; i++) { if (!excludesUnescapedForComparison.Contains(((IItem)items[i]).EvaluatedInclude)) { remainingItems.Add(items[i]); } } items = remainingItems; // Filter the metadata as appropriate if (keepMetadata != null) { foreach (var item in items) { var metadataToRemove = item.MetadataNames.Where(name => !keepMetadata.Contains(name)); foreach (var metadataName in metadataToRemove) { item.RemoveMetadata(metadataName); } } } else if (removeMetadata != null) { foreach (var item in items) { var metadataToRemove = item.MetadataNames.Where(name => removeMetadata.Contains(name)); foreach (var metadataName in metadataToRemove) { item.RemoveMetadata(metadataName); } } } return(items); }
private List <ItemSpecFragment> BuildItemFragments(IElementLocation itemSpecLocation, string projectDirectory, bool expandProperties) { // Code corresponds to Evaluator.CreateItemsFromInclude var evaluatedItemspecEscaped = ItemSpecString; if (string.IsNullOrEmpty(evaluatedItemspecEscaped)) { return(new List <ItemSpecFragment>()); } // STEP 1: Expand properties in Include if (expandProperties) { evaluatedItemspecEscaped = Expander.ExpandIntoStringLeaveEscaped( ItemSpecString, ExpanderOptions.ExpandProperties, itemSpecLocation); } var semicolonCount = 0; foreach (var c in evaluatedItemspecEscaped) { if (c == ';') { semicolonCount++; } } // estimate the number of fragments with the number of semicolons. This is will overestimate in case of transforms with semicolons, but won't underestimate. var fragments = new List <ItemSpecFragment>(semicolonCount + 1); // STEP 2: Split Include on any semicolons, and take each split in turn if (evaluatedItemspecEscaped.Length > 0) { var splitsEscaped = ExpressionShredder.SplitSemiColonSeparatedList(evaluatedItemspecEscaped); foreach (var splitEscaped in splitsEscaped) { // STEP 3: If expression is "@(x)" copy specified list with its metadata, otherwise just treat as string var itemReferenceFragment = ProcessItemExpression( splitEscaped, itemSpecLocation, projectDirectory, out var isItemListExpression); if (isItemListExpression) { fragments.Add(itemReferenceFragment); } else { // The expression is not of the form "@(X)". Treat as string // Code corresponds to EngineFileUtilities.GetFileList if (!FileMatcher.HasWildcards(splitEscaped)) { // 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 fragments.Add(new ValueFragment(splitEscaped, projectDirectory)); } else if (EscapingUtilities.ContainsEscapedWildcards(splitEscaped)) { // '*' is an illegal character to have in a filename. // todo: file-system assumption on legal path characters: https://github.com/dotnet/msbuild/issues/781 // Just return the original string. fragments.Add(new ValueFragment(splitEscaped, projectDirectory)); } else { // Unescape before handing it to the filesystem. var filespecUnescaped = EscapingUtilities.UnescapeAll(splitEscaped); fragments.Add(new GlobFragment(filespecUnescaped, projectDirectory)); } } } } return(fragments); }
/// <summary> /// Takes an item specification, evaluates it and expands it into a list of items /// </summary> /// <param name="originalItem">The original item data</param> /// <param name="expander">The expander to use.</param> /// <param name="keepMetadata">An <see cref="ISet{String}"/> of metadata names to keep.</param> /// <param name="removeMetadata">An <see cref="ISet{String}"/> of metadata names to remove.</param> /// <remarks> /// This code is very close to that which exists in the Evaluator.EvaluateItemXml method. However, because /// it invokes type constructors, and those constructors take arguments of fundamentally different types, it has not /// been refactored. /// </remarks> /// <returns>A list of items.</returns> private IList <ProjectItemInstance> ExpandItemIntoItems ( ProjectItemGroupTaskItemInstance originalItem, Expander <ProjectPropertyInstance, ProjectItemInstance> expander, ISet <string> keepMetadata, ISet <string> removeMetadata ) { ProjectErrorUtilities.VerifyThrowInvalidProject(!(keepMetadata != null && removeMetadata != null), originalItem.KeepMetadataLocation, "KeepAndRemoveMetadataMutuallyExclusive"); IList <ProjectItemInstance> items = new List <ProjectItemInstance>(); // UNDONE: (Refactor) This code also exists in largely the same form in Evaluator.CreateItemsFromInclude. // STEP 1: Expand properties and metadata in Include string evaluatedInclude = expander.ExpandIntoStringLeaveEscaped(originalItem.Include, ExpanderOptions.ExpandPropertiesAndMetadata, originalItem.IncludeLocation); // STEP 2: Split Include on any semicolons, and take each split in turn if (evaluatedInclude.Length > 0) { IList <string> includeSplits = ExpressionShredder.SplitSemiColonSeparatedList(evaluatedInclude); ProjectItemInstanceFactory itemFactory = new ProjectItemInstanceFactory(this.Project, originalItem.ItemType); foreach (string includeSplit in includeSplits) { // STEP 3: If expression is "@(x)" copy specified list with its metadata, otherwise just treat as string bool throwaway; IList <ProjectItemInstance> itemsFromSplit = expander.ExpandSingleItemVectorExpressionIntoItems(includeSplit, itemFactory, ExpanderOptions.ExpandItems, false /* do not include null expansion results */, out throwaway, originalItem.IncludeLocation); if (itemsFromSplit != null) { // Expression is in form "@(X)", so add these items directly. foreach (ProjectItemInstance item in itemsFromSplit) { items.Add(item); } } else { // The expression is not of the form "@(X)". Treat as string string[] includeSplitFiles = EngineFileUtilities.GetFileListEscaped(Project.Directory, includeSplit); foreach (string includeSplitFile in includeSplitFiles) { items.Add(new ProjectItemInstance(Project, originalItem.ItemType, includeSplitFile, includeSplit /* before wildcard expansion */, null, null, originalItem.Location.File)); } } } // STEP 4: Evaluate, split, expand and subtract any Exclude if (originalItem.Exclude.Length > 0) { string evaluatedExclude = expander.ExpandIntoStringLeaveEscaped(originalItem.Exclude, ExpanderOptions.ExpandAll, originalItem.ExcludeLocation); if (evaluatedExclude.Length > 0) { IList <string> excludeSplits = ExpressionShredder.SplitSemiColonSeparatedList(evaluatedExclude); HashSet <string> excludesUnescapedForComparison = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (string excludeSplit in excludeSplits) { string[] excludeSplitFiles = EngineFileUtilities.GetFileListUnescaped(Project.Directory, excludeSplit); foreach (string excludeSplitFile in excludeSplitFiles) { excludesUnescapedForComparison.Add(excludeSplitFile); } } List <ProjectItemInstance> remainingItems = new List <ProjectItemInstance>(); for (int i = 0; i < items.Count; i++) { if (!excludesUnescapedForComparison.Contains(((IItem)items[i]).EvaluatedInclude)) { remainingItems.Add(items[i]); } } items = remainingItems; } } } // Filter the metadata as appropriate if (keepMetadata != null) { foreach (var item in items) { var metadataToRemove = item.MetadataNames.Where(name => !keepMetadata.Contains(name)); foreach (var metadataName in metadataToRemove) { item.RemoveMetadata(metadataName); } } } else if (removeMetadata != null) { foreach (var item in items) { var metadataToRemove = item.MetadataNames.Where(name => removeMetadata.Contains(name)); foreach (var metadataName in metadataToRemove) { item.RemoveMetadata(metadataName); } } } return(items); }
public void PropertyFunctionDoesTaskHostExist_NonexistentTaskHost() { string taskHostName = Environment.GetEnvironmentVariable("MSBUILDTASKHOST_EXE_NAME"); try { Environment.SetEnvironmentVariable("MSBUILDTASKHOST_EXE_NAME", "asdfghjkl.exe"); NodeProviderOutOfProcTaskHost.ClearCachedTaskHostPaths(); PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::DoesTaskHostExist('CLR2', 'CurrentArchitecture'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); // CLR has been forced to pretend not to exist, whether it actually does or not Assert.True(String.Equals("false", result, StringComparison.OrdinalIgnoreCase)); } finally { Environment.SetEnvironmentVariable("MSBUILDTASKHOST_EXE_NAME", taskHostName); NodeProviderOutOfProcTaskHost.ClearCachedTaskHostPaths(); } }
public void PropertyFunctionStaticMethodIntrinsicMaths() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::Add(39.9, 2.1))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal((39.9 + 2.1).ToString(), result); result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::Add(40, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal((40 + 2).ToString(), result); result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::Subtract(44, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal((44 - 2).ToString(), result); result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::Subtract(42.9, 0.9))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal((42.9 - 0.9).ToString(), result); result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::Multiply(21, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal((21 * 2).ToString(), result); result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::Multiply(84.0, 0.5))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal((84.0 * 0.5).ToString(), result); result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::Divide(84, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal((84 / 2).ToString(), result); result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::Divide(84.4, 2.0))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal((84.4 / 2.0).ToString(), result); result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::Modulo(85, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal((85 % 2).ToString(), result); result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::Modulo(2345.5, 43))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal((2345.5 % 43).ToString(), result); // test for overflow wrapping result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::Add(9223372036854775807, 20))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); double expectedResult = 9223372036854775807D + 20D; Assert.Equal(expectedResult.ToString(), result); result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseOr(40, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal((40 | 2).ToString(), result); result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseAnd(42, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal((42 & 2).ToString(), result); result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseXor(213, 255))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal((213 ^ 255).ToString(), result); result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseNot(-43))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal((~-43).ToString(), result); }
public void PropertyFunctionGenericListReturn() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped("$([MSBuild]::__GetListTest())", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal("A;B;C;D", result); }
public void Medley() { // Make absolutely sure that the static method cache hasn't been polluted by the other tests. AvailableStaticMethods.Reset_ForUnitTestsOnly(); PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); pg.Set(ProjectPropertyInstance.Create("File", @"foo\file.txt")); pg.Set(ProjectPropertyInstance.Create("a", "no")); pg.Set(ProjectPropertyInstance.Create("b", "true")); pg.Set(ProjectPropertyInstance.Create("c", "1")); pg.Set(ProjectPropertyInstance.Create("position", "4")); pg.Set(ProjectPropertyInstance.Create("d", "xxx")); pg.Set(ProjectPropertyInstance.Create("e", "xxx")); pg.Set(ProjectPropertyInstance.Create("and", "and")); pg.Set(ProjectPropertyInstance.Create("a_semi_b", "a;b")); pg.Set(ProjectPropertyInstance.Create("a_apos_b", "a'b")); pg.Set(ProjectPropertyInstance.Create("foo_apos_foo", "foo'foo")); pg.Set(ProjectPropertyInstance.Create("a_escapedsemi_b", "a%3bb")); pg.Set(ProjectPropertyInstance.Create("a_escapedapos_b", "a%27b")); pg.Set(ProjectPropertyInstance.Create("has_trailing_slash", @"foo\")); pg.Set(ProjectPropertyInstance.Create("emptystring", @"")); pg.Set(ProjectPropertyInstance.Create("space", @" ")); pg.Set(ProjectPropertyInstance.Create("listofthings", @"a;b;c;d;e;f;g;h;i;j;k;l")); pg.Set(ProjectPropertyInstance.Create("input", @"EXPORT a")); pg.Set(ProjectPropertyInstance.Create("propertycontainingnullasastring", @"null")); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string[,] validTests = { {"$(input.ToString()[1])", "X"}, {"$(input[1])", "X"}, {"$(listofthings.Split(';')[$(position)])","e"}, {@"$([System.Text.RegularExpressions.Regex]::Match($(Input), `EXPORT\s+(.+)`).Groups[1].Value)","a"}, {"$([MSBuild]::Add(1,2).CompareTo(3))", "0"}, {"$([MSBuild]::Add(1,2).CompareTo(3))", "0"}, {"$([MSBuild]::Add(1,2).CompareTo(3.0))", "0"}, {"$([MSBuild]::Add(1,2).CompareTo('3'))", "0"}, {"$([MSBuild]::Add(1,2).CompareTo(3.1))", "-1"}, {"$([MSBuild]::Add(1,2).CompareTo(2))", "1"}, {"$([MSBuild]::Add(1,2).Equals(3))", "True"}, {"$([MSBuild]::Add(1,2).Equals(3.0))", "True"}, {"$([MSBuild]::Add(1,2).Equals('3'))", "True"}, {"$([MSBuild]::Add(1,2).Equals(3.1))", "False"}, {"$(a.Insert(0,'%28'))", "%28no"}, {"$(a.Insert(0,'\"'))", "\"no"}, {"$(a.Insert(0,'(('))", "%28%28no"}, {"$(a.Insert(0,'))'))", "%29%29no"}, {"A$(Reg:A)A", "AA"}, {"A$(Reg:AA)", "A"}, {"$(Reg:AA)", ""}, {"$(Reg:AAAA)", ""}, {"$(Reg:AAA)", ""}, {"$([MSBuild]::Add(2,$([System.Convert]::ToInt64('28', 16))))", "42"}, {"$([MSBuild]::Add(2,$([System.Convert]::ToInt64('28', $([System.Convert]::ToInt32(16))))))", "42"}, {"$(e.Length.ToString())", "3"}, {"$(e.get_Length().ToString())", "3"}, {"$(emptystring.Length)", "0" }, {"$(space.Length)", "1" }, {"$([System.TimeSpan]::Equals(null, null))", "True"}, // constant, unquoted null is a special value {"$([MSBuild]::Add(40,null))", "40"}, {"$([MSBuild]::Add( 40 , null ))", "40"}, {"$([MSBuild]::Add(null,40))", "40"}, {"$([MSBuild]::Escape(';'))", "%3b"}, {"$([MSBuild]::UnEscape('%3b'))", ";"}, {"$(e.Substring($(e.Length)))", ""}, {"$([System.Int32]::MaxValue)", System.Int32.MaxValue.ToString()}, {"x$()", "x"}, {"A$(Reg:A)A", "AA"}, {"A$(Reg:AA)", "A"}, {"$(Reg:AA)", ""}, {"$(Reg:AAAA)", ""}, {"$(Reg:AAA)", ""} }; string[] errorTests = { "$(input[)", "$(input.ToString()])", "$(input.ToString()[)", "$(input.ToString()[12])", "$(input[])", "$(input[-1])", "$(listofthings.Split(';')[)", "$(listofthings.Split(';')['goo'])", "$(listofthings.Split(';')[])", "$(listofthings.Split(';')[-1])", "$([]::())", @" $( $( [System.IO]::Path.GetDirectory('c:\foo\bar\baz.txt') ).Substring( '$([System.IO]::Path.GetPathRoot( '$([System.IO]::Path.GetDirectory('c:\foo\bar\baz.txt'))' ).Length)' ) ", "$([Microsoft.VisualBasic.FileIO.FileSystem]::CurrentDirectory)", // not allowed "$(e.Length..ToString())", "$(SomeStuff.get_Length(null))", "$(SomeStuff.Substring((1)))", "$(b.Substring(-10, $(c)))", "$(b.Substring(-10, $(emptystring)))", "$(b.Substring(-10, $(space)))", "$([MSBuild]::Add.Sub(null,40))", "$([MSBuild]::Add( ,40))", // empty parameter is empty string "$([MSBuild]::Add('',40))", // empty quoted parameter is empty string "$([MSBuild]::Add(40,,,))", "$([MSBuild]::Add(40, ,,))", "$([MSBuild]::Add(40,)", "$([MSBuild]::Add(40,X)", "$([MSBuild]::Add(40,", "$([MSBuild]::Add(40", "$([MSBuild]::Add(,))", // gives "Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true." "$([System.TimeSpan]::Equals(,))", // empty parameter is interpreted as empty string "$([System.TimeSpan]::Equals($(space),$(emptystring)))", // empty parameter is interpreted as empty string "$([System.TimeSpan]::Equals($(emptystring),$(emptystring)))", // empty parameter is interpreted as empty string "$([MSBuild]::Add($(PropertyContainingNullAsAString),40))", // a property containing the word null is a string "null" "$([MSBuild]::Add('null',40))", // the word null is a string "null" "$(SomeStuff.Substring(-10))", "$(.Length)", "$(.Substring(1))", "$(.get_Length())", "$(e.)", "$(e..)", "$(e..Length)", "$(e$(d).Length)", "$($(d).Length)", "$(e`.Length)", "$([System.IO.Path]Combine::Combine(`a`,`b`))", "$([System.IO.Path]::Combine((`a`,`b`))", "$([System.IO.Path]::Combine(`|`,`b`))", "$([System.IO.Path]Combine(::Combine(`a`,`b`))", "$([System.IO.Path]Combine(`::Combine(`a`,`b`)`, `b`)`)", "$([System.IO.Path]::`Combine(`a`, `b`)`)", "$([System.IO.Path]::(`Combine(`a`, `b`)`))", "$([System.DateTime]foofoo::Now)", "$([System.DateTime].Now)", "$([].Now)", "$([ ].Now)", "$([ .Now)", "$([])", "$([ )", "$([ ])", "$([System.Diagnostics.Process]::Start(`NOTEPAD.EXE`))", "$([[]]::Start(`NOTEPAD.EXE`))", "$([(::Start(`NOTEPAD.EXE`))", "$([Goop]::Start(`NOTEPAD.EXE`))", "$([System.Threading.Thread]::CurrentThread)", "$", "$(", "$((", "@", "@(", "@()", "%", "%(", "%()", "exists", "exists(", "exists()", "exists( )", "exists(,)", "@(x->'", "@(x->''", "@(x-", "@(x->'x','", "@(x->'x',''", "@(x->'x','')", "-1>x", "\n", "\t", "+-1", "$(SomeStuff.)", "$(SomeStuff.!)", "$(SomeStuff.`)", "$(SomeStuff.GetType)", "$(goop.baz`)", "$(SomeStuff.Substring(HELLO!))", "$(SomeStuff.ToLowerInvariant()_goop)", "$(SomeStuff($(System.DateTime.Now)))", "$(System.Foo.Bar.Lgg)", "$(SomeStuff.Lgg)", "$(SomeStuff($(Value)))", "$(e.$(e.Length))", "$(e.Substring($(e.Substring(,)))", "$(e.Substring($(e.Substring(a)))", "$(e.Substring($([System.IO.Path]::Combine(`a`, `b`))))", "$([]::())", "$((((", "$(Registry:X)", "$($())", "$", "()" }; string result; for (int i = 0; i < validTests.GetLength(0); i++) { result = expander.ExpandIntoStringLeaveEscaped(validTests[i, 0], ExpanderOptions.ExpandProperties, MockElementLocation.Instance); if (!String.Equals(result, validTests[i, 1])) { string message = "FAILURE: " + validTests[i, 0] + " expanded to '" + result + "' instead of '" + validTests[i, 1] + "'"; Console.WriteLine(message); Assert.True(false, message); } else { Console.WriteLine(validTests[i, 0] + " expanded to '" + result + "'"); } } for (int i = 0; i < errorTests.GetLength(0); i++) { // If an expression is invalid, // - Expansion may throw InvalidProjectFileException, or // - return the original unexpanded expression bool success = true; bool caughtException = false; result = String.Empty; try { result = expander.ExpandIntoStringLeaveEscaped(errorTests[i], ExpanderOptions.ExpandProperties, MockElementLocation.Instance); if (String.Compare(result, errorTests[i]) == 0) { Console.WriteLine(errorTests[i] + " did not expand."); success = false; } } catch (InvalidProjectFileException ex) { Console.WriteLine(errorTests[i] + " caused '" + ex.Message + "'"); caughtException = true; } Assert.True( (success == false || caughtException == true), "FAILURE: Expected '" + errorTests[i] + "' to not parse or not be evaluated but it evaluated to '" + result + "'" ); } }
public void PropertyFunctionDictionaryReturn() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped("$([System.Environment]::GetEnvironmentVariables())", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ToUpperInvariant(); string expected = ("OS=" + Environment.GetEnvironmentVariable("OS")).ToUpperInvariant(); Assert.True(result.Contains(expected)); }
public void PropertyFunctionStaticMethodNested() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); pg.Set(ProjectPropertyInstance.Create("File", @"foo\file.txt")); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped(@"$([System.IO.Path]::Combine(`c:\`, $([System.IO.Path]::Combine(`foo`,`file.txt`))))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal(@"c:\foo\file.txt", result); }
public void PropertyFunctionArrayReturnManualSplitter() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); pg.Set(ProjectPropertyInstance.Create("List", "A-B-C-D")); pg.Set(ProjectPropertyInstance.Create("Splitter", "-")); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped("$(List.Split($(Splitter.ToCharArray())))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal("A;B;C;D", result); }
public void PropertyFunctionStaticMethodChained() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string dateTime = "'" + _dateToParse + "'"; string result = expander.ExpandIntoStringLeaveEscaped(@"$([System.DateTime]::Parse(" + dateTime + ").ToString(`yyyy/MM/dd HH:mm:ss`))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal(DateTime.Parse(_dateToParse).ToString("yyyy/MM/dd HH:mm:ss"), result); }
public void PropertyFunctionInvalid7() { Assert.Throws<InvalidProjectFileException>(() => { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); pg.Set(ProjectPropertyInstance.Create("SomeStuff", "This IS SOME STUff")); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped("[$(SomeStuff.Substring(-10))]", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); } ); }
public void PropertyFunctionStaticMethodDirectoryNameOfFileAbove() { string tempPath = Path.GetTempPath(); string tempFile = Path.GetFileName(FileUtilities.GetTemporaryFile()); try { string directoryStart = Path.Combine(tempPath, "one\\two\\three\\four\\five"); PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); pg.Set(ProjectPropertyInstance.Create("StartingDirectory", directoryStart)); pg.Set(ProjectPropertyInstance.Create("FileToFind", tempFile)); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::GetDirectoryNameOfFileAbove($(StartingDirectory), $(FileToFind)))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal(Microsoft.Build.Shared.FileUtilities.EnsureTrailingSlash(tempPath), Microsoft.Build.Shared.FileUtilities.EnsureTrailingSlash(result)); result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::GetDirectoryNameOfFileAbove($(StartingDirectory), Hobbits))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal(String.Empty, result); } finally { File.Delete(tempFile); } }
public void PropertyFunctionInvalid8() { Assert.Throws<InvalidProjectFileException>(() => { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped("$(([System.DateTime]::Now).ToString(\"MM.dd.yyyy\"))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); } ); }
public void PropertyFunctionStaticMethodArithmeticAddDouble() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::Add(39.9, 2.1))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal((39.9 + 2.1).ToString(), result); }
public void PropertyFunctionInvalidNoMetadataFunctions() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped("[%(LowerLetterList.Identity.ToUpper())]", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal("[%(LowerLetterList.Identity.ToUpper())]", result); }
public void PropertyFunctionValueOrDefaultFromEnvironment() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); pg["BonkersTargetsPath"] = ProjectPropertyInstance.Create("BonkersTargetsPath", "Bonkers"); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::ValueOrDefault('$(BonkersTargetsPath)', '42'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal("Bonkers", result); pg["BonkersTargetsPath"] = ProjectPropertyInstance.Create("BonkersTargetsPath", String.Empty); result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::ValueOrDefault('$(BonkersTargetsPath)', '43'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal("43", result); }
public void PropertyFunctionNoCollisionsOnType() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); pg.Set(ProjectPropertyInstance.Create("System", "The System Namespace")); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped("$(System)", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal("The System Namespace", result); }
public void PropertyFunctionDoesTaskHostExist_Evaluated() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); pg["Runtime"] = ProjectPropertyInstance.Create("Runtime", "CurrentRuntime"); pg["Architecture"] = ProjectPropertyInstance.Create("Architecture", "CurrentArchitecture"); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::DoesTaskHostExist('$(Runtime)', '$(Architecture)'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); // This is the current, so it had better be true! Assert.True(String.Equals("true", result, StringComparison.OrdinalIgnoreCase)); }
public void PropertyFunctionStaticMethodMakeRelative() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); pg.Set(ProjectPropertyInstance.Create("ParentPath", @"c:\abc\def")); pg.Set(ProjectPropertyInstance.Create("FilePath", @"c:\abc\def\foo.cpp")); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::MakeRelative($(ParentPath), `$(FilePath)`))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal(@"foo.cpp", result); }
public void PropertyFunctionStaticMethodFileAttributes() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string tempFile = FileUtilities.GetTemporaryFile(); try { File.SetAttributes(tempFile, FileAttributes.ReadOnly | FileAttributes.Archive); string result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseAnd(32,$([System.IO.File]::GetAttributes(" + tempFile + "))))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal("32", result); } finally { File.SetAttributes(tempFile, FileAttributes.Normal); File.Delete(tempFile); } }
public void PropertyFunctionConstructor2() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); pg.Set(ProjectPropertyInstance.Create("ver1", @"1.2.3.4")); pg.Set(ProjectPropertyInstance.Create("ver2", @"2.2.3.4")); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped(@"$([System.Version]::new($(ver1)).CompareTo($([System.Version]::new($(ver2)))))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal(@"-1", result); }
public void PropertySimpleSpaced() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); pg.Set(ProjectPropertyInstance.Create("SomeStuff", "This IS SOME STUff")); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped(@"$( SomeStuff )", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal(String.Empty, result); }
public void PropertyStaticFunctionAllEnabled() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string env = Environment.GetEnvironmentVariable("MSBUILDENABLEALLPROPERTYFUNCTIONS"); try { Environment.SetEnvironmentVariable("MSBUILDENABLEALLPROPERTYFUNCTIONS", "1"); string result = expander.ExpandIntoStringLeaveEscaped("$([Microsoft.VisualBasic.FileIO.FileSystem]::CurrentDirectory)", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal(0, String.Compare(Directory.GetCurrentDirectory(), result, StringComparison.OrdinalIgnoreCase)); } finally { Environment.SetEnvironmentVariable("MSBUILDENABLEALLPROPERTYFUNCTIONS", env); AvailableStaticMethods.Reset_ForUnitTestsOnly(); } }
public void PropertyFunctionConsumingItemMetadata() { ProjectInstance project = ProjectHelpers.CreateEmptyProjectInstance(); PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); Dictionary<string, string> itemMetadataTable = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); itemMetadataTable["Compile.Identity"] = "fOo.Cs"; StringMetadataTable itemMetadata = new StringMetadataTable(itemMetadataTable); List<ProjectItemInstance> ig = new List<ProjectItemInstance>(); pg.Set(ProjectPropertyInstance.Create("SomePath", @"c:\some\path")); ig.Add(new ProjectItemInstance(project, "Compile", "fOo.Cs", project.FullPath)); ItemDictionary<ProjectItemInstance> itemsByType = new ItemDictionary<ProjectItemInstance>(); itemsByType.ImportItems(ig); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg, itemsByType, itemMetadata); string result = expander.ExpandIntoStringLeaveEscaped(@"$([System.IO.Path]::Combine($(SomePath),%(Compile.Identity)))", ExpanderOptions.ExpandAll, MockElementLocation.Instance); Assert.Equal(@"c:\some\path\fOo.Cs", result); }
public void PropertyStaticFunctionUsingNamespaceNotFound() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string env = Environment.GetEnvironmentVariable("MSBUILDENABLEALLPROPERTYFUNCTIONS"); try { Environment.SetEnvironmentVariable("MSBUILDENABLEALLPROPERTYFUNCTIONS", "1"); Assert.Throws<InvalidProjectFileException>(() => expander.ExpandIntoStringLeaveEscaped("$([Microsoft.FOO.FileIO.FileSystem]::CurrentDirectory)", ExpanderOptions.ExpandProperties, MockElementLocation.Instance)); Assert.Throws<InvalidProjectFileException>(() => expander.ExpandIntoStringLeaveEscaped("$([Foo.Baz]::new())", ExpanderOptions.ExpandProperties, MockElementLocation.Instance)); Assert.Throws<InvalidProjectFileException>(() => expander.ExpandIntoStringLeaveEscaped("$([Foo]::new())", ExpanderOptions.ExpandProperties, MockElementLocation.Instance)); Assert.Throws<InvalidProjectFileException>(() => expander.ExpandIntoStringLeaveEscaped("$([Foo.]::new())", ExpanderOptions.ExpandProperties, MockElementLocation.Instance)); Assert.Throws<InvalidProjectFileException>(() => expander.ExpandIntoStringLeaveEscaped("$([.Foo]::new())", ExpanderOptions.ExpandProperties, MockElementLocation.Instance)); Assert.Throws<InvalidProjectFileException>(() => expander.ExpandIntoStringLeaveEscaped("$([.]::new())", ExpanderOptions.ExpandProperties, MockElementLocation.Instance)); Assert.Throws<InvalidProjectFileException>(() => expander.ExpandIntoStringLeaveEscaped("$([]::new())", ExpanderOptions.ExpandProperties, MockElementLocation.Instance)); } finally { Environment.SetEnvironmentVariable("MSBUILDENABLEALLPROPERTYFUNCTIONS", env); AvailableStaticMethods.Reset_ForUnitTestsOnly(); } }
private IEnumerable <ItemFragment> BuildItemFragments(IElementLocation itemSpecLocation, bool expandProperties) { var builder = ImmutableList.CreateBuilder <ItemFragment>(); // Code corresponds to Evaluator.CreateItemsFromInclude var evaluatedItemspecEscaped = ItemSpecString; if (string.IsNullOrEmpty(evaluatedItemspecEscaped)) { return(builder.ToImmutable()); } // STEP 1: Expand properties in Include if (expandProperties) { evaluatedItemspecEscaped = Expander.ExpandIntoStringLeaveEscaped(ItemSpecString, ExpanderOptions.ExpandProperties, itemSpecLocation); } // STEP 2: Split Include on any semicolons, and take each split in turn if (evaluatedItemspecEscaped.Length > 0) { var splitsEscaped = ExpressionShredder.SplitSemiColonSeparatedList(evaluatedItemspecEscaped); foreach (var splitEscaped in splitsEscaped) { // STEP 3: If expression is "@(x)" copy specified list with its metadata, otherwise just treat as string bool isItemListExpression; var itemReferenceFragment = ProcessItemExpression(splitEscaped, itemSpecLocation, out isItemListExpression); if (isItemListExpression) { builder.Add(itemReferenceFragment); } else { // The expression is not of the form "@(X)". Treat as string // Code corresponds to EngineFileUtilities.GetFileList var containsEscapedWildcards = EscapingUtilities.ContainsEscapedWildcards(splitEscaped); var containsRealWildcards = FileMatcher.HasWildcards(splitEscaped); // '*' is an illegal character to have in a filename. // todo file-system assumption on legal path characters: https://github.com/Microsoft/msbuild/issues/781 if (containsEscapedWildcards && containsRealWildcards) { // Just return the original string. builder.Add(new ValueFragment(splitEscaped, itemSpecLocation.File)); } else if (!containsEscapedWildcards && containsRealWildcards) { // Unescape before handing it to the filesystem. var filespecUnescaped = EscapingUtilities.UnescapeAll(splitEscaped); builder.Add(new GlobFragment(filespecUnescaped, itemSpecLocation.File)); } 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 builder.Add(new ValueFragment(splitEscaped, itemSpecLocation.File)); } } } } return(builder.ToImmutable()); }
public void PropertyFunctionStaticMethodQuoted4() { PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); string result = expander.ExpandIntoStringLeaveEscaped("$([System.DateTime]::Now.ToString(\"MM.dd.yyyy\"))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal(DateTime.Now.ToString("MM.dd.yyyy"), result); }