mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Create SquirrelCli project, merge SyncReleases into it, refactor command line args
This commit is contained in:
100
Squirrel.sln
100
Squirrel.sln
@@ -11,8 +11,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Setup", "src\Setup\Setup.vc
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Update", "src\Update\Update.csproj", "{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SyncReleases", "src\SyncReleases\SyncReleases.csproj", "{EB521191-1EBF-4D06-8541-ED192E2EE378}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionLevel", "SolutionLevel", "{ED657D2C-F8A0-4012-A64F-7367D41BE4D2}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
@@ -26,6 +24,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WriteZipToSetup", "src\Writ
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StubExecutable", "src\StubExecutable\StubExecutable.vcxproj", "{C028DB2A-E7C5-4232-8C22-D5FBA2176136}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SquirrelCli", "src\SquirrelCli\SquirrelCli.csproj", "{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
CIBuild|Any CPU = CIBuild|Any CPU
|
||||
@@ -244,54 +244,6 @@ Global
|
||||
{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Release|x64.Build.0 = Release|Any CPU
|
||||
{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Release|x86.Build.0 = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.CIBuild|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.CIBuild|Any CPU.Build.0 = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.CIBuild|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.CIBuild|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.CIBuild|x64.ActiveCfg = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.CIBuild|x64.Build.0 = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.CIBuild|x86.ActiveCfg = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.CIBuild|x86.Build.0 = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Coverage|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Coverage|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Coverage|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Coverage|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Coverage|x64.ActiveCfg = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Coverage|x64.Build.0 = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Coverage|x86.ActiveCfg = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Coverage|x86.Build.0 = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Debug|x64.Build.0 = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Debug|x86.Build.0 = Debug|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Release|x64.ActiveCfg = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Release|x64.Build.0 = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Release|x86.ActiveCfg = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Release|x86.Build.0 = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Release|x64.Build.0 = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{EB521191-1EBF-4D06-8541-ED192E2EE378}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.CIBuild|Any CPU.ActiveCfg = Debug|Win32
|
||||
{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.CIBuild|Any CPU.Build.0 = Debug|Win32
|
||||
{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.CIBuild|Mixed Platforms.ActiveCfg = Release|Win32
|
||||
@@ -386,6 +338,54 @@ Global
|
||||
{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Release|x64.Build.0 = Release|x64
|
||||
{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Release|x86.ActiveCfg = Release|Win32
|
||||
{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Release|x86.Build.0 = Release|Win32
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.CIBuild|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.CIBuild|Any CPU.Build.0 = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.CIBuild|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.CIBuild|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.CIBuild|x64.ActiveCfg = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.CIBuild|x64.Build.0 = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.CIBuild|x86.ActiveCfg = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.CIBuild|x86.Build.0 = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Coverage|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Coverage|Any CPU.Build.0 = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Coverage|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Coverage|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Coverage|x64.ActiveCfg = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Coverage|x64.Build.0 = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Coverage|x86.ActiveCfg = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Coverage|x86.Build.0 = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Mono Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Mono Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Mono Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Mono Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Mono Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Mono Debug|x64.Build.0 = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Mono Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Mono Debug|x86.Build.0 = Debug|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Mono Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Mono Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Mono Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Mono Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Mono Release|x64.ActiveCfg = Release|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Mono Release|x64.Build.0 = Release|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Mono Release|x86.ActiveCfg = Release|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Mono Release|x86.Build.0 = Release|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Release|x64.Build.0 = Release|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{19E8EBF5-0277-422F-BF49-C66D9DBA5AA4}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
10
build.ps1
10
build.ps1
@@ -20,11 +20,11 @@ foreach ($Folder in $Folders) {
|
||||
|
||||
# Build single-exe packaged projects
|
||||
dotnet publish -v minimal -c Release "$PSScriptRoot\src\Update\Update.csproj" -o "$Out"
|
||||
dotnet publish -v minimal -c Release "$PSScriptRoot\src\SyncReleases\SyncReleases.csproj" -o "$Out"
|
||||
dotnet publish -v minimal -c Release "$PSScriptRoot\src\SquirrelCli\SquirrelCli.csproj" -o "$Out"
|
||||
|
||||
# Copy over all files we need
|
||||
Move-Item "$Out\Update.exe" -Destination "$Out\Squirrel.exe"
|
||||
Move-Item "$Out\Update.com" -Destination "$Out\Squirrel.com"
|
||||
# Move-Item "$Out\Update.exe" -Destination "$Out\Squirrel.exe"
|
||||
# Move-Item "$Out\Update.com" -Destination "$Out\Squirrel.com"
|
||||
|
||||
# Move-Item "$Out\Update.pdb" -Destination "$Out\Squirrel.pdb"
|
||||
# New-Item -Path "$Out\lib" -ItemType "directory" | Out-Null
|
||||
@@ -38,7 +38,9 @@ Copy-Item "$In\Win32\WriteZipToSetup.pdb" -Destination "$Out"
|
||||
|
||||
Copy-Item -Path "$PSScriptRoot\vendor\7zip\*" -Destination "$Out" -Recurse
|
||||
Copy-Item -Path "$PSScriptRoot\vendor\wix\*" -Destination "$Out" -Recurse
|
||||
Copy-Item "$PSScriptRoot\.nuget\NuGet.exe" -Destination "$Out"
|
||||
Copy-Item "$PSScriptRoot\vendor\NuGet.exe" -Destination "$Out"
|
||||
Copy-Item "$PSScriptRoot\vendor\rcedit.exe" -Destination "$Out"
|
||||
Copy-Item "$PSScriptRoot\vendor\signtool.exe" -Destination "$Out"
|
||||
|
||||
Remove-Item "$Out\*.pdb"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Squirrel.Update
|
||||
namespace Squirrel.Lib
|
||||
{
|
||||
internal static class AuthenticodeTools
|
||||
{
|
||||
193
src/Squirrel/Lib/ValidatedOptionSet.cs
Normal file
193
src/Squirrel/Lib/ValidatedOptionSet.cs
Normal file
@@ -0,0 +1,193 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Mono.Options;
|
||||
|
||||
namespace Squirrel.Lib
|
||||
{
|
||||
internal class OptionValidationException : Exception
|
||||
{
|
||||
public OptionValidationException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public OptionValidationException(string propertyName, string message) : base($"Argument '{propertyName}': {message}")
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class ValidatedOptionSet : OptionSet
|
||||
{
|
||||
protected virtual bool IsNullOrDefault(string propertyName)
|
||||
{
|
||||
var p = this.GetType().GetProperty(propertyName);
|
||||
object argument = p.GetValue(this, null);
|
||||
|
||||
// deal with normal scenarios
|
||||
if (argument == null) return true;
|
||||
|
||||
// deal with non-null nullables
|
||||
Type methodType = argument.GetType();
|
||||
if (Nullable.GetUnderlyingType(methodType) != null) return false;
|
||||
|
||||
// deal with boxed value types
|
||||
Type argumentType = argument.GetType();
|
||||
if (argumentType.IsValueType && argumentType != methodType) {
|
||||
object obj = Activator.CreateInstance(argument.GetType());
|
||||
return obj.Equals(argument);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected virtual void IsRequired(params string[] propertyNames)
|
||||
{
|
||||
foreach (var property in propertyNames) {
|
||||
IsRequired(property);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void IsRequired(string propertyName)
|
||||
{
|
||||
if (IsNullOrDefault(propertyName))
|
||||
throw new OptionValidationException($"Argument '{propertyName}' is required");
|
||||
}
|
||||
|
||||
protected virtual void IsValidFile(string propertyName)
|
||||
{
|
||||
var p = this.GetType().GetProperty(propertyName);
|
||||
var path = p.GetValue(this, null) as string;
|
||||
if (path != null)
|
||||
if (!File.Exists(path))
|
||||
throw new OptionValidationException($"Argument '{propertyName}': Expected file to exist at this location but no file was found");
|
||||
}
|
||||
|
||||
protected virtual void IsValidUrl(string propertyName)
|
||||
{
|
||||
var p = this.GetType().GetProperty(propertyName);
|
||||
var val = p.GetValue(this, null) as string;
|
||||
if (val != null)
|
||||
if (!Utility.IsHttpUrl(val))
|
||||
throw new OptionValidationException(propertyName, "Must start with http or https and be a valid URI.");
|
||||
|
||||
}
|
||||
|
||||
public abstract void Validate();
|
||||
|
||||
public virtual void WriteOptionDescriptions()
|
||||
{
|
||||
WriteOptionDescriptions(Console.Out);
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class CommandAction
|
||||
{
|
||||
public string Command { get; protected set; }
|
||||
public string Description { get; protected set; }
|
||||
public abstract void Execute(IEnumerable<string> args);
|
||||
public abstract void PrintHelp();
|
||||
}
|
||||
|
||||
internal class CommandAction<T> : CommandAction where T : ValidatedOptionSet, new()
|
||||
{
|
||||
public T Options { get; }
|
||||
public Action<T> Action { get; }
|
||||
|
||||
public CommandAction(string command, string description, T options, Action<T> action)
|
||||
{
|
||||
Command = command;
|
||||
Description = description;
|
||||
Options = options;
|
||||
Action = action;
|
||||
}
|
||||
|
||||
public override void Execute(IEnumerable<string> args)
|
||||
{
|
||||
Options.Parse(args);
|
||||
Options.Validate();
|
||||
Action(Options);
|
||||
}
|
||||
|
||||
public override void PrintHelp()
|
||||
{
|
||||
Options.WriteOptionDescriptions();
|
||||
}
|
||||
}
|
||||
|
||||
internal class CommandSet : List<CommandAction>
|
||||
{
|
||||
//public CommandSet() : base(StringComparer.InvariantCultureIgnoreCase) { }
|
||||
|
||||
public void Add<T>(string command, string description, T options, Action<T> action) where T : ValidatedOptionSet, new()
|
||||
{
|
||||
this.Add(new CommandAction<T>(command, description, options, action));
|
||||
}
|
||||
|
||||
public virtual void Execute(string[] args)
|
||||
{
|
||||
if (args.Length == 0)
|
||||
throw new OptionValidationException("Must specify a command to execute.");
|
||||
|
||||
var combined = String.Join(" ", args);
|
||||
CommandAction cmd = null;
|
||||
|
||||
foreach (var k in this.OrderByDescending(k => k.Command.Length)) {
|
||||
if (combined.StartsWith(k.Command, StringComparison.InvariantCultureIgnoreCase)) {
|
||||
cmd = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd == null)
|
||||
throw new OptionValidationException($"Command was not specified or does not exist.");
|
||||
|
||||
cmd.Execute(combined.Substring(cmd.Command.Length).Split(' '));
|
||||
}
|
||||
|
||||
public virtual void WriteHelp()
|
||||
{
|
||||
var exeName = Path.GetFileName(AssemblyRuntimeInfo.EntryExePath);
|
||||
Console.WriteLine($"Usage: {exeName} [command] [options]");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Commands:");
|
||||
|
||||
var array = this.ToArray();
|
||||
for (var i = 0; i < array.Length; i++) {
|
||||
var c = array[i];
|
||||
|
||||
// print command name + desc
|
||||
Console.WriteLine();
|
||||
Utility.ConsoleWriteWithColor(c.Command, ConsoleColor.Blue);
|
||||
if (!String.IsNullOrWhiteSpace(c.Description))
|
||||
Console.Write(": " + c.Description);
|
||||
|
||||
|
||||
//Console.Write(c.Command);
|
||||
//if(String.IsNullOrWhiteSpace(c.Description))
|
||||
// Console.WriteLine();
|
||||
//else
|
||||
// Console.WriteLine(": " + c.Description);
|
||||
|
||||
|
||||
//Console.Write(c.);
|
||||
|
||||
// group similar command parameters together
|
||||
if (i + 1 < array.Length) {
|
||||
if (c.GetType() == array[i + 1].GetType()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
c.PrintHelp();
|
||||
|
||||
//Console.WriteLine();
|
||||
//c.Value.WriteOptionDescriptions();
|
||||
//Console.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,3 +6,5 @@ using System.Runtime.InteropServices;
|
||||
[assembly: InternalsVisibleTo("Squirrel.Tests")]
|
||||
[assembly: InternalsVisibleTo("Update")]
|
||||
[assembly: InternalsVisibleTo("SyncReleases")]
|
||||
[assembly: InternalsVisibleTo("SquirrelCli")]
|
||||
[assembly: InternalsVisibleTo("Squirrel")]
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<Title>Squirrel</Title>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>9</LangVersion>
|
||||
<AssemblyName>Squirrel.Lib</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -341,16 +341,24 @@ namespace Squirrel
|
||||
}
|
||||
}
|
||||
|
||||
public static string FindHelperExecutable(string toFind, IEnumerable<string> additionalDirs = null)
|
||||
public static string FindHelperExecutable(string toFind, IEnumerable<string> additionalDirs = null, bool throwWhenNotFound = false)
|
||||
{
|
||||
if (File.Exists(toFind))
|
||||
return Path.GetFullPath(toFind);
|
||||
|
||||
additionalDirs = additionalDirs ?? Enumerable.Empty<string>();
|
||||
var dirs = (new[] { AppContext.BaseDirectory, Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) })
|
||||
.Concat(additionalDirs ?? Enumerable.Empty<string>());
|
||||
.Concat(additionalDirs ?? Enumerable.Empty<string>()).Select(Path.GetFullPath);
|
||||
|
||||
var exe = @".\" + toFind;
|
||||
return dirs
|
||||
var result = dirs
|
||||
.Select(x => Path.Combine(x, toFind))
|
||||
.FirstOrDefault(x => File.Exists(x)) ?? exe;
|
||||
.FirstOrDefault(x => File.Exists(x));
|
||||
|
||||
if (result == null && throwWhenNotFound)
|
||||
throw new Exception($"Could not find helper '{exe}'.");
|
||||
|
||||
return result ?? exe;
|
||||
}
|
||||
|
||||
static string find7Zip()
|
||||
@@ -668,6 +676,47 @@ namespace Squirrel
|
||||
return This.Log().LogIfThrows(LogLevel.Error, message, block);
|
||||
}
|
||||
|
||||
public static void WarnIfThrows(this IFullLogger This, Action block, string message = null)
|
||||
{
|
||||
This.LogIfThrows(LogLevel.Warn, message, block);
|
||||
}
|
||||
|
||||
public static Task WarnIfThrows(this IFullLogger This, Func<Task> block, string message = null)
|
||||
{
|
||||
return This.LogIfThrows(LogLevel.Warn, message, block);
|
||||
}
|
||||
|
||||
public static Task<T> WarnIfThrows<T>(this IFullLogger This, Func<Task<T>> block, string message = null)
|
||||
{
|
||||
return This.LogIfThrows(LogLevel.Warn, message, block);
|
||||
}
|
||||
|
||||
public static void ErrorIfThrows(this IFullLogger This, Action block, string message = null)
|
||||
{
|
||||
This.LogIfThrows(LogLevel.Error, message, block);
|
||||
}
|
||||
|
||||
public static Task ErrorIfThrows(this IFullLogger This, Func<Task> block, string message = null)
|
||||
{
|
||||
return This.LogIfThrows(LogLevel.Error, message, block);
|
||||
}
|
||||
|
||||
public static Task<T> ErrorIfThrows<T>(this IFullLogger This, Func<Task<T>> block, string message = null)
|
||||
{
|
||||
return This.LogIfThrows(LogLevel.Error, message, block);
|
||||
}
|
||||
|
||||
public static void ConsoleWriteWithColor(string text, ConsoleColor color)
|
||||
{
|
||||
var fc = Console.ForegroundColor;
|
||||
var bc = Console.BackgroundColor;
|
||||
Console.ForegroundColor = color;
|
||||
Console.BackgroundColor = ConsoleColor.Black;
|
||||
Console.Write(text);
|
||||
Console.ForegroundColor = fc;
|
||||
Console.BackgroundColor = bc;
|
||||
}
|
||||
|
||||
static IFullLogger logger;
|
||||
static IFullLogger Log()
|
||||
{
|
||||
|
||||
129
src/SquirrelCli/Options.cs
Normal file
129
src/SquirrelCli/Options.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Squirrel.Lib;
|
||||
|
||||
namespace SquirrelCli
|
||||
{
|
||||
internal abstract class BaseOptions : ValidatedOptionSet
|
||||
{
|
||||
public string releaseDir { get; private set; } = ".\\Releases";
|
||||
public BaseOptions()
|
||||
{
|
||||
Add("r=|releaseDir=", "Release directory containing releasified packages", v => releaseDir = v);
|
||||
}
|
||||
}
|
||||
|
||||
internal class ReleasifyOptions : BaseOptions
|
||||
{
|
||||
public string package { get; set; }
|
||||
public string splashImage { get; private set; }
|
||||
public string iconPath { get; private set; }
|
||||
public string signParams { get; private set; }
|
||||
public string framework { get; private set; }
|
||||
public bool noDelta { get; private set; }
|
||||
public string baseUrl { get; private set; }
|
||||
|
||||
public ReleasifyOptions()
|
||||
{
|
||||
Add("p=|package=", "Path to a nuget package to releasify", v => package = v);
|
||||
Add("s=|splashImage=", "Image to be displayed during installation (can be jpg, png, gif, etc)", v => splashImage = v);
|
||||
Add("i=|iconPath=", "Ico file that will be used where possible", v => iconPath = v);
|
||||
Add("n=|signParams=", "Sign the installer via SignTool.exe with the parameters given", v => signParams = v);
|
||||
Add("f=|framework=", "Set the required .NET framework version, e.g. net461", v => framework = v);
|
||||
Add("no-delta", "Don't generate delta packages to save time", v => noDelta = true);
|
||||
Add("b=|baseUrl=", "Provides a base URL to prefix the RELEASES file packages with", v => baseUrl = v, true);
|
||||
}
|
||||
|
||||
public override void Validate()
|
||||
{
|
||||
IsValidFile(nameof(iconPath));
|
||||
IsValidFile(nameof(splashImage));
|
||||
IsValidUrl(nameof(baseUrl));
|
||||
IsRequired(nameof(package));
|
||||
IsValidFile(nameof(package));
|
||||
}
|
||||
}
|
||||
|
||||
internal class PackOptions : ReleasifyOptions
|
||||
{
|
||||
public string packName { get; private set; }
|
||||
public string packVersion { get; private set; }
|
||||
public string packAuthors { get; private set; }
|
||||
public string packDirectory { get; private set; }
|
||||
|
||||
public PackOptions()
|
||||
{
|
||||
Add("packName=", "desc", v => packName = v);
|
||||
Add("packVersion=", "desc", v => packVersion = v);
|
||||
Add("packAuthors=", "desc", v => packAuthors = v);
|
||||
Add("packDirectory=", "desc", v => packDirectory = v);
|
||||
|
||||
// remove 'package' argument
|
||||
Remove("package");
|
||||
Remove("p");
|
||||
}
|
||||
|
||||
public override void Validate()
|
||||
{
|
||||
IsRequired(nameof(packName), nameof(packVersion), nameof(packAuthors), nameof(packDirectory));
|
||||
IsValidFile(nameof(iconPath));
|
||||
IsValidFile(nameof(splashImage));
|
||||
IsValidUrl(nameof(baseUrl));
|
||||
}
|
||||
}
|
||||
|
||||
internal class SyncBackblazeOptions : BaseOptions
|
||||
{
|
||||
public string b2KeyId { get; private set; }
|
||||
public string b2AppKey { get; private set; }
|
||||
public string b2BucketId { get; private set; }
|
||||
|
||||
public SyncBackblazeOptions()
|
||||
{
|
||||
Add("b2BucketId=", "Id or name of the bucket in B2, S3, etc", v => b2BucketId = v);
|
||||
Add("b2keyid=", "B2 Auth Key Id", v => b2KeyId = v);
|
||||
Add("b2key=", "B2 Auth Key", v => b2AppKey = v);
|
||||
}
|
||||
|
||||
public override void Validate()
|
||||
{
|
||||
IsRequired(nameof(b2KeyId), nameof(b2AppKey), nameof(b2BucketId));
|
||||
}
|
||||
}
|
||||
|
||||
internal class SyncHttpOptions : BaseOptions
|
||||
{
|
||||
public string url { get; private set; }
|
||||
public string token { get; private set; }
|
||||
|
||||
public SyncHttpOptions()
|
||||
{
|
||||
Add("url=", "Url to the simple http folder where the releases are found", v => url = v);
|
||||
}
|
||||
|
||||
public override void Validate()
|
||||
{
|
||||
IsRequired(nameof(url));
|
||||
}
|
||||
}
|
||||
|
||||
internal class SyncGithubOptions : BaseOptions
|
||||
{
|
||||
public string repoUrl { get; private set; }
|
||||
public string token { get; private set; }
|
||||
|
||||
public SyncGithubOptions()
|
||||
{
|
||||
Add("repoUrl=", "Url to the github repository (eg. 'https://github.com/myname/myrepo')", v => repoUrl = v);
|
||||
Add("token=", "The oauth token to use as login credentials", v => token = v);
|
||||
}
|
||||
|
||||
public override void Validate()
|
||||
{
|
||||
IsRequired(nameof(repoUrl));
|
||||
}
|
||||
}
|
||||
}
|
||||
407
src/SquirrelCli/Program.cs
Normal file
407
src/SquirrelCli/Program.cs
Normal file
@@ -0,0 +1,407 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Mono.Options;
|
||||
using Squirrel;
|
||||
using Squirrel.Json;
|
||||
using Squirrel.Lib;
|
||||
using Squirrel.NuGet;
|
||||
using Squirrel.SimpleSplat;
|
||||
using SquirrelCli.Sources;
|
||||
|
||||
namespace SquirrelCli
|
||||
{
|
||||
class Program : IEnableLogger
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
//var pg = new Program();
|
||||
var commands = new CommandSet {
|
||||
{ "releasify", "Take an existing nuget package and turn it into a Squirrel release", new ReleasifyOptions(), Releasify },
|
||||
{ "pack", "Creates a nuget package from a folder and releasifies it in a single step", new PackOptions(), Pack },
|
||||
{ "b2-down", "Download recent releases from BackBlaze B2", new SyncBackblazeOptions(), o => new BackblazeRepository(o).DownloadRecentPackages().Wait() },
|
||||
{ "b2-up", "Upload releases to BackBlaze B2", new SyncBackblazeOptions(), o => new BackblazeRepository(o).UploadMissingPackages().Wait() },
|
||||
{ "http-down", "Download recent releases from an HTTP source", new SyncHttpOptions(), o => new SimpleWebRepository(o).DownloadRecentPackages().Wait() },
|
||||
//{ "http-up", "sync", new SyncHttpOptions(), o => new SimpleWebRepository(o).UploadMissingPackages().Wait() },
|
||||
{ "github-down", "Download recent releases from GitHub", new SyncGithubOptions(), o => new GitHubRepository(o).DownloadRecentPackages().Wait() },
|
||||
//{ "github-up", "sync", new SyncGithubOptions(), o => new GitHubRepository(o).UploadMissingPackages().Wait() },
|
||||
};
|
||||
|
||||
var logger = new ConsoleLogger();
|
||||
|
||||
try {
|
||||
// check for help argument
|
||||
bool help = false;
|
||||
new OptionSet() { { "h|?|help", _ => help = true }, }.Parse(args);
|
||||
if (help) {
|
||||
commands.WriteHelp();
|
||||
return -1;
|
||||
} else {
|
||||
// parse cli and run command
|
||||
SquirrelLocator.CurrentMutable.Register(() => logger, typeof(Squirrel.SimpleSplat.ILogger));
|
||||
commands.Execute(args);
|
||||
}
|
||||
return 0;
|
||||
} catch (Exception ex) {
|
||||
Console.WriteLine();
|
||||
logger.Write(ex.ToString(), LogLevel.Error);
|
||||
Console.WriteLine();
|
||||
commands.WriteHelp();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static IFullLogger Log => SquirrelLocator.Current.GetService<ILogManager>().GetLogger(typeof(Program));
|
||||
|
||||
static string[] VendorDirs => new string[] {
|
||||
Path.Combine(AssemblyRuntimeInfo.BaseDirectory, "..", "..", "..", "vendor")
|
||||
};
|
||||
static string BootstrapperPath => Utility.FindHelperExecutable("Setup.exe", throwWhenNotFound: true);
|
||||
static string UpdatePath => Utility.FindHelperExecutable("Update.exe", throwWhenNotFound: true);
|
||||
static string NugetPath => Utility.FindHelperExecutable("NuGet.exe", VendorDirs, throwWhenNotFound: true);
|
||||
|
||||
static void Pack(PackOptions options)
|
||||
{
|
||||
using (Utility.WithTempDirectory(out var tmpDir)) {
|
||||
string nuspec = $@"
|
||||
<?xml version=""1.0"" encoding=""utf-8""?>
|
||||
<package>
|
||||
<metadata>
|
||||
<id>{options.packName}</id>
|
||||
<title>{options.packName}</title>
|
||||
<description>{options.packName}</description>
|
||||
<authors>{options.packAuthors}</authors>
|
||||
<version>0</version>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src=""**"" target=""lib\app\"" exclude=""*.pdb;*.nupkg;*.vshost.*""/>
|
||||
</files>
|
||||
</package>
|
||||
".Trim();
|
||||
var nuspecPath = Path.Combine(tmpDir, options.packName + ".nuspec");
|
||||
File.WriteAllText(nuspecPath, nuspec);
|
||||
|
||||
var args = $"pack \"{nuspecPath}\" -BasePath \"{options.packDirectory}\" -OutputDirectory \"{tmpDir}\" -Version {options.packVersion}";
|
||||
|
||||
Log.Info($"Packing '{options.packDirectory}' into nupkg.");
|
||||
var res = Utility.InvokeProcessAsync(NugetPath, args, CancellationToken.None).Result;
|
||||
|
||||
if (res.Item1 != 0)
|
||||
throw new Exception($"Failed nuget pack (exit {res.Item1}): \r\n " + res.Item2);
|
||||
|
||||
var nupkgPath = Directory.EnumerateFiles(tmpDir).Where(f => f.EndsWith(".nupkg")).FirstOrDefault();
|
||||
if (nupkgPath == null)
|
||||
throw new Exception($"Failed to generate nupkg, unspecified error");
|
||||
|
||||
options.package = nupkgPath;
|
||||
Releasify(options);
|
||||
}
|
||||
}
|
||||
|
||||
static void Releasify(ReleasifyOptions options)
|
||||
{
|
||||
var targetDir = options.releaseDir ?? Path.Combine(".", "Releases");
|
||||
if (!Directory.Exists(targetDir)) {
|
||||
Directory.CreateDirectory(targetDir);
|
||||
}
|
||||
|
||||
var frameworkVersion = options.framework;
|
||||
var signingOpts = options.signParams;
|
||||
var package = options.package;
|
||||
var baseUrl = options.baseUrl;
|
||||
var generateDeltas = !options.noDelta;
|
||||
var backgroundGif = options.splashImage;
|
||||
var setupIcon = options.iconPath;
|
||||
|
||||
// validate that the provided "frameworkVersion" is supported by Setup.exe
|
||||
if (!String.IsNullOrWhiteSpace(frameworkVersion)) {
|
||||
var chkFrameworkResult = Utility.InvokeProcessAsync(BootstrapperPath, "--checkFramework " + frameworkVersion, CancellationToken.None).Result;
|
||||
if (chkFrameworkResult.Item1 != 0) {
|
||||
throw new ArgumentException($"Unsupported FrameworkVersion: '{frameworkVersion}'. {chkFrameworkResult.Item2}");
|
||||
}
|
||||
}
|
||||
|
||||
// copy input package to target output directory
|
||||
if (!package.EndsWith(".nupkg", StringComparison.InvariantCultureIgnoreCase))
|
||||
throw new ArgumentException("package must be packed with nuget and end in '.nupkg'");
|
||||
var di = new DirectoryInfo(targetDir);
|
||||
File.Copy(package, Path.Combine(di.FullName, Path.GetFileName(package)), true);
|
||||
|
||||
var allNuGetFiles = di.EnumerateFiles()
|
||||
.Where(x => x.Name.EndsWith(".nupkg", StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
var toProcess = allNuGetFiles.Where(x => !x.Name.Contains("-delta") && !x.Name.Contains("-full"));
|
||||
var processed = new List<string>();
|
||||
|
||||
var releaseFilePath = Path.Combine(di.FullName, "RELEASES");
|
||||
var previousReleases = new List<ReleaseEntry>();
|
||||
if (File.Exists(releaseFilePath)) {
|
||||
previousReleases.AddRange(ReleaseEntry.ParseReleaseFile(File.ReadAllText(releaseFilePath, Encoding.UTF8)));
|
||||
}
|
||||
|
||||
foreach (var file in toProcess) {
|
||||
Log.Info("Creating release package: " + file.FullName);
|
||||
|
||||
var rp = new ReleasePackage(file.FullName);
|
||||
rp.CreateReleasePackage(Path.Combine(di.FullName, rp.SuggestedReleaseFileName), contentsPostProcessHook: pkgPath => {
|
||||
|
||||
// create sub executable for all exe's in this package (except Squirrel!)
|
||||
new DirectoryInfo(pkgPath).GetAllFilesRecursively()
|
||||
.Where(x => x.Name.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase))
|
||||
.Where(x => !x.Name.Contains("squirrel.exe", StringComparison.InvariantCultureIgnoreCase))
|
||||
.Where(x => Utility.IsFileTopLevelInPackage(x.FullName, pkgPath))
|
||||
.Where(x => Utility.ExecutableUsesWin32Subsystem(x.FullName))
|
||||
.ForEachAsync(x => createExecutableStubForExe(x.FullName))
|
||||
.Wait();
|
||||
|
||||
// copy myself into the package so Squirrel can also be updated
|
||||
// how we find the lib dir is a huge hack here, but 'ReleasePackage' verifies there can only be one of these so it should be fine.
|
||||
var re = new Regex(@"lib[\\\/][^\\\/]*[\\\/]?", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
|
||||
var libDir = Directory
|
||||
.EnumerateDirectories(pkgPath, "*", SearchOption.AllDirectories)
|
||||
.Where(d => re.IsMatch(d))
|
||||
.OrderBy(d => d.Length)
|
||||
.FirstOrDefault();
|
||||
File.Copy(UpdatePath, Path.Combine(libDir, "Squirrel.exe"));
|
||||
|
||||
// sign all exe's in this package
|
||||
if (signingOpts == null) return;
|
||||
new DirectoryInfo(pkgPath).GetAllFilesRecursively()
|
||||
.Where(x => Utility.FileIsLikelyPEImage(x.Name))
|
||||
.ForEachAsync(async x => {
|
||||
if (isPEFileSigned(x.FullName)) {
|
||||
Log.Info("{0} is already signed, skipping", x.FullName);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Info("About to sign {0}", x.FullName);
|
||||
await signPEFile(x.FullName, signingOpts);
|
||||
}, 1)
|
||||
.Wait();
|
||||
});
|
||||
|
||||
processed.Add(rp.ReleasePackageFile);
|
||||
|
||||
var prev = ReleaseEntry.GetPreviousRelease(previousReleases, rp, targetDir);
|
||||
if (prev != null && generateDeltas) {
|
||||
var deltaBuilder = new DeltaPackageBuilder(null);
|
||||
|
||||
var dp = deltaBuilder.CreateDeltaPackage(prev, rp,
|
||||
Path.Combine(di.FullName, rp.SuggestedReleaseFileName.Replace("full", "delta")));
|
||||
processed.Insert(0, dp.InputPackageFile);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var file in toProcess) { File.Delete(file.FullName); }
|
||||
|
||||
var newReleaseEntries = processed
|
||||
.Select(packageFilename => ReleaseEntry.GenerateFromFile(packageFilename, baseUrl))
|
||||
.ToList();
|
||||
var distinctPreviousReleases = previousReleases
|
||||
.Where(x => !newReleaseEntries.Select(e => e.Version).Contains(x.Version));
|
||||
var releaseEntries = distinctPreviousReleases.Concat(newReleaseEntries).ToList();
|
||||
|
||||
ReleaseEntry.WriteReleaseFile(releaseEntries, releaseFilePath);
|
||||
|
||||
var targetSetupExe = Path.Combine(di.FullName, "Setup.exe");
|
||||
var newestFullRelease = Squirrel.EnumerableExtensions.MaxBy(releaseEntries, x => x.Version).Where(x => !x.IsDelta).First();
|
||||
|
||||
File.Copy(BootstrapperPath, targetSetupExe, true);
|
||||
var zipPath = createSetupEmbeddedZip(Path.Combine(di.FullName, newestFullRelease.Filename), di.FullName, signingOpts, setupIcon).Result;
|
||||
|
||||
var writeZipToSetup = Utility.FindHelperExecutable("WriteZipToSetup.exe");
|
||||
|
||||
try {
|
||||
string arguments = $"\"{targetSetupExe}\" \"{zipPath}\"";
|
||||
if (!String.IsNullOrWhiteSpace(frameworkVersion)) {
|
||||
arguments += $" --set-required-framework \"{frameworkVersion}\"";
|
||||
}
|
||||
if (!String.IsNullOrWhiteSpace(backgroundGif)) {
|
||||
arguments += $" --set-splash \"{Path.GetFullPath(backgroundGif)}\"";
|
||||
}
|
||||
|
||||
var result = Utility.InvokeProcessAsync(writeZipToSetup, arguments, CancellationToken.None).Result;
|
||||
if (result.Item1 != 0) throw new Exception("Failed to write Zip to Setup.exe!\n\n" + result.Item2);
|
||||
} catch (Exception ex) {
|
||||
Log.ErrorException("Failed to update Setup.exe with new Zip file", ex);
|
||||
throw;
|
||||
} finally {
|
||||
File.Delete(zipPath);
|
||||
}
|
||||
|
||||
Utility.Retry(() =>
|
||||
setPEVersionInfoAndIcon(targetSetupExe, new ZipPackage(package), setupIcon).Wait());
|
||||
|
||||
if (signingOpts != null) {
|
||||
signPEFile(targetSetupExe, signingOpts).Wait();
|
||||
}
|
||||
|
||||
//if (generateMsi) {
|
||||
// createMsiPackage(targetSetupExe, new ZipPackage(package), packageAs64Bit).Wait();
|
||||
|
||||
// if (signingOpts != null) {
|
||||
// signPEFile(targetSetupExe.Replace(".exe", ".msi"), signingOpts).Wait();
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
static async Task<string> createSetupEmbeddedZip(string fullPackage, string releasesDir, string signingOpts, string setupIcon)
|
||||
{
|
||||
string tempPath;
|
||||
|
||||
Log.Info("Building embedded zip file for Setup.exe");
|
||||
using (Utility.WithTempDirectory(out tempPath, null)) {
|
||||
Log.ErrorIfThrows(() => {
|
||||
File.Copy(UpdatePath, Path.Combine(tempPath, "Update.exe"));
|
||||
File.Copy(fullPackage, Path.Combine(tempPath, Path.GetFileName(fullPackage)));
|
||||
}, "Failed to write package files to temp dir: " + tempPath);
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(setupIcon)) {
|
||||
Log.ErrorIfThrows(() => {
|
||||
File.Copy(setupIcon, Path.Combine(tempPath, "setupIcon.ico"));
|
||||
}, "Failed to write icon to temp dir: " + tempPath);
|
||||
}
|
||||
|
||||
var releases = new[] { ReleaseEntry.GenerateFromFile(fullPackage) };
|
||||
ReleaseEntry.WriteReleaseFile(releases, Path.Combine(tempPath, "RELEASES"));
|
||||
|
||||
var target = Path.GetTempFileName();
|
||||
File.Delete(target);
|
||||
|
||||
// Sign Update.exe so that virus scanners don't think we're
|
||||
// pulling one over on them
|
||||
if (signingOpts != null) {
|
||||
var di = new DirectoryInfo(tempPath);
|
||||
|
||||
var files = di.EnumerateFiles()
|
||||
.Where(x => x.Name.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase))
|
||||
.Select(x => x.FullName);
|
||||
|
||||
await files.ForEachAsync(x => signPEFile(x, signingOpts));
|
||||
}
|
||||
|
||||
Log.ErrorIfThrows(() =>
|
||||
ZipFile.CreateFromDirectory(tempPath, target, CompressionLevel.Optimal, false),
|
||||
"Failed to create Zip file from directory: " + tempPath);
|
||||
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
static async Task signPEFile(string exePath, string signingOpts)
|
||||
{
|
||||
// Try to find SignTool.exe
|
||||
var exe = @".\signtool.exe";
|
||||
if (!File.Exists(exe)) {
|
||||
exe = Path.Combine(AssemblyRuntimeInfo.BaseDirectory, "signtool.exe");
|
||||
|
||||
// Run down PATH and hope for the best
|
||||
if (!File.Exists(exe)) exe = "signtool.exe";
|
||||
}
|
||||
|
||||
var processResult = await Utility.InvokeProcessAsync(exe,
|
||||
String.Format("sign {0} \"{1}\"", signingOpts, exePath), CancellationToken.None);
|
||||
|
||||
if (processResult.Item1 != 0) {
|
||||
var optsWithPasswordHidden = new Regex(@"/p\s+\w+").Replace(signingOpts, "/p ********");
|
||||
var msg = String.Format("Failed to sign, command invoked was: '{0} sign {1} {2}'",
|
||||
exe, optsWithPasswordHidden, exePath);
|
||||
|
||||
throw new Exception(msg);
|
||||
} else {
|
||||
Console.WriteLine(processResult.Item2);
|
||||
}
|
||||
}
|
||||
static bool isPEFileSigned(string path)
|
||||
{
|
||||
try {
|
||||
return AuthenticodeTools.IsTrusted(path);
|
||||
} catch (Exception ex) {
|
||||
Log.ErrorException("Failed to determine signing status for " + path, ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static async Task createExecutableStubForExe(string fullName)
|
||||
{
|
||||
var exe = Utility.FindHelperExecutable(@"StubExecutable.exe");
|
||||
|
||||
var target = Path.Combine(
|
||||
Path.GetDirectoryName(fullName),
|
||||
Path.GetFileNameWithoutExtension(fullName) + "_ExecutionStub.exe");
|
||||
|
||||
await Utility.CopyToAsync(exe, target);
|
||||
|
||||
await Utility.InvokeProcessAsync(
|
||||
Utility.FindHelperExecutable("WriteZipToSetup.exe"),
|
||||
String.Format("--copy-stub-resources \"{0}\" \"{1}\"", fullName, target),
|
||||
CancellationToken.None);
|
||||
}
|
||||
|
||||
static async Task setPEVersionInfoAndIcon(string exePath, IPackage package, string iconPath = null)
|
||||
{
|
||||
var realExePath = Path.GetFullPath(exePath);
|
||||
var company = String.Join(",", package.Authors);
|
||||
var verStrings = new Dictionary<string, string>() {
|
||||
{ "CompanyName", company },
|
||||
{ "LegalCopyright", package.Copyright ?? "Copyright © " + DateTime.Now.Year.ToString() + " " + company },
|
||||
{ "FileDescription", package.Summary ?? package.Description ?? "Installer for " + package.Id },
|
||||
{ "ProductName", package.Description ?? package.Summary ?? package.Id },
|
||||
};
|
||||
|
||||
var args = verStrings.Aggregate(new StringBuilder("\"" + realExePath + "\""), (acc, x) => { acc.AppendFormat(" --set-version-string \"{0}\" \"{1}\"", x.Key, x.Value); return acc; });
|
||||
args.AppendFormat(" --set-file-version {0} --set-product-version {0}", package.Version.ToString());
|
||||
if (iconPath != null) {
|
||||
args.AppendFormat(" --set-icon \"{0}\"", Path.GetFullPath(iconPath));
|
||||
}
|
||||
|
||||
// Try to find rcedit.exe
|
||||
string exe = Utility.FindHelperExecutable("rcedit.exe");
|
||||
|
||||
var processResult = await Utility.InvokeProcessAsync(exe, args.ToString(), CancellationToken.None);
|
||||
|
||||
if (processResult.Item1 != 0) {
|
||||
var msg = String.Format(
|
||||
"Failed to modify resources, command invoked was: '{0} {1}'\n\nOutput was:\n{2}",
|
||||
exe, args, processResult.Item2);
|
||||
|
||||
throw new Exception(msg);
|
||||
} else {
|
||||
Console.WriteLine(processResult.Item2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ConsoleLogger : Squirrel.SimpleSplat.ILogger
|
||||
{
|
||||
readonly object gate = 42;
|
||||
public LogLevel Level { get; set; } = LogLevel.Info;
|
||||
public void Write(string message, LogLevel logLevel)
|
||||
{
|
||||
if (logLevel < Level) {
|
||||
return;
|
||||
}
|
||||
|
||||
lock (gate) {
|
||||
string lvl = logLevel.ToString().Substring(0, 4).ToUpper();
|
||||
if (logLevel == LogLevel.Error || logLevel == LogLevel.Fatal) {
|
||||
Utility.ConsoleWriteWithColor($"[{lvl}] {message}\r\n", ConsoleColor.Red);
|
||||
} else if (logLevel == LogLevel.Warn) {
|
||||
Utility.ConsoleWriteWithColor($"[{lvl}] {message}\r\n", ConsoleColor.Yellow);
|
||||
} else {
|
||||
Console.WriteLine($"[{lvl}] {message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
src/SquirrelCli/SquirrelCli.csproj
Normal file
33
src/SquirrelCli/SquirrelCli.csproj
Normal file
@@ -0,0 +1,33 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<SelfContained>true</SelfContained>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<CompressionInSingleFile>true</CompressionInSingleFile>
|
||||
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
|
||||
<ApplicationIcon>squirrel.ico</ApplicationIcon>
|
||||
<AssemblyName>Squirrel</AssemblyName>
|
||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="squirrel.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Octokit" Version="0.50.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="System.IO" Version="4.3.0" />
|
||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||
<PackageReference Include="System.Security.Cryptography.Algorithms" Version="4.3.1" />
|
||||
<PackageReference Include="B2Net" Version="0.7.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Squirrel\Squirrel.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -8,17 +8,19 @@ using B2Net;
|
||||
using B2Net.Models;
|
||||
using Squirrel;
|
||||
|
||||
namespace Squirrel.SyncReleases.Sources
|
||||
namespace SquirrelCli.Sources
|
||||
{
|
||||
internal class BackblazeRepository : IPackageRepository
|
||||
{
|
||||
private B2StorageProvider _b2;
|
||||
public BackblazeRepository(string keyId, string appKey, string bucketId)
|
||||
private DirectoryInfo releasesDir;
|
||||
public BackblazeRepository(SyncBackblazeOptions options)
|
||||
{
|
||||
_b2 = new B2StorageProvider(keyId, appKey, bucketId);
|
||||
_b2 = new B2StorageProvider(options.b2KeyId, options.b2AppKey, options.b2BucketId);
|
||||
releasesDir = new DirectoryInfo(options.releaseDir);
|
||||
}
|
||||
|
||||
public async Task DownloadRecentPackages(DirectoryInfo releasesDir)
|
||||
public async Task DownloadRecentPackages()
|
||||
{
|
||||
Console.WriteLine("Downloading RELEASES");
|
||||
var releasesBytes = await _b2.DownloadFile("RELEASES");
|
||||
@@ -45,7 +47,7 @@ namespace Squirrel.SyncReleases.Sources
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UploadMissingPackages(DirectoryInfo releasesDir)
|
||||
public async Task UploadMissingPackages()
|
||||
{
|
||||
foreach (var f in releasesDir.GetFiles()) {
|
||||
await _b2.UploadFile(File.ReadAllBytes(f.FullName), f.Name);
|
||||
26
src/SquirrelCli/Sync/GitHubRepository.cs
Normal file
26
src/SquirrelCli/Sync/GitHubRepository.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SquirrelCli.Sources
|
||||
{
|
||||
internal class GitHubRepository : IPackageRepository
|
||||
{
|
||||
private SyncGithubOptions _options;
|
||||
|
||||
public GitHubRepository(SyncGithubOptions options)
|
||||
{
|
||||
_options = options;
|
||||
}
|
||||
|
||||
public Task DownloadRecentPackages()
|
||||
{
|
||||
return SyncImplementations.SyncFromGitHub(_options.repoUrl, _options.token, new DirectoryInfo(_options.releaseDir));
|
||||
}
|
||||
|
||||
public Task UploadMissingPackages()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/SquirrelCli/Sync/IPackageRepository.cs
Normal file
11
src/SquirrelCli/Sync/IPackageRepository.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SquirrelCli.Sources
|
||||
{
|
||||
internal interface IPackageRepository
|
||||
{
|
||||
public Task DownloadRecentPackages();
|
||||
public Task UploadMissingPackages();
|
||||
}
|
||||
}
|
||||
27
src/SquirrelCli/Sync/SimpleWebRepository.cs
Normal file
27
src/SquirrelCli/Sync/SimpleWebRepository.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SquirrelCli.Sources
|
||||
{
|
||||
|
||||
internal class SimpleWebRepository : IPackageRepository
|
||||
{
|
||||
private readonly SyncHttpOptions options;
|
||||
|
||||
public SimpleWebRepository(SyncHttpOptions options)
|
||||
{
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public Task DownloadRecentPackages()
|
||||
{
|
||||
return SyncImplementations.SyncRemoteReleases(new Uri(options.url), new DirectoryInfo(options.releaseDir));
|
||||
}
|
||||
|
||||
public Task UploadMissingPackages()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ using Octokit;
|
||||
using System.Reflection;
|
||||
using System.Net;
|
||||
|
||||
namespace Squirrel.SyncReleases.Sources
|
||||
namespace SquirrelCli.Sources
|
||||
{
|
||||
internal class SyncImplementations
|
||||
{
|
||||
@@ -151,6 +151,7 @@ namespace Squirrel.SyncReleases.Sources
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning disable SYSLIB0014 // Type or member is obsolete
|
||||
class NotBrokenWebClient : WebClient
|
||||
{
|
||||
protected override WebRequest GetWebRequest(Uri address)
|
||||
@@ -164,4 +165,5 @@ namespace Squirrel.SyncReleases.Sources
|
||||
return hwr;
|
||||
}
|
||||
}
|
||||
#pragma warning restore SYSLIB0014 // Type or member is obsolete
|
||||
}
|
||||
45
src/SquirrelCli/app.manifest
Normal file
45
src/SquirrelCli/app.manifest
Normal file
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.2.0.0" name="Squirrel.app"/>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- Windows Vista -->
|
||||
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
|
||||
|
||||
<!-- Windows 7 -->
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
|
||||
|
||||
<!-- Windows 8 -->
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
|
||||
|
||||
<!-- Windows 8.1 -->
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
|
||||
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.Windows.Common-Controls"
|
||||
version="6.0.0.0"
|
||||
processorArchitecture="*"
|
||||
publicKeyToken="6595b64144ccf1df"
|
||||
language="*"
|
||||
/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
|
||||
</assembly>
|
||||
BIN
src/SquirrelCli/squirrel.ico
Normal file
BIN
src/SquirrelCli/squirrel.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 137 KiB |
@@ -1,150 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Mono.Options;
|
||||
using Octokit;
|
||||
using Squirrel.SimpleSplat;
|
||||
using Squirrel;
|
||||
using Squirrel.Json;
|
||||
using Squirrel.SyncReleases.Sources;
|
||||
|
||||
namespace Squirrel.SyncReleases
|
||||
{
|
||||
class Program : IEnableLogger
|
||||
{
|
||||
static OptionSet opts;
|
||||
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
var pg = new Program();
|
||||
try {
|
||||
return pg.main(args).GetAwaiter().GetResult();
|
||||
} catch (Exception ex) {
|
||||
Console.Error.WriteLine(ex);
|
||||
Console.Error.WriteLine("> SyncReleases.exe -h for help");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
async Task<int> main(string[] args)
|
||||
{
|
||||
using (var logger = new SetupLogLogger(false) { Level = Squirrel.SimpleSplat.LogLevel.Info }) {
|
||||
Squirrel.SimpleSplat.SquirrelLocator.CurrentMutable.Register(() => logger, typeof(Squirrel.SimpleSplat.ILogger));
|
||||
|
||||
var releaseDir = default(string);
|
||||
var repoUrl = default(string);
|
||||
var token = default(string);
|
||||
var provider = default(string);
|
||||
var upload = default(bool);
|
||||
var showHelp = default(bool);
|
||||
|
||||
var b2KeyId = default(string);
|
||||
var b2AppKey = default(string);
|
||||
var bucketId = default(string);
|
||||
|
||||
opts = new OptionSet() {
|
||||
"Usage: SyncReleases.exe [OPTS]",
|
||||
"Utility to download from or upload packages to a remote package release repository",
|
||||
"Can be used to fully automate the distribution of new releases from CI or other scripts",
|
||||
"",
|
||||
"Options:",
|
||||
{ "h|?|help", "Display help and exit", v => showHelp = true },
|
||||
{ "r=|releaseDir=", "Path to the local release directory to sync with remote", v => releaseDir = v},
|
||||
{ "u=|url=", "A GitHub repository url, or a remote web url", v => repoUrl = v},
|
||||
{ "t=|token=", "The OAuth token to use as login credentials", v => token = v},
|
||||
{ "p=|provider=", "Specify the release repository type, can be 'github', 'web', or 'b2'", v => provider = v },
|
||||
{ "upload", "Upload releases in the releaseDir to the remote repository", v => upload = true },
|
||||
{ "bucketId=", "Id or name of the bucket in B2, S3, etc", v => bucketId = v },
|
||||
{ "b2keyid=", "B2 Auth Key Id", v => b2KeyId = v },
|
||||
{ "b2key=", "B2 Auth Key", v => b2AppKey = v },
|
||||
};
|
||||
|
||||
opts.Parse(args);
|
||||
|
||||
if (showHelp) {
|
||||
ShowHelp();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(provider)) throw new ArgumentNullException(nameof(provider));
|
||||
if (String.IsNullOrWhiteSpace(releaseDir)) throw new ArgumentNullException(nameof(releaseDir));
|
||||
var releaseDirectoryInfo = new DirectoryInfo(releaseDir ?? Path.Combine(".", "Releases"));
|
||||
if (!releaseDirectoryInfo.Exists) releaseDirectoryInfo.Create();
|
||||
|
||||
IPackageRepository repository;
|
||||
|
||||
if (provider.Equals("github", StringComparison.OrdinalIgnoreCase)) {
|
||||
if (String.IsNullOrWhiteSpace(repoUrl)) throw new ArgumentNullException(nameof(repoUrl));
|
||||
if (String.IsNullOrWhiteSpace(token)) throw new ArgumentNullException(nameof(repoUrl));
|
||||
repository = new GitHubRepository(repoUrl, token);
|
||||
} else if (provider.Equals("web", StringComparison.OrdinalIgnoreCase)) {
|
||||
if (String.IsNullOrWhiteSpace(repoUrl)) throw new ArgumentNullException(nameof(repoUrl));
|
||||
repository = new SimpleWebRepository(new Uri(repoUrl));
|
||||
} else if (provider.Equals("b2", StringComparison.OrdinalIgnoreCase)) {
|
||||
if (String.IsNullOrWhiteSpace(b2KeyId)) throw new ArgumentNullException(nameof(b2KeyId));
|
||||
if (String.IsNullOrWhiteSpace(b2AppKey)) throw new ArgumentNullException(nameof(b2AppKey));
|
||||
if (String.IsNullOrWhiteSpace(bucketId)) throw new ArgumentNullException(nameof(bucketId));
|
||||
repository = new BackblazeRepository(b2KeyId, b2AppKey, bucketId);
|
||||
} else {
|
||||
throw new Exception("Release provider missing or invalid");
|
||||
}
|
||||
|
||||
var mode = upload ? "Uploading" : "Downloading";
|
||||
Console.WriteLine(mode + " using provider " + repository.GetType().Name);
|
||||
|
||||
if (upload) {
|
||||
await repository.UploadMissingPackages(releaseDirectoryInfo);
|
||||
} else {
|
||||
await repository.DownloadRecentPackages(releaseDirectoryInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void ShowHelp()
|
||||
{
|
||||
opts.WriteOptionDescriptions(Console.Out);
|
||||
}
|
||||
}
|
||||
|
||||
class SetupLogLogger : Squirrel.SimpleSplat.ILogger, IDisposable
|
||||
{
|
||||
StreamWriter inner;
|
||||
readonly object gate = 42;
|
||||
public Squirrel.SimpleSplat.LogLevel Level { get; set; }
|
||||
|
||||
public SetupLogLogger(bool saveInTemp)
|
||||
{
|
||||
var dir = saveInTemp ?
|
||||
Path.GetTempPath() :
|
||||
AppContext.BaseDirectory;
|
||||
|
||||
var file = Path.Combine(dir, "SquirrelSetup.log");
|
||||
if (File.Exists(file)) File.Delete(file);
|
||||
|
||||
inner = new StreamWriter(file, false, Encoding.UTF8);
|
||||
}
|
||||
|
||||
public void Write(string message, LogLevel logLevel)
|
||||
{
|
||||
if (logLevel < Level) {
|
||||
return;
|
||||
}
|
||||
|
||||
lock (gate) inner.WriteLine(message);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (gate) inner.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Squirrel.SyncReleases.Sources
|
||||
{
|
||||
internal class GitHubRepository : IPackageRepository
|
||||
{
|
||||
public string RepoUrl { get; }
|
||||
public string Token { get; }
|
||||
|
||||
public GitHubRepository(string repoUrl, string token)
|
||||
{
|
||||
RepoUrl = repoUrl;
|
||||
Token = token;
|
||||
}
|
||||
|
||||
public Task DownloadRecentPackages(DirectoryInfo releasesDir)
|
||||
{
|
||||
return SyncImplementations.SyncFromGitHub(RepoUrl, Token, releasesDir);
|
||||
}
|
||||
|
||||
public Task UploadMissingPackages(DirectoryInfo releasesDir)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Squirrel.SyncReleases.Sources
|
||||
{
|
||||
internal interface IPackageRepository
|
||||
{
|
||||
public Task DownloadRecentPackages(DirectoryInfo releasesDir);
|
||||
public Task UploadMissingPackages(DirectoryInfo releasesDir);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Squirrel.SyncReleases.Sources
|
||||
{
|
||||
|
||||
internal class SimpleWebRepository : IPackageRepository
|
||||
{
|
||||
public Uri TargetUri { get; }
|
||||
|
||||
public SimpleWebRepository(Uri targetUri)
|
||||
{
|
||||
TargetUri = targetUri;
|
||||
}
|
||||
|
||||
public Task DownloadRecentPackages(DirectoryInfo releasesDir)
|
||||
{
|
||||
return SyncImplementations.SyncRemoteReleases(TargetUri, releasesDir);
|
||||
}
|
||||
|
||||
public Task UploadMissingPackages(DirectoryInfo releasesDir)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<LangVersion>9</LangVersion>
|
||||
<RootNamespace>Squirrel.SyncReleases</RootNamespace>
|
||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<SelfContained>true</SelfContained>
|
||||
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
|
||||
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Octokit" Version="0.50.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="System.IO" Version="4.3.0" />
|
||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||
<PackageReference Include="System.Security.Cryptography.Algorithms" Version="4.3.1" />
|
||||
<PackageReference Include="B2Net" Version="0.7.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Squirrel\Squirrel.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -13,6 +13,7 @@ using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Squirrel.NuGet;
|
||||
using Squirrel.Lib;
|
||||
|
||||
namespace Squirrel.Update
|
||||
{
|
||||
|
||||
Binary file not shown.
@@ -22,12 +22,6 @@
|
||||
<ApplicationIcon>update.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="rcedit.exe" CopyToOutputDirectory="PreserveNewest" />
|
||||
<None Include="signtool.exe" CopyToOutputDirectory="PreserveNewest" />
|
||||
<None Include="update.com" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Squirrel\Squirrel.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
0
.nuget/NuGet.exe → vendor/NuGet.exe
vendored
0
.nuget/NuGet.exe → vendor/NuGet.exe
vendored
Reference in New Issue
Block a user