Asset refactoring and content files

This commit is contained in:
Pavel Krymets 2016-02-17 10:08:27 -08:00
parent 388bb7260c
commit a71112ce8f
34 changed files with 1301 additions and 173 deletions

View file

@ -82,6 +82,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Installer", "Installer", "{
EndProject EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.Cli.Msi.Tests", "test\Installer\Microsoft.DotNet.Cli.Msi.Tests\Microsoft.DotNet.Cli.Msi.Tests.xproj", "{0B31C336-149D-471A-B7B1-27B0F1E80F83}" Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.Cli.Msi.Tests", "test\Installer\Microsoft.DotNet.Cli.Msi.Tests\Microsoft.DotNet.Cli.Msi.Tests.xproj", "{0B31C336-149D-471A-B7B1-27B0F1E80F83}"
EndProject EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Extensions.DependencyModel.Tests", "..\cli1\test\Microsoft.Extensions.DependencyModel.Tests\Microsoft.Extensions.DependencyModel.Tests.xproj", "{4A4711D8-4312-49FC-87B5-4F183F4C6A51}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -526,22 +528,22 @@ Global
{BD4F0750-4E81-4AD2-90B5-E470881792C3}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU {BD4F0750-4E81-4AD2-90B5-E470881792C3}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
{BD4F0750-4E81-4AD2-90B5-E470881792C3}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU {BD4F0750-4E81-4AD2-90B5-E470881792C3}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
{BD4F0750-4E81-4AD2-90B5-E470881792C3}.RelWithDebInfo|x64.Build.0 = Release|Any CPU {BD4F0750-4E81-4AD2-90B5-E470881792C3}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.Debug|Any CPU.Build.0 = Debug|Any CPU {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.Debug|x64.ActiveCfg = Debug|Any CPU {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Debug|x64.ActiveCfg = Debug|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.Debug|x64.Build.0 = Debug|Any CPU {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Debug|x64.Build.0 = Debug|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.MinSizeRel|x64.Build.0 = Debug|Any CPU {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.Release|Any CPU.ActiveCfg = Release|Any CPU {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.Release|Any CPU.Build.0 = Release|Any CPU {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Release|Any CPU.Build.0 = Release|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.Release|x64.ActiveCfg = Release|Any CPU {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Release|x64.ActiveCfg = Release|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.Release|x64.Build.0 = Release|Any CPU {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Release|x64.Build.0 = Release|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.RelWithDebInfo|x64.Build.0 = Release|Any CPU {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
{0B31C336-149D-471A-B7B1-27B0F1E80F83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0B31C336-149D-471A-B7B1-27B0F1E80F83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0B31C336-149D-471A-B7B1-27B0F1E80F83}.Debug|Any CPU.Build.0 = Debug|Any CPU {0B31C336-149D-471A-B7B1-27B0F1E80F83}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0B31C336-149D-471A-B7B1-27B0F1E80F83}.Debug|x64.ActiveCfg = Debug|Any CPU {0B31C336-149D-471A-B7B1-27B0F1E80F83}.Debug|x64.ActiveCfg = Debug|Any CPU
@ -591,7 +593,7 @@ Global
{947DD232-8D9B-4B78-9C6A-94F807D2DD58} = {713CBFBB-5392-438D-B766-A9A585EF1BB8} {947DD232-8D9B-4B78-9C6A-94F807D2DD58} = {713CBFBB-5392-438D-B766-A9A585EF1BB8}
{947DD232-8D9B-4B78-9C6A-94F807D22222} = {713CBFBB-5392-438D-B766-A9A585EF1BB8} {947DD232-8D9B-4B78-9C6A-94F807D22222} = {713CBFBB-5392-438D-B766-A9A585EF1BB8}
{BD4F0750-4E81-4AD2-90B5-E470881792C3} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F} {BD4F0750-4E81-4AD2-90B5-E470881792C3} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
{0745410A-6629-47EB-AAB5-08D6288CAD72} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} {4A4711D8-4312-49FC-87B5-4F183F4C6A51} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
{0E3300A4-DF54-40BF-87D8-E7658330C288} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} {0E3300A4-DF54-40BF-87D8-E7658330C288} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
{0B31C336-149D-471A-B7B1-27B0F1E80F83} = {0E3300A4-DF54-40BF-87D8-E7658330C288} {0B31C336-149D-471A-B7B1-27B0F1E80F83} = {0E3300A4-DF54-40BF-87D8-E7658330C288}
EndGlobalSection EndGlobalSection

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="Local" value="Packages" />
</packageSources>
</configuration>

View file

@ -0,0 +1,19 @@
using System;
using System.Reflection;
namespace TestAppWithContentPackage
{
public class Program
{
public static int Main(string[] args)
{
foreach (var name in Assembly.GetEntryAssembly().GetManifestResourceNames())
{
Console.WriteLine(name);
}
Console.WriteLine(typeof(Foo).FullName);
Console.WriteLine(typeof(MyNamespace.Util).FullName);
return 0;
}
}
}

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0.24720" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.24720</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>ea239e10-75e8-4305-966e-fec926a5aee6</ProjectGuid>
<RootNamespace>TestAppWithContentPackage</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View file

@ -0,0 +1,14 @@
{
"version": "1.0.0-*",
"compilationOptions": {
"emitEntryPoint": true
},
"dependencies": {
"NETStandard.Library": "1.0.0-rc2-23811",
"SharedContentA": "1.0.0-*"
},
"frameworks": {
"dnxcore50": { }
}
}

View file

@ -20,14 +20,20 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common
{ {
private readonly ProjectContext _context; private readonly ProjectContext _context;
private readonly LibraryExporter _exporter;
private readonly OutputPaths _outputPaths; private readonly OutputPaths _outputPaths;
private readonly LibraryExporter _exporter; private readonly string _runtimeOutputPath;
private readonly string _intermediateOutputPath;
public Executable(ProjectContext context, OutputPaths outputPaths, LibraryExporter exporter) public Executable(ProjectContext context, OutputPaths outputPaths, LibraryExporter exporter)
{ {
_context = context; _context = context;
_outputPaths = outputPaths; _outputPaths = outputPaths;
_runtimeOutputPath = outputPaths.RuntimeOutputPath;
_intermediateOutputPath = outputPaths.IntermediateOutputDirectoryPath;
_exporter = exporter; _exporter = exporter;
} }
@ -38,68 +44,75 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common
throw new InvalidOperationException($"Can not make output runnable for framework {_context.TargetFramework}, because it doesn't have runtime target"); throw new InvalidOperationException($"Can not make output runnable for framework {_context.TargetFramework}, because it doesn't have runtime target");
} }
var outputPath = _outputPaths.RuntimeOutputPath; CopyContentFiles();
ExportRuntimeAssets();
CopyContentFiles(outputPath);
ExportRuntimeAssets(outputPath);
} }
private void ExportRuntimeAssets(string outputPath) private void ExportRuntimeAssets()
{ {
if (_context.TargetFramework.IsDesktop()) if (_context.TargetFramework.IsDesktop())
{ {
MakeCompilationOutputRunnableForFullFramework(outputPath); MakeCompilationOutputRunnableForFullFramework();
} }
else else
{ {
MakeCompilationOutputRunnableForCoreCLR(outputPath); MakeCompilationOutputRunnableForCoreCLR();
} }
} }
private void MakeCompilationOutputRunnableForFullFramework( private void MakeCompilationOutputRunnableForFullFramework()
string outputPath)
{ {
CopyAllDependencies(outputPath, _exporter.GetDependencies()); var dependencies = _exporter.GetDependencies();
CopyAssemblies(dependencies);
CopyAssets(dependencies);
GenerateBindingRedirects(_exporter); GenerateBindingRedirects(_exporter);
} }
private void MakeCompilationOutputRunnableForCoreCLR(string outputPath) private void MakeCompilationOutputRunnableForCoreCLR()
{ {
WriteDepsFileAndCopyProjectDependencies(_exporter, _context.ProjectFile.Name, outputPath); WriteDepsFileAndCopyProjectDependencies(_exporter);
// TODO: Pick a host based on the RID // TODO: Pick a host based on the RID
CoreHost.CopyTo(outputPath, _context.ProjectFile.Name + Constants.ExeSuffix); CoreHost.CopyTo(_runtimeOutputPath, _context.ProjectFile.Name + Constants.ExeSuffix);
} }
private void CopyContentFiles(string outputPath) private void CopyContentFiles()
{ {
var contentFiles = new ContentFiles(_context); var contentFiles = new ContentFiles(_context);
contentFiles.StructuredCopyTo(outputPath); contentFiles.StructuredCopyTo(_runtimeOutputPath);
} }
private static void CopyAllDependencies(string outputPath, IEnumerable<LibraryExport> libraryExports) private void CopyAssemblies(IEnumerable<LibraryExport> libraryExports)
{ {
foreach (var libraryExport in libraryExports) foreach (var libraryExport in libraryExports)
{ {
libraryExport.RuntimeAssemblies.CopyTo(outputPath); libraryExport.RuntimeAssemblies.CopyTo(_runtimeOutputPath);
libraryExport.NativeLibraries.CopyTo(outputPath); libraryExport.NativeLibraries.CopyTo(_runtimeOutputPath);
libraryExport.RuntimeAssets.StructuredCopyTo(outputPath);
} }
} }
private static void WriteDepsFileAndCopyProjectDependencies( private void CopyAssets(IEnumerable<LibraryExport> libraryExports)
LibraryExporter exporter, {
string projectFileName, foreach (var libraryExport in libraryExports)
string outputPath) {
libraryExport.RuntimeAssets.StructuredCopyTo(
_runtimeOutputPath,
_intermediateOutputPath);
}
}
private void WriteDepsFileAndCopyProjectDependencies(LibraryExporter exporter)
{ {
exporter exporter
.GetDependencies(LibraryType.Package) .GetDependencies(LibraryType.Package)
.WriteDepsTo(Path.Combine(outputPath, projectFileName + FileNameSuffixes.Deps)); .WriteDepsTo(Path.Combine(_runtimeOutputPath, _context.ProjectFile.Name + FileNameSuffixes.Deps));
var projectExports = exporter.GetDependencies(LibraryType.Project); var projectExports = exporter.GetDependencies(LibraryType.Project);
CopyAssemblies(projectExports);
CopyAssets(projectExports);
CopyAllDependencies(outputPath, projectExports); var packageExports = exporter.GetDependencies(LibraryType.Package);
CopyAssets(packageExports);
} }
public void GenerateBindingRedirects(LibraryExporter exporter) public void GenerateBindingRedirects(LibraryExporter exporter)

View file

@ -53,7 +53,7 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
} }
} }
public static void StructuredCopyTo(this IEnumerable<LibraryAsset> assets, string destinationPath) public static void StructuredCopyTo(this IEnumerable<LibraryAsset> assets, string destinationPath, string tempLocation)
{ {
if (!Directory.Exists(destinationPath)) if (!Directory.Exists(destinationPath))
{ {
@ -63,8 +63,9 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
foreach (var asset in assets) foreach (var asset in assets)
{ {
var targetName = ResolveTargetName(destinationPath, asset); var targetName = ResolveTargetName(destinationPath, asset);
var transformedFile = asset.GetTransformedFile(tempLocation);
File.Copy(asset.ResolvedPath, targetName, overwrite: true); File.Copy(transformedFile, targetName, overwrite: true);
} }
} }

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0.24720" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.24720</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>bd4f0750-4e81-4ad2-90b5-e470881792c3</ProjectGuid>
<RootNamespace>Microsoft.DotNet.InternalAbstractions</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View file

@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text;
using Microsoft.DotNet.Cli.Compiler.Common; using Microsoft.DotNet.Cli.Compiler.Common;
using Microsoft.DotNet.ProjectModel.Compilation;
using NuGet.Frameworks; using NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel.Workspaces namespace Microsoft.DotNet.ProjectModel.Workspaces
@ -78,7 +79,10 @@ namespace Microsoft.DotNet.ProjectModel.Workspaces
foreach (var file in project.ProjectFile.Files.SourceFiles) foreach (var file in project.ProjectFile.Files.SourceFiles)
{ {
AddSourceFile(projectInfo, file); using (var stream = File.OpenRead(file))
{
AddSourceFile(projectInfo, file, stream);
}
} }
var exporter = project.CreateExporter(configuration); var exporter = project.CreateExporter(configuration);
@ -104,16 +108,17 @@ namespace Microsoft.DotNet.ProjectModel.Workspaces
foreach (var file in dependency.SourceReferences) foreach (var file in dependency.SourceReferences)
{ {
AddSourceFile(projectInfo, file); using (var stream = file.GetTransformedStream())
{
AddSourceFile(projectInfo, file.ResolvedPath, stream);
}
} }
} }
return projectInfo.Id; return projectInfo.Id;
} }
private void AddSourceFile(ProjectInfo projectInfo, string file) private void AddSourceFile(ProjectInfo projectInfo, string file, Stream stream)
{
using (var stream = File.OpenRead(file))
{ {
var sourceText = SourceText.From(stream, encoding: Encoding.UTF8); var sourceText = SourceText.From(stream, encoding: Encoding.UTF8);
var id = DocumentId.CreateNewId(projectInfo.Id); var id = DocumentId.CreateNewId(projectInfo.Id);
@ -122,7 +127,6 @@ namespace Microsoft.DotNet.ProjectModel.Workspaces
var loader = TextLoader.From(TextAndVersion.Create(sourceText, version)); var loader = TextLoader.From(TextAndVersion.Create(sourceText, version));
OnDocumentAdded(DocumentInfo.Create(id, file, filePath: file, loader: loader)); OnDocumentAdded(DocumentInfo.Create(id, file, filePath: file, loader: loader));
} }
}
private MetadataReference GetMetadataReference(string path) private MetadataReference GetMetadataReference(string path)
{ {

View file

@ -3,7 +3,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using Microsoft.DotNet.ProjectModel.Utilities;
using Microsoft.Extensions.Internal; using Microsoft.Extensions.Internal;
namespace Microsoft.DotNet.ProjectModel.Compilation namespace Microsoft.DotNet.ProjectModel.Compilation
@ -13,12 +15,14 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
public string Name { get; } public string Name { get; }
public string RelativePath { get; } public string RelativePath { get; }
public string ResolvedPath { get; } public string ResolvedPath { get; }
public Action<Stream, Stream> Transform { get; set; }
public LibraryAsset(string name, string relativePath, string resolvedPath) public LibraryAsset(string name, string relativePath, string resolvedPath, Action<Stream, Stream> transform = null)
{ {
Name = name; Name = name;
RelativePath = relativePath; RelativePath = relativePath;
ResolvedPath = resolvedPath; ResolvedPath = resolvedPath;
Transform = transform;
} }
public bool Equals(LibraryAsset other) public bool Equals(LibraryAsset other)
@ -42,5 +46,25 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
combiner.Add(ResolvedPath); combiner.Add(ResolvedPath);
return combiner.CombinedHash; return combiner.CombinedHash;
} }
public static LibraryAsset CreateFromRelativePath(string basePath, string relativePath, Action<Stream, Stream> transform = null)
{
return new LibraryAsset(
Path.GetFileNameWithoutExtension(relativePath),
relativePath,
Path.Combine(basePath, relativePath),
transform);
}
public static LibraryAsset CreateFromAbsolutePath(string basePath, string absolutePath, Action<Stream, Stream> transform = null)
{
var relativePath = absolutePath.Replace(PathUtility.EnsureTrailingSlash(basePath), string.Empty);
return new LibraryAsset(
Path.GetFileNameWithoutExtension(relativePath),
relativePath,
absolutePath,
transform);
}
} }
} }

