Added another command line parser. Has a nice parameter verification framework

This commit is contained in:
Holger Boerchers 2018-08-16 21:36:25 +02:00
parent a08d551403
commit bfb6971564
11 changed files with 118 additions and 283 deletions

View File

@ -21,6 +21,10 @@
<assemblyIdentity name="NuGet.Packaging" publicKeyToken="31bf3856ad364e35" culture="neutral"/> <assemblyIdentity name="NuGet.Packaging" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.5.0.4" newVersion="4.5.0.4"/> <bindingRedirect oldVersion="0.0.0.0-4.5.0.4" newVersion="4.5.0.4"/>
</dependentAssembly> </dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0"/>
</dependentAssembly>
</assemblyBinding> </assemblyBinding>
</runtime> </runtime>
</configuration> </configuration>

View File

@ -1,54 +0,0 @@
using System.ComponentModel;
using System.IO;
namespace KattekerCreator
{
public class ApplicationArguments
{
private string _changeLog;
private string _programFile;
private string _outputDir;
[DisplayName("Program")]
[Description("Path to the program file")]
public string ProgramFile
{
get => _programFile;
set => _programFile = Path.GetFullPath(value);
}
[DisplayName("Changelog")]
[Description("Path of the changelog file")]
public string ChangeLog
{
get => _changeLog;
set => _changeLog = Path.GetFullPath(value);
}
[DisplayName("Channel")]
[Description("Channel of releasing.")]
public string Channel { get; set; }
[DisplayName("Out")]
[Description("Directory for the output")]
public string OutputDir
{
get => _outputDir;
set => _outputDir = Path.GetFullPath(value);
}
[DisplayName("Publish")]
[Description("Path for output from the point of view of the application.")]
public string PublishDir { get; set; }
[DisplayName("Version")]
[Description("Override version number of the application.")]
public string Version { get; set; }
[DisplayName("Filter")]
[Description("Filter parameter. Use minimatch pattern.")]
public string FilterAsString { get; set; }
public string[] Filter => string.IsNullOrWhiteSpace(FilterAsString) ? new string[0] : FilterAsString.Split(';');
}
}

View File

@ -15,17 +15,17 @@ namespace KattekerCreator
private readonly string _description; private readonly string _description;
private readonly string _productName; private readonly string _productName;
public AssemblyFileInfo(ApplicationArguments appArguments, string tempDir) public AssemblyFileInfo(string programFile, string version, string tempDir)
{ {
FileInfo = new FileInfo(appArguments.ProgramFile); FileInfo = new FileInfo(programFile);
using (var resourceInfo = new ResourceInfo()) using (var resourceInfo = new ResourceInfo())
{ {
resourceInfo.Load(appArguments.ProgramFile); resourceInfo.Load(programFile);
if (resourceInfo.ResourceTypes.All(x => x.ResourceType != Kernel32.ResourceTypes.RT_VERSION)) return; if (resourceInfo.ResourceTypes.All(x => x.ResourceType != Kernel32.ResourceTypes.RT_VERSION)) return;
var versionResource = (VersionResource) resourceInfo[Kernel32.ResourceTypes.RT_VERSION].First(); var versionResource = (VersionResource) resourceInfo[Kernel32.ResourceTypes.RT_VERSION].First();
var stringFileInfo = ((StringFileInfo) versionResource[nameof(StringFileInfo)]).Strings var stringFileInfo = ((StringFileInfo) versionResource[nameof(StringFileInfo)]).Strings
.FirstOrDefault().Value; .FirstOrDefault().Value;
AssemblyIconPath = GetAssemblyIcon(appArguments.ProgramFile, tempDir); AssemblyIconPath = GetAssemblyIcon(programFile, tempDir);
if (stringFileInfo.Strings.ContainsKey("CompanyName")) if (stringFileInfo.Strings.ContainsKey("CompanyName"))
_company = stringFileInfo.Strings["CompanyName"].StringValue.TrimEnd('\0'); _company = stringFileInfo.Strings["CompanyName"].StringValue.TrimEnd('\0');
if (stringFileInfo.Strings.ContainsKey("FileDescription")) if (stringFileInfo.Strings.ContainsKey("FileDescription"))
@ -35,7 +35,7 @@ namespace KattekerCreator
if (stringFileInfo.Strings.ContainsKey("ProductName")) if (stringFileInfo.Strings.ContainsKey("ProductName"))
_productName = stringFileInfo.Strings["ProductName"].StringValue.TrimEnd('\0'); _productName = stringFileInfo.Strings["ProductName"].StringValue.TrimEnd('\0');
if (!stringFileInfo.Strings.ContainsKey("ProductVersion")) return; if (!stringFileInfo.Strings.ContainsKey("ProductVersion")) return;
AssemblyVersion = appArguments.Version != null ? GetSemanticVersion(appArguments.Version) : GetSemanticVersion(stringFileInfo.Strings["ProductVersion"].StringValue.TrimEnd('\0')); AssemblyVersion = version != null ? GetSemanticVersion(version) : GetSemanticVersion(stringFileInfo.Strings["ProductVersion"].StringValue.TrimEnd('\0'));
} }
} }

