Skip to content

Commit

Permalink
Support dev builds for auto updater
Browse files Browse the repository at this point in the history
  • Loading branch information
HebaruSan committed Jan 10, 2024
1 parent c197f23 commit d713c32
Show file tree
Hide file tree
Showing 46 changed files with 842 additions and 525 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,18 @@ jobs:
image: mono:${{ matrix.mono }}

steps:
- uses: actions/checkout@v3

- name: Adding HTTPS support to APT for old Mono images
run: |
apt-get update || true
apt-get install -y apt-transport-https
- name: Installing checkout/build dependencies
run: apt-get update && apt-get install -y git
- uses: actions/checkout@v3

- name: Setup .NET Core
uses: actions/setup-dotnet@v3
with:
dotnet-version: '7'
- name: Installing build dependencies
run: apt-get update && apt-get install -y git
- name: Install runtime dependencies
run: apt-get install -y xvfb
- name: Restore cache for _build/tools
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ jobs:
image: mono:latest

steps:
- name: Installing checkout/build dependencies
run: apt-get update && apt-get install -y git make sed gzip fakeroot lintian dpkg-dev gpg createrepo
- uses: actions/checkout@v3

- name: Check version
Expand All @@ -35,8 +37,6 @@ jobs:
uses: actions/setup-dotnet@v3
with:
dotnet-version: '7'
- name: Installing build dependencies
run: apt-get update && apt-get install -y git make sed gzip fakeroot lintian dpkg-dev gpg createrepo
- name: Installing runtime dependencies
run: apt-get install -y xvfb
- name: Install Docker
Expand Down Expand Up @@ -119,6 +119,9 @@ jobs:
echo "$DOCKERHUB_PASSWORD" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin
./build docker-metadata --exclusive
- name: Create a version.json file for S3
shell: bash
run: python bin/version_info.py > _build/repack/Release/version.json
- name: Push ckan.exe and netkan.exe to S3
# Send ckan.exe and netkan.exe to https://ksp-ckan.s3-us-west-2.amazonaws.com/
uses: jakejarvis/s3-sync-action@master
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ jobs:
image: mono:latest

steps:
- name: Installing checkout/build dependencies
run: apt-get update && apt-get install -y git make sed libplist-utils xorriso gzip fakeroot lintian rpm wget jq dpkg-dev gpg createrepo
- uses: actions/checkout@v3

- name: Setup .NET Core
uses: actions/setup-dotnet@v3
with:
dotnet-version: '7'
- name: Installing build dependencies
run: apt-get update && apt-get install -y git make sed libplist-utils xorriso gzip fakeroot lintian rpm wget jq dpkg-dev gpg createrepo
- name: Installing runtime dependencies
run: apt-get install -y xvfb

Expand Down
63 changes: 45 additions & 18 deletions Cmdline/Action/Upgrade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
using System.Collections.Generic;
using System.Transactions;

using Autofac;
using log4net;

using CKAN.Versioning;
using CKAN.Configuration;

namespace CKAN.CmdLine
{
Expand Down Expand Up @@ -47,38 +49,63 @@ public int RunCommand(CKAN.GameInstance instance, object raw_options)
user.RaiseMessage(" or ckan upgrade --all");
if (AutoUpdate.CanUpdate)
{
user.RaiseMessage(" or ckan upgrade ckan");
user.RaiseMessage(" or ckan upgrade ckan [--stable-release|--dev-build]");
}
return Exit.BADOPT;
}