View file

@ -0,0 +1,44 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.IO;
namespace Microsoft.DotNet.ProjectModel.Compilation
{
public static class LibraryAssetExtensions
{
public static string GetTransformedFile(this LibraryAsset asset, string tempLocation, string tempName = null)
{
if (asset.Transform == null)
{
return asset.ResolvedPath;
}
tempName = tempName ?? Path.GetFileName(asset.RelativePath);
using (var input = File.OpenRead(asset.ResolvedPath))
{
var transformedName = Path.Combine(tempLocation, tempName);
using (var output = File.OpenWrite(transformedName))
{
asset.Transform(input, output);
}
return transformedName;
}
}
public static Stream GetTransformedStream(this LibraryAsset asset)
{
if (asset.Transform == null)
{
return File.OpenRead(asset.ResolvedPath);
}
using (var input = File.OpenRead(asset.ResolvedPath))
{
var output = new MemoryStream();
asset.Transform(input, output);
return output;
}
}
}
}

View file

@ -34,10 +34,15 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
/// </summary> /// </summary>
public IEnumerable<LibraryAsset> CompilationAssemblies { get; } public IEnumerable<LibraryAsset> CompilationAssemblies { get; }
/// <summary>
/// Get a list of embedded resource files provided by this export.
/// </summary>
public IEnumerable<LibraryAsset> EmbeddedResources { get; }
/// <summary> /// <summary>
/// Gets a list of fully-qualified paths to source code file references /// Gets a list of fully-qualified paths to source code file references
/// </summary> /// </summary>
public IEnumerable<string> SourceReferences { get; } public IEnumerable<LibraryAsset> SourceReferences { get; }
/// <summary> /// <summary>
/// Get a list of analyzers provided by this export. /// Get a list of analyzers provided by this export.
@ -46,10 +51,11 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
public LibraryExport(LibraryDescription library, public LibraryExport(LibraryDescription library,
IEnumerable<LibraryAsset> compileAssemblies, IEnumerable<LibraryAsset> compileAssemblies,
IEnumerable<string> sourceReferences, IEnumerable<LibraryAsset> sourceReferences,
IEnumerable<LibraryAsset> runtimeAssemblies, IEnumerable<LibraryAsset> runtimeAssemblies,
IEnumerable<LibraryAsset> runtimeAssets, IEnumerable<LibraryAsset> runtimeAssets,
IEnumerable<LibraryAsset> nativeLibraries, IEnumerable<LibraryAsset> nativeLibraries,
IEnumerable<LibraryAsset> embeddedResources,
IEnumerable<AnalyzerReference> analyzers) IEnumerable<AnalyzerReference> analyzers)
{ {
Library = library; Library = library;
@ -58,6 +64,7 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
RuntimeAssemblies = runtimeAssemblies; RuntimeAssemblies = runtimeAssemblies;
RuntimeAssets = runtimeAssets; RuntimeAssets = runtimeAssets;
NativeLibraries = nativeLibraries; NativeLibraries = nativeLibraries;
EmbeddedResources = embeddedResources;
AnalyzerReferences = analyzers; AnalyzerReferences = analyzers;
} }

