Fixing versions

- Added --version-suffix to build and publish
- Support reading DOTNET_* version variables everywhere versions can be read
- Show the commit sha in dotnet --version
- Added tests that check the assembly output version
- Set DOTNET_BUILD_VERSION when producing the CLI app itself so that it has the version information stamped in for help.
This commit is contained in:
David Fowler 2016-02-18 01:09:23 -08:00
parent 02e39cf81d
commit 69b5e3f815
17 changed files with 297 additions and 35 deletions

View file

@ -1,5 +1,5 @@
{
"dnx": {
"projects": "src/*/project.json;test/src/*/project.json;scripts/*/project.json"
"projects": "src/*/project.json;test/*/project.json;scripts/*/project.json"
}
}

View file

@ -135,12 +135,18 @@ namespace Microsoft.DotNet.Cli.Build.Framework
public Command Environment(IDictionary<string, string> env)
{
foreach(var item in env)
foreach (var item in env)
{
_process.StartInfo.Environment[item.Key] = item.Value;
}
return this;
}
public Command Environment(string key, string value)
{
_process.StartInfo.Environment[key] = value;
return this;
}
public CommandResult Execute()
{

View file

@ -157,11 +157,14 @@ namespace Microsoft.DotNet.Cli.Build
var configuration = c.BuildContext.Get<string>("Configuration");
var binDir = Path.Combine(outputDir, "bin");
var buildVesion = c.BuildContext.Get<BuildVersion>("BuildVersion");
Mkdirp(binDir);
foreach (var project in ProjectsToPublish)
{
// TODO: Use the flag once we get a full build round tripped
// --version-suffix buildVesion.VersionSuffix
dotnet.Publish(
"--native-subdirectory",
"--output",
@ -169,6 +172,7 @@ namespace Microsoft.DotNet.Cli.Build
"--configuration",
configuration,
Path.Combine(c.BuildContext.BuildDirectory, "src", project))
.Environment("DOTNET_BUILD_VERSION", buildVesion.VersionSuffix)
.Execute()
.EnsureSuccessful();
}
@ -210,7 +214,7 @@ namespace Microsoft.DotNet.Cli.Build
}
// Generate .version file
var version = c.BuildContext.Get<BuildVersion>("BuildVersion").SimpleVersion;
var version = buildVesion.SimpleVersion;
var content = $@"{c.BuildContext["CommitHash"]}{Environment.NewLine}{version}{Environment.NewLine}";
File.WriteAllText(Path.Combine(outputDir, ".version"), content);

View file

@ -84,6 +84,17 @@ namespace Microsoft.DotNet.ProjectModel
.Build();
}
public static ProjectContextBuilder CreateBuilder(string projectPath, NuGetFramework framework)
{
if (projectPath.EndsWith(Project.FileName))
{
projectPath = Path.GetDirectoryName(projectPath);
}
return new ProjectContextBuilder()
.WithProjectDirectory(projectPath)
.WithTargetFramework(framework);
}
/// <summary>
/// Creates a project context for each framework located in the project at <paramref name="projectPath"/>
/// </summary>

View file

