diff --git a/Microsoft.DotNet.Cli.sln b/Microsoft.DotNet.Cli.sln
index f7171285b..203948f0c 100644
--- a/Microsoft.DotNet.Cli.sln
+++ b/Microsoft.DotNet.Cli.sln
@@ -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
diff --git a/TestAssets/TestProjects/TestAppWithContentPackage/NuGet.Config b/TestAssets/TestProjects/TestAppWithContentPackage/NuGet.Config
new file mode 100644
index 000000000..4a43c6b88
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppWithContentPackage/NuGet.Config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/TestAssets/TestProjects/TestAppWithContentPackage/Packages/SharedContentA.1.0.0.nupkg b/TestAssets/TestProjects/TestAppWithContentPackage/Packages/SharedContentA.1.0.0.nupkg
new file mode 100644
index 000000000..22c50bfed
Binary files /dev/null and b/TestAssets/TestProjects/TestAppWithContentPackage/Packages/SharedContentA.1.0.0.nupkg differ
diff --git a/TestAssets/TestProjects/TestAppWithContentPackage/Program.cs b/TestAssets/TestProjects/TestAppWithContentPackage/Program.cs
new file mode 100644
index 000000000..b71b81142
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppWithContentPackage/Program.cs
@@ -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;
+ }
+ }
+}
diff --git a/TestAssets/TestProjects/TestAppWithContentPackage/TestAppWithContentPackage.xproj b/TestAssets/TestProjects/TestAppWithContentPackage/TestAppWithContentPackage.xproj
new file mode 100644
index 000000000..718199108
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppWithContentPackage/TestAppWithContentPackage.xproj
@@ -0,0 +1,19 @@
+
+
+
+ 14.0.24720
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+ ea239e10-75e8-4305-966e-fec926a5aee6
+ TestAppWithContentPackage
+ ..\..\..\artifacts\obj\$(MSBuildProjectName)
+ ..\..\..\artifacts\bin\$(MSBuildProjectName)\
+
+
+
+ 2.0
+
+
+
\ No newline at end of file
diff --git a/TestAssets/TestProjects/TestAppWithContentPackage/project.json b/TestAssets/TestProjects/TestAppWithContentPackage/project.json
new file mode 100644
index 000000000..d9dd13dfc
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppWithContentPackage/project.json
@@ -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": { }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.Compiler.Common/Executable.cs b/src/Microsoft.DotNet.Compiler.Common/Executable.cs
index 7cbc53ec4..31f92825f 100644
--- a/src/Microsoft.DotNet.Compiler.Common/Executable.cs
+++ b/src/Microsoft.DotNet.Compiler.Common/Executable.cs
@@ -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 libraryExports)
+ private void CopyAssemblies(IEnumerable 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 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)
diff --git a/src/Microsoft.DotNet.Compiler.Common/LibraryExporterExtensions.cs b/src/Microsoft.DotNet.Compiler.Common/LibraryExporterExtensions.cs
index bf7e7403f..c4e088401 100644
--- a/src/Microsoft.DotNet.Compiler.Common/LibraryExporterExtensions.cs
+++ b/src/Microsoft.DotNet.Compiler.Common/LibraryExporterExtensions.cs
@@ -53,7 +53,7 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
}
}
- public static void StructuredCopyTo(this IEnumerable assets, string destinationPath)
+ public static void StructuredCopyTo(this IEnumerable 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);
}
}
diff --git a/src/Microsoft.DotNet.InternalAbstractions/Microsoft.DotNet.InternalAbstractions.xproj b/src/Microsoft.DotNet.InternalAbstractions/Microsoft.DotNet.InternalAbstractions.xproj
new file mode 100644
index 000000000..b898305b0
--- /dev/null
+++ b/src/Microsoft.DotNet.InternalAbstractions/Microsoft.DotNet.InternalAbstractions.xproj
@@ -0,0 +1,18 @@
+
+
+
+ 14.0.24720
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+ bd4f0750-4e81-4ad2-90b5-e470881792c3
+ Microsoft.DotNet.InternalAbstractions
+ ..\..\artifacts\obj\$(MSBuildProjectName)
+ ..\..\artifacts\bin\$(MSBuildProjectName)\
+
+
+ 2.0
+
+
+
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectModel.Workspaces/ProjectJsonWorkspace.cs b/src/Microsoft.DotNet.ProjectModel.Workspaces/ProjectJsonWorkspace.cs
index 8560e426e..9dbdedf8a 100644
--- a/src/Microsoft.DotNet.ProjectModel.Workspaces/ProjectJsonWorkspace.cs
+++ b/src/Microsoft.DotNet.ProjectModel.Workspaces/ProjectJsonWorkspace.cs
@@ -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)
diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryAsset.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryAsset.cs
index d7740a94d..6186f26e5 100644
--- a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryAsset.cs
+++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryAsset.cs
@@ -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 Transform { get; set; }
- public LibraryAsset(string name, string relativePath, string resolvedPath)
+ public LibraryAsset(string name, string relativePath, string resolvedPath, Action 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 transform = null)
+ {
+ return new LibraryAsset(
+ Path.GetFileNameWithoutExtension(relativePath),
+ relativePath,
+ Path.Combine(basePath, relativePath),
+ transform);
+ }
+
+ public static LibraryAsset CreateFromAbsolutePath(string basePath, string absolutePath, Action transform = null)
+ {
+ var relativePath = absolutePath.Replace(PathUtility.EnsureTrailingSlash(basePath), string.Empty);
+
+ return new LibraryAsset(
+ Path.GetFileNameWithoutExtension(relativePath),
+ relativePath,
+ absolutePath,
+ transform);
+ }
}
}
diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryAssetExtension.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryAssetExtension.cs
new file mode 100644
index 000000000..93b466639
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryAssetExtension.cs
@@ -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;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExport.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExport.cs
index 1db48a791..0380fc56a 100644
--- a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExport.cs
+++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExport.cs
@@ -34,10 +34,15 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
///
public IEnumerable CompilationAssemblies { get; }
+ ///
+ /// Get a list of embedded resource files provided by this export.
+ ///
+ public IEnumerable EmbeddedResources { get; }
+
///
/// Gets a list of fully-qualified paths to source code file references
///
- public IEnumerable SourceReferences { get; }
+ public IEnumerable SourceReferences { get; }
///
/// Get a list of analyzers provided by this export.
@@ -46,10 +51,11 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
public LibraryExport(LibraryDescription library,
IEnumerable compileAssemblies,
- IEnumerable sourceReferences,
+ IEnumerable sourceReferences,
IEnumerable runtimeAssemblies,
IEnumerable runtimeAssets,
IEnumerable nativeLibraries,
+ IEnumerable embeddedResources,
IEnumerable analyzers)
{
Library = library;
@@ -58,6 +64,7 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
RuntimeAssemblies = runtimeAssemblies;
RuntimeAssets = runtimeAssets;
NativeLibraries = nativeLibraries;
+ EmbeddedResources = embeddedResources;
AnalyzerReferences = analyzers;
}
diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExportBuilder.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExportBuilder.cs
new file mode 100644
index 000000000..42d98c897
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExportBuilder.cs
@@ -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 _runtimeAssemblies;
+
+ private IList _runtimeAssets;
+
+ private IList _compilationAssemblies;
+
+ private IList _compilationAssets;
+
+ private IList _debugAssets;
+
+ private IList _sourceReferences;
+
+ private IList _nativeLibraries;
+
+ private IList _embeddedResources;
+
+ private IList _analyzerReferences;
+
+ public LibraryDescription Library { get; set; }
+
+ public IEnumerable RuntimeAssemblies => _runtimeAssemblies;
+
+ public IEnumerable RuntimeAssets => _runtimeAssets;
+
+ public IEnumerable CompilationAssemblies => _compilationAssemblies;
+
+ public IEnumerable CompilationAssets => _compilationAssets;
+
+ public IEnumerable SourceReferences => _sourceReferences;
+
+ public IEnumerable NativeLibraries => _nativeLibraries;
+
+ public IEnumerable EmbeddedResources => _embeddedResources;
+
+ public IEnumerable 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.Value,
+ SourceReferences ?? EmptyArray.Value,
+ RuntimeAssemblies ?? EmptyArray.Value,
+ RuntimeAssets ?? EmptyArray.Value,
+ NativeLibraries ?? EmptyArray.Value,
+ EmbeddedResources ?? EmptyArray.Value,
+ AnalyzerReferences ?? EmptyArray.Value);
+ }
+
+ public LibraryExportBuilder WithLibrary(LibraryDescription libraryDescription)
+ {
+ Library = libraryDescription;
+ return this;
+ }
+
+ public LibraryExportBuilder WithRuntimeAssemblies(IEnumerable assets)
+ {
+ Replace(ref _runtimeAssemblies, assets);
+ return this;
+ }
+
+ public LibraryExportBuilder WithRuntimeAssets(IEnumerable assets)
+ {
+ Replace(ref _runtimeAssets, assets);
+ return this;
+ }
+
+ public LibraryExportBuilder WithCompilationAssemblies(IEnumerable assets)
+ {
+ Replace(ref _compilationAssemblies, assets);
+ return this;
+ }
+
+ public LibraryExportBuilder WithSourceReferences(IEnumerable assets)
+ {
+ Replace(ref _sourceReferences, assets);
+ return this;
+ }
+
+ public LibraryExportBuilder WithNativeLibraries(IEnumerable assets)
+ {
+ Replace(ref _nativeLibraries, assets);
+ return this;
+ }
+
+ public LibraryExportBuilder WithEmbedddedResources(IEnumerable assets)
+ {
+ Replace(ref _embeddedResources, assets);
+ return this;
+ }
+
+ public LibraryExportBuilder WithAnalyzerReference(IEnumerable 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(ref IList list, IEnumerable enumerable)
+ {
+ list = new List(enumerable);
+ }
+
+ private void Add(ref IList list, T item)
+ {
+ if (list == null)
+ {
+ list = new List();
+ }
+ list.Add(item);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs
index 706d16ab0..ea5989e83 100644
--- a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs
+++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs
@@ -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();
- var sourceReferences = new List();
+ var sourceReferences = new List();
var analyzerReferences = new List();
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(),
- sourceReferences: Enumerable.Empty(),
- nativeLibraries: Enumerable.Empty(),
- runtimeAssets: Enumerable.Empty(),
- runtimeAssemblies: EmptyArray.Value,
- analyzers: EmptyArray.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();
- 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();
- PopulateAssets(package, package.RuntimeAssemblies, runtimeAssemblies);
-
- var compileAssemblies = new List();
- PopulateAssets(package, package.CompileTimeAssemblies, compileAssemblies);
-
- var sourceReferences = new List();
- foreach (var sharedSource in GetSharedSources(package))
+ if (package.ContentFiles.Any())
{
- sourceReferences.Add(sharedSource);
+ var parameters = PPFileParameters.CreateForProject(_rootProject.Project);
+ Action 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.Value, nativeLibraries, analyzers);
+ return builder.Build();
}
private LibraryExport ExportProject(ProjectDescription project)
{
- var compileAssemblies = new List();
- var runtimeAssets = new List();
- var sourceReferences = new List();
+ 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 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.Value, EmptyArray.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.Value :
- new[] { new LibraryAsset(library.Identity.Name, library.Path, library.Path) },
- EmptyArray.Value,
- EmptyArray.Value,
- EmptyArray.Value,
- EmptyArray.Value,
- EmptyArray.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 GetSharedSources(PackageDescription package)
+ private IEnumerable 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 GetAnalyzerReferences(PackageDescription package)
@@ -348,14 +382,11 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
}
- private void PopulateAssets(PackageDescription package, IEnumerable section, IList assets)
+ private IEnumerable PopulateAssets(PackageDescription package, IEnumerable 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);
}
}
diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/Preprocessor/PPFileParameters.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/Preprocessor/PPFileParameters.cs
new file mode 100644
index 000000000..eca04ad66
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectModel/Compilation/Preprocessor/PPFileParameters.cs
@@ -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 CreateForProject(Project project)
+ {
+ return new Dictionary()
+ {
+ {"rootnamespace", project.Name },
+ {"assemblyname", project.Name }
+ };
+ }
+ }
+}
diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/Preprocessor/PPFilePreprocessor.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/Preprocessor/PPFilePreprocessor.cs
new file mode 100644
index 000000000..c2d597c97
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectModel/Compilation/Preprocessor/PPFilePreprocessor.cs
@@ -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 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 parameters)
+ {
+ string value;
+ if (!parameters.TryGetValue(name, out value))
+ {
+ throw new InvalidOperationException($"The replacement token '{name}' has no value.");
+ }
+ return value;
+ }
+ }
+}
diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/Preprocessor/PPFileTokenizer.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/Preprocessor/PPFileTokenizer.cs
new file mode 100644
index 000000000..8567aeb48
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectModel/Compilation/Preprocessor/PPFileTokenizer.cs
@@ -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;
+ }
+
+ ///
+ /// Gets the next token.
+ ///
+ /// The parsed token. Or null if no more tokens are available.
+ 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
+ }
+ }
+}
diff --git a/src/Microsoft.DotNet.ProjectModel/Graph/BuildAction.cs b/src/Microsoft.DotNet.ProjectModel/Graph/BuildAction.cs
new file mode 100644
index 000000000..8d59abbb0
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectModel/Graph/BuildAction.cs
@@ -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
+ {
+ 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);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectModel/Graph/LockFileReader.cs b/src/Microsoft.DotNet.ProjectModel/Graph/LockFileReader.cs
index 9f3592b02..3985e20fd 100644
--- a/src/Microsoft.DotNet.ProjectModel/Graph/LockFileReader.cs
+++ b/src/Microsoft.DotNet.ProjectModel/Graph/LockFileReader.cs
@@ -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(
diff --git a/src/Microsoft.DotNet.ProjectModel/Graph/LockFileTargetContentFile.cs b/src/Microsoft.DotNet.ProjectModel/Graph/LockFileTargetContentFile.cs
new file mode 100644
index 000000000..72eecd0c1
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectModel/Graph/LockFileTargetContentFile.cs
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectModel/Graph/LockFileTargetLibrary.cs b/src/Microsoft.DotNet.ProjectModel/Graph/LockFileTargetLibrary.cs
index 7339fed39..eb593e3a4 100644
--- a/src/Microsoft.DotNet.ProjectModel/Graph/LockFileTargetLibrary.cs
+++ b/src/Microsoft.DotNet.ProjectModel/Graph/LockFileTargetLibrary.cs
@@ -30,5 +30,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
public IList ResourceAssemblies { get; set; } = new List();
public IList NativeLibraries { get; set; } = new List();
+
+ public IList ContentFiles { get; set; } = new List();
}
}
diff --git a/src/Microsoft.DotNet.ProjectModel/PackageDescription.cs b/src/Microsoft.DotNet.ProjectModel/PackageDescription.cs
index b66d8a941..5327a4896 100644
--- a/src/Microsoft.DotNet.ProjectModel/PackageDescription.cs
+++ b/src/Microsoft.DotNet.ProjectModel/PackageDescription.cs
@@ -42,6 +42,8 @@ namespace Microsoft.DotNet.ProjectModel
public IEnumerable NativeLibraries => Target.NativeLibraries;
+ public IEnumerable ContentFiles => Target.ContentFiles;
+
private IEnumerable FilterPlaceholders(IList items)
{
return items.Where(a => !PackageDependencyProvider.IsPlaceholderFile(a));
diff --git a/src/Microsoft.DotNet.ProjectModel/ProjectExtensions.cs b/src/Microsoft.DotNet.ProjectModel/ProjectExtensions.cs
new file mode 100644
index 000000000..2c5d9c69c
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectModel/ProjectExtensions.cs
@@ -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[] _compilerNameToLanguageId =
+ {
+ new KeyValuePair("csc", "cs"),
+ new KeyValuePair("vbc", "vb"),
+ new KeyValuePair("fsc", "fs")
+ };
+
+ public static string GetSourceCodeLanguage(this Project project)
+ {
+ foreach (var kvp in _compilerNameToLanguageId)
+ {
+ if (kvp.Key == project.CompilerName)
+ {
+ return kvp.Value;
+ }
+ }
+ return null;
+ }
+ }
+}
diff --git a/src/Microsoft.DotNet.ProjectModel/ProjectReader.cs b/src/Microsoft.DotNet.ProjectModel/ProjectReader.cs
index 744023c1a..1336d21dc 100644
--- a/src/Microsoft.DotNet.ProjectModel/ProjectReader.cs
+++ b/src/Microsoft.DotNet.ProjectModel/ProjectReader.cs
@@ -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.Value;
diff --git a/src/dotnet/commands/dotnet-build/CompileContext.cs b/src/dotnet/commands/dotnet-build/CompileContext.cs
index 91010bb3b..e66a08fd6 100644
--- a/src/dotnet/commands/dotnet-build/CompileContext.cs
+++ b/src/dotnet/commands/dotnet-build/CompileContext.cs
@@ -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)))
{
diff --git a/src/dotnet/commands/dotnet-compile/CompilerUtil.cs b/src/dotnet/commands/dotnet-compile/CompilerUtil.cs
index bc7f13a32..dda381ee7 100644
--- a/src/dotnet/commands/dotnet-compile/CompilerUtil.cs
+++ b/src/dotnet/commands/dotnet-compile/CompilerUtil.cs
@@ -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[] s_compilerNameToLanguageId =
- {
- new KeyValuePair("csc", "cs"),
- new KeyValuePair("vbc", "vb"),
- new KeyValuePair("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 GetCommandsInvokedByCompile(ProjectContext project)
{
- return new List {ResolveCompilerName(project), "compile"};
+ return new List {project.ProjectFile.CompilerName, "compile"};
}
}
}
\ No newline at end of file
diff --git a/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs b/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs
index 960b2b97a..674542dca 100644
--- a/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs
+++ b/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs
@@ -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");
diff --git a/src/dotnet/commands/dotnet-projectmodel-server/Helpers/ProjectExtensions.cs b/src/dotnet/commands/dotnet-projectmodel-server/Helpers/ProjectExtensions.cs
index c7eb9b30e..ef28bbc23 100644
--- a/src/dotnet/commands/dotnet-projectmodel-server/Helpers/ProjectExtensions.cs
+++ b/src/dotnet/commands/dotnet-projectmodel-server/Helpers/ProjectExtensions.cs
@@ -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;
diff --git a/src/dotnet/commands/dotnet-projectmodel-server/InternalModels/ProjectContextSnapshot.cs b/src/dotnet/commands/dotnet-projectmodel-server/InternalModels/ProjectContextSnapshot.cs
index 167115a64..195bf5ba1 100644
--- a/src/dotnet/commands/dotnet-projectmodel-server/InternalModels/ProjectContextSnapshot.cs
+++ b/src/dotnet/commands/dotnet-projectmodel-server/InternalModels/ProjectContextSnapshot.cs
@@ -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();
diff --git a/src/dotnet/commands/dotnet-publish/PublishCommand.cs b/src/dotnet/commands/dotnet-publish/PublishCommand.cs
index 0f0f2316a..ffd8f4988 100644
--- a/src/dotnet/commands/dotnet-publish/PublishCommand.cs
+++ b/src/dotnet/commands/dotnet-publish/PublishCommand.cs
@@ -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
@@ -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())
{
diff --git a/test/Microsoft.DotNet.ProjectModel.Tests/LibraryExporterPackageTests.cs b/test/Microsoft.DotNet.ProjectModel.Tests/LibraryExporterPackageTests.cs
new file mode 100644
index 000000000..1fe4cbb7b
--- /dev/null
+++ b/test/Microsoft.DotNet.ProjectModel.Tests/LibraryExporterPackageTests.cs
@@ -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(), true);
+ }
+
+ [Fact]
+ private void ExportsPackageNativeLibraries()
+ {
+ var description = CreateDescription(
+ new LockFileTargetLibrary()
+ {
+ NativeLibraries = new List()
+ {
+ { 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()
+ {
+ { 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()
+ {
+ { 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()
+ {
+ 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()
+ {
+ 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()
+ {
+ 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()
+ {
+ 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()
+ {
+ 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()
+ {
+ 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"));
+ }
+ }
+}
diff --git a/test/Microsoft.DotNet.ProjectModel.Tests/PreprocessorTests.cs b/test/Microsoft.DotNet.ProjectModel.Tests/PreprocessorTests.cs
new file mode 100644
index 000000000..5a0fec8db
--- /dev/null
+++ b/test/Microsoft.DotNet.ProjectModel.Tests/PreprocessorTests.cs
@@ -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 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()
+ {
+ { "a", "AValue" },
+ { "b", "BValue" }
+ };
+ var result = Preprocess(input, parameters);
+ result.Should().Be(output);
+ }
+
+ [Fact]
+ public void ThrowsOnParameterNotFound()
+ {
+ var ex = Assert.Throws(() => Preprocess("$a$", new Dictionary()));
+ ex.Message.Should().Contain("a");
+ }
+ }
+}
diff --git a/test/dotnet-compile.Tests/CompilerTests.cs b/test/dotnet-compile.Tests/CompilerTests.cs
index c0ed48edb..4c4057e7e 100644
--- a/test/dotnet-compile.Tests/CompilerTests.cs
+++ b/test/dotnet-compile.Tests/CompilerTests.cs
@@ -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