View file

@ -0,0 +1,173 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
namespace Microsoft.DotNet.ProjectModel.Compilation
{
public class LibraryExportBuilder
{
private IList<LibraryAsset> _runtimeAssemblies;
private IList<LibraryAsset> _runtimeAssets;
private IList<LibraryAsset> _compilationAssemblies;
private IList<LibraryAsset> _compilationAssets;
private IList<LibraryAsset> _debugAssets;
private IList<LibraryAsset> _sourceReferences;
private IList<LibraryAsset> _nativeLibraries;
private IList<LibraryAsset> _embeddedResources;
private IList<AnalyzerReference> _analyzerReferences;
public LibraryDescription Library { get; set; }
public IEnumerable<LibraryAsset> RuntimeAssemblies => _runtimeAssemblies;
public IEnumerable<LibraryAsset> RuntimeAssets => _runtimeAssets;
public IEnumerable<LibraryAsset> CompilationAssemblies => _compilationAssemblies;
public IEnumerable<LibraryAsset> CompilationAssets => _compilationAssets;
public IEnumerable<LibraryAsset> SourceReferences => _sourceReferences;
public IEnumerable<LibraryAsset> NativeLibraries => _nativeLibraries;
public IEnumerable<LibraryAsset> EmbeddedResources => _embeddedResources;
public IEnumerable<AnalyzerReference> AnalyzerReferences => _analyzerReferences;
public static LibraryExportBuilder Create(LibraryDescription library = null)
{
return new LibraryExportBuilder().WithLibrary(library);
}
public LibraryExport Build()
{
if (Library == null)
{
throw new InvalidOperationException("Cannot build LibraryExport withoud Library set");
}
return new LibraryExport(
Library,
CompilationAssemblies ?? EmptyArray<LibraryAsset>.Value,
SourceReferences ?? EmptyArray<LibraryAsset>.Value,
RuntimeAssemblies ?? EmptyArray<LibraryAsset>.Value,
RuntimeAssets ?? EmptyArray<LibraryAsset>.Value,
NativeLibraries ?? EmptyArray<LibraryAsset>.Value,
EmbeddedResources ?? EmptyArray<LibraryAsset>.Value,
AnalyzerReferences ?? EmptyArray<AnalyzerReference>.Value);
}
public LibraryExportBuilder WithLibrary(LibraryDescription libraryDescription)
{
Library = libraryDescription;
return this;
}
public LibraryExportBuilder WithRuntimeAssemblies(IEnumerable<LibraryAsset> assets)
{
Replace(ref _runtimeAssemblies, assets);
return this;
}
public LibraryExportBuilder WithRuntimeAssets(IEnumerable<LibraryAsset> assets)
{
Replace(ref _runtimeAssets, assets);
return this;
}
public LibraryExportBuilder WithCompilationAssemblies(IEnumerable<LibraryAsset> assets)
{
Replace(ref _compilationAssemblies, assets);
return this;
}
public LibraryExportBuilder WithSourceReferences(IEnumerable<LibraryAsset> assets)
{
Replace(ref _sourceReferences, assets);
return this;
}
public LibraryExportBuilder WithNativeLibraries(IEnumerable<LibraryAsset> assets)
{
Replace(ref _nativeLibraries, assets);
return this;
}
public LibraryExportBuilder WithEmbedddedResources(IEnumerable<LibraryAsset> assets)
{
Replace(ref _embeddedResources, assets);
return this;
}
public LibraryExportBuilder WithAnalyzerReference(IEnumerable<AnalyzerReference> assets)
{
Replace(ref _analyzerReferences, assets);
return this;
}
public LibraryExportBuilder AddRuntimeAssembly(LibraryAsset asset)
{
Add(ref _runtimeAssemblies, asset);
return this;
}
public LibraryExportBuilder AddRuntimeAsset(LibraryAsset asset)
{
Add(ref _runtimeAssets, asset);
return this;
}
public LibraryExportBuilder AddCompilationAssembly(LibraryAsset asset)
{
Add(ref _compilationAssemblies, asset);
return this;
}
public LibraryExportBuilder AddSourceReference(LibraryAsset asset)
{
Add(ref _sourceReferences, asset);
return this;
}
public LibraryExportBuilder AddNativeLibrary(LibraryAsset asset)
{
Add(ref _compilationAssets, asset);
return this;
}
public LibraryExportBuilder AddEmbedddedResource(LibraryAsset asset)
{
Add(ref _embeddedResources, asset);
return this;
}
public LibraryExportBuilder AddAnalyzerReference(AnalyzerReference asset)
{
Add(ref _analyzerReferences, asset);
return this;
}
private void Replace<T>(ref IList<T> list, IEnumerable<T> enumerable)
{
list = new List<T>(enumerable);
}
private void Add<T>(ref IList<T> list, T item)
{
if (list == null)
{
list = new List<T>();
}
list.Add(item);
}
}
}

View file