@ -36,7 +36,7 @@ namespace Microsoft.DotNet.ProjectModel
private Func<string, LockFile> LockFileResolver { get; set; }
private ProjectReaderSettings Settings { get; set; }
private ProjectReaderSettings Settings { get; set; } = ProjectReaderSettings.ReadFromEnvironment();
public ProjectContextBuilder()
{

View file

@ -1,8 +1,21 @@
namespace Microsoft.DotNet.ProjectModel
using System;
namespace Microsoft.DotNet.ProjectModel
{
public class ProjectReaderSettings
{
public string VersionSuffix { get; set; }
public string AssemblyFileVersion { get; set; }
public static ProjectReaderSettings ReadFromEnvironment()
{
var settings = new ProjectReaderSettings
{
VersionSuffix = Environment.GetEnvironmentVariable("DOTNET_BUILD_VERSION"),
AssemblyFileVersion = Environment.GetEnvironmentVariable("DOTNET_ASSEMBLY_FILE_VERSION")
};
return settings;
}
}
}

View file

@ -3,8 +3,12 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Test;
using Microsoft.Extensions.PlatformAbstractions;
using NuGet.Frameworks;
using Microsoft.DotNet.ProjectModel.Server;
using Microsoft.DotNet.Tools.Build;
using Microsoft.DotNet.Tools.Compiler;
@ -14,13 +18,10 @@ using Microsoft.DotNet.Tools.Compiler.Native;
using Microsoft.DotNet.Tools.Help;
using Microsoft.DotNet.Tools.New;
using Microsoft.DotNet.Tools.Publish;
using Microsoft.Extensions.PlatformAbstractions;
using Microsoft.DotNet.Tools.Restore;
using NuGet.Frameworks;
using Microsoft.DotNet.Tools.Resgen;
using Microsoft.DotNet.Tools.Run;
using Microsoft.DotNet.Tools.Test;
using Microsoft.DotNet.Tools.Repl;
using Microsoft.DotNet.Tools.Resgen;
using Microsoft.DotNet.Tools.Restore;
using Microsoft.DotNet.Tools.Run;
namespace Microsoft.DotNet.Cli
{
@ -134,6 +135,12 @@ namespace Microsoft.DotNet.Cli
{
HelpCommand.PrintVersionHeader();
var commitSha = GetCommitSha();
Reporter.Output.WriteLine();
Reporter.Output.WriteLine("Product Information:");
Reporter.Output.WriteLine($" Version: {HelpCommand.ProductVersion}");
Reporter.Output.WriteLine($" Commit Sha: {commitSha.Substring(0, 10)}");
Reporter.Output.WriteLine();
var runtimeEnvironment = PlatformServices.Default.Runtime;
Reporter.Output.WriteLine("Runtime Environment:");
Reporter.Output.WriteLine($" OS Name: {runtimeEnvironment.OperatingSystem}");
@ -151,5 +158,18 @@ namespace Microsoft.DotNet.Cli
{
return (shortName != null && candidate.Equals("-" + shortName)) || (longName != null && candidate.Equals("--" + longName));
}
private static string GetCommitSha()
{
// The CLI ships with a .version file that stores the commit information
var versionFile = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", ".version"));
if (File.Exists(versionFile))
{
return File.ReadLines(versionFile).FirstOrDefault();
}
return null;
}
}
}

View file

@ -284,8 +284,8 @@ namespace Microsoft.DotNet.Tools.Build
var args = new List<string>();
args.Add("--framework");
args.Add($"{projectDependency.Framework}");
args.Add($"{projectDependency.Framework}");
args.Add("--configuration");
args.Add(_args.ConfigValue);
args.Add(projectDependency.Project.ProjectDirectory);
@ -296,6 +296,12 @@ namespace Microsoft.DotNet.Tools.Build
args.Add(_args.RuntimeValue);
}
if (!string.IsNullOrEmpty(_args.VersionSuffixValue))
{
args.Add("--version-suffix");
args.Add(_args.VersionSuffixValue);
}
if (!string.IsNullOrWhiteSpace(_args.BuildBasePathValue))
{
args.Add("--build-base-path");
@ -312,7 +318,7 @@ namespace Microsoft.DotNet.Tools.Build
// todo: add methods to CompilerCommandApp to generate the arg string?
var args = new List<string>();
args.Add("--framework");
args.Add(_rootProject.TargetFramework.ToString());
args.Add(_rootProject.TargetFramework.ToString());
args.Add("--configuration");
args.Add(_args.ConfigValue);
@ -328,6 +334,12 @@ namespace Microsoft.DotNet.Tools.Build
args.Add(_args.OutputValue);
}
if (!string.IsNullOrEmpty(_args.VersionSuffixValue))
{
args.Add("--version-suffix");
args.Add(_args.VersionSuffixValue);
}
if (!string.IsNullOrEmpty(_args.BuildBasePathValue))
{
args.Add("--build-base-path");

View file

@ -26,6 +26,7 @@ namespace Microsoft.DotNet.Tools.Compiler
private CommandOption _buildBasePath;
private CommandOption _frameworkOption;
private CommandOption _runtimeOption;
private CommandOption _versionSuffixOption;
private CommandOption _configurationOption;
private CommandArgument _projectArgument;
private CommandOption _nativeOption;
@ -41,7 +42,8 @@ namespace Microsoft.DotNet.Tools.Compiler
public string ProjectPathValue { get; set; }
public string BuildBasePathValue { get; set; }
public string OutputValue { get; set; }
public string RuntimeValue{ get; set; }
public string RuntimeValue { get; set; }
public string VersionSuffixValue { get; set; }
public string ConfigValue { get; set; }
public bool IsNativeValue { get; set; }
public string ArchValue { get; set; }
@ -53,7 +55,7 @@ namespace Microsoft.DotNet.Tools.Compiler
public string CppCompilerFlagsValue { get; set; }
// workaround: CommandLineApplication is internal therefore I cannot make _app protected so baseclasses can add their own params
private readonly Dictionary<string, CommandOption> baseClassOptions;
private readonly Dictionary<string, CommandOption> baseClassOptions;
public CompilerCommandApp(string name, string fullName, string description)
{
@ -78,6 +80,7 @@ namespace Microsoft.DotNet.Tools.Compiler
_frameworkOption = _app.Option("-f|--framework <FRAMEWORK>", "Compile a specific framework", CommandOptionType.MultipleValue);
_configurationOption = _app.Option("-c|--configuration <CONFIGURATION>", "Configuration under which to build", CommandOptionType.SingleValue);
_runtimeOption = _app.Option("-r|--runtime <RUNTIME_IDENTIFIER>", "Target runtime to publish for", CommandOptionType.SingleValue);
_versionSuffixOption = _app.Option("--version-suffix <VERSION_SUFFIX>", "Defines what `*` should be replaced with in version field in project.json", CommandOptionType.SingleValue);
_projectArgument = _app.Argument("<PROJECT>", "The project to compile, defaults to the current directory. Can be a path to a project.json or a project directory");
// Native Args
@ -106,6 +109,7 @@ namespace Microsoft.DotNet.Tools.Compiler
BuildBasePathValue = _buildBasePath.Value();
ConfigValue = _configurationOption.Value() ?? Constants.DefaultConfiguration;
RuntimeValue = _runtimeOption.Value();
VersionSuffixValue = _versionSuffixOption.Value();
IsNativeValue = _nativeOption.HasValue();
ArchValue = _archOption.Value();
@ -117,11 +121,24 @@ namespace Microsoft.DotNet.Tools.Compiler
CppCompilerFlagsValue = _cppCompilerFlagsOption.Value();
IEnumerable<ProjectContext> contexts;
// Set defaults based on the environment
var settings = ProjectReaderSettings.ReadFromEnvironment();
if (!string.IsNullOrEmpty(VersionSuffixValue))
{
settings.VersionSuffix = VersionSuffixValue;
}
if (_frameworkOption.HasValue())
{
contexts = _frameworkOption.Values
.Select(f => ProjectContext.Create(ProjectPathValue, NuGetFramework.Parse(f)));
.Select(f =>
{
return ProjectContext.CreateBuilder(ProjectPathValue, NuGetFramework.Parse(f))
.WithReaderSettings(settings)
.Build();
});
}
else
{
@ -131,7 +148,7 @@ namespace Microsoft.DotNet.Tools.Compiler
}
else
{
contexts = ProjectContext.CreateContextForEachFramework(ProjectPathValue, settings: null);
contexts = ProjectContext.CreateContextForEachFramework(ProjectPathValue, settings);
}
}
@ -145,11 +162,12 @@ namespace Microsoft.DotNet.Tools.Compiler
public CompilerCommandApp ShallowCopy()
{
return (CompilerCommandApp) MemberwiseClone();
return (CompilerCommandApp)MemberwiseClone();
}
// CommandOptionType is internal. Cannot pass it as argument. Therefore the method name encodes the option type.
protected void AddNoValueOption(string optionTemplate, string descriptino){
protected void AddNoValueOption(string optionTemplate, string descriptino)
{
baseClassOptions[optionTemplate] = _app.Option(optionTemplate, descriptino, CommandOptionType.NoValue);
}
@ -169,7 +187,7 @@ namespace Microsoft.DotNet.Tools.Compiler
}
else
{
return new [] { RuntimeValue };
return new[] { RuntimeValue };
}
}
}

