Add --shortcuts property to cli and pass through to nuspec

This commit is contained in:
Caelan Sayler
2024-05-24 16:50:40 +01:00
parent 242f5a9283
commit d4fc0d62f9
8 changed files with 76 additions and 28 deletions

View File

@@ -91,6 +91,8 @@ public class PackTask : MSBuildAsyncTask
public string? Categories { get; set; } public string? Categories { get; set; }
public string? Shortcuts { get; set; }
protected override async Task<bool> ExecuteAsync(CancellationToken cancellationToken) protected override async Task<bool> ExecuteAsync(CancellationToken cancellationToken)
{ {
//System.Diagnostics.Debugger.Launch(); //System.Diagnostics.Debugger.Launch();

View File

@@ -22,6 +22,7 @@
<VelopackPackTitle Condition="'$(VelopackPackTitle)' == ''">$(Product)</VelopackPackTitle> <VelopackPackTitle Condition="'$(VelopackPackTitle)' == ''">$(Product)</VelopackPackTitle>
<VelopackPackAuthors Condition="'$(VelopackPackAuthors)' == ''">$(Authors)</VelopackPackAuthors> <VelopackPackAuthors Condition="'$(VelopackPackAuthors)' == ''">$(Authors)</VelopackPackAuthors>
<VelopackTargetRuntime Condition="'$(VelopackTargetRuntime)' == ''">$(RuntimeIdentifier)</VelopackTargetRuntime> <VelopackTargetRuntime Condition="'$(VelopackTargetRuntime)' == ''">$(RuntimeIdentifier)</VelopackTargetRuntime>
<VelopackShortcuts Condition="'$(VelopackShortcuts)' == ''">Desktop,StartMenuRoot</VelopackShortcuts>
<!-- Allows a cross platform app (eg. Avalonia) to specify all three via csproj and have them applied correctly --> <!-- Allows a cross platform app (eg. Avalonia) to specify all three via csproj and have them applied correctly -->
<!-- TODO: this should probably switch based on the target RID and not the current OS, but we currently don't <!-- TODO: this should probably switch based on the target RID and not the current OS, but we currently don't
@@ -88,6 +89,7 @@
SignParallel="$(VelopackSignParallel)" SignParallel="$(VelopackSignParallel)"
SignTemplate="$(VelopackSignTemplate)" SignTemplate="$(VelopackSignTemplate)"
Categories="$(VelopackCategories)" Categories="$(VelopackCategories)"
Shortcuts="$(VelopackShortcuts)"
/> />
</Target> </Target>

View File

@@ -36,6 +36,10 @@ public class WindowsPackCommandRunner : PackageBuilder<WindowsPackOptions>
Log.Info("Skipping VelopackApp.Build.Run() check."); Log.Info("Skipping VelopackApp.Build.Run() check.");
} }
// add nuspec metadata
ExtraNuspecMetadata["runtimeDependencies"] = GetRuntimeDependencies();
ExtraNuspecMetadata["shortcutLocations"] = GetShortcutLocations();
// copy files to temp dir, so we can modify them // copy files to temp dir, so we can modify them
var dir = TempDir.CreateSubdirectory("PreprocessPackDirWin"); var dir = TempDir.CreateSubdirectory("PreprocessPackDirWin");
CopyFiles(new DirectoryInfo(packDir), dir, progress, true); CopyFiles(new DirectoryInfo(packDir), dir, progress, true);
@@ -76,7 +80,32 @@ public class WindowsPackCommandRunner : PackageBuilder<WindowsPackOptions>
return Task.FromResult(packDir); return Task.FromResult(packDir);
} }
protected override string GetRuntimeDependencies() protected string GetShortcutLocations()
{
if (String.IsNullOrWhiteSpace(Options.Shortcuts))
return null;
try {
var shortcuts = Options.Shortcuts.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Trim())
.Select(x => (ShortcutLocation) Enum.Parse(typeof(ShortcutLocation), x, true))
.ToList();
if (shortcuts.Count == 0)
return null;
var shortcutString = string.Join(",", shortcuts.Select(x => x.ToString()));
Log.Debug($"Shortcut Locations: {shortcutString}");
return shortcutString;
} catch (Exception ex) {
throw new UserInfoException(
$"Invalid shortcut locations '{Options.Shortcuts}'. " +
$"Valid values for comma delimited list are: {string.Join(", ", Enum.GetNames(typeof(ShortcutLocation)))}." +
$"Error was {ex.Message}");
}
}
protected string GetRuntimeDependencies()
{ {
if (string.IsNullOrWhiteSpace(Options.Runtimes)) if (string.IsNullOrWhiteSpace(Options.Runtimes))
return ""; return "";

View File

@@ -21,4 +21,6 @@ public class WindowsPackOptions : WindowsReleasifyOptions, INugetPackCommand, IP
public bool NoPortable { get; set; } public bool NoPortable { get; set; }
public bool NoInst { get; set; } public bool NoInst { get; set; }
public string Shortcuts { get; set; }
} }