@ -6,9 +6,12 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Microsoft.DotNet.ProjectModel.Compilation.Preprocessor;
using Microsoft.DotNet.ProjectModel.Files;
using Microsoft.DotNet.ProjectModel.Graph; using Microsoft.DotNet.ProjectModel.Graph;
using Microsoft.DotNet.ProjectModel.Resolution; using Microsoft.DotNet.ProjectModel.Resolution;
using Microsoft.DotNet.ProjectModel.Utilities; using Microsoft.DotNet.ProjectModel.Utilities;
using Microsoft.DotNet.Tools.Compiler;
using NuGet.Frameworks; using NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel.Compilation namespace Microsoft.DotNet.ProjectModel.Compilation
@ -89,7 +92,7 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
} }
var compilationAssemblies = new List<LibraryAsset>(); var compilationAssemblies = new List<LibraryAsset>();
var sourceReferences = new List<string>(); var sourceReferences = new List<LibraryAsset>();
var analyzerReferences = new List<AnalyzerReference>(); var analyzerReferences = new List<AnalyzerReference>();
var libraryExport = GetExport(library); var libraryExport = GetExport(library);
@ -111,13 +114,15 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
analyzerReferences.AddRange(libraryExport.AnalyzerReferences); analyzerReferences.AddRange(libraryExport.AnalyzerReferences);
} }
yield return new LibraryExport(library, yield return LibraryExportBuilder.Create(library)
compilationAssemblies, .WithCompilationAssemblies(compilationAssemblies)
sourceReferences, .WithSourceReferences(sourceReferences)
libraryExport.RuntimeAssemblies, .WithRuntimeAssemblies(libraryExport.RuntimeAssemblies)
libraryExport.RuntimeAssets, .WithRuntimeAssets(libraryExport.RuntimeAssets)
libraryExport.NativeLibraries, .WithNativeLibraries(libraryExport.NativeLibraries)
analyzerReferences); .WithEmbedddedResources(libraryExport.EmbeddedResources)
.WithAnalyzerReference(analyzerReferences)
.Build();
} }
} }
@ -131,13 +136,7 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
if (!library.Resolved) if (!library.Resolved)
{ {
// For a unresolved project reference returns a export with empty asset. // For a unresolved project reference returns a export with empty asset.
return new LibraryExport(library: library, return LibraryExportBuilder.Create(library).Build();
compileAssemblies: Enumerable.Empty<LibraryAsset>(),
sourceReferences: Enumerable.Empty<string>(),
nativeLibraries: Enumerable.Empty<LibraryAsset>(),
runtimeAssets: Enumerable.Empty<LibraryAsset>(),
runtimeAssemblies: EmptyArray<LibraryAsset>.Value,
analyzers: EmptyArray<AnalyzerReference>.Value);
} }
if (Equals(LibraryType.Package, library.Identity.Type)) if (Equals(LibraryType.Package, library.Identity.Type))
@ -156,32 +155,57 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
private LibraryExport ExportPackage(PackageDescription package) private LibraryExport ExportPackage(PackageDescription package)
{ {
var nativeLibraries = new List<LibraryAsset>(); var builder = LibraryExportBuilder.Create(package);
PopulateAssets(package, package.NativeLibraries, nativeLibraries); builder.WithNativeLibraries(PopulateAssets(package, package.NativeLibraries));
builder.WithRuntimeAssemblies(PopulateAssets(package, package.RuntimeAssemblies));
builder.WithCompilationAssemblies(PopulateAssets(package, package.CompileTimeAssemblies));
builder.WithSourceReferences(GetSharedSources(package));
builder.WithAnalyzerReference(GetAnalyzerReferences(package));
var runtimeAssemblies = new List<LibraryAsset>(); if (package.ContentFiles.Any())
PopulateAssets(package, package.RuntimeAssemblies, runtimeAssemblies);
var compileAssemblies = new List<LibraryAsset>();
PopulateAssets(package, package.CompileTimeAssemblies, compileAssemblies);
var sourceReferences = new List<string>();
foreach (var sharedSource in GetSharedSources(package))
{ {
sourceReferences.Add(sharedSource); var parameters = PPFileParameters.CreateForProject(_rootProject.Project);
Action<Stream, Stream> transform = (input, output) => PPFilePreprocessor.Preprocess(input, output, parameters);
var sourceCodeLanguage = _rootProject.Project.GetSourceCodeLanguage();
var languageGroups = package.ContentFiles.GroupBy(file => file.CodeLanguage);
var selectedGroup = languageGroups.FirstOrDefault(g => g.Key == sourceCodeLanguage) ??
languageGroups.FirstOrDefault(g => g.Key == null);
if (selectedGroup != null)
{
foreach (var contentFile in selectedGroup)
{
if (contentFile.CodeLanguage != null &&
string.Compare(contentFile.CodeLanguage, sourceCodeLanguage, StringComparison.OrdinalIgnoreCase) != 0)
{
continue;
} }
var analyzers = GetAnalyzerReferences(package); var fileTransform = contentFile.PPOutputPath != null ? transform : null;
return new LibraryExport(package, compileAssemblies, var fullPath = Path.Combine(package.Path, contentFile.Path);
sourceReferences, runtimeAssemblies, EmptyArray<LibraryAsset>.Value, nativeLibraries, analyzers); if (contentFile.BuildAction == BuildAction.Compile)
{
builder.AddSourceReference(LibraryAsset.CreateFromRelativePath(package.Path, contentFile.Path, fileTransform));
}
else if (contentFile.BuildAction == BuildAction.EmbeddedResource)
{
builder.AddEmbedddedResource(LibraryAsset.CreateFromRelativePath(package.Path, contentFile.Path, fileTransform));
}
if (contentFile.CopyToOutput)
{
builder.AddRuntimeAsset(new LibraryAsset(contentFile.Path, contentFile.OutputPath, fullPath, fileTransform));
}
}
}
}
return builder.Build();
} }
private LibraryExport ExportProject(ProjectDescription project) private LibraryExport ExportProject(ProjectDescription project)
{ {
var compileAssemblies = new List<LibraryAsset>(); var builder = LibraryExportBuilder.Create(project);
var runtimeAssets = new List<LibraryAsset>();
var sourceReferences = new List<string>();
if (!string.IsNullOrEmpty(project.TargetFrameworkInfo?.AssemblyPath)) if (!string.IsNullOrEmpty(project.TargetFrameworkInfo?.AssemblyPath))
{ {
@ -194,50 +218,61 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
null, null,
Path.GetFullPath(Path.Combine(project.Project.ProjectDirectory, assemblyPath))); Path.GetFullPath(Path.Combine(project.Project.ProjectDirectory, assemblyPath)));
compileAssemblies.Add(compileAsset); builder.AddCompilationAssembly(compileAsset);
runtimeAssets.Add(new LibraryAsset(Path.GetFileName(pdbPath), Path.GetFileName(pdbPath), pdbPath)); builder.AddRuntimeAsset(new LibraryAsset(Path.GetFileName(pdbPath), Path.GetFileName(pdbPath), pdbPath));
} }
else if (project.Project.Files.SourceFiles.Any()) else if (project.Project.Files.SourceFiles.Any())
{ {
var outputPaths = project.GetOutputPaths(_buildBasePath, _solutionRootPath, _configuration, _runtime); var outputPaths = project.GetOutputPaths(_buildBasePath, _solutionRootPath, _configuration, _runtime);
CompilationOutputFiles files;
if (project == _rootProject && var compilationAssembly = outputPaths.CompilationFiles.Assembly;
!string.IsNullOrWhiteSpace(_runtime) && var compilationAssemblyAsset = LibraryAsset.CreateFromAbsolutePath(
project.Project.HasRuntimeOutput(_configuration)) outputPaths.CompilationFiles.BasePath,
compilationAssembly);
builder.AddCompilationAssembly(compilationAssemblyAsset);
if (ExportsRuntime(project))
{ {
files = outputPaths.RuntimeFiles; var runtimeAssemblyAsset = LibraryAsset.CreateFromAbsolutePath(
outputPaths.RuntimeFiles.BasePath,
outputPaths.RuntimeFiles.Assembly);
builder.AddRuntimeAssembly(runtimeAssemblyAsset);
builder.WithRuntimeAssets(CollectAssets(outputPaths.RuntimeFiles));
} }
else else
{ {
files = outputPaths.CompilationFiles; builder.AddRuntimeAssembly(compilationAssemblyAsset);
builder.WithRuntimeAssets(CollectAssets(outputPaths.CompilationFiles));
}
} }
var assemblyPath = files.Assembly; builder.WithSourceReferences(project.Project.Files.SharedFiles.Select(f =>
compileAssemblies.Add(new LibraryAsset(project.Identity.Name, null, assemblyPath)); LibraryAsset.CreateFromAbsolutePath(project.Path, f)
));
return builder.Build();
}
private IEnumerable<LibraryAsset> CollectAssets(CompilationOutputFiles files)
{
var assemblyPath = files.Assembly;
foreach (var path in files.All()) foreach (var path in files.All())
{ {
if (string.Equals(assemblyPath, path)) if (string.Equals(assemblyPath, path))
{ {
continue; continue;
} }
yield return LibraryAsset.CreateFromAbsolutePath(files.BasePath, path);
runtimeAssets.Add(new LibraryAsset(Path.GetFileName(path), path.Replace(files.BasePath, string.Empty), path));
} }
} }
// Add shared sources private bool ExportsRuntime(ProjectDescription project)
foreach (var sharedFile in project.Project.Files.SharedFiles)
{ {
sourceReferences.Add(sharedFile); return project == _rootProject &&
} !string.IsNullOrWhiteSpace(_runtime) &&
project.Project.HasRuntimeOutput(_configuration);
// No support for ref or native in projects, so runtimeAssemblies is
// just the same as compileAssemblies and nativeLibraries are empty
// Also no support for analyzer projects
return new LibraryExport(project, compileAssemblies, sourceReferences,
compileAssemblies, runtimeAssets, EmptyArray<LibraryAsset>.Value, EmptyArray<AnalyzerReference>.Value);
} }
private static string ResolvePath(Project project, string configuration, string path) private static string ResolvePath(Project project, string configuration, string path)
@ -258,25 +293,24 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
{ {
// We assume the path is to an assembly. Framework libraries only export compile-time stuff // We assume the path is to an assembly. Framework libraries only export compile-time stuff
// since they assume the runtime library is present already // since they assume the runtime library is present already
return new LibraryExport( var builder = LibraryExportBuilder.Create(library);
library, if (!string.IsNullOrEmpty(library.Path))
string.IsNullOrEmpty(library.Path) ? {
EmptyArray<LibraryAsset>.Value : builder.WithCompilationAssemblies(new []
new[] { new LibraryAsset(library.Identity.Name, library.Path, library.Path) }, {
EmptyArray<string>.Value, new LibraryAsset(library.Identity.Name, null, library.Path)
EmptyArray<LibraryAsset>.Value, });
EmptyArray<LibraryAsset>.Value, }
EmptyArray<LibraryAsset>.Value, return builder.Build();
EmptyArray<AnalyzerReference>.Value);
} }
private IEnumerable<string> GetSharedSources(PackageDescription package) private IEnumerable<LibraryAsset> GetSharedSources(PackageDescription package)
{ {
return package return package
.Library .Library
.Files .Files
.Where(path => path.StartsWith("shared" + Path.DirectorySeparatorChar)) .Where(path => path.StartsWith("shared" + Path.DirectorySeparatorChar))
.Select(path => Path.Combine(package.Path, path)); .Select(path => LibraryAsset.CreateFromRelativePath(package.Path, path));
} }
private IEnumerable<AnalyzerReference> GetAnalyzerReferences(PackageDescription package) private IEnumerable<AnalyzerReference> GetAnalyzerReferences(PackageDescription package)
@ -348,14 +382,11 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
} }
private void PopulateAssets(PackageDescription package, IEnumerable<LockFileItem> section, IList<LibraryAsset> assets) private IEnumerable<LibraryAsset> PopulateAssets(PackageDescription package, IEnumerable<LockFileItem> section)
{ {
foreach (var assemblyPath in section) foreach (var assemblyPath in section)
{ {
assets.Add(new LibraryAsset( yield return LibraryAsset.CreateFromRelativePath(package.Path, assemblyPath.Path);
Path.GetFileNameWithoutExtension(assemblyPath),
assemblyPath,
Path.Combine(package.Path, assemblyPath)));
} }
} }