View File

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace Minimatch namespace Minimatch

View File

@ -1,167 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
namespace KattekerCreator.Helper
{
public class SimpleCommandLineParser<TObject> where TObject : new()
{
private TObject _parsedObject;
public SimpleCommandLineParser(IEnumerable<string> args)
{
Parse(args);
}
private IDictionary<string, string[]> Arguments { get; } = new Dictionary<string, string[]>();
public bool Contains(string name) => Arguments.ContainsKey(name);
public TObject GetObject()
{
if (!EqualityComparer<TObject>.Default.Equals(_parsedObject, default(TObject)))
return _parsedObject;
_parsedObject = new TObject();
try
{
LoopProperties(pi =>
{
var displayName = GetDisplayName(pi);
if (displayName == null) return;
if (!Arguments.TryGetValue(displayName.ToLowerInvariant(), out var argument)) return;
if (pi.PropertyType == typeof(bool))
{
pi.SetValue(_parsedObject, true);
return;
}
if (pi.PropertyType.IsArray)
pi.SetValue(_parsedObject, argument);
else
pi.SetValue(_parsedObject, argument.FirstOrDefault());
});
}
catch (Exception e)
{
Log.WriteErrorLine("Error parsing commandline arguments: " + e.Message);
ShowHelp();
}
return _parsedObject;
}
public void ShowHelp(TextWriter textWriter = null)
{
if (textWriter == null) textWriter = Console.Out;
var executable = Assembly.GetExecutingAssembly().GetName().Name + ".exe";
var assemblyTitle = ((AssemblyTitleAttribute) Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(AssemblyTitleAttribute), false))?.Title ?? executable;
var assemblyDescription = ((AssemblyDescriptionAttribute) Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(AssemblyDescriptionAttribute), false))?.Description;
textWriter.WriteLine();
textWriter.WriteLine(assemblyTitle);
textWriter.WriteLine();
textWriter.WriteLine(assemblyDescription);
textWriter.WriteLine();
textWriter.WriteLine(executable + " <options>");
textWriter.WriteLine();
var dict = new Dictionary<string, string>();
LoopProperties(pi =>
{
var displayName = GetDisplayName(pi);
if (displayName == null) return;
var description = GetDescription(pi);
if (pi.PropertyType == typeof(bool)) description = "(Switch) " + description;
dict.Add(displayName, description);
});
var longestWord = dict.Keys.Max(x => x.Length);
foreach (var kv in dict)
{
textWriter.Write("-" + kv.Key.PadRight(longestWord + 3, ' '));
textWriter.WriteLine(kv.Value);
}
textWriter.WriteLine();
textWriter.WriteLine("A switch will be set to true, if it will called.");
textWriter.WriteLine($"Example: {executable} <Switch>");
textWriter.WriteLine();
textWriter.WriteLine("A parameter will be set.");
textWriter.WriteLine($"Example: {executable} <Key> \"Value\"");
}
/// <summary>
/// Shows the current set options.
/// </summary>
/// <param name="textWriter">If not set Console.Out will be set.</param>
public void ShowProgramArguments(TextWriter textWriter = null)
{
if (textWriter == null) textWriter = Console.Out;
LoopProperties(pi =>
{
var displayName = GetDisplayName(pi);
if (displayName == null) return;
var value = pi.GetValue(_parsedObject);
textWriter.Write(displayName.PadRight(20, ' '));
if (value == null)
{
textWriter.WriteLine("<NOT SET>");
}
else
{
if (value.GetType().IsArray)
{
var arrayAsString = ((IEnumerable) value)
.Cast<object>()
.Aggregate(string.Empty, (current, x) => current + x?.ToString() + ", ");
textWriter.WriteLine(arrayAsString);
}
else
{
textWriter.WriteLine(value.ToString());
}
}
});
}
private static TAttribute GetAttribute<TAttribute>(MemberInfo memberInfo) where TAttribute : Attribute =>
(TAttribute) Attribute.GetCustomAttribute(memberInfo, typeof(TAttribute));
private static string GetDescription(MemberInfo memberInfo) => GetAttribute<DescriptionAttribute>(memberInfo)?.Description;
private static string GetDisplayName(MemberInfo memberInfo) => GetAttribute<DisplayNameAttribute>(memberInfo)?.DisplayName;
private static void LoopProperties(Action<PropertyInfo> action)
{
var properties = typeof(TObject).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var propertyInfo in properties)
action.Invoke(propertyInfo);
}
private void Parse(IEnumerable<string> args)
{
var currentName = "";
var values = new List<string>();
foreach (var arg in args)
{
if (arg.StartsWith("-", StringComparison.Ordinal))
{
if (!string.IsNullOrWhiteSpace(currentName))
Arguments[currentName.ToLowerInvariant()] = values.ToArray();
values.Clear();
currentName = arg.Substring(1);
}
else if (string.IsNullOrWhiteSpace(currentName))
{
Arguments[arg] = new string[0];
}
else
{
values.Add(arg);
}
}
if (currentName != "")
Arguments[currentName.ToLowerInvariant()] = values.ToArray();
}
}
}