View File

@@ -30,7 +30,7 @@ public abstract class PackageBuilder<T> : ICommand<T>
protected string Channel { get; private set; } protected string Channel { get; private set; }
protected string RuntimeDependencies { get; private set; } protected Dictionary<string, string> ExtraNuspecMetadata { get; } = new();
private readonly Regex REGEX_EXCLUDES = new Regex(@".*[\\\/]createdump.*|.*\.vshost\..*|.*\.nupkg$", RegexOptions.IgnoreCase | RegexOptions.Compiled); private readonly Regex REGEX_EXCLUDES = new Regex(@".*[\\\/]createdump.*|.*\.vshost\..*|.*\.nupkg$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
@@ -91,7 +91,6 @@ public abstract class PackageBuilder<T> : ICommand<T>
using var _1 = Utility.GetTempDirectory(out var pkgTempDir); using var _1 = Utility.GetTempDirectory(out var pkgTempDir);
TempDir = new DirectoryInfo(pkgTempDir); TempDir = new DirectoryInfo(pkgTempDir);
Options = options; Options = options;
RuntimeDependencies = GetRuntimeDependencies();
ConcurrentBag<(string from, string to)> filesToCopy = new(); ConcurrentBag<(string from, string to)> filesToCopy = new();
@@ -168,11 +167,6 @@ public abstract class PackageBuilder<T> : ICommand<T>
}); });
} }
protected virtual string GetRuntimeDependencies()
{
return null;
}
protected abstract string[] GetMainExeSearchPaths(string packDirectory, string mainExeName); protected abstract string[] GetMainExeSearchPaths(string packDirectory, string mainExeName);
protected virtual string GenerateNuspecContent() protected virtual string GenerateNuspecContent()
@@ -184,29 +178,35 @@ public abstract class PackageBuilder<T> : ICommand<T>
var releaseNotes = Options.ReleaseNotes; var releaseNotes = Options.ReleaseNotes;
var rid = Options.TargetRuntime; var rid = Options.TargetRuntime;
string releaseNotesText = ""; string extraMetadata = "";
void addMetadata(string key, string value)
{
if (!String.IsNullOrEmpty(key) && !String.IsNullOrEmpty(value)) {
if (!SecurityElement.IsValidText(value)) {
value = $"""<![CDATA[{"\n"}{value}{"\n"}]]>""";
}
extraMetadata += $"<{key}>{value}</{key}>{Environment.NewLine}";
}
}
if (ExtraNuspecMetadata.Any()) {
foreach (var kvp in ExtraNuspecMetadata) {
addMetadata(kvp.Key, kvp.Value);
}
}
if (!String.IsNullOrEmpty(releaseNotes)) { if (!String.IsNullOrEmpty(releaseNotes)) {
var markdown = File.ReadAllText(releaseNotes); var markdown = File.ReadAllText(releaseNotes);
var html = Markdown.ToHtml(markdown); addMetadata("releaseNotes", markdown);
releaseNotesText = $""" addMetadata("releaseNotesHtml", Markdown.ToHtml(markdown));
<releaseNotes>{SecurityElement.Escape(markdown)}</releaseNotes>
<releaseNotesHtml><![CDATA[{"\n"}{html}{"\n"}]]></releaseNotesHtml>
""";
} }
string osMinVersionText = "";
if (rid?.HasVersion == true) { if (rid?.HasVersion == true) {
osMinVersionText = $"<osMinVersion>{rid.Version}</osMinVersion>"; addMetadata("osMinVersion", rid.Version.ToString());
} }
string machineArchitectureText = "";
if (rid?.HasArchitecture == true) { if (rid?.HasArchitecture == true) {
machineArchitectureText = $"<machineArchitecture>{rid.Architecture}</machineArchitecture>"; addMetadata("machineArchitecture", rid.Architecture.ToString());
}
string runtimeDependenciesText = "";
if (!String.IsNullOrWhiteSpace(RuntimeDependencies)) {
runtimeDependenciesText = $"<runtimeDependencies>{RuntimeDependencies}</runtimeDependencies>";
} }
string nuspec = $""" string nuspec = $"""
@@ -222,10 +222,7 @@ public abstract class PackageBuilder<T> : ICommand<T>
<mainExe>{MainExeName}</mainExe> <mainExe>{MainExeName}</mainExe>
<os>{rid.BaseRID.GetOsShortName()}</os> <os>{rid.BaseRID.GetOsShortName()}</os>
<rid>{rid.ToDisplay(RidDisplayType.NoVersion)}</rid> <rid>{rid.ToDisplay(RidDisplayType.NoVersion)}</rid>
{osMinVersionText} {extraMetadata.Trim()}
{machineArchitectureText}
{releaseNotesText}
{runtimeDependenciesText}
</metadata> </metadata>
</package> </package>
""".Trim(); """.Trim();