if (!options.upgrade_all && options.modules[0] == "ckan" && AutoUpdate.CanUpdate)
{
user.RaiseMessage(Properties.Resources.UpgradeQueryingCKAN);
AutoUpdate.Instance.FetchLatestReleaseInfo();
var latestVersion = AutoUpdate.Instance.latestUpdate.Version;
var currentVersion = new ModuleVersion(Meta.GetVersion(VersionFormat.Short));
if (options.dev_build && options.stable_release)
{
user.RaiseMessage(Properties.Resources.UpgradeCannotCombineFlags);
return Exit.BADOPT;
}
var config = ServiceLocator.Container.Resolve<IConfiguration>();
var devBuild = options.dev_build
|| (!options.stable_release && config.DevBuilds);
if (devBuild != config.DevBuilds)
{
config.DevBuilds = devBuild;
user.RaiseMessage(
config.DevBuilds
? Properties.Resources.UpgradeSwitchingToDevBuilds
: Properties.Resources.UpgradeSwitchingToStableReleases);
}

if (latestVersion.IsGreaterThan(currentVersion))
user.RaiseMessage(Properties.Resources.UpgradeQueryingCKAN);
try
{
user.RaiseMessage(Properties.Resources.UpgradeNewCKANAvailable, latestVersion);
var releaseNotes = AutoUpdate.Instance.latestUpdate.ReleaseNotes;
user.RaiseMessage(releaseNotes);
user.RaiseMessage("");
user.RaiseMessage("");
var upd = new AutoUpdate();
var update = upd.GetUpdate(config.DevBuilds);
var latestVersion = update.Version;
var currentVersion = new ModuleVersion(Meta.GetVersion());

if (user.RaiseYesNoDialog(Properties.Resources.UpgradeProceed))
if (!latestVersion.Equals(currentVersion))
{
user.RaiseMessage(Properties.Resources.UpgradePleaseWait);
AutoUpdate.Instance.StartUpdateProcess(false);
user.RaiseMessage(Properties.Resources.UpgradeNewCKANAvailable, latestVersion);
var releaseNotes = update.ReleaseNotes;
user.RaiseMessage(releaseNotes);
user.RaiseMessage("");
user.RaiseMessage("");

if (user.RaiseYesNoDialog(Properties.Resources.UpgradeProceed))
{
user.RaiseMessage(Properties.Resources.UpgradePleaseWait);
upd.StartUpdateProcess(false, config.DevBuilds, user);
}
}
else
{
user.RaiseMessage(Properties.Resources.UpgradeAlreadyHaveLatest);
}
return Exit.OK;
}
else
catch (Exception exc)
{
user.RaiseMessage(Properties.Resources.UpgradeAlreadyHaveLatest);
user.RaiseError("Upgrade failed: {0}", exc.Message);
return Exit.ERROR;
}

return Exit.OK;
}

try
Expand Down
8 changes: 8 additions & 0 deletions Cmdline/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,14 @@ internal class UpgradeOptions : InstanceSpecificOptions
[Option("all", DefaultValue = false, HelpText = "Upgrade all available updated modules")]
public bool upgrade_all { get; set; }

[Option("dev-build", DefaultValue = false,
HelpText = "For `ckan` option only, use dev builds")]
public bool dev_build { get; set; }

[Option("stable-release", DefaultValue = false,
HelpText = "For `ckan` option only, use stable releases")]
public bool stable_release { get; set; }

[ValueList(typeof (List<string>))]
[InstalledIdentifiers]
public List<string> modules { get; set; }
Expand Down
3 changes: 3 additions & 0 deletions Cmdline/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,9 @@ Try `ckan list` for a list of installed mods.</value></data>
<data name="UpdateRemovedHeader" xml:space="preserve"><value>Removed modules [Name (CKAN identifier)]:</value></data>
<data name="UpdateUpdatedHeader" xml:space="preserve"><value>Updated modules [Name (CKAN identifier)]:</value></data>
<data name="UpdateSummary" xml:space="preserve"><value>Updated information on {0} compatible modules</value></data>
<data name="UpgradeCannotCombineFlags" xml:space="preserve"><value>The `--dev-build` and `--stable-release` flags cannot be combined!</value></data>
<data name="UpgradeSwitchingToDevBuilds" xml:space="preserve"><value>Switching to dev builds</value></data>
<data name="UpgradeSwitchingToStableReleases" xml:space="preserve"><value>Switching to stable releases</value></data>
<data name="UpgradeQueryingCKAN" xml:space="preserve"><value>Querying the latest CKAN version</value></data>
<data name="UpgradeNewCKANAvailable" xml:space="preserve"><value>New CKAN version available - {0}</value></data>
<data name="UpgradeProceed" xml:space="preserve"><value>Proceed with install?</value></data>
Expand Down
118 changes: 118 additions & 0 deletions Core/AutoUpdate/AutoUpdate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;
using System.Reflection;

