178 lines
7.6 KiB
C#

using Katteker;
using KattekerCreator.Helper;
using KattekerCreator.Types;
using McMaster.Extensions.CommandLineUtils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace KattekerCreator
{
internal class Program : ProgramArguments
{
private static readonly string BaseDirectory = AppDomain.CurrentDomain.BaseDirectory;
private static string MakeNsis => Path.Combine(BaseDirectory, "nsis", "makensis.exe");
private AssemblyFileInfo _assemblyFileInfo;
private TemporaryDirectory _tempDir;
private Releases _releases;
static int Main(string[] args)
{
return CommandLineApplication.Execute<Program>(args);
}
protected override int OnExecute(CommandLineApplication app)
{
//Override commandline arguments, if 'ConfigurationPath' is set.
if (TryReadConfigFile(ConfigurationPath, out var dictionary))
{
OverridePropertyValues(this, dictionary);
}
//Create temp-dir
using (_tempDir = TemporaryDirectory.Create())
{
_releases = new Releases(OutputDir);
//Modify AppStub
var appStubFile = ModifyAppStub();
//Acquire infos from Executable.
_assemblyFileInfo = new AssemblyFileInfo(ProgramFile, Version, _tempDir.Path);
var configFile = CreateConfigFile();
//Generate NSIS-Script
var additionalFiles = new[]
{
new PhysicalFile(appStubFile, Path.GetFileName(ProgramFile)),
new PhysicalFile(configFile, Path.Combine($"app-{_assemblyFileInfo.AssemblyVersion}", Path.GetFileName(configFile) ?? string.Empty))
};
var templateFile = GenerateNsisTemplate(additionalFiles);
//Start makensis.exe
var setupFilePath = CompileSetupScript(templateFile);
//TODO Sign setup
Utils.SignExecutable(CertificatePath, CertificatePassword, setupFilePath);
//Copy to Output-Folder
CopyToOutputFolder(setupFilePath);
//Create/Modify RELEASE File
var releaseEntry = AddPackageToReleaseFile(setupFilePath);
//Copy installer as setup.exe
CopyAsSetup(setupFilePath, releaseEntry);
return 0;
}
}
private void CopyToOutputFolder(string setupFilePath)
{
if (setupFilePath == null) throw new ArgumentNullException(nameof(setupFilePath));
var setupFile = Path.GetFileName(setupFilePath);
if (string.IsNullOrEmpty(setupFile)) throw new ArgumentException();
if (!File.Exists(setupFilePath)) throw new FileNotFoundException(setupFile);
if (!Directory.Exists(OutputDir)) Directory.CreateDirectory(OutputDir);
if (!string.IsNullOrEmpty(ChangeLog))
{
var changeLogFilename = Path.GetFileName(ChangeLog);
if (!File.Exists(ChangeLog)) throw new FileNotFoundException(ChangeLog);
File.Copy(ChangeLog, Path.Combine(OutputDir, changeLogFilename), true);
}
File.Copy(setupFilePath, Path.Combine(OutputDir, setupFile), true);
}
private string ModifyAppStub()
{
var baseFile = Path.Combine(BaseDirectory, "contrib", Constants.ExecutionStub);
var targetFile = Path.Combine(_tempDir.Path, Constants.ExecutionStub);
File.Copy(baseFile, targetFile);
Utils.CopyResources(ProgramFile, targetFile);
Utils.SignExecutable(CertificatePath, CertificatePassword, targetFile);
return targetFile;
}
private string CreateConfigFile()
{
var pathToFile = Path.Combine(_tempDir.Path, Constants.KattekerConfig);
var kattekerConfig = new KattekerConfig
{
Publish = PublishDir ?? OutputDir,
Changelog = Path.GetFileName(ChangeLog),
Channel = Channel
};
kattekerConfig.WriteToFile(pathToFile);
return pathToFile;
}
private static string GenerateFilename(string name, string version, string extension, bool isDelta = false) => $"{name}-{version}-{(isDelta ? "delta" : "full")}.{extension}";
private string GenerateNsisTemplate(IEnumerable<PhysicalFile> additionalFiles)
{
try
{
var assemblyName = Path.GetFileNameWithoutExtension(_assemblyFileInfo.FileInfo.Name);
var outFile = Path.Combine(_tempDir.Path, GenerateFilename(assemblyName, _assemblyFileInfo.AssemblyVersion.ToString(), "nsi"));
var setupTemplate = new SetupTemplate
{
Executable = _assemblyFileInfo.FileInfo.Name,
AssemblyName = assemblyName,
AppName = _assemblyFileInfo.ProductName,
CompanyName = _assemblyFileInfo.Company,
Description = _assemblyFileInfo.Description,
IconPath = _assemblyFileInfo.AssemblyIconPath,
Version = _assemblyFileInfo.AssemblyVersion,
HelpUrl = "http://example.org", //Not used at the moment.
UserInterface = Path.Combine(BaseDirectory, "contrib", "LoadingBar_Icon.exe"),
UninstallIcon = Path.Combine(BaseDirectory, "contrib", "uninstall.ico"),
OutFile = Path.GetFileName(Path.ChangeExtension(outFile, "exe")),
ReleaseChannel = Channel
};
var path = Path.GetDirectoryName(ProgramFile) ?? string.Empty;
setupTemplate.Files.AddRange(additionalFiles);
var files = Utils.EnumerateFiles(path, Filter).ToArray();
setupTemplate.InstallSize = (long)Math.Floor(files.Sum(x => x.Length) / 1024f);
setupTemplate.Files.AddRange(files.Select(x => new PhysicalFile(x.FullName, x.FullName.Replace(path, $"app-{_assemblyFileInfo.AssemblyVersion}"))));
var transformText = setupTemplate.TransformText();
File.WriteAllText(outFile, transformText);
return outFile;
}
catch (Exception e)
{
Log.WriteErrorLine(e.Message);
throw;
}
}
private static string CompileSetupScript(string templateFile)
{
if (!File.Exists(MakeNsis)) throw new FileNotFoundException("NSIS not installed properly.");
var exitCode = Utils.ExecuteProcess(MakeNsis, $"\"{templateFile}\"");
if (exitCode != 0) throw new Exception($"{Path.GetFileName(MakeNsis)} has exited with exit code: {exitCode}");
return Path.ChangeExtension(templateFile, "exe");
}
private ReleaseEntry AddPackageToReleaseFile(string setupFilePath)
{
try
{
var result = _releases.Add(setupFilePath, _assemblyFileInfo.AssemblyVersion);
_releases.WriteReleaseFile();
return result;
}
catch (Exception e)
{
Log.WriteErrorLine(e.Message);
throw;
}
}
private void CopyAsSetup(string setupFilePath, ReleaseEntry releaseEntry)
{
if (!_releases.IsLatestEntry(releaseEntry)) return;
var target = Path.Combine(OutputDir, Constants.SetupFile);
File.Delete(target);
File.Copy(setupFilePath, target);
}
}
}