View File

@ -38,18 +38,27 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<AutoGenerateBindingRedirects>false</AutoGenerateBindingRedirects>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="McMaster.Extensions.CommandLineUtils, Version=2.2.5.0, Culture=neutral, PublicKeyToken=6f71cb76b82f055d, processorArchitecture=MSIL">
<HintPath>..\packages\McMaster.Extensions.CommandLineUtils.2.2.5\lib\net45\McMaster.Extensions.CommandLineUtils.dll</HintPath>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.IO.Compression" /> <Reference Include="System.IO.Compression" />
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="Vestris.ResourceLib, Version=1.6.422.0, Culture=neutral, PublicKeyToken=ec632d8ba5e5750d, processorArchitecture=MSIL"> <Reference Include="Vestris.ResourceLib, Version=1.6.422.0, Culture=neutral, PublicKeyToken=ec632d8ba5e5750d, processorArchitecture=MSIL">
<HintPath>..\packages\Vestris.ResourceLib.1.6.422\lib\Vestris.ResourceLib.dll</HintPath> <HintPath>..\packages\Vestris.ResourceLib.1.6.422\lib\Vestris.ResourceLib.dll</HintPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="ApplicationArguments.cs" />
<Compile Include="AssemblyFileInfo.cs" /> <Compile Include="AssemblyFileInfo.cs" />
<Compile Include="Helper\Log.cs" /> <Compile Include="Helper\Log.cs" />
<Compile Include="Helper\TemporaryDirectory.cs" /> <Compile Include="Helper\TemporaryDirectory.cs" />
@ -60,8 +69,8 @@
<Compile Include="PathFragments.cs" /> <Compile Include="PathFragments.cs" />
<Compile Include="PhysicalFile.cs" /> <Compile Include="PhysicalFile.cs" />
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Program.Arguments.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Helper\SimpleCommandLineParser.cs" />
<Compile Include="Helper\Utils.cs" /> <Compile Include="Helper\Utils.cs" />
<Compile Include="SetupTmpl.cs"> <Compile Include="SetupTmpl.cs">
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>