View file

@ -27,7 +27,7 @@ Common Commands:
run Compiles and immediately executes a .NET project
repl Launch an interactive session (read, eval, print, loop)
pack Creates a NuGet package";
private static readonly string ProductVersion = GetProductVersion();
public static readonly string ProductVersion = GetProductVersion();
private static string GetProductVersion()
{

View file

@ -51,9 +51,7 @@ namespace Microsoft.DotNet.Tools.Compiler
}
// Set defaults based on the environment
var settings = new ProjectReaderSettings();
settings.VersionSuffix = Environment.GetEnvironmentVariable("DOTNET_BUILD_VERSION");
settings.AssemblyFileVersion = Environment.GetEnvironmentVariable("DOTNET_ASSEMBLY_FILE_VERSION");
var settings = ProjectReaderSettings.ReadFromEnvironment();
if (versionSuffix.HasValue())
{

View file

@ -24,6 +24,7 @@ namespace Microsoft.DotNet.Tools.Publish
var runtime = app.Option("-r|--runtime <RUNTIME_IDENTIFIER>", "Target runtime to publish for", CommandOptionType.SingleValue);
var buildBasePath = app.Option("-b|--build-base-path <OUTPUT_DIR>", "Directory in which to place temporary outputs", CommandOptionType.SingleValue);
var output = app.Option("-o|--output <OUTPUT_PATH>", "Path in which to publish the app", CommandOptionType.SingleValue);
var versionSuffix = app.Option("--version-suffix <VERSION_SUFFIX>", "Defines what `*` should be replaced with in version field in project.json", CommandOptionType.SingleValue);
var configuration = app.Option("-c|--configuration <CONFIGURATION>", "Configuration under which to build", CommandOptionType.SingleValue);
var projectPath = app.Argument("<PROJECT>", "The project to publish, defaults to the current directory. Can be a path to a project.json or a project directory");
var nativeSubdirectories = app.Option("--native-subdirectory", "Temporary mechanism to include subdirectories from native assets of dependency packages in output", CommandOptionType.NoValue);
@ -39,6 +40,7 @@ namespace Microsoft.DotNet.Tools.Publish
publish.Configuration = configuration.Value() ?? Constants.DefaultConfiguration;
publish.NativeSubdirectories = nativeSubdirectories.HasValue();
publish.ProjectPath = projectPath.Value;
publish.VersionSuffix = versionSuffix.Value();
if (string.IsNullOrEmpty(publish.ProjectPath))
{

View file

@ -28,7 +28,7 @@ namespace Microsoft.DotNet.Tools.Publish
public bool NativeSubdirectories { get; set; }
public NuGetFramework NugetFramework { get; set; }
public IEnumerable<ProjectContext> ProjectContexts { get; set; }
public string VersionSuffix { get; set; }
public int NumberOfProjects { get; private set; }
public int NumberOfPublishedProjects { get; private set; }
@ -80,12 +80,12 @@ namespace Microsoft.DotNet.Tools.Publish
/// <param name="configuration">Debug or Release</param>
/// <param name="nativeSubdirectories"></param>
/// <returns>Return 0 if successful else return non-zero</returns>
private static bool PublishProjectContext(ProjectContext context, string buildBasePath, string outputPath, string configuration, bool nativeSubdirectories)
private bool PublishProjectContext(ProjectContext context, string buildBasePath, string outputPath, string configuration, bool nativeSubdirectories)
{
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);
if (string.IsNullOrEmpty(outputPath))
{
outputPath = context.GetOutputPaths(configuration, buildBasePath, outputPath).RuntimeOutputPath;
@ -118,6 +118,13 @@ namespace Microsoft.DotNet.Tools.Publish
configuration,
context.ProjectFile.ProjectDirectory
};
if (!string.IsNullOrEmpty(VersionSuffix))
{
args.Add("--version-suffix");
args.Add(VersionSuffix);
}
if (!string.IsNullOrEmpty(buildBasePath))
{
args.Add("--build-base-path");
@ -228,7 +235,7 @@ namespace Microsoft.DotNet.Tools.Publish
{
Directory.CreateDirectory(destinationDirectory);
}
File.Copy(file.ResolvedPath, Path.Combine(destinationDirectory, Path.GetFileName(file.ResolvedPath)), overwrite: true);
}
}

View file

@ -16,6 +16,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
private string _buidBasePathDirectory;
private string _configuration;
private string _framework;
private string _versionSuffix;
private bool _noHost;
private bool _native;
private string _architecture;
@ -66,6 +67,16 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
$"--framework {_framework}";
}
}
private string VersionSuffixOption
{
get
{
return _versionSuffix == string.Empty ?
"" :
$"--version-suffix {_versionSuffix}";
}
}
private string NoHostOption
{
@ -183,6 +194,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
string buidBasePath="",
string configuration="",
string framework="",
string versionSuffix="",
bool noHost=false,
bool native=false,
string architecture="",
@ -203,6 +215,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
_outputDirectory = output;
_buidBasePathDirectory = buidBasePath;
_configuration = configuration;
_versionSuffix = versionSuffix;
_framework = framework;
_noHost = noHost;
_native = native;
@ -238,7 +251,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
private string BuildArgs()
{
return $"{BuildProfile} {NoDependencies} {NoIncremental} \"{_projectPath}\" {OutputOption} {BuildBasePathOption} {ConfigurationOption} {FrameworkOption} {NoHostOption} {NativeOption} {ArchitectureOption} {IlcArgsOption} {IlcPathOption} {AppDepSDKPathOption} {NativeCppModeOption} {CppCompilerFlagsOption}";
return $"{BuildProfile} {NoDependencies} {NoIncremental} \"{_projectPath}\" {OutputOption} {BuildBasePathOption} {ConfigurationOption} {FrameworkOption} {VersionSuffixOption} {NoHostOption} {NativeOption} {ArchitectureOption} {IlcArgsOption} {IlcPathOption} {AppDepSDKPathOption} {NativeCppModeOption} {CppCompilerFlagsOption}";
}
}
}

