public void BuildAssetsUtils_GenerateContentFilesItem_CopyToOutput_Flatten() { // Arrange var path = "contentFiles/cs/net46/a/b/c.txt"; var item = new LockFileContentFile(path); item.BuildAction = BuildAction.None; item.CodeLanguage = "cs"; item.CopyToOutput = true; item.OutputPath = "c.txt"; // Act var node = BuildAssetsUtils.GenerateContentFilesItem(path, item, "a", "1.0.0"); var metadata = node.Elements().ToDictionary(e => e.Name.LocalName, e => e.Value, StringComparer.OrdinalIgnoreCase); // Assert Assert.Equal("a", metadata["NuGetPackageId"]); Assert.Equal("1.0.0", metadata["NuGetPackageVersion"]); Assert.Equal("None", metadata["NuGetItemType"]); Assert.Equal("True", metadata["Private"]); Assert.Equal("c.txt", metadata["TargetPath"]); Assert.Equal("a/b/c.txt", metadata["Link"].Replace('\\', '/')); Assert.Equal("PreserveNewest", metadata["CopyToOutputDirectory"]); Assert.False(metadata.ContainsKey("DestinationSubDirectory")); }
public AssetsFileTargetLibraryContentFile(LockFileContentFile file) { Requires.NotNull(file, nameof(file)); BuildAction = file.BuildAction.Value; CodeLanguage = file.CodeLanguage; CopyToOutput = file.CopyToOutput; OutputPath = file.OutputPath; Path = file.Path ?? ""; // Path should always be present so don't require consumers to null check. Not worth throwing if null though. PPOutputPath = file.PPOutputPath; }
public static XElement GenerateContentFilesItem(string path, LockFileContentFile item, string packageId, string packageVersion) { var entry = new XElement(Namespace + item.BuildAction.Value, new XAttribute("Include", path), new XAttribute("Condition", $"Exists('{path}')"), new XElement(Namespace + "NuGetPackageId", packageId), new XElement(Namespace + "NuGetPackageVersion", packageVersion), new XElement(Namespace + "NuGetItemType", item.BuildAction), new XElement(Namespace + "Pack", false)); var privateFlag = false; if (item.CopyToOutput) { var outputPath = item.OutputPath ?? item.PPOutputPath; if (outputPath != null) { // Convert / to \ outputPath = LockFileUtils.ToDirectorySeparator(outputPath); privateFlag = true; entry.Add(new XElement(Namespace + "CopyToOutputDirectory", "PreserveNewest")); entry.Add(new XElement(Namespace + "TargetPath", outputPath)); var destinationSubDirectory = Path.GetDirectoryName(outputPath); if (!string.IsNullOrEmpty(destinationSubDirectory)) { entry.Add(new XElement(Namespace + "DestinationSubDirectory", destinationSubDirectory + Path.DirectorySeparatorChar)); } } } entry.Add(new XElement(Namespace + "Private", privateFlag.ToString())); // Remove contentFile/lang/tfm/ from start of the path var linkPath = string.Join(string.Empty + Path.DirectorySeparatorChar, item.Path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries) .Skip(3) .ToArray()); if (linkPath != null) { entry.Add(new XElement(Namespace + "Link", linkPath)); } return(entry); }
public void BuildAssetsUtils_GenerateContentFilesItem_CompileAsset() { // Arrange var path = "contentFiles/cs/net46/test/test.cs"; var item = new LockFileContentFile(path); item.BuildAction = BuildAction.Compile; item.CodeLanguage = "cs"; // Act var node = BuildAssetsUtils.GenerateContentFilesItem(path, item, "a", "1.0.0"); var metadata = node.Elements().ToDictionary(e => e.Name.LocalName, e => e.Value, StringComparer.OrdinalIgnoreCase); // Assert Assert.Equal("a", metadata["NuGetPackageId"]); Assert.Equal("1.0.0", metadata["NuGetPackageVersion"]); Assert.Equal("Compile", metadata["NuGetItemType"]); Assert.Equal("False", metadata["Private"]); Assert.Equal("test/test.cs", metadata["Link"].Replace('\\', '/')); }
/// <summary> /// Apply build actions from the nuspec to items from the contentFiles folder. /// </summary> internal static List <LockFileContentFile> GetContentFileGroup( NuspecReader nuspec, List <ContentItemGroup> contentFileGroups) { var results = new List <LockFileContentFile>(contentFileGroups.Count); var rootFolderPathLength = ContentFilesFolderName.Length; // Read the contentFiles section of the nuspec // Read the entries so that the bottom entry has priority var nuspecContentFiles = nuspec.GetContentFiles().ToList(); // Initialize mappings var entryMappings = new Dictionary <string, List <ContentFilesEntry> >(StringComparer.OrdinalIgnoreCase); var languageMappings = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); foreach (var group in contentFileGroups) { var codeLanguage = group.Properties[ManagedCodeConventions.PropertyNames.CodeLanguage] as string; foreach (var item in group.Items) { if (!entryMappings.ContainsKey(item.Path)) { entryMappings.Add(item.Path, new List <ContentFilesEntry>()); languageMappings.Add(item.Path, codeLanguage); } } } // Virtual root for file globbing var rootDirectory = new VirtualFileInfo(VirtualFileProvider.RootDir, isDirectory: true); // Apply all nuspec property mappings to the files returned by content model foreach (var filesEntry in nuspecContentFiles) { // this is validated in the nuspec reader Debug.Assert(filesEntry.Include != null, "invalid contentFiles entry"); // Create a filesystem matcher for globbing patterns var matcher = new Matcher(StringComparison.OrdinalIgnoreCase); matcher.AddInclude(filesEntry.Include); if (filesEntry.Exclude != null) { matcher.AddExclude(filesEntry.Exclude); } // Check each file against the patterns foreach (var file in entryMappings.Keys) { // Remove contentFiles/ from the string Debug.Assert(file.StartsWith(ContentFilesFolderName, StringComparison.OrdinalIgnoreCase), "invalid file path: " + file); // All files should begin with the same root folder if (file.Length > rootFolderPathLength) { var relativePath = file.Substring(rootFolderPathLength, file.Length - rootFolderPathLength); // Check if the nuspec group include/exclude patterns apply to the file var virtualDirectory = new VirtualFileProvider(new List <string>() { relativePath }); var globbingDirectory = new FileProviderGlobbingDirectory( virtualDirectory, fileInfo: rootDirectory, parent: null); // Currently Matcher only returns the file name not the full path, each file must be // check individually. var matchResults = matcher.Execute(globbingDirectory); if (matchResults.Files.Any()) { entryMappings[file].Add(filesEntry); } } } } // Create lock file entries for each item in the contentFiles folder foreach (var file in entryMappings.Keys) { // defaults var action = BuildAction.Parse(PackagingConstants.ContentFilesDefaultBuildAction); var copyToOutput = false; var flatten = false; // _._ is needed for empty codeLanguage groups if (file.EndsWith(PackagingCoreConstants.ForwardSlashEmptyFolder, StringComparison.Ordinal)) { action = BuildAction.None; } else { // apply each entry // entries may not have all the attributes, if a value is null // ignore it and continue using the previous value. foreach (var filesEntry in entryMappings[file]) { if (!string.IsNullOrEmpty(filesEntry.BuildAction)) { action = BuildAction.Parse(filesEntry.BuildAction); } if (filesEntry.CopyToOutput.HasValue) { copyToOutput = filesEntry.CopyToOutput.Value; } if (filesEntry.Flatten.HasValue) { flatten = filesEntry.Flatten.Value; } } } // Add attributes to the lock file item var lockFileItem = new LockFileContentFile(file); // Add the language from the directory path lockFileItem.CodeLanguage = languageMappings[file].ToLowerInvariant(); if (!action.IsKnown) { // Throw an error containing the package identity, invalid action, and file where it occurred. var message = string.Format(CultureInfo.CurrentCulture, Strings.Error_UnknownBuildAction, nuspec.GetIdentity(), action, file); throw new PackagingException(message); } lockFileItem.BuildAction = action; lockFileItem.CopyToOutput = copyToOutput; // Check if this is a .pp transform. If the filename is ".pp" ignore it since it will // have no file name after the transform. var isPP = lockFileItem.Path.EndsWith(".pp", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(Path.GetFileNameWithoutExtension(lockFileItem.Path)); if (copyToOutput) { string destination = null; if (flatten) { destination = Path.GetFileName(lockFileItem.Path); } else { // Find path relative to the TxM // Ex: contentFiles/cs/net45/config/config.xml -> config/config.xml destination = GetContentFileFolderRelativeToFramework(file); } if (isPP) { // Remove .pp from the output file path destination = destination.Substring(0, destination.Length - 3); } lockFileItem.OutputPath = destination; } // Add the pp transform file if one exists if (isPP) { var destination = lockFileItem.Path.Substring(0, lockFileItem.Path.Length - 3); destination = GetContentFileFolderRelativeToFramework(destination); lockFileItem.PPOutputPath = destination; } results.Add(lockFileItem); } return(results); }