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
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
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
GlobalSection(SolutionConfigurationPlatforms) = preSolution
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|x64.ActiveCfg = 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
{0745410A-6629-47EB-AAB5-08D6288CAD72}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.Debug|x64.ActiveCfg = Debug|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.Debug|x64.Build.0 = Debug|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.Release|Any CPU.Build.0 = Release|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.Release|x64.ActiveCfg = Release|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.Release|x64.Build.0 = Release|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
{0745410A-6629-47EB-AAB5-08D6288CAD72}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
{4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Debug|x64.ActiveCfg = Debug|Any CPU
{4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Debug|x64.Build.0 = Debug|Any CPU
{4A4711D8-4312-49FC-87B5-4F183F4C6A51}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
{4A4711D8-4312-49FC-87B5-4F183F4C6A51}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
{4A4711D8-4312-49FC-87B5-4F183F4C6A51}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{4A4711D8-4312-49FC-87B5-4F183F4C6A51}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Release|Any CPU.Build.0 = Release|Any CPU
{4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Release|x64.ActiveCfg = Release|Any CPU
{4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Release|x64.Build.0 = Release|Any CPU
{4A4711D8-4312-49FC-87B5-4F183F4C6A51}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
{4A4711D8-4312-49FC-87B5-4F183F4C6A51}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
{4A4711D8-4312-49FC-87B5-4F183F4C6A51}.RelWithDebInfo|x64.ActiveCfg = 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.Build.0 = 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-94F807D22222} = {713CBFBB-5392-438D-B766-A9A585EF1BB8}
{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}
{0B31C336-149D-471A-B7B1-27B0F1E80F83} = {0E3300A4-DF54-40BF-87D8-E7658330C288}
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 LibraryExporter _exporter;
private readonly OutputPaths _outputPaths;
private readonly LibraryExporter _exporter;
private readonly string _runtimeOutputPath;
private readonly string _intermediateOutputPath;
public Executable(ProjectContext context, OutputPaths outputPaths, LibraryExporter exporter)
{
_context = context;
_outputPaths = outputPaths;
_runtimeOutputPath = outputPaths.RuntimeOutputPath;
_intermediateOutputPath = outputPaths.IntermediateOutputDirectoryPath;
_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");
}
var outputPath = _outputPaths.RuntimeOutputPath;
CopyContentFiles(outputPath);
ExportRuntimeAssets(outputPath);
CopyContentFiles();
ExportRuntimeAssets();
}
private void ExportRuntimeAssets(string outputPath)
private void ExportRuntimeAssets()
{
if (_context.TargetFramework.IsDesktop())
{
MakeCompilationOutputRunnableForFullFramework(outputPath);
MakeCompilationOutputRunnableForFullFramework();
}
else
{
MakeCompilationOutputRunnableForCoreCLR(outputPath);
MakeCompilationOutputRunnableForCoreCLR();
}
}
private void MakeCompilationOutputRunnableForFullFramework(
string outputPath)
private void MakeCompilationOutputRunnableForFullFramework()
{
CopyAllDependencies(outputPath, _exporter.GetDependencies());
var dependencies = _exporter.GetDependencies();
CopyAssemblies(dependencies);
CopyAssets(dependencies);
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
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);
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)
{
libraryExport.RuntimeAssemblies.CopyTo(outputPath);
libraryExport.NativeLibraries.CopyTo(outputPath);
libraryExport.RuntimeAssets.StructuredCopyTo(outputPath);
libraryExport.RuntimeAssemblies.CopyTo(_runtimeOutputPath);
libraryExport.NativeLibraries.CopyTo(_runtimeOutputPath);
}
}
private static void WriteDepsFileAndCopyProjectDependencies(
LibraryExporter exporter,
string projectFileName,
string outputPath)
private void CopyAssets(IEnumerable<LibraryExport> libraryExports)
{
foreach (var libraryExport in libraryExports)
{
libraryExport.RuntimeAssets.StructuredCopyTo(
_runtimeOutputPath,
_intermediateOutputPath);
}
}
private void WriteDepsFileAndCopyProjectDependencies(LibraryExporter exporter)
{
exporter
.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);
CopyAssemblies(projectExports);
CopyAssets(projectExports);
CopyAllDependencies(outputPath, projectExports);
var packageExports = exporter.GetDependencies(LibraryType.Package);
CopyAssets(packageExports);
}
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))
{
@ -63,8 +63,9 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
foreach (var asset in assets)
{
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.Text;
using Microsoft.DotNet.Cli.Compiler.Common;
using Microsoft.DotNet.ProjectModel.Compilation;
using NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel.Workspaces
@ -78,7 +79,10 @@ namespace Microsoft.DotNet.ProjectModel.Workspaces
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);
@ -104,24 +108,24 @@ namespace Microsoft.DotNet.ProjectModel.Workspaces
foreach (var file in dependency.SourceReferences)
{
AddSourceFile(projectInfo, file);
using (var stream = file.GetTransformedStream())
{
AddSourceFile(projectInfo, file.ResolvedPath, stream);
}
}
}
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 id = DocumentId.CreateNewId(projectInfo.Id);
var version = VersionStamp.Create();
var sourceText = SourceText.From(stream, encoding: Encoding.UTF8);
var id = DocumentId.CreateNewId(projectInfo.Id);
var version = VersionStamp.Create();
var loader = TextLoader.From(TextAndVersion.Create(sourceText, version));
OnDocumentAdded(DocumentInfo.Create(id, file, filePath: file, loader: loader));
}
var loader = TextLoader.From(TextAndVersion.Create(sourceText, version));
OnDocumentAdded(DocumentInfo.Create(id, file, filePath: file, loader: loader));
}
private MetadataReference GetMetadataReference(string path)