View File

@ -0,0 +1,55 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using McMaster.Extensions.CommandLineUtils;
namespace KattekerCreator
{
[Command(Name = "KattekerCreator", Description = "Creates Installation and Update packages.")]
[HelpOption("-?")]
public partial class Program
{
private string _changeLog;
private string _programFile;
private string _outputDir;
[Argument(0, Description = "Path to the program file")]
[FileExists]
[Required]
private string ProgramFile
{
get => _programFile;
set => _programFile = Path.GetFullPath(value);
}
[Option("-L|--changelog", Description = "Path of the changelog file")]
private string ChangeLog
{
get => _changeLog;
set => _changeLog = Path.GetFullPath(value);
}
[Option("-C|--channel", Description = "Channel of releasing")]
private string Channel { get; set; }
[Option("-O|--output", Description = "Directory for the output")]
[Required]
private string OutputDir
{
get => _outputDir;
set => _outputDir = Path.GetFullPath(value);
}
[Option("-P|--publish", Description = "Path for output from the point of view of the application")]
private string PublishDir { get; set; }
[Option("-V|--version", Description = "Override version number of the application")]
private string Version { get; set; }
[Option("-F|--filter", Description = "Filter parameter. Use minimatch pattern.")]
private string FilterAsString { get; set; }
private IEnumerable<string> Filter => string.IsNullOrWhiteSpace(FilterAsString) ? Enumerable.Empty<string>() : FilterAsString.Split(';');
}
}

View File

