Skip to content
This repository has been archived by the owner on Jul 5, 2024. It is now read-only.

Commit

Permalink
Remove dependency on System.ValueType
Browse files Browse the repository at this point in the history
  • Loading branch information
caesay committed Nov 14, 2023
1 parent 9eb03d8 commit 52e6024
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 32 deletions.
8 changes: 4 additions & 4 deletions src/Squirrel/Internal/HelperExe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,21 +94,21 @@ public static async Task CompileWixTemplateToMsi(string wxsTarget, string output
var candleParams = new string[] { "-nologo", "-ext", "WixNetFxExtension", "-out", objFile, wxsTarget };
var processResult = await Utility.InvokeProcessAsync(WixCandlePath, candleParams, CancellationToken.None, workingDir).ConfigureAwait(false);

if (processResult.Item1 != 0) {
if (processResult.ExitCode != 0) {
var msg = String.Format(
"Failed to compile WiX template, command invoked was: '{0} {1}'\n\nOutput was:\n{2}",
"candle.exe", Utility.ArgsToCommandLine(candleParams), processResult.Item2);
"candle.exe", Utility.ArgsToCommandLine(candleParams), processResult.StdOutput);
throw new Exception(msg);
}

// Light links and binds one or more .wixobj files and creates a Windows Installer database (.msi or .msm).
var lightParams = new string[] { "-ext", "WixNetFxExtension", "-spdb", "-sval", "-out", outputFile, objFile };
processResult = await Utility.InvokeProcessAsync(WixLightPath, lightParams, CancellationToken.None, workingDir).ConfigureAwait(false);

if (processResult.Item1 != 0) {
if (processResult.ExitCode != 0) {
var msg = String.Format(
"Failed to link WiX template, command invoked was: '{0} {1}'\n\nOutput was:\n{2}",
"light.exe", Utility.ArgsToCommandLine(lightParams), processResult.Item2);
"light.exe", Utility.ArgsToCommandLine(lightParams), processResult.StdOutput);
throw new Exception(msg);
}
} finally {
Expand Down
22 changes: 18 additions & 4 deletions src/Squirrel/Internal/StringFileInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,25 @@ protected StringFileInfo(Version fileVersion, Version productVersion, uint fileF
FileDate = fileDate;
}

public class VersionInfoItem
{
public uint CodePage { get; set; }
public string Key { get; set; }
public string Value { get; set; }

public VersionInfoItem(uint codePage, string key, string value)
{
CodePage = codePage;
Key = key;
Value = value;
}
}

// vi can be null on exit
// Item1 = language | codepage
// Item2 = Key
// Item3 = Value
public static IEnumerable<(uint CodePage, string Key, string Value)> ReadVersionInfo(string fileName, out StringFileInfo vi)
public static IEnumerable<VersionInfoItem> ReadVersionInfo(string fileName, out StringFileInfo vi)
{
int num;
int size = GetFileVersionInfoSize(fileName, out num);
Expand All @@ -75,7 +89,7 @@ protected StringFileInfo(Version fileVersion, Version productVersion, uint fileF
// Item1 = language | codepage
// Item2 = Key
// Item3 = Value
public static IEnumerable<(uint CodePage, string Key, string Value)> ReadVersionInfo(byte[] buffer, out StringFileInfo vi)
public static IEnumerable<VersionInfoItem> ReadVersionInfo(byte[] buffer, out StringFileInfo vi)
{
int offset;
// The offset calculated here is unused
Expand Down Expand Up @@ -118,7 +132,7 @@ protected StringFileInfo(Version fileVersion, Version productVersion, uint fileF
return ReadVersionInfoInternal(buffer, fibs);
}

protected static IEnumerable<(uint CodePage, string Key, string Value)> ReadVersionInfoInternal(byte[] buffer, FileInfoBaseStruct fibs)
protected static IEnumerable<VersionInfoItem> ReadVersionInfoInternal(byte[] buffer, FileInfoBaseStruct fibs)
{
int sfiOrValOffset = (fibs.ValueOffset + fibs.ValueLength + 3) & (~3);

Expand Down Expand Up @@ -148,7 +162,7 @@ protected StringFileInfo(Version fileVersion, Version productVersion, uint fileF
int len = FindLengthUnicodeSZ(buffer, stri.ValueOffset, stri.ValueOffset + (stri.ValueLength * 2));
string value = Encoding.Unicode.GetString(buffer, stri.ValueOffset, len * 2);

yield return (langCharset, stri.Key, value);
yield return new VersionInfoItem(langCharset, stri.Key, value);

striOffset = nextStriOffset;
}
Expand Down
36 changes: 30 additions & 6 deletions src/Squirrel/Internal/Utility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -280,11 +280,23 @@ public static string EscapeCmdExeMetachars(string command)
return result.ToString();
}

public class ProcessResult
{
public int ExitCode { get; set; }
public string StdOutput { get; set; }

public ProcessResult(int exitCode, string stdOutput)
{
ExitCode = exitCode;
StdOutput = stdOutput;
}
}

/// <summary>
/// This function will escape command line arguments such that CommandLineToArgvW is guarenteed to produce the same output as the 'args' parameter.
/// It also will automatically execute wine if trying to run an exe while not on windows.
/// </summary>
public static Task<(int ExitCode, string StdOutput)> InvokeProcessAsync(string fileName, IEnumerable<string> args, CancellationToken ct, string workingDirectory = "")
public static Task<ProcessResult> InvokeProcessAsync(string fileName, IEnumerable<string> args, CancellationToken ct, string workingDirectory = "")
{
if (Environment.OSVersion.Platform != PlatformID.Win32NT && fileName.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)) {
return InvokeProcessUnsafeAsync(CreateProcessStartInfo("wine", ArgsToCommandLine(new string[] { fileName }.Concat(args)), workingDirectory), ct);
Expand All @@ -306,7 +318,7 @@ public static ProcessStartInfo CreateProcessStartInfo(string fileName, string ar
return psi;
}

public static async Task<(int ExitCode, string StdOutput)> InvokeProcessUnsafeAsync(ProcessStartInfo psi, CancellationToken ct)
public static async Task<ProcessResult> InvokeProcessUnsafeAsync(ProcessStartInfo psi, CancellationToken ct)
{
var pi = Process.Start(psi);
await Task.Run(() => {
Expand All @@ -329,7 +341,7 @@ await Task.Run(() => {
}
}

return (pi.ExitCode, textResult.Trim());
return new ProcessResult(pi.ExitCode, textResult.Trim());
}

public static Task ForEachAsync<T>(this IEnumerable<T> source, Action<T> body, int degreeOfParallelism = 4)
Expand Down Expand Up @@ -870,10 +882,22 @@ public static bool ByteArrayCompareFast(byte[] a1, byte[] a2)
}
#endif

public class ProcessInfo
{
public string ProcessExePath { get; set; }
public int ProcessId { get; set; }

public ProcessInfo(string processExePath, int processId)
{
ProcessExePath = processExePath;
ProcessId = processId;
}
}

#if NET5_0_OR_GREATER
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
#endif
public static List<(string ProcessExePath, int ProcessId)> EnumerateProcesses()
public static List<ProcessInfo> EnumerateProcesses()
{
var pids = new int[2048];
var gch = GCHandle.Alloc(pids, GCHandleType.Pinned);
Expand All @@ -884,7 +908,7 @@ public static bool ByteArrayCompareFast(byte[] a1, byte[] a2)
if (bytesReturned < 1)
throw new Exception("Failed to enumerate processes");

List<(string ProcessExePath, int ProcessId)> ret = new();
List<ProcessInfo> ret = new();

for (int i = 0; i < bytesReturned / sizeof(int); i++) {
IntPtr hProcess = IntPtr.Zero;
Expand All @@ -902,7 +926,7 @@ public static bool ByteArrayCompareFast(byte[] a1, byte[] a2)
if (String.IsNullOrWhiteSpace(exePath) || !File.Exists(exePath))
continue;

ret.Add((sb.ToString(), pids[i]));
ret.Add(new ProcessInfo(sb.ToString(), pids[i]));
} catch (Exception) {
// don't care
} finally {
Expand Down
26 changes: 22 additions & 4 deletions src/Squirrel/ReleaseEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -386,30 +386,48 @@ internal static ReleasePackage GetPreviousRelease(IEnumerable<ReleaseEntry> rele
static readonly Regex _suffixRegex = new Regex(@"(-full|-delta)?\.nupkg$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
static readonly Regex _versionStartRegex = new Regex(@"[\.-](0|[1-9]\d*)\.(0|[1-9]\d*)($|[^\d])", RegexOptions.Compiled);

internal class EntryNameInfo
{
public string PackageName { get; set; }
public SemanticVersion Version { get; set; }
public bool IsDelta { get; set; }

public EntryNameInfo()
{
}

public EntryNameInfo(string packageName, SemanticVersion version, bool isDelta)
{
PackageName = packageName;
Version = version;
IsDelta = isDelta;
}
}

/// <summary>
/// Takes a filename such as 'My-Cool3-App-1.0.1-build.23-full.nupkg' and separates it into
/// it's name and version (eg. 'My-Cool3-App', and '1.0.1-build.23'). Returns null values if
/// the filename can not be parsed.
/// </summary>
internal static (string PackageName, SemanticVersion Version, bool IsDelta) ParseEntryFileName(string fileName)
internal static EntryNameInfo ParseEntryFileName(string fileName)
{
if (!fileName.EndsWith(".nupkg", StringComparison.OrdinalIgnoreCase))
return (null, null, false);
return new EntryNameInfo();

bool delta = Path.GetFileNameWithoutExtension(fileName).EndsWith("-delta", StringComparison.OrdinalIgnoreCase);

var nameAndVer = _suffixRegex.Replace(Path.GetFileName(fileName), "");

var match = _versionStartRegex.Match(nameAndVer);
if (!match.Success)
return (null, null, delta);
return new EntryNameInfo(null, null, delta);

var verIdx = match.Index;
var name = nameAndVer.Substring(0, verIdx);
var version = nameAndVer.Substring(verIdx + 1);

var semVer = new SemanticVersion(version);
return (name, semVer, delta);
return new EntryNameInfo(name, semVer, delta);
}
}
}
20 changes: 16 additions & 4 deletions src/Squirrel/RuntimeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -457,13 +457,25 @@ public override Task<bool> CheckIsSupported()

const string UninstallRegSubKey = @"Software\Microsoft\Windows\CurrentVersion\Uninstall";

private class VCVersion
{
public SemanticVersion Ver { get; set; }
public RuntimeCpu Cpu { get; set; }

public VCVersion(SemanticVersion ver, RuntimeCpu cpu)
{
Ver = ver;
Cpu = cpu;
}
}

/// <summary>
/// Returns the list of currently installed VC++ redistributables, as reported by the
/// Windows Programs &amp; Features dialog.
/// </summary>
public static (SemanticVersion Ver, RuntimeCpu Cpu)[] GetInstalledVCVersions()
private static VCVersion[] GetInstalledVCVersions()
{
List<(SemanticVersion Ver, RuntimeCpu Cpu)> results = new List<(SemanticVersion Ver, RuntimeCpu Cpu)>();
List<VCVersion> results = new();

void searchreg(RegistryKey view)
{
Expand All @@ -476,9 +488,9 @@ void searchreg(RegistryKey view)
// these entries do not get added into the correct registry hive, so we need to determine
// the cpu architecture from the name. I hate this but what can I do?
if (name.Contains("x64") && Environment.Is64BitOperatingSystem) {
results.Add((v, RuntimeCpu.x64));
results.Add(new VCVersion(v, RuntimeCpu.x64));
} else {
results.Add((v, RuntimeCpu.x86));
results.Add(new VCVersion(v, RuntimeCpu.x86));
}
}
}
Expand Down
1 change: 0 additions & 1 deletion src/Squirrel/Squirrel.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
</ItemGroup>

<ItemGroup Condition=" $(TargetFramework.StartsWith('net4')) ">
<PackageReference Include="System.ValueTuple" Version="4.5" />
<Reference Include="System.Web" />
<Reference Include="System.Net.Http" />
<Reference Include="System.IO.Compression" />
Expand Down
24 changes: 19 additions & 5 deletions src/Squirrel/UpdateManager.ApplyReleases.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ public async Task FullUninstall()
if (!releases.Any())
return;

var (currentRelease, currentVersion) = releases.OrderByDescending(x => x.Version).FirstOrDefault();
var currentLocalRelease = releases.OrderByDescending(x => x.Version).FirstOrDefault();
var currentRelease = currentLocalRelease.Directory;
var currentVersion = currentLocalRelease.Version;

this.Log().Info("Starting full uninstall");
if (currentRelease.Exists) {
Expand Down Expand Up @@ -630,7 +632,7 @@ await squirrelApps.ForEachAsync(async exe => {
// Finally, clean up the app-X.Y.Z directories
await toCleanup.ForEachAsync(x => {
try {
if (runningProcesses.All(p => p.Item1 == null || !p.Item1.StartsWith(x.FullName, StringComparison.OrdinalIgnoreCase))) {
if (runningProcesses.All(p => p.ProcessExePath == null || !p.ProcessExePath.StartsWith(x.FullName, StringComparison.OrdinalIgnoreCase))) {
Utility.DeleteFileOrDirectoryHardOrGiveUp(x.FullName);
}
Expand Down Expand Up @@ -681,15 +683,27 @@ internal async Task<List<ReleaseEntry>> updateLocalReleasesFile()
return await Task.Run(() => ReleaseEntry.BuildReleasesFile(Utility.PackageDirectoryForAppDir(rootAppDirectory))).ConfigureAwait(false);
}

IEnumerable<(DirectoryInfo Directory, SemanticVersion Version)> getReleases()
class LocalReleaseDirectory
{
public DirectoryInfo Directory { get; set; }
public SemanticVersion Version { get; set; }

public LocalReleaseDirectory(DirectoryInfo directory, SemanticVersion version)
{
Directory = directory;
Version = version;
}
}

IEnumerable<LocalReleaseDirectory> getReleases()
{
var rootDirectory = new DirectoryInfo(rootAppDirectory);

if (!rootDirectory.Exists) return Enumerable.Empty<(DirectoryInfo Directory, SemanticVersion Version)>();
if (!rootDirectory.Exists) return Enumerable.Empty<LocalReleaseDirectory>();

return rootDirectory.GetDirectories()
.Where(x => x.Name.StartsWith("app-", StringComparison.InvariantCultureIgnoreCase))
.Select(x => (x, new SemanticVersion(x.Name.Substring(4))));
.Select(x => new LocalReleaseDirectory(x, new SemanticVersion(x.Name.Substring(4))));
}

DirectoryInfo getDirectoryForRelease(SemanticVersion releaseVersion)
Expand Down
8 changes: 4 additions & 4 deletions src/Squirrel/UpdateManager.InstallHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,22 +108,22 @@ public void KillAllProcessesBelongingToPackage()
.Where(x => {
// Processes we can't query will have an empty process name, we can't kill them
// anyways
if (String.IsNullOrWhiteSpace(x.Item1)) return false;
if (String.IsNullOrWhiteSpace(x.ProcessExePath)) return false;
// Files that aren't in our root app directory are untouched
if (!Utility.IsFileInDirectory(x.ProcessExePath, rootAppDirectory)) return false;
// Never kill our own EXE
if (ourExePath != null && x.Item1.Equals(ourExePath, StringComparison.OrdinalIgnoreCase)) return false;
if (ourExePath != null && x.ProcessExePath.Equals(ourExePath, StringComparison.OrdinalIgnoreCase)) return false;
var name = Path.GetFileName(x.Item1).ToLowerInvariant();
var name = Path.GetFileName(x.ProcessExePath).ToLowerInvariant();
if (name == "squirrel.exe" || name == "update.exe") return false;
return true;
})
.ForEach(x => {
try {
this.WarnIfThrows(() => Process.GetProcessById(x.Item2).Kill());
this.WarnIfThrows(() => Process.GetProcessById(x.ProcessId).Kill());
} catch { }
});
}
Expand Down

0 comments on commit 52e6024

Please sign in to comment.