View file

@ -3,7 +3,9 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.DotNet.ProjectModel.Utilities;
using Microsoft.Extensions.Internal;
namespace Microsoft.DotNet.ProjectModel.Compilation
@ -13,12 +15,14 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
public string Name { get; }
public string RelativePath { 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;
RelativePath = relativePath;
ResolvedPath = resolvedPath;
Transform = transform;
}
public bool Equals(LibraryAsset other)
@ -42,5 +46,25 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
combiner.Add(ResolvedPath);
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>
public IEnumerable<LibraryAsset> CompilationAssemblies { get; }
/// <summary>
/// Get a list of embedded resource files provided by this export.
/// </summary>
public IEnumerable<LibraryAsset> EmbeddedResources { get; }
/// <summary>
/// Gets a list of fully-qualified paths to source code file references
/// </summary>
public IEnumerable<string> SourceReferences { get; }
public IEnumerable<LibraryAsset> SourceReferences { get; }
/// <summary>
/// Get a list of analyzers provided by this export.
@ -46,10 +51,11 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
public LibraryExport(LibraryDescription library,
IEnumerable<LibraryAsset> compileAssemblies,
IEnumerable<string> sourceReferences,
IEnumerable<LibraryAsset> sourceReferences,
IEnumerable<LibraryAsset> runtimeAssemblies,
IEnumerable<LibraryAsset> runtimeAssets,
IEnumerable<LibraryAsset> nativeLibraries,
IEnumerable<LibraryAsset> embeddedResources,
IEnumerable<AnalyzerReference> analyzers)
{
Library = library;
@ -58,6 +64,7 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
RuntimeAssemblies = runtimeAssemblies;
RuntimeAssets = runtimeAssets;
NativeLibraries = nativeLibraries;
EmbeddedResources = embeddedResources;
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.IO;
using System.Linq;
using Microsoft.DotNet.ProjectModel.Compilation.Preprocessor;
using Microsoft.DotNet.ProjectModel.Files;
using Microsoft.DotNet.ProjectModel.Graph;
using Microsoft.DotNet.ProjectModel.Resolution;
using Microsoft.DotNet.ProjectModel.Utilities;
using Microsoft.DotNet.Tools.Compiler;
using NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel.Compilation
@ -89,7 +92,7 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
}
var compilationAssemblies = new List<LibraryAsset>();
var sourceReferences = new List<string>();
var sourceReferences = new List<LibraryAsset>();
var analyzerReferences = new List<AnalyzerReference>();
var libraryExport = GetExport(library);
@ -111,13 +114,15 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
analyzerReferences.AddRange(libraryExport.AnalyzerReferences);
}
yield return new LibraryExport(library,
compilationAssemblies,
sourceReferences,
libraryExport.RuntimeAssemblies,
libraryExport.RuntimeAssets,
libraryExport.NativeLibraries,
analyzerReferences);
yield return LibraryExportBuilder.Create(library)
.WithCompilationAssemblies(compilationAssemblies)
.WithSourceReferences(sourceReferences)
.WithRuntimeAssemblies(libraryExport.RuntimeAssemblies)
.WithRuntimeAssets(libraryExport.RuntimeAssets)
.WithNativeLibraries(libraryExport.NativeLibraries)
.WithEmbedddedResources(libraryExport.EmbeddedResources)
.WithAnalyzerReference(analyzerReferences)
.Build();
}
}
@ -131,13 +136,7 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
if (!library.Resolved)
{
// For a unresolved project reference returns a export with empty asset.
return new LibraryExport(library: library,
compileAssemblies: Enumerable.Empty<LibraryAsset>(),
sourceReferences: Enumerable.Empty<string>(),
nativeLibraries: Enumerable.Empty<LibraryAsset>(),
runtimeAssets: Enumerable.Empty<LibraryAsset>(),
runtimeAssemblies: EmptyArray<LibraryAsset>.Value,
analyzers: EmptyArray<AnalyzerReference>.Value);
return LibraryExportBuilder.Create(library).Build();
}
if (Equals(LibraryType.Package, library.Identity.Type))
@ -156,32 +155,57 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
private LibraryExport ExportPackage(PackageDescription package)
{
var nativeLibraries = new List<LibraryAsset>();
PopulateAssets(package, package.NativeLibraries, nativeLibraries);
var builder = LibraryExportBuilder.Create(package);
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>();
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))
if (package.ContentFiles.Any())
{
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 fileTransform = contentFile.PPOutputPath != null ? transform : null;
var fullPath = Path.Combine(package.Path, contentFile.Path);
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));
}
}
}
}
var analyzers = GetAnalyzerReferences(package);
return new LibraryExport(package, compileAssemblies,
sourceReferences, runtimeAssemblies, EmptyArray<LibraryAsset>.Value, nativeLibraries, analyzers);
return builder.Build();
}
private LibraryExport ExportProject(ProjectDescription project)
{
var compileAssemblies = new List<LibraryAsset>();
var runtimeAssets = new List<LibraryAsset>();
var sourceReferences = new List<string>();
var builder = LibraryExportBuilder.Create(project);
if (!string.IsNullOrEmpty(project.TargetFrameworkInfo?.AssemblyPath))
{
@ -194,50 +218,61 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
null,
Path.GetFullPath(Path.Combine(project.Project.ProjectDirectory, assemblyPath)));
compileAssemblies.Add(compileAsset);
runtimeAssets.Add(new LibraryAsset(Path.GetFileName(pdbPath), Path.GetFileName(pdbPath), pdbPath));
builder.AddCompilationAssembly(compileAsset);
builder.AddRuntimeAsset(new LibraryAsset(Path.GetFileName(pdbPath), Path.GetFileName(pdbPath), pdbPath));
}
else if (project.Project.Files.SourceFiles.Any())
{
var outputPaths = project.GetOutputPaths(_buildBasePath, _solutionRootPath, _configuration, _runtime);
CompilationOutputFiles files;
if (project == _rootProject &&
!string.IsNullOrWhiteSpace(_runtime) &&
project.Project.HasRuntimeOutput(_configuration))
var compilationAssembly = outputPaths.CompilationFiles.Assembly;
var compilationAssemblyAsset = LibraryAsset.CreateFromAbsolutePath(
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
{
files = outputPaths.CompilationFiles;
}
var assemblyPath = files.Assembly;
compileAssemblies.Add(new LibraryAsset(project.Identity.Name, null, assemblyPath));
foreach (var path in files.All())
{
if (string.Equals(assemblyPath, path))
{
continue;
}
runtimeAssets.Add(new LibraryAsset(Path.GetFileName(path), path.Replace(files.BasePath, string.Empty), path));
builder.AddRuntimeAssembly(compilationAssemblyAsset);
builder.WithRuntimeAssets(CollectAssets(outputPaths.CompilationFiles));
}
}
// Add shared sources
foreach (var sharedFile in project.Project.Files.SharedFiles)
builder.WithSourceReferences(project.Project.Files.SharedFiles.Select(f =>
LibraryAsset.CreateFromAbsolutePath(project.Path, f)
));
return builder.Build();
}
private IEnumerable<LibraryAsset> CollectAssets(CompilationOutputFiles files)
{
var assemblyPath = files.Assembly;
foreach (var path in files.All())
{
sourceReferences.Add(sharedFile);
if (string.Equals(assemblyPath, path))
{
continue;
}
yield return LibraryAsset.CreateFromAbsolutePath(files.BasePath, path);
}
}
// 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 bool ExportsRuntime(ProjectDescription project)
{
return project == _rootProject &&
!string.IsNullOrWhiteSpace(_runtime) &&
project.Project.HasRuntimeOutput(_configuration);
}
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
// since they assume the runtime library is present already
return new LibraryExport(
library,
string.IsNullOrEmpty(library.Path) ?
EmptyArray<LibraryAsset>.Value :
new[] { new LibraryAsset(library.Identity.Name, library.Path, library.Path) },
EmptyArray<string>.Value,
EmptyArray<LibraryAsset>.Value,
EmptyArray<LibraryAsset>.Value,
EmptyArray<LibraryAsset>.Value,
EmptyArray<AnalyzerReference>.Value);
var builder = LibraryExportBuilder.Create(library);
if (!string.IsNullOrEmpty(library.Path))
{
builder.WithCompilationAssemblies(new []
{
new LibraryAsset(library.Identity.Name, null, library.Path)
});
}
return builder.Build();
}
private IEnumerable<string> GetSharedSources(PackageDescription package)
private IEnumerable<LibraryAsset> GetSharedSources(PackageDescription package)
{
return package
.Library
.Files
.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)
@ -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)
{
assets.Add(new LibraryAsset(
Path.GetFileNameWithoutExtension(assemblyPath),
assemblyPath,
Path.Combine(package.Path, assemblyPath)));
yield return LibraryAsset.CreateFromRelativePath(package.Path, assemblyPath.Path);
}
}

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.ResourceAssemblies = ReadObject(jobject.ValueAsJsonObject("resource"), ReadFileItem);
library.NativeLibraries = ReadObject(jobject.ValueAsJsonObject("native"), ReadFileItem);
library.ContentFiles = ReadObject(jobject.ValueAsJsonObject("contentFiles"), ReadContentFile);
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)
{
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> 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<LockFileContentFile> ContentFiles => Target.ContentFiles;
private IEnumerable<LockFileItem> FilterPlaceholders(IList<LockFileItem> items)
{
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.LicenseUrl = rawProject.ValueAsString("licenseUrl");
project.IconUrl = rawProject.ValueAsString("iconUrl");
project.CompilerName = rawProject.ValueAsString("compilerName");
project.CompilerName = rawProject.ValueAsString("compilerName") ?? "csc";
project.TestRunner = rawProject.ValueAsString("testRunner");
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)
{
var projectCompiler = CompilerUtil.ResolveCompilerName(project);
var projectCompiler = project.ProjectFile.CompilerName;
if (!KnownCompilers.Any(knownCompiler => knownCompiler.Equals(projectCompiler, StringComparison.Ordinal)))
{

View file

@ -6,7 +6,6 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.Cli.Compiler.Common;
using Microsoft.DotNet.ProjectModel.Compilation;
@ -20,34 +19,12 @@ namespace Microsoft.DotNet.Tools.Compiler
{
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)
{
var languageId = context.ProjectFile.AnalyzerOptions?.LanguageId;
if (languageId == null)
{
var compilerName = ResolveCompilerName(context);
foreach (var kvp in s_compilerNameToLanguageId)
{
if (kvp.Key == compilerName)
{
languageId = kvp.Value;
}
}
languageId = context.ProjectFile.GetSourceCodeLanguage();
}
return languageId;
@ -166,7 +143,7 @@ namespace Microsoft.DotNet.Tools.Compiler
//used in incremental precondition checks
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.Utils;
using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.ProjectModel.Compilation;
using Microsoft.DotNet.ProjectModel.Utilities;
using Microsoft.Extensions.DependencyModel;
@ -90,7 +91,15 @@ namespace Microsoft.DotNet.Tools.Compiler
foreach (var dependency in dependencies)
{
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
compilerArgs.AddRange(dependency.AnalyzerReferences
@ -126,7 +135,7 @@ namespace Microsoft.DotNet.Tools.Compiler
var sourceFiles = CompilerUtil.GetCompilationSources(context);
compilerArgs.AddRange(sourceFiles);
var compilerName = CompilerUtil.ResolveCompilerName(context);
var compilerName = context.ProjectFile.CompilerName;
// Write RSP file
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.IO;

View file

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.DotNet.ProjectModel.Compilation;
using Microsoft.DotNet.ProjectModel.Server.Helpers;
using Microsoft.DotNet.ProjectModel.Server.Models;
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.
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));
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()}");
var options = context.ProjectFile.GetCompilerOptions(context.TargetFramework, configuration);
var outputPaths = context.GetOutputPaths(configuration, buildBasePath, 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>
@ -148,7 +149,7 @@ namespace Microsoft.DotNet.Tools.Publish
PublishFiles(export.RuntimeAssemblies, outputPath, nativeSubdirectories: false);
PublishFiles(export.NativeLibraries, outputPath, nativeSubdirectories);
export.RuntimeAssets.StructuredCopyTo(outputPath);
export.RuntimeAssets.StructuredCopyTo(outputPath, outputPaths.IntermediateOutputDirectoryPath);
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.IO;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Test.Utilities;
using FluentAssertions;
using Xunit;
namespace Microsoft.DotNet.Tools.Compiler.Tests
@ -106,6 +108,44 @@ namespace Microsoft.DotNet.Tools.Compiler.Tests
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)
{
// copy all the files to temp dir