View file

@ -0,0 +1,22 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.DotNet.ProjectModel.Compilation.Preprocessor
{
public class PPFileParameters
{
public static IDictionary<string, string> CreateForProject(Project project)
{
return new Dictionary<string, string>()
{
{"rootnamespace", project.Name },
{"assemblyname", project.Name }
};
}
}
}

View file

@ -0,0 +1,53 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.IO;
namespace Microsoft.DotNet.Tools.Compiler
{
public class PPFilePreprocessor
{
public static void Preprocess(Stream input, Stream output, IDictionary<string, string> parameters)
{
string text;
using (var streamReader = new StreamReader(input))
{
text = streamReader.ReadToEnd();
}
var tokenizer = new PPFileTokenizer(text);
using (var streamWriter = new StreamWriter(output))
{
while (true)
{
var token = tokenizer.Read();
if (token == null)
{
break;
}
if (token.Category == PPFileTokenizer.TokenCategory.Variable)
{
var replaced = ReplaceToken(token.Value, parameters);
streamWriter.Write(replaced);
}
else
{
streamWriter.Write(token.Value);
}
}
}
}
private static string ReplaceToken(string name, IDictionary<string, string> parameters)
{
string value;
if (!parameters.TryGetValue(name, out value))
{
throw new InvalidOperationException($"The replacement token '{name}' has no value.");
}
return value;
}
}
}

View file

@ -0,0 +1,124 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Globalization;
using System.Text;
namespace Microsoft.DotNet.Tools.Compiler
{
public class PPFileTokenizer
{
private readonly string _text;
private int _index;
public PPFileTokenizer(string text)
{
_text = text;
_index = 0;
}
/// <summary>
/// Gets the next token.
/// </summary>
/// <returns>The parsed token. Or null if no more tokens are available.</returns>
public Token Read()
{
if (_index >= _text.Length)
{
return null;
}
if (_text[_index] == '$')
{
_index++;
return ParseTokenAfterDollarSign();
}
return ParseText();
}
private static bool IsWordChar(char ch)
{
// See http://msdn.microsoft.com/en-us/library/20bw873z.aspx#WordCharacter
var c = CharUnicodeInfo.GetUnicodeCategory(ch);
return c == UnicodeCategory.LowercaseLetter ||
c == UnicodeCategory.UppercaseLetter ||
c == UnicodeCategory.TitlecaseLetter ||
c == UnicodeCategory.OtherLetter ||
c == UnicodeCategory.ModifierLetter ||
c == UnicodeCategory.DecimalDigitNumber ||
c == UnicodeCategory.ConnectorPunctuation;
}
// Parses and returns the next token after a $ is just read.
// _index is one char after the $.
private Token ParseTokenAfterDollarSign()
{
var sb = new StringBuilder();
while (_index < _text.Length)
{
var ch = _text[_index];
if (ch == '$')
{
++_index;
if (sb.Length == 0)
{
// escape sequence "$$" is encountered
return new Token(TokenCategory.Text, "$");
}
// matching $ is read. So the token is a variable.
return new Token(TokenCategory.Variable, sb.ToString());
}
if (IsWordChar(ch))
{
sb.Append(ch);
++_index;
}
else
{
// non word char encountered. So the current token
// is not a variable after all.
sb.Insert(0, '$');
sb.Append(ch);
++_index;
return new Token(TokenCategory.Text, sb.ToString());
}
}
// no matching $ is found and the end of text is reached.
// So the current token is a text.
sb.Insert(0, '$');
return new Token(TokenCategory.Text, sb.ToString());
}
private Token ParseText()
{
var sb = new StringBuilder();
while (_index < _text.Length
&& _text[_index] != '$')
{
sb.Append(_text[_index]);
_index++;
}
return new Token(TokenCategory.Text, sb.ToString());
}
public class Token
{
public string Value { get; private set; }
public TokenCategory Category { get; private set; }
public Token(TokenCategory category, string value)
{
Category = category;
Value = value;
}
}
public enum TokenCategory
{
Text,
Variable
}
}
}

View file

@ -0,0 +1,86 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
namespace Microsoft.DotNet.ProjectModel.Graph
{
public struct BuildAction : IEquatable<BuildAction>
{
public static readonly BuildAction Compile = new BuildAction(nameof(Compile));
public static readonly BuildAction EmbeddedResource = new BuildAction(nameof(EmbeddedResource));
public static readonly BuildAction Resource = new BuildAction(nameof(Resource));
// Default value
public static readonly BuildAction None = new BuildAction(nameof(None));
public string Value { get; }
private BuildAction(string value)
{
Value = value;
}
public static bool TryParse(string value, out BuildAction type)
{
// We only support values we know about
if (string.Equals(Compile.Value, value, StringComparison.OrdinalIgnoreCase))
{
type = Compile;
return true;
}
else if (string.Equals(EmbeddedResource.Value, value, StringComparison.OrdinalIgnoreCase))
{
type = EmbeddedResource;
return true;
}
else if (string.Equals(Resource.Value, value, StringComparison.OrdinalIgnoreCase))
{
type = Resource;
return true;
}
else if (string.Equals(None.Value, value, StringComparison.OrdinalIgnoreCase))
{
type = None;
return true;
}
type = None;
return false;
}
public override string ToString()
{
return $"BuildAction.{Value}";
}
public bool Equals(BuildAction other)
{
return string.Equals(other.Value, Value, StringComparison.OrdinalIgnoreCase);
}
public override bool Equals(object obj)
{
return obj is BuildAction && Equals((BuildAction)obj);
}
public static bool operator ==(BuildAction left, BuildAction right)
{
return Equals(left, right);
}
public static bool operator !=(BuildAction left, BuildAction right)
{
return !Equals(left, right);
}
public override int GetHashCode()
{
if (string.IsNullOrEmpty(Value))
{
return 0;
}
return StringComparer.OrdinalIgnoreCase.GetHashCode(Value);
}
}
}

View file

