Flow project metadata to assembly
This commit is contained in:
parent
fb461c27bf
commit
ab5b16c00c
8 changed files with 246 additions and 12 deletions
|
@ -0,0 +1,72 @@
|
|||
// 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.Reflection;
|
||||
using System.Resources;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using System.IO;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace Microsoft.Dotnet.Cli.Compiler.Common
|
||||
{
|
||||
public class AssemblyInfoFileGenerator
|
||||
{
|
||||
public static string Generate(AssemblyInfoOptions metadata, IEnumerable<string> sourceFiles)
|
||||
{
|
||||
var projectAttributes = new Dictionary<Type, string>()
|
||||
{
|
||||
[typeof(AssemblyTitleAttribute)] = EscapeCharacters(metadata.Title),
|
||||
[typeof(AssemblyDescriptionAttribute)] = EscapeCharacters(metadata.Description),
|
||||
[typeof(AssemblyCopyrightAttribute)] = EscapeCharacters(metadata.Copyright),
|
||||
[typeof(AssemblyFileVersionAttribute)] = EscapeCharacters(metadata.AssemblyFileVersion?.ToString()),
|
||||
[typeof(AssemblyVersionAttribute)] = EscapeCharacters(metadata.AssemblyVersion?.ToString()),
|
||||
[typeof(AssemblyInformationalVersionAttribute)] = EscapeCharacters(metadata.InformationalVersion),
|
||||
[typeof(AssemblyCultureAttribute)] = EscapeCharacters(metadata.Culture),
|
||||
[typeof(NeutralResourcesLanguageAttribute)] = EscapeCharacters(metadata.NeutralLanguage)
|
||||
};
|
||||
|
||||
var existingAttributes = new List<Type>();
|
||||
foreach (var sourceFile in sourceFiles)
|
||||
{
|
||||
var tree = CSharpSyntaxTree.ParseText(File.ReadAllText(sourceFile));
|
||||
var root = tree.GetRoot();
|
||||
|
||||
// assembly attributes can be only on first level
|
||||
foreach (var attributeListSyntax in root.ChildNodes().OfType<AttributeListSyntax>())
|
||||
{
|
||||
if (attributeListSyntax.Target.Identifier.Kind() == SyntaxKind.AssemblyKeyword)
|
||||
{
|
||||
foreach (var attributeSyntax in attributeListSyntax.Attributes)
|
||||
{
|
||||
var projectAttribute = projectAttributes.FirstOrDefault(attribute => IsSameAttribute(attribute.Key, attributeSyntax));
|
||||
if (projectAttribute.Key != null)
|
||||
{
|
||||
existingAttributes.Add(projectAttribute.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join(Environment.NewLine, projectAttributes
|
||||
.Where(projectAttribute => projectAttribute.Value != null && !existingAttributes.Contains(projectAttribute.Key))
|
||||
.Select(projectAttribute => $"[assembly:{projectAttribute.Key.FullName}(\"{projectAttribute.Value}\")]"));
|
||||
}
|
||||
|
||||
private static bool IsSameAttribute(Type attributeType, AttributeSyntax attributeSyntax)
|
||||
{
|
||||
var name = attributeSyntax.Name.ToString();
|
||||
// This check is quite stupid but we can not do more without semantic model
|
||||
return attributeType.FullName.StartsWith(name) || attributeType.Name.StartsWith(name);
|
||||
}
|
||||
|
||||
private static string EscapeCharacters(string str)
|
||||
{
|
||||
return str != null ? SymbolDisplay.FormatLiteral(str, quote: false) : null;
|
||||
}
|
||||
}
|
||||
}
|
143
src/Microsoft.DotNet.Compiler.Common/AssemblyInfoOptions.cs
Normal file
143
src/Microsoft.DotNet.Compiler.Common/AssemblyInfoOptions.cs
Normal file
|
@ -0,0 +1,143 @@
|
|||
// 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 Microsoft.DotNet.ProjectModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.CommandLine;
|
||||
|
||||
namespace Microsoft.Dotnet.Cli.Compiler.Common
|
||||
{
|
||||
public class AssemblyInfoOptions
|
||||
{
|
||||
private const string TitleOptionName = "title";
|
||||
|
||||
private const string DescriptionOptionName = "description";
|
||||
|
||||
private const string CopyrightOptionName = "copyright";
|
||||
|
||||
private const string AssemblyFileVersionOptionName = "file-version";
|
||||
|
||||
private const string AssemblyVersionOptionName = "version";
|
||||
|
||||
private const string InformationalVersionOptionName = "informational-version";
|
||||
|
||||
private const string CultureOptionName = "culture";
|
||||
|
||||
private const string NeutralCultureOptionName = "neutral-language";
|
||||
|
||||
public string Title { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
public string Copyright { get; set; }
|
||||
|
||||
public string AssemblyFileVersion { get; set; }
|
||||
|
||||
public string AssemblyVersion { get; set; }
|
||||
|
||||
public string InformationalVersion { get; set; }
|
||||
|
||||
public string Culture { get; set; }
|
||||
|
||||
public string NeutralLanguage { get; set; }
|
||||
|
||||
public static AssemblyInfoOptions CreateForProject(Project project)
|
||||
{
|
||||
return new AssemblyInfoOptions()
|
||||
{
|
||||
AssemblyVersion = project.Version?.Version.ToString(),
|
||||
AssemblyFileVersion = project.AssemblyFileVersion.ToString(),
|
||||
InformationalVersion = project.Version.ToString(),
|
||||
Copyright = project.Copyright,
|
||||
Description = project.Description,
|
||||
Title = project.Title,
|
||||
NeutralLanguage = project.Language
|
||||
};
|
||||
}
|
||||
|
||||
public static AssemblyInfoOptions Parse(ArgumentSyntax syntax)
|
||||
{
|
||||
string version = null;
|
||||
string informationalVersion = null;
|
||||
string fileVersion = null;
|
||||
string title = null;
|
||||
string description = null;
|
||||
string copyright = null;
|
||||
string culture = null;
|
||||
string neutralCulture = null;
|
||||
|
||||
syntax.DefineOption(AssemblyVersionOptionName, ref version, "Assembly version");
|
||||
|
||||
syntax.DefineOption(TitleOptionName, ref title, "Assembly title");
|
||||
|
||||
syntax.DefineOption(DescriptionOptionName, ref description, "Assembly description");
|
||||
|
||||
syntax.DefineOption(CopyrightOptionName, ref copyright, "Assembly copyright");
|
||||
|
||||
syntax.DefineOption(NeutralCultureOptionName, ref neutralCulture, "Assembly neutral culture");
|
||||
|
||||
syntax.DefineOption(CultureOptionName, ref culture, "Assembly culture");
|
||||
|
||||
syntax.DefineOption(InformationalVersionOptionName, ref informationalVersion, "Assembly informational version");
|
||||
|
||||
syntax.DefineOption(AssemblyFileVersionOptionName, ref fileVersion, "Assembly title");
|
||||
|
||||
return new AssemblyInfoOptions()
|
||||
{
|
||||
AssemblyFileVersion = fileVersion,
|
||||
AssemblyVersion = version,
|
||||
Copyright = copyright,
|
||||
NeutralLanguage = neutralCulture,
|
||||
Description = description,
|
||||
InformationalVersion = informationalVersion,
|
||||
Title = title
|
||||
};
|
||||
}
|
||||
|
||||
public static IEnumerable<string> SerializeToArgs(AssemblyInfoOptions assemblyInfoOptions)
|
||||
{
|
||||
var options = new List<string>();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(assemblyInfoOptions.Title))
|
||||
{
|
||||
options.Add(FormatOption(TitleOptionName, assemblyInfoOptions.Title));
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(assemblyInfoOptions.Description))
|
||||
{
|
||||
options.Add(FormatOption(DescriptionOptionName, assemblyInfoOptions.Description));
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(assemblyInfoOptions.Copyright))
|
||||
{
|
||||
options.Add(FormatOption(CopyrightOptionName, assemblyInfoOptions.Copyright));
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(assemblyInfoOptions.AssemblyFileVersion))
|
||||
{
|
||||
options.Add(FormatOption(AssemblyFileVersionOptionName, assemblyInfoOptions.AssemblyFileVersion));
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(assemblyInfoOptions.AssemblyVersion))
|
||||
{
|
||||
options.Add(FormatOption(AssemblyVersionOptionName, assemblyInfoOptions.AssemblyVersion));
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(assemblyInfoOptions.InformationalVersion))
|
||||
{
|
||||
options.Add(FormatOption(InformationalVersionOptionName, assemblyInfoOptions.InformationalVersion));
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(assemblyInfoOptions.Culture))
|
||||
{
|
||||
options.Add(FormatOption(CultureOptionName, assemblyInfoOptions.Culture));
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(assemblyInfoOptions.NeutralLanguage))
|
||||
{
|
||||
options.Add(FormatOption(NeutralCultureOptionName, assemblyInfoOptions.NeutralLanguage));
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
private static string FormatOption(string optionName, string value)
|
||||
{
|
||||
return $"--{optionName}:{value}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,9 @@
|
|||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"System.Linq": "4.0.1-rc2-23608",
|
||||
"System.Reflection": "4.0.10-rc2-23608",
|
||||
"System.CommandLine": "0.1.0-*",
|
||||
"Microsoft.CodeAnalysis.CSharp": "1.1.1",
|
||||
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
|
||||
"Microsoft.DotNet.Cli.Utils": {
|
||||
"type": "build",
|
||||
|
|
|
@ -13,6 +13,7 @@ using System.Text;
|
|||
using Microsoft.DotNet.Cli.Compiler.Common;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.Dotnet.Cli.Compiler.Common;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Compiler.Csc
|
||||
{
|
||||
|
@ -25,6 +26,7 @@ namespace Microsoft.DotNet.Tools.Compiler.Csc
|
|||
DebugHelper.HandleDebugSwitch(ref args);
|
||||
|
||||
CommonCompilerOptions commonOptions = null;
|
||||
AssemblyInfoOptions assemblyInfoOptions = null;
|
||||
string tempOutDir = null;
|
||||
IReadOnlyList<string> references = Array.Empty<string>();
|
||||
IReadOnlyList<string> resources = Array.Empty<string>();
|
||||
|
@ -37,6 +39,8 @@ namespace Microsoft.DotNet.Tools.Compiler.Csc
|
|||
{
|
||||
commonOptions = CommonCompilerOptionsExtensions.Parse(syntax);
|
||||
|
||||
assemblyInfoOptions = AssemblyInfoOptions.Parse(syntax);
|
||||
|
||||
syntax.DefineOption("temp-output", ref tempOutDir, "Compilation temporary directory");
|
||||
|
||||
syntax.DefineOption("out", ref outputName, "Name of the output assembly");
|
||||
|
@ -46,7 +50,6 @@ namespace Microsoft.DotNet.Tools.Compiler.Csc
|
|||
syntax.DefineOptionList("resource", ref resources, "Resources to embed");
|
||||
|
||||
syntax.DefineParameterList("source-files", ref sources, "Compilation sources");
|
||||
|
||||
if (tempOutDir == null)
|
||||
{
|
||||
syntax.ReportError("Option '--temp-output' is required");
|
||||
|
@ -63,6 +66,11 @@ namespace Microsoft.DotNet.Tools.Compiler.Csc
|
|||
var allArgs = new List<string>(translated);
|
||||
allArgs.AddRange(GetDefaultOptions());
|
||||
|
||||
// Generate assembly info
|
||||
var assemblyInfo = Path.Combine(tempOutDir, $"dotnet-compile.assemblyinfo.cs");
|
||||
File.WriteAllText(assemblyInfo, AssemblyInfoFileGenerator.Generate(assemblyInfoOptions, sources));
|
||||
allArgs.Add($"\"{assemblyInfo}\"");
|
||||
|
||||
if (outputName != null)
|
||||
{
|
||||
allArgs.Add($"-out:\"{outputName}\"");
|
||||
|
|
|
@ -8,6 +8,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Dnx.Runtime.Common.CommandLine;
|
||||
using Microsoft.Dotnet.Cli.Compiler.Common;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.Cli.Compiler.Common;
|
||||
using Microsoft.DotNet.Tools.Common;
|
||||
|
@ -309,6 +310,9 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
// Add compilation options to the args
|
||||
compilerArgs.AddRange(compilationOptions.SerializeToArgs());
|
||||
|
||||
// Add metadata options
|
||||
compilerArgs.AddRange(AssemblyInfoOptions.SerializeToArgs(AssemblyInfoOptions.CreateForProject(context.ProjectFile)));
|
||||
|
||||
foreach (var dependency in dependencies)
|
||||
{
|
||||
var projectDependency = dependency.Library as ProjectDescription;
|
||||
|
@ -332,7 +336,6 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add project source files
|
||||
var sourceFiles = context.ProjectFile.Files.SourceFiles;
|
||||
compilerArgs.AddRange(sourceFiles);
|
||||
|
@ -660,7 +663,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
// {file}.resx -> {file}.resources
|
||||
var resourcesFile = Path.Combine(intermediateOutputPath, name);
|
||||
|
||||
var result = Command.Create("dotnet-resgen", $"\"{fileName}\" -o \"{resourcesFile}\"")
|
||||
var result = Command.Create("dotnet-resgen", $"\"{fileName}\" -o \"{resourcesFile}\" -v \"{project.Version.Version}\"")
|
||||
.ForwardStdErr()
|
||||
.ForwardStdOut()
|
||||
.Execute();
|
||||
|
@ -725,6 +728,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
arguments.AddRange(references.Select(r => $"-r \"{r.ResolvedPath}\""));
|
||||
arguments.Add($"-o \"{resourceOuputFile}\"");
|
||||
arguments.Add($"-c {culture}");
|
||||
arguments.Add($"-v {project.Version.Version}");
|
||||
|
||||
foreach (var resourceFile in resourceFileGroup)
|
||||
{
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||
using Microsoft.Dnx.Runtime.Common.CommandLine;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using System;
|
||||
using Microsoft.Dotnet.Cli.Compiler.Common;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Resgen
|
||||
{
|
||||
|
@ -23,6 +24,7 @@ namespace Microsoft.DotNet.Tools.Resgen
|
|||
|
||||
var ouputFile = app.Option("-o", "Output file name", CommandOptionType.SingleValue);
|
||||
var culture = app.Option("-c", "Ouput assembly culture", CommandOptionType.SingleValue);
|
||||
var version = app.Option("-v", "Ouput assembly version", CommandOptionType.SingleValue);
|
||||
var references = app.Option("-r", "Compilation references", CommandOptionType.MultipleValue);
|
||||
var inputFiles = app.Argument("<input>", "Input files", true);
|
||||
|
||||
|
@ -42,10 +44,14 @@ namespace Microsoft.DotNet.Tools.Resgen
|
|||
case ResourceFileType.Dll:
|
||||
using (var outputStream = outputResourceFile.File.Create())
|
||||
{
|
||||
var metadata = new AssemblyInfoOptions();
|
||||
metadata.Culture = culture.Value();
|
||||
metadata.AssemblyVersion = version.Value();
|
||||
|
||||
ResourceAssemblyGenerator.Generate(intputResourceFiles,
|
||||
outputStream,
|
||||
metadata,
|
||||
Path.GetFileNameWithoutExtension(outputResourceFile.File.Name),
|
||||
culture.Value(),
|
||||
references.Values.ToArray()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,13 +7,14 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.Dotnet.Cli.Compiler.Common;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Resgen
|
||||
{
|
||||
internal class ResourceAssemblyGenerator
|
||||
{
|
||||
public static void Generate(ResourceSource[] sourceFiles, Stream outputStream, string asemblyName, string culture, string[] references)
|
||||
public static void Generate(ResourceSource[] sourceFiles, Stream outputStream, AssemblyInfoOptions metadata, string assemblyName, string[] references)
|
||||
{
|
||||
if (sourceFiles == null)
|
||||
{
|
||||
|
@ -51,17 +52,14 @@ namespace Microsoft.DotNet.Tools.Resgen
|
|||
}
|
||||
|
||||
var compilationOptions = new CSharpCompilationOptions(outputKind: OutputKind.DynamicallyLinkedLibrary);
|
||||
var compilation = CSharpCompilation.Create(asemblyName,
|
||||
var compilation = CSharpCompilation.Create(assemblyName,
|
||||
references: references.Select(reference => MetadataReference.CreateFromFile(reference)),
|
||||
options: compilationOptions);
|
||||
|
||||
if (!string.IsNullOrEmpty(culture))
|
||||
compilation = compilation.AddSyntaxTrees(new[]
|
||||
{
|
||||
compilation = compilation.AddSyntaxTrees(new[]
|
||||
{
|
||||
CSharpSyntaxTree.ParseText($"[assembly:System.Reflection.AssemblyCultureAttribute(\"{culture}\")]")
|
||||
});
|
||||
}
|
||||
CSharpSyntaxTree.ParseText(AssemblyInfoFileGenerator.Generate(metadata, Enumerable.Empty<string>()))
|
||||
});
|
||||
|
||||
var result = compilation.Emit(outputStream, manifestResources: resourceDescriptions);
|
||||
if (!result.Success)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
"System.Resources.ReaderWriter": "4.0.0-rc2-23608",
|
||||
|
||||
"Microsoft.CodeAnalysis.CSharp": "1.1.1",
|
||||
"Microsoft.DotNet.Compiler.Common": "1.0.0-*",
|
||||
"Microsoft.DotNet.Cli.Utils": {
|
||||
"type": "build",
|
||||
"version": "1.0.0-*"
|
||||
|
|
Loading…
Reference in a new issue