View file

@ -5,13 +5,16 @@ using Microsoft.DotNet.Cli.Utils;
using System;
using System.Diagnostics;
using System.IO;
using System.Collections.Generic;
namespace Microsoft.DotNet.Tools.Test.Utilities
{
public class TestCommand
{
protected string _command;
public Dictionary<string, string> Environment { get; } = new Dictionary<string, string>();
public TestCommand(string command)
{
_command = command;
@ -63,9 +66,14 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
RedirectStandardOutput = true
};
foreach (var item in Environment)
{
psi.Environment[item.Key] = item.Value;
}
var process = new Process
{
StartInfo = psi
StartInfo = psi,
};
process.EnableRaisingEvents = true;

View file

@ -1,15 +1,12 @@
// 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.IO;
using System.Linq;
using FluentAssertions;
using FluentAssertions.Common;
using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.Tools.Test.Utilities;
using Microsoft.Extensions.PlatformAbstractions;
using NuGet.Frameworks;
using Xunit;
namespace Microsoft.DotNet.Tools.Builder.Tests
@ -93,6 +90,44 @@ namespace Microsoft.DotNet.Tools.Builder.Tests
appruntime.Should().Exist().And.HaveFiles(_runtimeFiles);
}
[Fact]
public void SettingVersionInEnvironment_ShouldStampedAssemblyInfoInOutputAssembly()
{
var testInstance = TestAssetsManager.CreateTestInstance("TestLibraryWithConfiguration")
.WithLockFiles();
var cmd = new BuildCommand(Path.Combine(testInstance.TestRoot, Project.FileName), framework: DefaultFramework);
cmd.Environment["DOTNET_BUILD_VERSION"] = "85";
cmd.Environment["DOTNET_ASSEMBLY_FILE_VERSION"] = "345";
cmd.ExecuteWithCapturedOutput().Should().Pass();
var output = Path.Combine(testInstance.TestRoot, "bin", "Debug", DefaultFramework, "TestLibraryWithConfiguration.dll");
var informationalVersion = PeReaderUtils.GetAssemblyAttributeValue(output, "AssemblyInformationalVersionAttribute");
var fileVersion = PeReaderUtils.GetAssemblyAttributeValue(output, "AssemblyFileVersionAttribute");
informationalVersion.Should().NotBeNull();
informationalVersion.Should().BeEquivalentTo("1.0.0-85");
fileVersion.Should().NotBeNull();
fileVersion.Should().BeEquivalentTo("1.0.0.345");
}
[Fact]
public void SettingVersionSuffixFlag_ShouldStampedAssemblyInfoInOutputAssembly()
{
var testInstance = TestAssetsManager.CreateTestInstance("TestLibraryWithConfiguration")
.WithLockFiles();
var cmd = new BuildCommand(Path.Combine(testInstance.TestRoot, Project.FileName), framework: DefaultFramework, versionSuffix: "85");
cmd.ExecuteWithCapturedOutput().Should().Pass();
var output = Path.Combine(testInstance.TestRoot, "bin", "Debug", DefaultFramework, "TestLibraryWithConfiguration.dll");
var informationalVersion = PeReaderUtils.GetAssemblyAttributeValue(output, "AssemblyInformationalVersionAttribute");
informationalVersion.Should().NotBeNull();
informationalVersion.Should().BeEquivalentTo("1.0.0-85");
}
[Fact]
public void ResourceTest()
{

View file

@ -0,0 +1,115 @@
// 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.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
namespace Microsoft.DotNet.Tools.Builder.Tests
{
public static class PeReaderUtils
{
internal static string GetAssemblyAttributeValue(string assemblyPath, string attributeName)
{
if (!File.Exists(assemblyPath))
{
return null;
}
using (var stream = File.OpenRead(assemblyPath))
using (var peReader = new PEReader(stream))
{
if (!peReader.HasMetadata)
{
return null;
}
var mdReader = peReader.GetMetadataReader();
var attrs = mdReader.GetAssemblyDefinition().GetCustomAttributes()
.Select(ah => mdReader.GetCustomAttribute(ah));
foreach (var attr in attrs)
{
var ctorHandle = attr.Constructor;
if (ctorHandle.Kind != HandleKind.MemberReference)
{
continue;
}
var container = mdReader.GetMemberReference((MemberReferenceHandle)ctorHandle).Parent;
var name = mdReader.GetTypeReference((TypeReferenceHandle)container).Name;
if (!string.Equals(mdReader.GetString(name), attributeName))
{
continue;
}
var arguments = GetFixedStringArguments(mdReader, attr);
if (arguments.Count == 1)
{
return arguments[0];
}
}
}
return null;
}
/// <summary>
/// Gets the fixed (required) string arguments of a custom attribute.
/// Only attributes that have only fixed string arguments.
/// </summary>
private static List<string> GetFixedStringArguments(MetadataReader reader, CustomAttribute attribute)
{
// TODO: Nick Guerrera (Nick.Guerrera@microsoft.com) hacked this method for temporary use.
// There is a blob decoder feature in progress but it won't ship in time for our milestone.
// Replace this method with the blob decoder feature when later it is availale.
var signature = reader.GetMemberReference((MemberReferenceHandle)attribute.Constructor).Signature;
var signatureReader = reader.GetBlobReader(signature);
var valueReader = reader.GetBlobReader(attribute.Value);
var arguments = new List<string>();
var prolog = valueReader.ReadUInt16();
if (prolog != 1)
{
// Invalid custom attribute prolog
return arguments;
}
var header = signatureReader.ReadSignatureHeader();
if (header.Kind != SignatureKind.Method || header.IsGeneric)
{
// Invalid custom attribute constructor signature
return arguments;
}
int parameterCount;
if (!signatureReader.TryReadCompressedInteger(out parameterCount))
{
// Invalid custom attribute constructor signature
return arguments;
}
var returnType = signatureReader.ReadSignatureTypeCode();
if (returnType != SignatureTypeCode.Void)
{
// Invalid custom attribute constructor signature
return arguments;
}
for (int i = 0; i < parameterCount; i++)
{
var signatureTypeCode = signatureReader.ReadSignatureTypeCode();
if (signatureTypeCode == SignatureTypeCode.String)
{
// Custom attribute constructor must take only strings
arguments.Add(valueReader.ReadSerializedString());
}
}
return arguments;
}
}
}