@ -5,66 +5,41 @@ using System.IO;
using System.Linq; using System.Linq;
using Katteker; using Katteker;
using KattekerCreator.Helper; using KattekerCreator.Helper;
using McMaster.Extensions.CommandLineUtils;
namespace KattekerCreator namespace KattekerCreator
{ {
public class Program // ReSharper disable once ClassNeverInstantiated.Global
public partial class Program
{ {
//private const string MakeNsis = @"C:\Program Files (x86)\NSIS\makensis.exe"; private const string MakeNsis = @"C:\Program Files (x86)\NSIS\makensis.exe";
private readonly string _baseDirectory = AppDomain.CurrentDomain.BaseDirectory; private readonly string _baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
private string MakeNsis => Path.Combine(_baseDirectory, "NSIS", "makensis.exe"); //private string MakeNsis => Path.Combine(_baseDirectory, "NSIS", "makensis.exe");
private ApplicationArguments _appArguments;
private AssemblyFileInfo _assemblyFileInfo; private AssemblyFileInfo _assemblyFileInfo;
private TemporaryDirectory _tempDir; private TemporaryDirectory _tempDir;
private Releases _releases; private Releases _releases;
private static int Main(string[] args) private static int Main(string[] args) => CommandLineApplication.Execute<Program>(args);
{
var program = new Program();
try
{
return program.Run(args);
}
catch (Exception ex)
{
Log.WriteErrorLine(ex.Message);
if (ex.InnerException != null)
Log.WriteErrorLine(ex.InnerException.Message);
#if DEBUG
throw;
#else
return -1;
#endif
}
}
private int Run(string[] args) // ReSharper disable once UnusedMember.Local
private int OnExecute(CommandLineApplication app)
{ {
//Parse App-Arguments
var parser = new SimpleCommandLineParser<ApplicationArguments>(args);
if (args.Length == 0)
{
parser.ShowHelp();
return 1924;
}
_appArguments = parser.GetObject();
//Create tempdir //Create tempdir
using (_tempDir = Utils.CreateTempDirectory()) using (_tempDir = Utils.CreateTempDirectory())
{ {
_releases = new Releases(_appArguments.OutputDir); _releases = new Releases(OutputDir);
parser.ShowProgramArguments();
// TODO parser.ShowProgramArguments();
//Modify AppStub //Modify AppStub
var appStubFile = ModifyAppStub(); var appStubFile = ModifyAppStub();
//Acquire infos from Executable. //Acquire infos from Executable.
_assemblyFileInfo = new AssemblyFileInfo(_appArguments, _tempDir.Path); _assemblyFileInfo = new AssemblyFileInfo(ProgramFile, Version, _tempDir.Path);
var configFile = CreateConfigFile(); var configFile = CreateConfigFile();
//Generate NSIS-Script //Generate NSIS-Script
var additionalFiles = new[] var additionalFiles = new[]
{ {
new PhysicalFile(appStubFile, Path.GetFileName(_appArguments.ProgramFile)), new PhysicalFile(appStubFile, Path.GetFileName(ProgramFile)),
new PhysicalFile(configFile, Path.Combine($"app-{_assemblyFileInfo.AssemblyVersion}", Path.GetFileName(configFile) ?? string.Empty)) new PhysicalFile(configFile, Path.Combine($"app-{_assemblyFileInfo.AssemblyVersion}", Path.GetFileName(configFile) ?? string.Empty))
}; };
var templateFile = GenerateNsisTemplate(additionalFiles); var templateFile = GenerateNsisTemplate(additionalFiles);
@ -83,7 +58,7 @@ namespace KattekerCreator
private void CopyAsSetup(string setupFilePath, ReleaseEntry releaseEntry) private void CopyAsSetup(string setupFilePath, ReleaseEntry releaseEntry)
{ {
if (!_releases.IsLatestEntry(releaseEntry)) return; if (!_releases.IsLatestEntry(releaseEntry)) return;
var target = Path.Combine(_appArguments.OutputDir, Constants.SetupFile); var target = Path.Combine(OutputDir, Constants.SetupFile);
File.Delete(target); File.Delete(target);
File.Copy(setupFilePath, target); File.Copy(setupFilePath, target);
} }
@ -109,18 +84,18 @@ namespace KattekerCreator
var setupFile = Path.GetFileName(setupFilePath); var setupFile = Path.GetFileName(setupFilePath);
if (string.IsNullOrEmpty(setupFile)) throw new ArgumentException(); if (string.IsNullOrEmpty(setupFile)) throw new ArgumentException();
if (!File.Exists(setupFilePath)) throw new FileNotFoundException(setupFile); if (!File.Exists(setupFilePath)) throw new FileNotFoundException(setupFile);
if (!Directory.Exists(_appArguments.OutputDir)) Directory.CreateDirectory(_appArguments.OutputDir); if (!Directory.Exists(OutputDir)) Directory.CreateDirectory(OutputDir);
if (!string.IsNullOrEmpty(_appArguments.ChangeLog)) if (!string.IsNullOrEmpty(ChangeLog))
{ {
var changeLogFilename = Path.GetFileName(_appArguments.ChangeLog); var changeLogFilename = Path.GetFileName(ChangeLog);
if (!File.Exists(_appArguments.ChangeLog)) throw new FileNotFoundException(_appArguments.ChangeLog); if (!File.Exists(ChangeLog)) throw new FileNotFoundException(ChangeLog);
File.Copy(_appArguments.ChangeLog, Path.Combine(_appArguments.OutputDir, changeLogFilename), true); File.Copy(ChangeLog, Path.Combine(OutputDir, changeLogFilename), true);
} }
File.Copy(setupFilePath, Path.Combine(_appArguments.OutputDir, setupFile), true); File.Copy(setupFilePath, Path.Combine(OutputDir, setupFile), true);
} }
private string CompileSetupScript(string templateFile) private static string CompileSetupScript(string templateFile)
{ {
if (!File.Exists(MakeNsis)) throw new FileNotFoundException("NSIS not installed properly."); if (!File.Exists(MakeNsis)) throw new FileNotFoundException("NSIS not installed properly.");
int exitcode; int exitcode;
@ -148,9 +123,9 @@ namespace KattekerCreator
var pathToFile = Path.Combine(_tempDir.Path, Constants.KattekerConfig); var pathToFile = Path.Combine(_tempDir.Path, Constants.KattekerConfig);
var kattekerConfig = new KattekerConfig var kattekerConfig = new KattekerConfig
{ {
Publish = _appArguments.PublishDir ?? _appArguments.OutputDir, Publish = PublishDir ?? OutputDir,
Changelog = Path.GetFileName(_appArguments.ChangeLog), Changelog = Path.GetFileName(ChangeLog),
Channel = _appArguments.Channel Channel = Channel
}; };
kattekerConfig.WriteToFile(pathToFile); kattekerConfig.WriteToFile(pathToFile);
return pathToFile; return pathToFile;
@ -160,7 +135,7 @@ namespace KattekerCreator
{ {
var baseFile = new FileInfo(Path.Combine(_baseDirectory, Constants.ExecutionStub)); var baseFile = new FileInfo(Path.Combine(_baseDirectory, Constants.ExecutionStub));
var targetFile = baseFile.CopyTo(Path.Combine(_tempDir.Path, Constants.ExecutionStub)); var targetFile = baseFile.CopyTo(Path.Combine(_tempDir.Path, Constants.ExecutionStub));
Utils.CopyResources(_appArguments.ProgramFile, targetFile.FullName); Utils.CopyResources(ProgramFile, targetFile.FullName);
return targetFile.FullName; return targetFile.FullName;
} }
@ -183,11 +158,11 @@ namespace KattekerCreator
UserInterface = Path.Combine(_baseDirectory, "contrib", "LoadingBar_Icon.exe"), UserInterface = Path.Combine(_baseDirectory, "contrib", "LoadingBar_Icon.exe"),
UninstallIcon = Path.Combine(_baseDirectory, "contrib", "uninstall.ico"), UninstallIcon = Path.Combine(_baseDirectory, "contrib", "uninstall.ico"),
OutFile = Path.GetFileName(Path.ChangeExtension(outFile, "exe")), OutFile = Path.GetFileName(Path.ChangeExtension(outFile, "exe")),
ReleaseChannel = _appArguments.Channel ReleaseChannel = Channel
}; };
var path = Path.GetDirectoryName(_appArguments.ProgramFile) ?? string.Empty; var path = Path.GetDirectoryName(ProgramFile) ?? string.Empty;
setupTmpl.Files.AddRange(additionalFiles); setupTmpl.Files.AddRange(additionalFiles);
var files = Utils.EnumerateFiles(path, _appArguments.Filter).ToArray(); var files = Utils.EnumerateFiles(path, Filter).ToArray();
setupTmpl.InstallSize = (long) Math.Floor(files.Sum(x => x.Length) / 1024f); setupTmpl.InstallSize = (long) Math.Floor(files.Sum(x => x.Length) / 1024f);
setupTmpl.Files.AddRange(files.Select(x => new PhysicalFile(x.FullName, x.FullName.Replace(path, $"app-{_assemblyFileInfo.AssemblyVersion}")))); setupTmpl.Files.AddRange(files.Select(x => new PhysicalFile(x.FullName, x.FullName.Replace(path, $"app-{_assemblyFileInfo.AssemblyVersion}"))));
var transformText = setupTmpl.TransformText(); var transformText = setupTmpl.TransformText();

View File

@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="McMaster.Extensions.CommandLineUtils" version="2.2.5" targetFramework="net462" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net462" />
<package id="Vestris.ResourceLib" version="1.6.422" targetFramework="net462" /> <package id="Vestris.ResourceLib" version="1.6.422" targetFramework="net462" />
</packages> </packages>

View File

@ -111,6 +111,7 @@
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="app.config" />
<None Include="packages.config" /> <None Include="packages.config" />
<None Include="testdata\changelog.md"> <None Include="testdata\changelog.md">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

11
Katteker.Test/app.config Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>