View File

@@ -16,6 +16,8 @@ public class WindowsPackCommand : PackCommand
public string SignTemplate { get; private set; } public string SignTemplate { get; private set; }
public string Shortcuts { get; private set; }
public WindowsPackCommand() public WindowsPackCommand()
: base("pack", "Creates a release from a folder containing application files.") : base("pack", "Creates a release from a folder containing application files.")
{ {
@@ -23,7 +25,7 @@ public class WindowsPackCommand : PackCommand
IconOption.RequiresExtension(".ico"); IconOption.RequiresExtension(".ico");
AddOption<string>((v) => Runtimes = v, "-f", "--framework") AddOption<string>((v) => Runtimes = v, "-f", "--framework")
.SetDescription("List of required runtimes to install during setup. example: 'net6-x64-desktop,vcredist143'.") .SetDescription("List of required runtimes to install during setup. Example: 'net6-x64-desktop,vcredist143'.")
.SetArgumentHelpName("RUNTIMES"); .SetArgumentHelpName("RUNTIMES");
AddOption<FileInfo>((v) => SplashImage = v.ToFullNameOrNull(), "-s", "--splashImage") AddOption<FileInfo>((v) => SplashImage = v.ToFullNameOrNull(), "-s", "--splashImage")
@@ -50,6 +52,11 @@ public class WindowsPackCommand : PackCommand
.SetHidden() .SetHidden()
.SetDefault(10); .SetDefault(10);
AddOption<string>((v) => Shortcuts = v, "--shortcuts")
.SetDescription("List of locations to install shortcuts to during setup.")
.SetArgumentHelpName("LOC")
.SetDefault("Desktop,StartMenuRoot");
if (VelopackRuntimeInfo.IsWindows) { if (VelopackRuntimeInfo.IsWindows) {
var signParams = AddOption<string>((v) => SignParameters = v, "--signParams", "-n") var signParams = AddOption<string>((v) => SignParameters = v, "--signParams", "-n")
.SetDescription("Sign files via signtool.exe using these parameters.") .SetDescription("Sign files via signtool.exe using these parameters.")

View File

@@ -27,6 +27,7 @@ namespace Velopack.NuGet
public string? Title { get; private set; } public string? Title { get; private set; }
public string? Summary { get; private set; } public string? Summary { get; private set; }
public string? Copyright { get; private set; } public string? Copyright { get; private set; }
public IEnumerable<string> ShortcutLocations { get; private set; } = Enumerable.Empty<string>();
public IEnumerable<string> Authors { get; private set; } = Enumerable.Empty<string>(); public IEnumerable<string> Authors { get; private set; } = Enumerable.Empty<string>();
public IEnumerable<string> RuntimeDependencies { get; private set; } = Enumerable.Empty<string>(); public IEnumerable<string> RuntimeDependencies { get; private set; } = Enumerable.Empty<string>();
@@ -137,6 +138,9 @@ namespace Velopack.NuGet
case "channel": case "channel":
Channel = value; Channel = value;
break; break;
case "shortcutLocations":
ShortcutLocations = getCommaDelimitedValue(value);
break;
} }
} }

View File

@@ -18,6 +18,11 @@ namespace Velopack.Windows
[Flags] [Flags]
public enum ShortcutLocation public enum ShortcutLocation
{ {
/// <summary>
/// Represents no shortcut location
/// </summary>
None = 0,
/// <summary> /// <summary>
/// A shortcut in ProgramFiles within a publisher sub-directory /// A shortcut in ProgramFiles within a publisher sub-directory
/// </summary> /// </summary>