ProjectContext.MakeRunnable
PR Feedback Fixing naming of GetContentFiles
This commit is contained in:
parent
a20cffb9e3
commit
ef0fc05119
12 changed files with 374 additions and 219 deletions
|
@ -12,29 +12,29 @@ using System.Text;
|
|||
using System.Xml.Linq;
|
||||
using Microsoft.DotNet.ProjectModel.Compilation;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Compiler
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
{
|
||||
internal class BindingRedirectGenerator
|
||||
internal static class BindingRedirectGenerator
|
||||
{
|
||||
private const int TokenLength = 8;
|
||||
private const string Namespace = "urn:schemas-microsoft-com:asm.v1";
|
||||
|
||||
private static XName ConfigurationElementName = XName.Get("configuration");
|
||||
private static XName RuntimeElementName = XName.Get("runtime");
|
||||
private static XName AssemblyBindingElementName = XName.Get("assemblyBinding", Namespace);
|
||||
private static XName DependentAssemblyElementName = XName.Get("dependentAssembly", Namespace);
|
||||
private static XName AssemblyIdentityElementName = XName.Get("assemblyIdentity", Namespace);
|
||||
private static XName BindingRedirectElementName = XName.Get("bindingRedirect", Namespace);
|
||||
private static readonly XName ConfigurationElementName = XName.Get("configuration");
|
||||
private static readonly XName RuntimeElementName = XName.Get("runtime");
|
||||
private static readonly XName AssemblyBindingElementName = XName.Get("assemblyBinding", Namespace);
|
||||
private static readonly XName DependentAssemblyElementName = XName.Get("dependentAssembly", Namespace);
|
||||
private static readonly XName AssemblyIdentityElementName = XName.Get("assemblyIdentity", Namespace);
|
||||
private static readonly XName BindingRedirectElementName = XName.Get("bindingRedirect", Namespace);
|
||||
|
||||
private static XName NameAttributeName = XName.Get("name");
|
||||
private static XName PublicKeyTokenAttributeName = XName.Get("publicKeyToken");
|
||||
private static XName CultureAttributeName = XName.Get("culture");
|
||||
private static XName OldVersionAttributeName = XName.Get("oldVersion");
|
||||
private static XName NewVersionAttributeName = XName.Get("newVersion");
|
||||
private static readonly XName NameAttributeName = XName.Get("name");
|
||||
private static readonly XName PublicKeyTokenAttributeName = XName.Get("publicKeyToken");
|
||||
private static readonly XName CultureAttributeName = XName.Get("culture");
|
||||
private static readonly XName OldVersionAttributeName = XName.Get("oldVersion");
|
||||
private static readonly XName NewVersionAttributeName = XName.Get("newVersion");
|
||||
|
||||
private readonly SHA1 _sha1 = SHA1.Create();
|
||||
internal static SHA1 Sha1 { get; } = SHA1.Create();
|
||||
|
||||
public XDocument Generate(IEnumerable<LibraryExport> dependencies, XDocument document)
|
||||
internal static XDocument GenerateBindingRedirects(this IEnumerable<LibraryExport> dependencies, XDocument document)
|
||||
{
|
||||
var redirects = CollectRedirects(dependencies);
|
||||
|
||||
|
@ -57,7 +57,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
return document;
|
||||
}
|
||||
|
||||
private void AddDependentAssembly(AssemblyRedirect redirect, XElement assemblyBindings)
|
||||
private static void AddDependentAssembly(AssemblyRedirect redirect, XElement assemblyBindings)
|
||||
{
|
||||
var dependencyElement = assemblyBindings.Elements(DependentAssemblyElementName)
|
||||
.FirstOrDefault(element => IsSameAssembly(redirect, element));
|
||||
|
@ -80,16 +80,16 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
));
|
||||
}
|
||||
|
||||
private bool IsSameAssembly(AssemblyRedirect redirect, XElement dependentAssemblyElement)
|
||||
private static bool IsSameAssembly(AssemblyRedirect redirect, XElement dependentAssemblyElement)
|
||||
{
|
||||
var identity = dependentAssemblyElement.Element(AssemblyIdentityElementName);
|
||||
if (identity == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (string) identity.Attribute(NameAttributeName) == redirect.From.Name &&
|
||||
(string) identity.Attribute(PublicKeyTokenAttributeName) == redirect.From.PublicKeyToken &&
|
||||
(string) identity.Attribute(CultureAttributeName) == redirect.From.Culture;
|
||||
return (string)identity.Attribute(NameAttributeName) == redirect.From.Name &&
|
||||
(string)identity.Attribute(PublicKeyTokenAttributeName) == redirect.From.PublicKeyToken &&
|
||||
(string)identity.Attribute(CultureAttributeName) == redirect.From.Culture;
|
||||
}
|
||||
|
||||
public static XElement GetOrAddElement(XContainer parent, XName elementName)
|
||||
|
@ -107,7 +107,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
return element;
|
||||
}
|
||||
|
||||
private AssemblyRedirect[] CollectRedirects(IEnumerable<LibraryExport> dependencies)
|
||||
private static AssemblyRedirect[] CollectRedirects(IEnumerable<LibraryExport> dependencies)
|
||||
{
|
||||
var allRuntimeAssemblies = dependencies.SelectMany(d => d.RuntimeAssemblies).Select(GetAssemblyInfo).ToArray();
|
||||
var assemblyLookup = allRuntimeAssemblies.ToDictionary(r => r.Identity.ToLookupKey());
|
||||
|
@ -136,14 +136,14 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
return redirectAssemblies.ToArray();
|
||||
}
|
||||
|
||||
private AssemblyReferenceInfo GetAssemblyInfo(LibraryAsset arg)
|
||||
private static AssemblyReferenceInfo GetAssemblyInfo(LibraryAsset arg)
|
||||
{
|
||||
using (var peReader = new PEReader(File.OpenRead(arg.ResolvedPath)))
|
||||
{
|
||||
var metadataReader = peReader.GetMetadataReader();
|
||||
|
||||
var definition = metadataReader.GetAssemblyDefinition();
|
||||
|
||||
|
||||
var identity = new AssemblyIdentity(
|
||||
metadataReader.GetString(definition.Name),
|
||||
definition.Version,
|
||||
|
@ -168,7 +168,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
}
|
||||
}
|
||||
|
||||
private string GetPublicKeyToken(byte[] bytes)
|
||||
private static string GetPublicKeyToken(byte[] bytes)
|
||||
{
|
||||
if (bytes.Length == 0)
|
||||
{
|
||||
|
@ -183,7 +183,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
else
|
||||
{
|
||||
token = new byte[TokenLength];
|
||||
var sha1 = _sha1.ComputeHash(bytes);
|
||||
var sha1 = Sha1.ComputeHash(bytes);
|
||||
Array.Copy(sha1, sha1.Length - TokenLength, token, 0, TokenLength);
|
||||
Array.Reverse(token);
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
{
|
||||
Name = name;
|
||||
Version = version;
|
||||
Culture = string.IsNullOrEmpty(culture)? "neutral" : culture;
|
||||
Culture = string.IsNullOrEmpty(culture) ? "neutral" : culture;
|
||||
PublicKeyToken = publicKeyToken;
|
||||
}
|
||||
|
|
@ -141,7 +141,7 @@ namespace Microsoft.DotNet.Cli.Utils
|
|||
|
||||
return fileNames.Contains(commandName + FileNameSuffixes.DotNet.Exe) &&
|
||||
fileNames.Contains(commandName + FileNameSuffixes.DotNet.DynamicLib) &&
|
||||
fileNames.Contains(commandName + FileNameSuffixes.DotNet.Deps);
|
||||
fileNames.Contains(commandName + FileNameSuffixes.Deps);
|
||||
});
|
||||
|
||||
if (commandPackage == null) return null;
|
||||
|
|
30
src/Microsoft.DotNet.Cli.Utils/CoreHost.cs
Normal file
30
src/Microsoft.DotNet.Cli.Utils/CoreHost.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
using System.IO;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
{
|
||||
internal static class CoreHost
|
||||
{
|
||||
internal static string _path;
|
||||
|
||||
public static string FileName = "corehost" + FileNameSuffixes.CurrentPlatform.Exe;
|
||||
|
||||
public static string Path
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_path == null)
|
||||
{
|
||||
_path = Env.GetCommandPath(FileName, new[] {string.Empty});
|
||||
}
|
||||
|
||||
return _path;
|
||||
}
|
||||
}
|
||||
|
||||
public static void CopyTo(string destinationPath)
|
||||
{
|
||||
File.Copy(Path, destinationPath, overwrite: true);
|
||||
}
|
||||
}
|
||||
}
|
20
src/Microsoft.DotNet.Cli.Utils/CsvFormatter.cs
Normal file
20
src/Microsoft.DotNet.Cli.Utils/CsvFormatter.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
{
|
||||
internal static class CsvFormatter
|
||||
{
|
||||
internal static string EscapeRow(IEnumerable<string> values)
|
||||
{
|
||||
return values
|
||||
.Select(EscapeValue)
|
||||
.Aggregate((a, v) => a + "," + v);
|
||||
}
|
||||
|
||||
internal static string EscapeValue(string value)
|
||||
{
|
||||
return "\"" + value.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"";
|
||||
}
|
||||
}
|
||||
}
|
61
src/Microsoft.DotNet.Cli.Utils/Env.cs
Normal file
61
src/Microsoft.DotNet.Cli.Utils/Env.cs
Normal file
|
@ -0,0 +1,61 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
{
|
||||
internal static class Env
|
||||
{
|
||||
private static IEnumerable<string> _searchPaths;
|
||||
private static IEnumerable<string> _executableExtensions;
|
||||
|
||||
public static IEnumerable<string> ExecutableExtensions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_executableExtensions == null)
|
||||
{
|
||||
|
||||
_executableExtensions = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|
||||
? Environment.GetEnvironmentVariable("PATHEXT").Split(';').Select(e => e.ToLower())
|
||||
: new [] { string.Empty };
|
||||
}
|
||||
|
||||
return _executableExtensions;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<string> SearchPaths
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_searchPaths == null)
|
||||
{
|
||||
var searchPaths = new List<string> {AppContext.BaseDirectory};
|
||||
|
||||
searchPaths.AddRange(Environment.GetEnvironmentVariable("PATH").Split(Path.PathSeparator));
|
||||
|
||||
_searchPaths = searchPaths;
|
||||
}
|
||||
|
||||
return _searchPaths;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetCommandPath(string commandName, params string[] extensions)
|
||||
{
|
||||
if (!extensions.Any())
|
||||
extensions = Env.ExecutableExtensions.ToArray();
|
||||
|
||||
var commandPath = Env.SearchPaths.Join(
|
||||
extensions,
|
||||
p => true, s => true,
|
||||
(p, s) => Path.Combine(p, commandName + s))
|
||||
.FirstOrDefault(File.Exists);
|
||||
|
||||
return commandPath;
|
||||
}
|
||||
}
|
||||
}
|
59
src/Microsoft.DotNet.Cli.Utils/LibraryExporterExtensions.cs
Normal file
59
src/Microsoft.DotNet.Cli.Utils/LibraryExporterExtensions.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.DotNet.ProjectModel.Compilation;
|
||||
using System.Linq;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
{
|
||||
internal static class LibraryExporterExtensions
|
||||
{
|
||||
internal static void CopyProjectDependenciesTo(this LibraryExporter exporter, string path, params ProjectDescription[] except)
|
||||
{
|
||||
exporter.GetAllExports()
|
||||
.Where(e => !except.Contains(e.Library))
|
||||
.Where(e => e.Library is ProjectDescription)
|
||||
.SelectMany(e => e.NativeLibraries.Union(e.RuntimeAssemblies))
|
||||
.CopyTo(path);
|
||||
}
|
||||
|
||||
internal static void WriteDepsTo(this IEnumerable<LibraryExport> exports, string path)
|
||||
{
|
||||
File.WriteAllLines(path, exports.SelectMany(GenerateLines));
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GenerateLines(LibraryExport export)
|
||||
{
|
||||
return GenerateLines(export, export.RuntimeAssemblies, "runtime")
|
||||
.Union(GenerateLines(export, export.NativeLibraries, "native"));
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GenerateLines(LibraryExport export, IEnumerable<LibraryAsset> items, string type)
|
||||
{
|
||||
return items.Select(i => CsvFormatter.EscapeRow(new[]
|
||||
{
|
||||
export.Library.Identity.Type.Value,
|
||||
export.Library.Identity.Name,
|
||||
export.Library.Identity.Version.ToNormalizedString(),
|
||||
export.Library.Hash,
|
||||
type,
|
||||
i.Name,
|
||||
i.RelativePath
|
||||
}));
|
||||
}
|
||||
|
||||
internal static IEnumerable<LibraryAsset> RuntimeAssets(this LibraryExport export)
|
||||
{
|
||||
return export.RuntimeAssemblies.Union(export.NativeLibraries);
|
||||
}
|
||||
|
||||
internal static void CopyTo(this IEnumerable<LibraryAsset> assets, string destinationPath)
|
||||
{
|
||||
foreach (var asset in assets)
|
||||
{
|
||||
File.Copy(asset.ResolvedPath, Path.Combine(destinationPath, Path.GetFileName(asset.ResolvedPath)),
|
||||
overwrite: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Common
|
||||
|
@ -199,5 +198,17 @@ namespace Microsoft.DotNet.Tools.Common
|
|||
return GetPathWithBackSlashes(path);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool HasExtension(string filePath, string extension)
|
||||
{
|
||||
var comparison = StringComparison.Ordinal;
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
comparison = StringComparison.OrdinalIgnoreCase;
|
||||
}
|
||||
|
||||
return Path.GetExtension(filePath).Equals(extension, comparison);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,8 +2,14 @@
|
|||
// 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;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.ProjectModel.Graph;
|
||||
using Microsoft.DotNet.Tools.Common;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
|
@ -63,5 +69,118 @@ namespace Microsoft.DotNet.Cli.Utils
|
|||
|
||||
return rootOutputPath;
|
||||
}
|
||||
|
||||
internal static void MakeCompilationOutputRunnable(this ProjectContext context, string outputPath, string configuration)
|
||||
{
|
||||
context
|
||||
.ProjectFile
|
||||
.Files
|
||||
.GetContentFiles()
|
||||
.StructuredCopyTo(context.ProjectDirectory, outputPath)
|
||||
.RemoveAttribute(FileAttributes.ReadOnly);
|
||||
|
||||
var exporter = context.CreateExporter(configuration);
|
||||
|
||||
if (context.TargetFramework.IsDesktop())
|
||||
{
|
||||
exporter
|
||||
.GetDependencies()
|
||||
.SelectMany(e => e.RuntimeAssets())
|
||||
.CopyTo(outputPath);
|
||||
|
||||
GenerateBindingRedirects(context, outputPath, configuration);
|
||||
}
|
||||
else
|
||||
{
|
||||
exporter
|
||||
.GetDependencies(LibraryType.Package)
|
||||
.WriteDepsTo(Path.Combine(outputPath, context.ProjectFile.Name + FileNameSuffixes.Deps));
|
||||
|
||||
exporter.GetDependencies(LibraryType.Project)
|
||||
.SelectMany(e => e.RuntimeAssets())
|
||||
.CopyTo(outputPath);
|
||||
|
||||
CoreHost.CopyTo(Path.Combine(outputPath, context.ProjectFile.Name + Constants.ExeSuffix));
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<string> StructuredCopyTo(this IEnumerable<string> sourceFiles, string sourceDirectory, string targetDirectory)
|
||||
{
|
||||
if (sourceFiles == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(sourceFiles));
|
||||
}
|
||||
|
||||
var pathMap = sourceFiles
|
||||
.ToDictionary(s => s, s => Path.Combine(
|
||||
targetDirectory,
|
||||
PathUtility.GetRelativePath(sourceDirectory, s)));
|
||||
|
||||
foreach (var targetDir in pathMap.Values
|
||||
.Select(Path.GetDirectoryName)
|
||||
.Distinct()
|
||||
.Where(t => !Directory.Exists(t)))
|
||||
{
|
||||
Directory.CreateDirectory(targetDir);
|
||||
}
|
||||
|
||||
foreach (var sourceFilePath in pathMap.Keys)
|
||||
{
|
||||
File.Copy(
|
||||
sourceFilePath,
|
||||
pathMap[sourceFilePath],
|
||||
overwrite: true);
|
||||
}
|
||||
|
||||
return pathMap.Values;
|
||||
}
|
||||
|
||||
|
||||
private static IEnumerable<string> RemoveAttribute(this IEnumerable<string> files, FileAttributes attribute)
|
||||
{
|
||||
foreach (var file in files)
|
||||
{
|
||||
var fileAttributes = File.GetAttributes(file);
|
||||
if ((fileAttributes & attribute) == attribute)
|
||||
{
|
||||
File.SetAttributes(file, fileAttributes & ~attribute);
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
|
||||
private static void GenerateBindingRedirects(this ProjectContext context, string outputPath, string configuration)
|
||||
{
|
||||
var existingConfig = new DirectoryInfo(context.ProjectDirectory)
|
||||
.EnumerateFiles()
|
||||
.FirstOrDefault(f => f.Name.Equals("app.config", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
XDocument baseAppConfig = null;
|
||||
|
||||
if (existingConfig != null)
|
||||
{
|
||||
using (var fileStream = File.OpenRead(existingConfig.FullName))
|
||||
{
|
||||
baseAppConfig = XDocument.Load(fileStream);
|
||||
}
|
||||
}
|
||||
|
||||
var appConfig = context.CreateExporter(configuration).GetAllExports().GenerateBindingRedirects(baseAppConfig);
|
||||
|
||||
if (appConfig == null) return;
|
||||
|
||||
var path = Path.Combine(outputPath, context.ProjectFile.Name + ".exe.config");
|
||||
using (var stream = File.Create(path))
|
||||
{
|
||||
appConfig.Save(stream);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetDepsPath(this ProjectContext context, string buildConfiguration)
|
||||
{
|
||||
return Path.Combine(context.GetOutputDirectoryPath(buildConfiguration), context.ProjectFile.Name + ".deps");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
{
|
||||
"version": "1.0.0-*",
|
||||
"version": "1.0.0-*",
|
||||
|
||||
"shared": "**/*.cs",
|
||||
"shared": "**/*.cs",
|
||||
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
"Microsoft.DotNet.ProjectModel": "1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23616",
|
||||
"Microsoft.DotNet.ProjectModel": "1.0.0",
|
||||
"System.Reflection.Metadata": "1.1.0"
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"dnxcore50": { }
|
||||
}
|
||||
"frameworks": {
|
||||
"dnxcore50": { }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,30 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel
|
||||
{
|
||||
public static class FileNameSuffixes
|
||||
{
|
||||
public const string Deps = ".deps";
|
||||
|
||||
public static PlatformFileNameSuffixes CurrentPlatform
|
||||
{
|
||||
get
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return Windows;
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return Linux;
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return OSX;
|
||||
|
||||
throw new InvalidOperationException("Unknown Platform");
|
||||
}
|
||||
}
|
||||
|
||||
public static PlatformFileNameSuffixes DotNet { get; } = new PlatformFileNameSuffixes
|
||||
{
|
||||
DynamicLib = ".dll",
|
||||
Exe = ".exe",
|
||||
ProgramDatabase = ".pdb",
|
||||
StaticLib = ".lib",
|
||||
Deps = ".deps",
|
||||
StaticLib = ".lib"
|
||||
};
|
||||
|
||||
public static PlatformFileNameSuffixes Windows { get; } = new PlatformFileNameSuffixes
|
||||
|
@ -18,8 +32,7 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
DynamicLib = ".dll",
|
||||
Exe = ".exe",
|
||||
ProgramDatabase = ".pdb",
|
||||
StaticLib = ".lib",
|
||||
Deps = ".deps",
|
||||
StaticLib = ".lib"
|
||||
};
|
||||
|
||||
public static PlatformFileNameSuffixes OSX { get; } = new PlatformFileNameSuffixes
|
||||
|
@ -27,21 +40,26 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
DynamicLib = ".dylib",
|
||||
Exe = "",
|
||||
ProgramDatabase = ".pdb",
|
||||
StaticLib = ".a",
|
||||
Deps = ".deps"
|
||||
StaticLib = ".a"
|
||||
};
|
||||
|
||||
public static PlatformFileNameSuffixes Linux { get; } = new PlatformFileNameSuffixes
|
||||
{
|
||||
DynamicLib = ".so",
|
||||
Exe = "",
|
||||
ProgramDatabase = ".pdb",
|
||||
StaticLib = ".a"
|
||||
};
|
||||
|
||||
public struct PlatformFileNameSuffixes
|
||||
{
|
||||
public string DynamicLib { get; set; }
|
||||
public string DynamicLib { get; internal set; }
|
||||
|
||||
public string Exe { get; set; }
|
||||
public string Exe { get; internal set; }
|
||||
|
||||
public string ProgramDatabase { get; set; }
|
||||
public string ProgramDatabase { get; internal set; }
|
||||
|
||||
public string StaticLib { get; set; }
|
||||
|
||||
public string Deps { get; set; }
|
||||
public string StaticLib { get; internal set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,7 +138,7 @@ namespace Microsoft.DotNet.ProjectModel.Files
|
|||
get { return SharedPatternsGroup.SearchFiles(_projectDirectory).Distinct(); }
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetCopyToOutputFiles(IEnumerable<string> additionalExcludePatterns = null)
|
||||
public IEnumerable<string> GetContentFiles(IEnumerable<string> additionalExcludePatterns = null)
|
||||
{
|
||||
var patternGroup = new PatternGroup(ContentPatternsGroup.IncludePatterns,
|
||||
ContentPatternsGroup.ExcludePatterns.Concat(additionalExcludePatterns ?? new List<string>()),
|
||||
|
|
|
@ -14,6 +14,7 @@ using Microsoft.DotNet.Cli.Compiler.Common;
|
|||
using Microsoft.DotNet.Tools.Common;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.ProjectModel.Compilation;
|
||||
using Microsoft.DotNet.ProjectModel.Graph;
|
||||
using Microsoft.DotNet.ProjectModel.Utilities;
|
||||
using NuGet.Frameworks;
|
||||
using Microsoft.Extensions.DependencyModel;
|
||||
|
@ -348,9 +349,9 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
|
||||
if (success && !args.NoHostValue && compilationOptions.EmitEntryPoint.GetValueOrDefault())
|
||||
{
|
||||
MakeRunnable(runtimeContext,
|
||||
outputPath,
|
||||
libraryExporter);
|
||||
var projectContext = ProjectContext.Create(context.ProjectDirectory, context.TargetFramework, new[] { RuntimeIdentifier.Current });
|
||||
projectContext
|
||||
.MakeCompilationOutputRunnable(outputPath, args.ConfigValue);
|
||||
}
|
||||
|
||||
return PrintSummary(diagnostics, sw, success);
|
||||
|
@ -380,135 +381,13 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
return Path.Combine(outputPath, project.Name + outputExtension);
|
||||
}
|
||||
|
||||
private static void CleanOrCreateDirectory(string path)
|
||||
{
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.Delete(path, recursive: true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("Unable to remove directory: " + path);
|
||||
Console.WriteLine(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
private static void MakeRunnable(ProjectContext runtimeContext, string outputPath, LibraryExporter exporter)
|
||||
{
|
||||
CopyContents(runtimeContext, outputPath);
|
||||
|
||||
if (runtimeContext.TargetFramework.IsDesktop())
|
||||
{
|
||||
// On desktop we need to copy dependencies since we don't own the host
|
||||
foreach (var export in exporter.GetDependencies())
|
||||
{
|
||||
CopyExport(outputPath, export);
|
||||
}
|
||||
|
||||
GenerateBindingRedirects(runtimeContext, outputPath, exporter);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitHost(runtimeContext, outputPath, exporter);
|
||||
}
|
||||
}
|
||||
|
||||
private static void GenerateBindingRedirects(ProjectContext runtimeContext, string outputPath, LibraryExporter exporter)
|
||||
{
|
||||
var appConfigNames = new[] { "app.config", "App.config" };
|
||||
XDocument baseAppConfig = null;
|
||||
|
||||
foreach (var appConfigName in appConfigNames)
|
||||
{
|
||||
var baseAppConfigPath = Path.Combine(runtimeContext.ProjectDirectory, appConfigName);
|
||||
|
||||
if (File.Exists(baseAppConfigPath))
|
||||
{
|
||||
using (var fileStream = File.OpenRead(baseAppConfigPath))
|
||||
{
|
||||
baseAppConfig = XDocument.Load(fileStream);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var generator = new BindingRedirectGenerator();
|
||||
var appConfig = generator.Generate(exporter.GetAllExports(), baseAppConfig);
|
||||
|
||||
if (appConfig != null)
|
||||
{
|
||||
var path = Path.Combine(outputPath, runtimeContext.ProjectFile.Name + ".exe.config");
|
||||
using (var stream = File.Create(path))
|
||||
{
|
||||
appConfig.Save(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void CopyExport(string outputPath, LibraryExport export)
|
||||
{
|
||||
CopyFiles(export.RuntimeAssemblies, outputPath);
|
||||
CopyFiles(export.NativeLibraries, outputPath);
|
||||
}
|
||||
|
||||
private static void EmitHost(ProjectContext runtimeContext, string outputPath, LibraryExporter exporter)
|
||||
{
|
||||
// Write the Host information file (basically a simplified form of the lock file)
|
||||
var lines = new List<string>();
|
||||
foreach (var export in exporter.GetAllExports())
|
||||
{
|
||||
if (export.Library == runtimeContext.RootProject)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (export.Library is ProjectDescription)
|
||||
{
|
||||
// Copy project dependencies to the output folder
|
||||
CopyFiles(export.RuntimeAssemblies, outputPath);
|
||||
CopyFiles(export.NativeLibraries, outputPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
lines.AddRange(GenerateLines(export, export.RuntimeAssemblies, "runtime"));
|
||||
lines.AddRange(GenerateLines(export, export.NativeLibraries, "native"));
|
||||
}
|
||||
}
|
||||
|
||||
File.WriteAllLines(Path.Combine(outputPath, runtimeContext.ProjectFile.Name + ".deps"), lines);
|
||||
|
||||
// Copy the host in
|
||||
CopyHost(Path.Combine(outputPath, runtimeContext.ProjectFile.Name + Constants.ExeSuffix));
|
||||
}
|
||||
|
||||
private static void CopyHost(string target)
|
||||
{
|
||||
var hostPath = Path.Combine(AppContext.BaseDirectory, Constants.HostExecutableName);
|
||||
File.Copy(hostPath, target, overwrite: true);
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GenerateLines(LibraryExport export, IEnumerable<LibraryAsset> items, string type)
|
||||
{
|
||||
return items.Select(item =>
|
||||
EscapeCsv(export.Library.Identity.Type.Value) + "," +
|
||||
EscapeCsv(export.Library.Identity.Name) + "," +
|
||||
EscapeCsv(export.Library.Identity.Version.ToNormalizedString()) + "," +
|
||||
EscapeCsv(export.Library.Hash) + "," +
|
||||
EscapeCsv(type) + "," +
|
||||
EscapeCsv(item.Name) + "," +
|
||||
EscapeCsv(item.RelativePath) + ",");
|
||||
}
|
||||
|
||||
private static string EscapeCsv(string input)
|
||||
{
|
||||
return "\"" + input.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"";
|
||||
}
|
||||
|
||||
private static bool PrintSummary(List<DiagnosticMessage> diagnostics, Stopwatch sw, bool success = true)
|
||||
{
|
||||
PrintDiagnostics(diagnostics);
|
||||
|
@ -663,49 +542,6 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
}
|
||||
}
|
||||
|
||||
private static void CopyContents(ProjectContext context, string outputPath)
|
||||
{
|
||||
var sourceFiles = context.ProjectFile.Files.GetCopyToOutputFiles();
|
||||
Copy(sourceFiles, context.ProjectDirectory, outputPath);
|
||||
}
|
||||
|
||||
private static void Copy(IEnumerable<string> sourceFiles, string sourceDirectory, string targetDirectory)
|
||||
{
|
||||
if (sourceFiles == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(sourceFiles));
|
||||
}
|
||||
|
||||
sourceDirectory = EnsureTrailingSlash(sourceDirectory);
|
||||
targetDirectory = EnsureTrailingSlash(targetDirectory);
|
||||
|
||||
foreach (var sourceFilePath in sourceFiles)
|
||||
{
|
||||
var fileName = Path.GetFileName(sourceFilePath);
|
||||
|
||||
var targetFilePath = sourceFilePath.Replace(sourceDirectory, targetDirectory);
|
||||
var targetFileParentFolder = Path.GetDirectoryName(targetFilePath);
|
||||
|
||||
// Create directory before copying a file
|
||||
if (!Directory.Exists(targetFileParentFolder))
|
||||
{
|
||||
Directory.CreateDirectory(targetFileParentFolder);
|
||||
}
|
||||
|
||||
File.Copy(
|
||||
sourceFilePath,
|
||||
targetFilePath,
|
||||
overwrite: true);
|
||||
|
||||
// clear read-only bit if set
|
||||
var fileAttributes = File.GetAttributes(targetFilePath);
|
||||
if ((fileAttributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
|
||||
{
|
||||
File.SetAttributes(targetFilePath, fileAttributes & ~FileAttributes.ReadOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string EnsureTrailingSlash(string path)
|
||||
{
|
||||
return EnsureTrailingCharacter(path, Path.DirectorySeparatorChar);
|
||||
|
|
Loading…
Reference in a new issue