@ -166,10 +166,39 @@ namespace Microsoft.DotNet.ProjectModel.Graph
library.CompileTimeAssemblies = ReadObject(jobject.ValueAsJsonObject("compile"), ReadFileItem); library.CompileTimeAssemblies = ReadObject(jobject.ValueAsJsonObject("compile"), ReadFileItem);
library.ResourceAssemblies = ReadObject(jobject.ValueAsJsonObject("resource"), ReadFileItem); library.ResourceAssemblies = ReadObject(jobject.ValueAsJsonObject("resource"), ReadFileItem);
library.NativeLibraries = ReadObject(jobject.ValueAsJsonObject("native"), ReadFileItem); library.NativeLibraries = ReadObject(jobject.ValueAsJsonObject("native"), ReadFileItem);
library.ContentFiles = ReadObject(jobject.ValueAsJsonObject("contentFiles"), ReadContentFile);
return library; return library;
} }
private static LockFileContentFile ReadContentFile(string property, JsonValue json)
{
var contentFile = new LockFileContentFile()
{
Path = property
};
var jsonObject = json as JsonObject;
if (jsonObject != null)
{
BuildAction action;
BuildAction.TryParse(jsonObject.ValueAsString("buildAction"), out action);
contentFile.BuildAction = action;
var codeLanguage = jsonObject.ValueAsString("codeLanguage");
if (codeLanguage == "any")
{
codeLanguage = null;
}
contentFile.CodeLanguage = codeLanguage;
contentFile.OutputPath = jsonObject.ValueAsString("outputPath");
contentFile.PPOutputPath = jsonObject.ValueAsString("ppOutputPath");
contentFile.CopyToOutput = ReadBool(jsonObject, "copyToOutput", false);
}
return contentFile;
}
private static ProjectFileDependencyGroup ReadProjectFileDependencyGroup(string property, JsonValue json) private static ProjectFileDependencyGroup ReadProjectFileDependencyGroup(string property, JsonValue json)
{ {
return new ProjectFileDependencyGroup( return new ProjectFileDependencyGroup(

View file

@ -0,0 +1,20 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.DotNet.ProjectModel.Graph
{
public class LockFileContentFile
{
public string Path { get; set; }
public string OutputPath { get; set; }
public string PPOutputPath { get; set; }
public BuildAction BuildAction { get; set; }
public string CodeLanguage { get; set; }
public bool CopyToOutput { get; set; } = false;
}
}

View file

@ -30,5 +30,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
public IList<LockFileItem> ResourceAssemblies { get; set; } = new List<LockFileItem>(); public IList<LockFileItem> ResourceAssemblies { get; set; } = new List<LockFileItem>();
public IList<LockFileItem> NativeLibraries { get; set; } = new List<LockFileItem>(); public IList<LockFileItem> NativeLibraries { get; set; } = new List<LockFileItem>();
public IList<LockFileContentFile> ContentFiles { get; set; } = new List<LockFileContentFile>();
} }
} }

View file

