Skip to content

Commit e6e4414

Browse files
authored
rework how updater works (#212)
* rework how updater works * changes from review * prepare 5.5.1
1 parent 26baf68 commit e6e4414

21 files changed

+301
-123
lines changed

.editorconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,8 +442,11 @@ dotnet_diagnostic.SA1602.severity = none
442442
dotnet_diagnostic.SA1649.severity = none
443443
dotnet_diagnostic.SA1633.severity = none
444444

445+
dotnet_diagnostic.NUnit2007.severity = error
446+
445447
dotnet_diagnostic.RCS1217.severity = none
446448

447449
dotnet_diagnostic.RS0030.severity = error
448450
csharp_style_prefer_primary_constructors = true:suggestion
449451
csharp_prefer_system_threading_lock = true:suggestion
452+
csharp_style_prefer_simple_property_accessors = true:suggestion

Common/Common.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,8 @@
77
<LangVersion>preview</LangVersion>
88
</PropertyGroup>
99

10+
<ItemGroup>
11+
<PackageReference Include="NuGet.Versioning" Version="6.14.0" />
12+
</ItemGroup>
13+
1014
</Project>

Common/PlatformSpecific.cs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using System.Runtime.InteropServices;
2+
using System.Security.Principal;
3+
4+
namespace Common;
5+
6+
public static class PlatformSpecific
7+
{
8+
// For Unix-like systems (Linux, macOS)
9+
static class UnixUserChecker
10+
{
11+
// Imports the geteuid() function from libc (the standard C library)
12+
// geteuid() returns the effective user ID of the calling process.
13+
// A value of 0 typically indicates the root user.
14+
[DllImport("libc", EntryPoint = "geteuid")]
15+
internal static extern uint geteuid();
16+
17+
public static bool IsRoot()
18+
=> geteuid() == 0;
19+
}
20+
21+
public static bool RunningAsAdmin()
22+
{
23+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
24+
{
25+
var identity = WindowsIdentity.GetCurrent();
26+
var principal = new WindowsPrincipal(identity);
27+
return principal.IsInRole(WindowsBuiltInRole.Administrator);
28+
}
29+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
30+
{
31+
return UnixUserChecker.IsRoot();
32+
}
33+
34+
return false;
35+
}
36+
37+
public static string EditorPlatformZipName(OSPlatform platform) =>
38+
platform == OSPlatform.Windows ? "win-x64.zip" :
39+
platform == OSPlatform.OSX ? "osx-x64.tar" :
40+
platform == OSPlatform.Linux ? "linux-x64.tar" :
41+
throw new PlatformNotSupportedException();
42+
43+
public static string EditorPlatformBinaryName(OSPlatform platform) =>
44+
platform == OSPlatform.Windows ? $"{VersionHelpers.ObjectEditorName}.exe" :
45+
platform == OSPlatform.OSX ? VersionHelpers.ObjectEditorName :
46+
platform == OSPlatform.Linux ? VersionHelpers.ObjectEditorName :
47+
throw new PlatformNotSupportedException();
48+
49+
public static OSPlatform GetPlatform =>
50+
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? OSPlatform.Windows :
51+
RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? OSPlatform.OSX :
52+
RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? OSPlatform.Linux :
53+
throw new PlatformNotSupportedException();
54+
}

Gui/VersionHelpers.cs renamed to Common/VersionHelpers.cs

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,38 @@
11
using Common.Logging;
22
using NuGet.Versioning;
3-
using System;
43
using System.Diagnostics;
5-
using System.IO;
4+
using System.Net.Http.Headers;
65
using System.Reflection;
6+
using System.Runtime.InteropServices;
77
using System.Text;
8-
9-
#if !DEBUG
10-
using Common;
11-
using System.Net.Http;
12-
using System.Net.Http.Headers;
138
using System.Text.Json;
14-
using System;
15-
#endif
169

17-
namespace Gui;
10+
namespace Common;
1811

1912
public static class VersionHelpers
2013
{
21-
public const string GithubApplicationName = "ObjectEditor";
14+
public const string ObjectEditorName = "ObjectEditor";
2215
public const string ObjectEditorUpdaterName = "ObjectEditorUpdater";
2316
public const string GithubIssuePage = "https://github.com/OpenLoco/ObjectEditor/issues";
2417
public const string GithubLatestReleaseDownloadPage = "https://github.com/OpenLoco/ObjectEditor/releases";
2518
public const string GithubLatestReleaseAPI = "https://api.github.com/repos/OpenLoco/ObjectEditor/releases/latest";
2619

27-
// todo: instead of going to downloads, start the auto-updater (ObjectEditorUpdater.exe) with the right args
2820
public static Process? OpenDownloadPage()
2921
=> Process.Start(new ProcessStartInfo(GithubLatestReleaseDownloadPage) { UseShellExecute = true });
3022

31-
public static void StartAutoUpdater(ILogger logger, SemanticVersion latestVersion)
23+
// win: object-editor-5.3.5-win-x64.zip
24+
// osx: object-editor-5.3.5-osx-x64.tar
25+
// linux: object-editor-5.3.5-linux-x64.tar
26+
27+
static string DownloadFilename(SemanticVersion latestVersion, OSPlatform platform)
28+
=> $"object-editor-{latestVersion}-{PlatformSpecific.EditorPlatformZipName(platform)}";
29+
30+
public static string UrlForDownload(SemanticVersion latestVersion, OSPlatform platform)
31+
=> $"{GithubLatestReleaseDownloadPage}/download/{latestVersion}/{DownloadFilename(latestVersion, platform)}";
32+
33+
public static void StartAutoUpdater(ILogger logger, SemanticVersion currentVersion, SemanticVersion latestVersion)
3234
{
35+
logger.Debug("Attempting to kill existing updater processes");
3336
try
3437
{
3538
// kill any existing processes of the updater
@@ -46,38 +49,52 @@ public static void StartAutoUpdater(ILogger logger, SemanticVersion latestVersio
4649
}
4750
}
4851

49-
// win: object-editor-5.3.5-win-x64.zip
50-
// osx: object-editor-5.3.5-osx-x64.tar
51-
// linux: object-editor-5.3.5-linux-x64.tar
52-
var platform = PlatformSpecific.EditorPlatformExtension;
53-
var filename = $"object-editor-{latestVersion}-{platform}";
52+
var editorExe = $"{ObjectEditorUpdaterName}.exe";
53+
if (!File.Exists(editorExe))
54+
{
55+
logger.Error($"Cannot find the auto-updater executable: {editorExe}. You'll need to manually download the update.");
56+
return;
57+
}
5458

55-
var startInfo = new ProcessStartInfo($"{ObjectEditorUpdaterName}.exe",
59+
var startInfo = new ProcessStartInfo(editorExe,
5660
[
5761
"--pid",
5862
$"{Environment.ProcessId}",
59-
"--url",
60-
$"{GithubLatestReleaseDownloadPage}/download/{latestVersion}/{filename}",
63+
"--current-version",
64+
currentVersion.ToString(),
6165
"--app-path",
6266
$"{Environment.ProcessPath}",
6367
])
6468
{
69+
// updater process will log to file
6570
UseShellExecute = false,
6671
CreateNoWindow = true,
6772
};
6873

74+
logger.Debug($"CurrentProcessId: {Environment.ProcessId}");
75+
logger.Debug($"CurrentProcessPath: {Environment.ProcessPath}");
76+
logger.Debug($"Attempting to start auto-updater \"{startInfo}\"");
6977
var process = Process.Start(startInfo);
70-
Environment.Exit(0);
78+
79+
if (process != null)
80+
{
81+
logger.Info($"Started auto-updater process (PID {process.Id}) to update from {currentVersion} to {latestVersion}. Editor will now close");
82+
Environment.Exit(0);
83+
}
84+
else
85+
{
86+
logger.Error("Failed to start auto-updater process. You'll need to manually download the update.");
87+
}
7188
}
7289
catch (Exception ex)
7390
{
74-
Debug.WriteLine($"Failed to start auto-updater: {ex}");
91+
logger.Error($"Failed to start auto-updater: {ex}");
7592
}
7693
}
7794

7895
public static SemanticVersion GetCurrentAppVersion()
7996
{
80-
var assembly = Assembly.GetExecutingAssembly();
97+
var assembly = Assembly.GetCallingAssembly();
8198
if (assembly == null)
8299
{
83100
return UnknownVersion;
@@ -94,12 +111,11 @@ public static SemanticVersion GetCurrentAppVersion()
94111
}
95112
}
96113

97-
#if !DEBUG
98114
// thanks for this one @IntelOrca, https://github.com/IntelOrca/PeggleEdit/blob/master/src/peggleedit/Forms/MainMDIForm.cs#L848-L861
99-
public static SemanticVersion GetLatestAppVersion(SemanticVersion currentVersion)
115+
public static SemanticVersion GetLatestAppVersion(string productName, SemanticVersion? currentVersion = null)
100116
{
101117
var client = new HttpClient();
102-
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(GithubApplicationName, currentVersion.ToString()));
118+
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(productName, currentVersion?.ToString()));
103119
var response = client.GetAsync(GithubLatestReleaseAPI).Result;
104120
if (response.IsSuccessStatusCode)
105121
{
@@ -109,11 +125,8 @@ public static SemanticVersion GetLatestAppVersion(SemanticVersion currentVersion
109125
return GetVersionFromText(versionText);
110126
}
111127

112-
#pragma warning disable CA2201 // Do not raise reserved exception types
113-
throw new Exception($"Unable to get latest version. Error={response.StatusCode}");
114-
#pragma warning restore CA2201 // Do not raise reserved exception types
128+
return UnknownVersion;
115129
}
116-
#endif
117130

118131
public static readonly SemanticVersion UnknownVersion = new(0, 0, 0, "unknown");
119132

Gui/Gui.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<OutputType>WinExe</OutputType>
44
<TargetFramework>net10.0</TargetFramework>
@@ -87,4 +87,5 @@
8787
<SubType>Code</SubType>
8888
</Compile>
8989
</ItemGroup>
90+
9091
</Project>

Gui/ObjectServiceClient.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Common;
12
using Common.Logging;
23
using Definitions.DTO;
34
using Definitions.Web;

Gui/PlatformSpecific.cs

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,42 +7,12 @@
77
using System.Diagnostics;
88
using System.IO;
99
using System.Runtime.InteropServices;
10-
using System.Security.Principal;
1110
using System.Threading.Tasks;
1211

1312
namespace Gui;
1413

15-
// For Unix-like systems (Linux, macOS)
16-
static class UnixUserChecker
17-
{
18-
// Imports the geteuid() function from libc (the standard C library)
19-
// geteuid() returns the effective user ID of the calling process.
20-
// A value of 0 typically indicates the root user.
21-
[DllImport("libc", EntryPoint = "geteuid")]
22-
internal static extern uint geteuid();
23-
24-
public static bool IsRoot()
25-
=> geteuid() == 0;
26-
}
27-
2814
public static class PlatformSpecific
2915
{
30-
public static bool RunningAsAdmin()
31-
{
32-
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
33-
{
34-
var identity = WindowsIdentity.GetCurrent();
35-
var principal = new WindowsPrincipal(identity);
36-
return principal.IsInRole(WindowsBuiltInRole.Administrator);
37-
}
38-
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
39-
{
40-
return UnixUserChecker.IsRoot();
41-
}
42-
43-
return false;
44-
}
45-
4616
public static void FolderOpenInDesktop(string directory, ILogger logger, string? filename = null)
4717
{
4818
try
@@ -55,12 +25,6 @@ public static void FolderOpenInDesktop(string directory, ILogger logger, string?
5525
}
5626
}
5727

58-
public static string EditorPlatformExtension
59-
=> RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "win-x64.zip" :
60-
RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "osx-x64.tar" :
61-
RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "linux-x64.tar" :
62-
"unknown";
63-
6428
static void FolderOpenInDesktopCore(string directory, string? filename = null)
6529
{
6630
if (!Directory.Exists(directory))

Gui/Program.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Avalonia;
22
using Avalonia.Logging;
33
using Avalonia.ReactiveUI;
4+
using Common;
45
using System;
56

67
namespace Gui;
@@ -24,7 +25,7 @@ public static void Main(string[] args)
2425

2526
static void PreventRunningAsAdmin()
2627
{
27-
if (PlatformSpecific.RunningAsAdmin())
28+
if (Common.PlatformSpecific.RunningAsAdmin())
2829
{
2930
const string errorMessage = "This application should not be run with elevated privileges. Please run it as a regular user.";
3031

Gui/ViewModels/AudioViewModel.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Common;
12
using Common.Logging;
23
using Definitions.ObjectModels.Objects.Sound;
34
using Gui.Models.Audio;

Gui/ViewModels/FolderTreeViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Avalonia.Controls.Selection;
44
using Avalonia.Media;
55
using Avalonia.Threading;
6+
using Common;
67
using Dat.Data;
78
using Definitions.ObjectModels;
89
using Definitions.ObjectModels.Types;
@@ -203,7 +204,6 @@ public FolderTreeViewModel(ObjectEditorModel model)
203204
_ = this.WhenAnyValue(o => o.CurrentLocalDirectory).Skip(1).Subscribe(async _ => await LoadDirectoryAsync(true));
204205
_ = this.WhenAnyValue(o => o.CurrentLocalDirectory).Skip(1).Subscribe(_ => this.RaisePropertyChanged(nameof(CurrentDirectory)));
205206

206-
207207
//_ = this.WhenAnyValue(o => o.SelectedTabIndex).Skip(1).Subscribe(_ => UpdateDirectoryItemsView());
208208
_ = this.WhenAnyValue(o => o.SelectedTabIndex).Skip(1).Subscribe(_ => this.RaisePropertyChanged(nameof(CurrentDirectory)));
209209
_ = this.WhenAnyValue(o => o.CurrentDirectory).Skip(1).Subscribe(async _ => await LoadDirectoryAsync(true));

0 commit comments

Comments
 (0)