using Autofac;
using Newtonsoft.Json;

using CKAN.Versioning;
using CKAN.Configuration;

namespace CKAN
{
/// <summary>
/// CKAN client auto-updating routines. This works in conjunction with the
/// auto-update helper to allow users to upgrade.
/// </summary>
public class AutoUpdate
{
public AutoUpdate()
{
}

public CkanUpdate GetUpdate(bool devBuild)
{
if (updates.TryGetValue(devBuild, out CkanUpdate update))
{
return update;
}
var newUpdate = devBuild
? new S3BuildCkanUpdate() as CkanUpdate
: new GitHubReleaseCkanUpdate();
updates.Add(devBuild, newUpdate);
return newUpdate;
}

private Dictionary<bool, CkanUpdate> updates = new Dictionary<bool, CkanUpdate>();

/// <summary>
/// Report whether it's possible to run the auto-updater.
/// Checks whether we can overwrite the running ckan.exe.
/// Windows doesn't let us check this because it locks the EXE
/// for a running process, so assume we can always overwrite on Windows.
/// </summary>
public static readonly bool CanUpdate = Platform.IsWindows || CanWrite(exePath);

/// <summary>
/// Downloads the new ckan.exe version, as well as the updater helper,
/// and then launches the helper allowing us to upgrade.
/// </summary>
/// <param name="launchCKANAfterUpdate">If set to <c>true</c> launch CKAN after update.</param>
public void StartUpdateProcess(bool launchCKANAfterUpdate, bool devBuild, IUser user = null)
{
var pid = Process.GetCurrentProcess().Id;

var update = GetUpdate(devBuild);

// download updater app and new ckan.exe
NetAsyncDownloader.DownloadWithProgress(update.Targets, user);

// run updater
SetExecutable(update.updaterFilename);
Process.Start(new ProcessStartInfo
{
Verb = "runas",
FileName = update.updaterFilename,
Arguments = string.Format(@"{0} ""{1}"" ""{2}"" {3}",
-pid, exePath,
update.ckanFilename,
launchCKANAfterUpdate ? "launch" : "nolaunch"),
UseShellExecute = false,
// Make child's stdin a pipe so it can tell when we exit
RedirectStandardInput = true,
CreateNoWindow = true,
});

// Caller should now exit. Let them do it safely.
}

public static void SetExecutable(string fileName)
{
// mark as executable if on Linux or Mac
if (Platform.IsUnix || Platform.IsMac)
{
// TODO: It would be really lovely (and safer!) to use the native system
// call here: http://docs.go-mono.com/index.aspx?link=M:Mono.Unix.Native.Syscall.chmod

string command = string.Format("+x \"{0}\"", fileName);

ProcessStartInfo permsinfo = new ProcessStartInfo("chmod", command)
{
UseShellExecute = false
};
Process permsprocess = Process.Start(permsinfo);
permsprocess.WaitForExit();
}
}

private static bool CanWrite(string path)
{
try
{
// Try to open the file for writing.
// We won't actually write, but we expect the OS to stop us if we don't have permissions.
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite)) { }
return true;
}
catch
{
return false;
}
}

// This is null when running tests, seemingly.
private static readonly string exePath = Assembly.GetEntryAssembly()?.Location ?? "";
}
}
26 changes: 26 additions & 0 deletions Core/AutoUpdate/CkanUpdate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.IO;
using System.Collections.Generic;

using CKAN.Versioning;

namespace CKAN
{
/// <summary>
/// Object representing a CKAN release
/// </summary>
public abstract class CkanUpdate
{
public CkanModuleVersion Version { get; protected set; }
public Uri ReleaseDownload { get; protected set; }
public long ReleaseSize { get; protected set; }
public Uri UpdaterDownload { get; protected set; }
public long UpdaterSize { get; protected set; }
public string ReleaseNotes { get; protected set; }

public string updaterFilename = $"{Path.GetTempPath()}{Guid.NewGuid()}.exe";
public string ckanFilename = $"{Path.GetTempPath()}{Guid.NewGuid()}.exe";

public abstract IList<NetAsyncDownloader.DownloadTarget> Targets { get; }
}
}
Loading

0 comments on commit d713c32

Please sign in to comment.