@ -42,6 +42,8 @@ namespace Microsoft.DotNet.ProjectModel
public IEnumerable<LockFileItem> NativeLibraries => Target.NativeLibraries; public IEnumerable<LockFileItem> NativeLibraries => Target.NativeLibraries;
public IEnumerable<LockFileContentFile> ContentFiles => Target.ContentFiles;
private IEnumerable<LockFileItem> FilterPlaceholders(IList<LockFileItem> items) private IEnumerable<LockFileItem> FilterPlaceholders(IList<LockFileItem> items)
{ {
return items.Where(a => !PackageDependencyProvider.IsPlaceholderFile(a)); return items.Where(a => !PackageDependencyProvider.IsPlaceholderFile(a));

View file

@ -0,0 +1,32 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.DotNet.ProjectModel
{
public static class ProjectExtensions
{
private static readonly KeyValuePair<string, string>[] _compilerNameToLanguageId =
{
new KeyValuePair<string, string>("csc", "cs"),
new KeyValuePair<string, string>("vbc", "vb"),
new KeyValuePair<string, string>("fsc", "fs")
};
public static string GetSourceCodeLanguage(this Project project)
{
foreach (var kvp in _compilerNameToLanguageId)
{
if (kvp.Key == project.CompilerName)
{
return kvp.Value;
}
}
return null;
}
}
}

View file

@ -141,7 +141,7 @@ namespace Microsoft.DotNet.ProjectModel
project.ProjectUrl = rawProject.ValueAsString("projectUrl"); project.ProjectUrl = rawProject.ValueAsString("projectUrl");
project.LicenseUrl = rawProject.ValueAsString("licenseUrl"); project.LicenseUrl = rawProject.ValueAsString("licenseUrl");
project.IconUrl = rawProject.ValueAsString("iconUrl"); project.IconUrl = rawProject.ValueAsString("iconUrl");
project.CompilerName = rawProject.ValueAsString("compilerName"); project.CompilerName = rawProject.ValueAsString("compilerName") ?? "csc";
project.TestRunner = rawProject.ValueAsString("testRunner"); project.TestRunner = rawProject.ValueAsString("testRunner");
project.Authors = rawProject.ValueAsStringArray("authors") ?? EmptyArray<string>.Value; project.Authors = rawProject.ValueAsStringArray("authors") ?? EmptyArray<string>.Value;

View file

@ -255,7 +255,7 @@ namespace Microsoft.DotNet.Tools.Build
private void CollectCompilerNamePreconditions(ProjectContext project, IncrementalPreconditions preconditions) private void CollectCompilerNamePreconditions(ProjectContext project, IncrementalPreconditions preconditions)
{ {
var projectCompiler = CompilerUtil.ResolveCompilerName(project); var projectCompiler = project.ProjectFile.CompilerName;
if (!KnownCompilers.Any(knownCompiler => knownCompiler.Equals(projectCompiler, StringComparison.Ordinal))) if (!KnownCompilers.Any(knownCompiler => knownCompiler.Equals(projectCompiler, StringComparison.Ordinal)))
{ {

View file

@ -6,7 +6,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Microsoft.DotNet.ProjectModel; using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.Cli.Compiler.Common; using Microsoft.DotNet.Cli.Compiler.Common;
using Microsoft.DotNet.ProjectModel.Compilation; using Microsoft.DotNet.ProjectModel.Compilation;
@ -20,34 +19,12 @@ namespace Microsoft.DotNet.Tools.Compiler
{ {
public static class CompilerUtil public static class CompilerUtil
{ {
public static string ResolveCompilerName(ProjectContext context)
{
var compilerName = context.ProjectFile.CompilerName;
compilerName = compilerName ?? "csc";
return compilerName;
}
private static readonly KeyValuePair<string, string>[] s_compilerNameToLanguageId =
{
new KeyValuePair<string, string>("csc", "cs"),
new KeyValuePair<string, string>("vbc", "vb"),
new KeyValuePair<string, string>("fsc", "fs")
};
public static string ResolveLanguageId(ProjectContext context) public static string ResolveLanguageId(ProjectContext context)
{ {
var languageId = context.ProjectFile.AnalyzerOptions?.LanguageId; var languageId = context.ProjectFile.AnalyzerOptions?.LanguageId;
if (languageId == null) if (languageId == null)
{ {
var compilerName = ResolveCompilerName(context); languageId = context.ProjectFile.GetSourceCodeLanguage();
foreach (var kvp in s_compilerNameToLanguageId)
{
if (kvp.Key == compilerName)
{
languageId = kvp.Value;
}
}
} }
return languageId; return languageId;
@ -166,7 +143,7 @@ namespace Microsoft.DotNet.Tools.Compiler
//used in incremental precondition checks //used in incremental precondition checks
public static IEnumerable<string> GetCommandsInvokedByCompile(ProjectContext project) public static IEnumerable<string> GetCommandsInvokedByCompile(ProjectContext project)
{ {
return new List<string> {ResolveCompilerName(project), "compile"}; return new List<string> {project.ProjectFile.CompilerName, "compile"};
} }
} }
} }

View file

@ -8,6 +8,7 @@ using System.Linq;
using Microsoft.DotNet.Cli.Compiler.Common; using Microsoft.DotNet.Cli.Compiler.Common;
using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.ProjectModel; using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.ProjectModel.Compilation;
using Microsoft.DotNet.ProjectModel.Utilities; using Microsoft.DotNet.ProjectModel.Utilities;
using Microsoft.Extensions.DependencyModel; using Microsoft.Extensions.DependencyModel;
@ -90,7 +91,15 @@ namespace Microsoft.DotNet.Tools.Compiler
foreach (var dependency in dependencies) foreach (var dependency in dependencies)
{ {
references.AddRange(dependency.CompilationAssemblies.Select(r => r.ResolvedPath)); references.AddRange(dependency.CompilationAssemblies.Select(r => r.ResolvedPath));
compilerArgs.AddRange(dependency.SourceReferences.Select(s => $"{s}"));
compilerArgs.AddRange(dependency.SourceReferences.Select(s => s.GetTransformedFile(intermediateOutputPath)));
foreach (var resourceFile in dependency.EmbeddedResources)
{
var transformedResource = resourceFile.GetTransformedFile(intermediateOutputPath);
var resourceName = ResourceManifestName.CreateManifestName(Path.GetFileName(resourceFile.ResolvedPath), context.ProjectFile.Name);
compilerArgs.Add($"--resource:\"{transformedResource}\",{resourceName}");
}
// Add analyzer references // Add analyzer references
compilerArgs.AddRange(dependency.AnalyzerReferences compilerArgs.AddRange(dependency.AnalyzerReferences
@ -126,7 +135,7 @@ namespace Microsoft.DotNet.Tools.Compiler
var sourceFiles = CompilerUtil.GetCompilationSources(context); var sourceFiles = CompilerUtil.GetCompilationSources(context);
compilerArgs.AddRange(sourceFiles); compilerArgs.AddRange(sourceFiles);
var compilerName = CompilerUtil.ResolveCompilerName(context); var compilerName = context.ProjectFile.CompilerName;
// Write RSP file // Write RSP file
var rsp = Path.Combine(intermediateOutputPath, $"dotnet-compile.rsp"); var rsp = Path.Combine(intermediateOutputPath, $"dotnet-compile.rsp");

View file

@ -1,4 +1,7 @@
using System; // Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;

View file

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.DotNet.ProjectModel.Compilation;
using Microsoft.DotNet.ProjectModel.Server.Helpers; using Microsoft.DotNet.ProjectModel.Server.Helpers;
using Microsoft.DotNet.ProjectModel.Server.Models; using Microsoft.DotNet.ProjectModel.Server.Models;
using Microsoft.DotNet.Cli.Compiler.Common; using Microsoft.DotNet.Cli.Compiler.Common;
@ -45,7 +46,7 @@ namespace Microsoft.DotNet.ProjectModel.Server
// both will be listed as dependencies. Prefix "fx/" will be added to ReferenceAssembly type dependency. // both will be listed as dependencies. Prefix "fx/" will be added to ReferenceAssembly type dependency.
foreach (var export in allExports.Values) foreach (var export in allExports.Values)
{ {
allSourceFiles.AddRange(export.SourceReferences); allSourceFiles.AddRange(export.SourceReferences.Select(f => f.ResolvedPath));
allFileReferences.AddRange(export.CompilationAssemblies.Select(asset => asset.ResolvedPath)); allFileReferences.AddRange(export.CompilationAssemblies.Select(asset => asset.ResolvedPath));
var diagnostics = diagnosticsLookup[export.Library].ToList(); var diagnostics = diagnosticsLookup[export.Library].ToList();

View file

@ -87,10 +87,11 @@ namespace Microsoft.DotNet.Tools.Publish
Reporter.Output.WriteLine($"Publishing {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}/{context.RuntimeIdentifier.Yellow()}"); Reporter.Output.WriteLine($"Publishing {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}/{context.RuntimeIdentifier.Yellow()}");
var options = context.ProjectFile.GetCompilerOptions(context.TargetFramework, configuration); var options = context.ProjectFile.GetCompilerOptions(context.TargetFramework, configuration);
var outputPaths = context.GetOutputPaths(configuration, buildBasePath, outputPath);
if (string.IsNullOrEmpty(outputPath)) if (string.IsNullOrEmpty(outputPath))
{ {
outputPath = Path.Combine(context.GetOutputPaths(configuration, buildBasePath, outputPath).RuntimeOutputPath, PublishSubfolderName); outputPath = Path.Combine(outputPaths.RuntimeOutputPath, PublishSubfolderName);
} }
var contextVariables = new Dictionary<string, string> var contextVariables = new Dictionary<string, string>
@ -148,7 +149,7 @@ namespace Microsoft.DotNet.Tools.Publish
PublishFiles(export.RuntimeAssemblies, outputPath, nativeSubdirectories: false); PublishFiles(export.RuntimeAssemblies, outputPath, nativeSubdirectories: false);
PublishFiles(export.NativeLibraries, outputPath, nativeSubdirectories); PublishFiles(export.NativeLibraries, outputPath, nativeSubdirectories);
export.RuntimeAssets.StructuredCopyTo(outputPath); export.RuntimeAssets.StructuredCopyTo(outputPath, outputPaths.IntermediateOutputDirectoryPath);
if (options.PreserveCompilationContext.GetValueOrDefault()) if (options.PreserveCompilationContext.GetValueOrDefault())
{ {

View file

@ -0,0 +1,299 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.DotNet.ProjectModel.Compilation;
using Microsoft.DotNet.ProjectModel.Graph;
using Microsoft.DotNet.ProjectModel.Resolution;
using Microsoft.DotNet.Tools.Test.Utilities;
using FluentAssertions;
using Xunit;
namespace Microsoft.DotNet.ProjectModel.Tests
{
public class LibraryExporterPackageTests
{
private const string PackagePath = "PackagePath";
private LibraryExport ExportSingle(LibraryDescription description = null)
{
var rootProject = new Project()
{
Name = "RootProject",
CompilerName = "csc"
};
var rootProjectDescription = new ProjectDescription(
new LibraryRange(),
rootProject,
new LibraryRange[] { },
new TargetFrameworkInformation(),
true);
if (description == null)
{
description = rootProjectDescription;
}
else
{
description.Parents.Add(rootProjectDescription);
}
var libraryManager = new LibraryManager(new[] { description }, new DiagnosticMessage[] { }, "");
var allExports = new LibraryExporter(rootProjectDescription, libraryManager, "config", "runtime", "basepath", "solutionroot").GetAllExports();
var export = allExports.Single();
return export;
}
private PackageDescription CreateDescription(LockFileTargetLibrary target = null, LockFilePackageLibrary package = null)
{
return new PackageDescription(PackagePath,
package ?? new LockFilePackageLibrary(),
target ?? new LockFileTargetLibrary(),
new List<LibraryRange>(), true);
}
[Fact]
private void ExportsPackageNativeLibraries()
{
var description = CreateDescription(
new LockFileTargetLibrary()
{
NativeLibraries = new List<LockFileItem>()
{
{ new LockFileItem() { Path = "lib/Native.so" } }
}
});
var result = ExportSingle(description);
result.NativeLibraries.Should().HaveCount(1);
var libraryAsset = result.NativeLibraries.First();
libraryAsset.Name.Should().Be("Native");
libraryAsset.Transform.Should().BeNull();
libraryAsset.RelativePath.Should().Be("lib/Native.so");
libraryAsset.ResolvedPath.Should().Be(Path.Combine(PackagePath, "lib/Native.so"));
}
[Fact]
private void ExportsPackageCompilationAssebmlies()
{
var description = CreateDescription(
new LockFileTargetLibrary()
{
CompileTimeAssemblies = new List<LockFileItem>()
{
{ new LockFileItem() { Path = "ref/Native.dll" } }
}
});
var result = ExportSingle(description);
result.CompilationAssemblies.Should().HaveCount(1);
var libraryAsset = result.CompilationAssemblies.First();
libraryAsset.Name.Should().Be("Native");
libraryAsset.Transform.Should().BeNull();
libraryAsset.RelativePath.Should().Be("ref/Native.dll");
libraryAsset.ResolvedPath.Should().Be(Path.Combine(PackagePath, "ref/Native.dll"));
}
[Fact]
private void ExportsPackageRuntimeAssebmlies()
{
var description = CreateDescription(
new LockFileTargetLibrary()
{
RuntimeAssemblies = new List<LockFileItem>()
{
{ new LockFileItem() { Path = "ref/Native.dll" } }
}
});
var result = ExportSingle(description);
result.RuntimeAssemblies.Should().HaveCount(1);
var libraryAsset = result.RuntimeAssemblies.First();
libraryAsset.Name.Should().Be("Native");
libraryAsset.Transform.Should().BeNull();
libraryAsset.RelativePath.Should().Be("ref/Native.dll");
libraryAsset.ResolvedPath.Should().Be(Path.Combine(PackagePath, "ref/Native.dll"));
}
[Fact]
private void ExportsSources()
{
var description = CreateDescription(
package: new LockFilePackageLibrary()
{
Files = new List<string>()
{
Path.Combine("shared", "file.cs")
}
});
var result = ExportSingle(description);
result.SourceReferences.Should().HaveCount(1);
var libraryAsset = result.SourceReferences.First();
libraryAsset.Name.Should().Be("file");
libraryAsset.Transform.Should().BeNull();
libraryAsset.RelativePath.Should().Be(Path.Combine("shared", "file.cs"));
libraryAsset.ResolvedPath.Should().Be(Path.Combine(PackagePath, "shared", "file.cs"));
}
[Fact]
private void ExportsCopyToOutputContentFiles()
{
var description = CreateDescription(
new LockFileTargetLibrary()
{
ContentFiles = new List<LockFileContentFile>()
{
new LockFileContentFile()
{
CopyToOutput = true,
Path = Path.Combine("content", "file.txt"),
OutputPath = Path.Combine("Out","Path.txt"),
PPOutputPath = "something"
}
}
});
var result = ExportSingle(description);
result.RuntimeAssets.Should().HaveCount(1);
var libraryAsset = result.RuntimeAssets.First();
libraryAsset.Transform.Should().NotBeNull();
libraryAsset.RelativePath.Should().Be(Path.Combine("Out", "Path.txt"));
libraryAsset.ResolvedPath.Should().Be(Path.Combine(PackagePath, "content", "file.txt"));
}
[Fact]
private void ExportsResourceContentFiles()
{
var description = CreateDescription(
new LockFileTargetLibrary()
{
ContentFiles = new List<LockFileContentFile>()
{
new LockFileContentFile()
{
BuildAction = BuildAction.EmbeddedResource,
Path = Path.Combine("content", "file.txt"),
PPOutputPath = "something"
}
}
});
var result = ExportSingle(description);
result.EmbeddedResources.Should().HaveCount(1);
var libraryAsset = result.EmbeddedResources.First();
libraryAsset.Transform.Should().NotBeNull();
libraryAsset.RelativePath.Should().Be(Path.Combine("content", "file.txt"));
libraryAsset.ResolvedPath.Should().Be(Path.Combine(PackagePath, "content", "file.txt"));
}
[Fact]
private void ExportsCompileContentFiles()
{
var description = CreateDescription(
new LockFileTargetLibrary()
{
ContentFiles = new List<LockFileContentFile>()
{
new LockFileContentFile()
{
BuildAction = BuildAction.Compile,
Path = Path.Combine("content", "file.cs"),
PPOutputPath = "something"
}
}
});
var result = ExportSingle(description);
result.SourceReferences.Should().HaveCount(1);
var libraryAsset = result.SourceReferences.First();
libraryAsset.Transform.Should().NotBeNull();
libraryAsset.RelativePath.Should().Be(Path.Combine("content", "file.cs"));
libraryAsset.ResolvedPath.Should().Be(Path.Combine(PackagePath, "content", "file.cs"));
}
[Fact]
private void SelectsContentFilesOfProjectCodeLanguage()
{
var description = CreateDescription(
new LockFileTargetLibrary()
{
ContentFiles = new List<LockFileContentFile>()
{
new LockFileContentFile()
{
BuildAction = BuildAction.Compile,
Path = Path.Combine("content", "file.cs"),
PPOutputPath = "something",
CodeLanguage = "cs"
},
new LockFileContentFile()
{
BuildAction = BuildAction.Compile,
Path = Path.Combine("content", "file.vb"),
PPOutputPath = "something",
CodeLanguage = "vb"
},
new LockFileContentFile()
{
BuildAction = BuildAction.Compile,
Path = Path.Combine("content", "file.any"),
PPOutputPath = "something",
}
}
});
var result = ExportSingle(description);
result.SourceReferences.Should().HaveCount(1);
var libraryAsset = result.SourceReferences.First();
libraryAsset.Transform.Should().NotBeNull();
libraryAsset.RelativePath.Should().Be(Path.Combine("content", "file.cs"));
libraryAsset.ResolvedPath.Should().Be(Path.Combine(PackagePath, "content", "file.cs"));
}
[Fact]
private void SelectsContentFilesWithNoLanguageIfProjectLanguageNotMathed()
{
var description = CreateDescription(
new LockFileTargetLibrary()
{
ContentFiles = new List<LockFileContentFile>()
{
new LockFileContentFile()
{
BuildAction = BuildAction.Compile,
Path = Path.Combine("content", "file.vb"),
PPOutputPath = "something",
CodeLanguage = "vb"
},
new LockFileContentFile()
{
BuildAction = BuildAction.Compile,
Path = Path.Combine("content", "file.any"),
PPOutputPath = "something",
}
}
});
var result = ExportSingle(description);
result.SourceReferences.Should().HaveCount(1);
var libraryAsset = result.SourceReferences.First();
libraryAsset.Transform.Should().NotBeNull();
libraryAsset.RelativePath.Should().Be(Path.Combine("content", "file.any"));
libraryAsset.ResolvedPath.Should().Be(Path.Combine(PackagePath, "content", "file.any"));
}
}
}

View file

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FluentAssertions;
using Xunit;
using Microsoft.DotNet.Tools.Compiler;
namespace Microsoft.DotNet.ProjectModel.Tests
{
public class PreprocessorTests
{
private string Preprocess(string text, IDictionary<string, string> parameters)
{
using (var input = new MemoryStream(Encoding.UTF8.GetBytes(text)))
{
using (var output = new MemoryStream())
{
PPFilePreprocessor.Preprocess(input, output, parameters);
return Encoding.UTF8.GetString(output.ToArray());
}
}
}
[Theory]
[InlineData("$a$", "AValue")]
[InlineData("$a", "$a")]
[InlineData("a$", "a$")]
[InlineData("$$a$", "$a$")]
[InlineData("$a$$b$", "AValueBValue")]
[InlineData("$$a$$$$b$$", "$a$$b$")]
public void ProcessesCorrectly(string input, string output)
{
var parameters = new Dictionary<string, string>()
{
{ "a", "AValue" },
{ "b", "BValue" }
};
var result = Preprocess(input, parameters);
result.Should().Be(output);
}
[Fact]
public void ThrowsOnParameterNotFound()
{
var ex = Assert.Throws<InvalidOperationException>(() => Preprocess("$a$", new Dictionary<string, string>()));
ex.Message.Should().Contain("a");
}
}
}

View file

@ -3,7 +3,9 @@
using System; using System;
using System.IO; using System.IO;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Test.Utilities; using Microsoft.DotNet.Tools.Test.Utilities;
using FluentAssertions;
using Xunit; using Xunit;
namespace Microsoft.DotNet.Tools.Compiler.Tests namespace Microsoft.DotNet.Tools.Compiler.Tests
@ -106,6 +108,44 @@ namespace Microsoft.DotNet.Tools.Compiler.Tests
buildCommand.Execute().Should().Pass(); buildCommand.Execute().Should().Pass();
} }
[Fact]
public void ContentFilesAreCopied()
{
var testInstance = TestAssetsManager.CreateTestInstance("TestAppWithContentPackage")
.WithLockFiles();
var root = testInstance.TestRoot;
// run compile
var outputDir = Path.Combine(root, "bin");
var testProject = ProjectUtils.GetProjectJson(root, "TestAppWithContentPackage");
var buildCommand = new BuildCommand(testProject, output: outputDir, framework: DefaultFramework);
var result = buildCommand.ExecuteWithCapturedOutput();
result.Should().Pass();
result = Command.Create(Path.Combine(outputDir, buildCommand.GetOutputExecutableName()), new string [0])
.CaptureStdErr()
.CaptureStdOut()
.Execute();
result.Should().Pass();
// verify the output xml file
new DirectoryInfo(outputDir).Sub("scripts").Should()
.Exist()
.And.HaveFile("run.cmd");
new DirectoryInfo(outputDir).Should()
.HaveFile("config.xml");
// verify embedded resources
result.StdOut.Should().Contain("TestAppWithContentPackage.dnf.png");
result.StdOut.Should().Contain("TestAppWithContentPackage.ui.png");
// verify 'all' language files not included
result.StdOut.Should().NotContain("TestAppWithContentPackage.dnf_all.png");
result.StdOut.Should().NotContain("TestAppWithContentPackage.ui_all.png");
// verify classes
result.StdOut.Should().Contain("TestAppWithContentPackage.Foo");
result.StdOut.Should().Contain("MyNamespace.Util");
}
private void CopyProjectToTempDir(string projectDir, TempDirectory tempDir) private void CopyProjectToTempDir(string projectDir, TempDirectory tempDir)
{ {
// copy all the files to temp dir // copy all the files to temp dir