From e0237b53091aae45d71e451f09eeaa8854c766f6 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Fri, 11 Mar 2016 22:55:32 +0100 Subject: [PATCH] Implemented two new build channels: beta and canary. Updated build system to allow building various types of releases. --- .../Library/AutoUpdater/AutoUpdateSettings.cs | 21 +++++ Duplicati/Library/AutoUpdater/Program.cs | 3 +- Duplicati/Library/AutoUpdater/UpdateInfo.cs | 2 + .../Library/AutoUpdater/UpdaterManager.cs | 53 +++++++++++- .../Server/Database/ApplicationSettings.cs | 16 +++- Duplicati/Server/UpdatePollThread.cs | 6 +- .../WebServer/RESTMethods/SystemInfo.cs | 3 + Duplicati/Server/webroot/ngax/index.html | 4 +- .../scripts/controllers/AboutController.js | 2 +- .../ngax/scripts/controllers/AppController.js | 2 +- .../controllers/SystemSettingsController.js | 4 +- .../controllers/UpdateChangelogController.js | 2 +- .../ngax/scripts/services/BrandingService.js | 17 +++- .../Server/webroot/ngax/styles/styles2.css | 18 ++++ .../Server/webroot/ngax/templates/about.html | 8 +- .../webroot/ngax/templates/settings.html | 37 ++++++++ .../ngax/templates/updatechangelog.html | 2 +- Updates/beta.manifest | 3 + Updates/build_version.txt | 2 +- Updates/canary.manifest | 3 + Updates/experimental.manifest | 3 + Updates/nightly.manifest | 3 + Updates/preview.manifest | 3 - Updates/stable.manifest | 3 + build-preview-update.sh => build-release.sh | 86 ++++++++++++++----- 25 files changed, 262 insertions(+), 44 deletions(-) create mode 100644 Updates/beta.manifest create mode 100644 Updates/canary.manifest create mode 100644 Updates/experimental.manifest create mode 100644 Updates/nightly.manifest delete mode 100644 Updates/preview.manifest create mode 100644 Updates/stable.manifest rename build-preview-update.sh => build-release.sh (50%) mode change 100755 => 100644 diff --git a/Duplicati/Library/AutoUpdater/AutoUpdateSettings.cs b/Duplicati/Library/AutoUpdater/AutoUpdateSettings.cs index 2943917c01..7fedab7a5b 100644 --- a/Duplicati/Library/AutoUpdater/AutoUpdateSettings.cs +++ b/Duplicati/Library/AutoUpdater/AutoUpdateSettings.cs @@ -30,6 +30,7 @@ public static class AutoUpdateSettings private const string UPDATE_INSTALL_FILE = "AutoUpdateInstallIDTemplate.txt"; internal const string UPDATEURL_ENVNAME_TEMPLATE = "AUTOUPDATER_{0}_URLS"; + internal const string UPDATECHANNEL_ENVNAME_TEMPLATE = "AUTOUPDATER_{0}_CHANNEL"; static AutoUpdateSettings() { @@ -83,6 +84,26 @@ public static bool UsesAlternateURLs } } + public static ReleaseType DefaultUpdateChannel + { + get + { + var channelstring = Environment.GetEnvironmentVariable(string.Format(UPDATECHANNEL_ENVNAME_TEMPLATE, AppName)); + if (string.IsNullOrWhiteSpace(channelstring)) + { + channelstring = UpdaterManager.BaseVersion.ReleaseType; + // Update from older builds + if (string.Equals(channelstring, "preview", StringComparison.InvariantCultureIgnoreCase)) + channelstring = "beta"; + } + + ReleaseType rt; + if (!Enum.TryParse(channelstring, true, out rt)) + rt = ReleaseType.Stable; + + return rt; + } + } public static string AppName { diff --git a/Duplicati/Library/AutoUpdater/Program.cs b/Duplicati/Library/AutoUpdater/Program.cs index 9ed701a1cd..ae15c0b644 100644 --- a/Duplicati/Library/AutoUpdater/Program.cs +++ b/Duplicati/Library/AutoUpdater/Program.cs @@ -111,10 +111,11 @@ private static void WriteUsage() Console.WriteLine("{0} - Disables updates completely", string.Format(UpdaterManager.SKIPUPDATE_ENVNAME_TEMPLATE, AutoUpdateSettings.AppName)); Console.WriteLine("{0} - Choose how to handle updates, valid settings: {1}", string.Format(UpdaterManager.UPDATE_STRATEGY_ENVNAME_TEMPLATE, AutoUpdateSettings.AppName), string.Join(", ", Enum.GetNames(typeof(AutoUpdateStrategy)))); Console.WriteLine("{0} - Use alternate updates urls", string.Format(AutoUpdateSettings.UPDATEURL_ENVNAME_TEMPLATE, AutoUpdateSettings.AppName)); + Console.WriteLine("{0} - Choose different channel than the default {1}, valid settings: {2}", string.Format(AutoUpdateSettings.UPDATECHANNEL_ENVNAME_TEMPLATE, AutoUpdateSettings.AppName), AutoUpdater.AutoUpdateSettings.DefaultUpdateChannel, string.Join(",", Enum.GetNames(typeof(ReleaseType)).Where( x => x != ReleaseType.Unknown.ToString()))); Console.WriteLine(); Console.WriteLine("Updates are downloaded from: {0}", string.Join(";", AutoUpdateSettings.URLs)); Console.WriteLine("Updates are installed in: {0}", UpdaterManager.INSTALLDIR); - Console.WriteLine("The base install dir is: {0}", UpdaterManager.InstalledBaseDir); + Console.WriteLine("The base version is \"{0}\" ({1}) and is installed in: {2}", UpdaterManager.BaseVersion.Displayname, UpdaterManager.BaseVersion.Version, UpdaterManager.InstalledBaseDir); Console.WriteLine("This version is \"{0}\" ({1}) and is installed in: {2}", UpdaterManager.SelfVersion.Displayname, System.Reflection.Assembly.GetExecutingAssembly().GetName().Version, System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)); Console.WriteLine(); } diff --git a/Duplicati/Library/AutoUpdater/UpdateInfo.cs b/Duplicati/Library/AutoUpdater/UpdateInfo.cs index 084a0c8621..d8a6ca639a 100644 --- a/Duplicati/Library/AutoUpdater/UpdateInfo.cs +++ b/Duplicati/Library/AutoUpdater/UpdateInfo.cs @@ -26,7 +26,9 @@ public enum ReleaseType { Unknown, Stable, + Beta, Experimental, + Canary, Nightly, Debug } diff --git a/Duplicati/Library/AutoUpdater/UpdaterManager.cs b/Duplicati/Library/AutoUpdater/UpdaterManager.cs index 9e5b79c343..6ff37b2b23 100644 --- a/Duplicati/Library/AutoUpdater/UpdaterManager.cs +++ b/Duplicati/Library/AutoUpdater/UpdaterManager.cs @@ -52,6 +52,8 @@ public static class UpdaterManager public static readonly UpdateInfo SelfVersion; + public static readonly UpdateInfo BaseVersion; + public static event Action OnError; private const string DATETIME_FORMAT = "yyyymmddhhMMss"; @@ -108,6 +110,7 @@ static UpdaterManager() } UpdateInfo selfVersion = null; + UpdateInfo baseVersion = null; try { selfVersion = ReadInstalledManifest(System.IO.Path.GetDirectoryName(Duplicati.Library.Utility.Utility.getEntryAssembly().Location)); @@ -116,6 +119,14 @@ static UpdaterManager() { } + try + { + baseVersion = ReadInstalledManifest(InstalledBaseDir); + } + catch + { + } + if (selfVersion == null) selfVersion = new UpdateInfo() { Displayname = "Current", @@ -129,7 +140,11 @@ static UpdaterManager() #endif }; + if (baseVersion == null) + baseVersion = selfVersion; + SelfVersion = selfVersion; + BaseVersion = baseVersion; } public static Version TryParseVersion(string str) @@ -195,12 +210,34 @@ public static string InstallID return ""; } } - - public static UpdateInfo CheckForUpdate() + + public static UpdateInfo CheckForUpdate(ReleaseType channel = ReleaseType.Unknown) { + if (channel == ReleaseType.Unknown) + channel = AutoUpdateSettings.DefaultUpdateChannel; + + // Attempt to match the url to change the channel if possible + // This allows overrides to the URLs for deployment of custom builds, + // but does not require that they adopt the channel system + var re = new System.Text.RegularExpressions.Regex(string.Format("(?.+)(?{0})(?/([^/]+).manifest)", string.Join("|", Enum.GetNames(typeof(ReleaseType)).Union(new [] { "preview", "rene" }) )), System.Text.RegularExpressions.RegexOptions.Compiled | System.Text.RegularExpressions.RegexOptions.IgnoreCase); - foreach(var url in MANIFEST_URLS) + foreach(var rawurl in MANIFEST_URLS) { + var url = rawurl; + var match = re.Match(url); + if (match.Success) + { + var mg = match.Groups["channel"]; + + // Replace the channel name with the chosen channel + url = + url.Substring(0, mg.Index) + + + channel.ToString().ToLowerInvariant() + + + url.Substring(mg.Index + mg.Length); + } + try { using(var tmpfile = new Library.Utility.TempFile()) @@ -220,9 +257,19 @@ public static UpdateInfo CheckForUpdate() if (TryParseVersion(update.Version) <= TryParseVersion(SelfVersion.Version)) return null; + // Don't install a debug update on a release build and vice versa if (string.Equals(SelfVersion.ReleaseType, "Debug", StringComparison.InvariantCultureIgnoreCase) && !string.Equals(update.ReleaseType, SelfVersion.ReleaseType, StringComparison.CurrentCultureIgnoreCase)) return null; + ReleaseType rt; + if (!Enum.TryParse(update.ReleaseType, true, out rt)) + rt = ReleaseType.Unknown; + + // If the update is too low to be considered, skip it + // Should never happen, but protects against mistakes in deployment + if (rt > channel) + return null; + LastUpdateCheckVersion = update; return update; } diff --git a/Duplicati/Server/Database/ApplicationSettings.cs b/Duplicati/Server/Database/ApplicationSettings.cs index f24f27ec4c..83c8ab693b 100644 --- a/Duplicati/Server/Database/ApplicationSettings.cs +++ b/Duplicati/Server/Database/ApplicationSettings.cs @@ -41,6 +41,7 @@ private class CONST public const string UNACKED_WARNING = "unacked-warning"; public const string SERVER_LISTEN_INTERFACE = "server-listen-interface"; public const string HAS_FIXED_INVALID_BACKUPID = "has-fixed-invalid-backup-id"; + public const string UPDATE_CHANNEL = "update-channel"; } private Dictionary m_values; @@ -62,7 +63,7 @@ private void ReloadSettings() foreach(var n in typeof(CONST).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.DeclaredOnly | System.Reflection.BindingFlags.Static).Select(x => (string)x.GetValue(null))) m_values[n] = null; foreach(var n in m_connection.GetSettings(Connection.APP_SETTINGS_ID)) - m_values[n.Name] = n.Value; + m_values[n.Name] = n.Value; } } @@ -417,6 +418,19 @@ public bool FixedInvalidBackupId } } + public string UpdateChannel + { + get + { + return m_values[CONST.UPDATE_CHANNEL]; + } + set + { + lock(m_connection.m_lock) + m_values[CONST.UPDATE_CHANNEL] = value; + SaveSettings(); + } + } } } diff --git a/Duplicati/Server/UpdatePollThread.cs b/Duplicati/Server/UpdatePollThread.cs index ddebc5ff94..f3d273ee2a 100644 --- a/Duplicati/Server/UpdatePollThread.cs +++ b/Duplicati/Server/UpdatePollThread.cs @@ -120,7 +120,11 @@ private void Run() try { - var update = Duplicati.Library.AutoUpdater.UpdaterManager.CheckForUpdate(); + Library.AutoUpdater.ReleaseType rt; + if (!Enum.TryParse(Program.DataConnection.ApplicationSettings.UpdateChannel, true, out rt)) + rt = Duplicati.Library.AutoUpdater.ReleaseType.Unknown; + + var update = Duplicati.Library.AutoUpdater.UpdaterManager.CheckForUpdate(rt); if (update != null) Program.DataConnection.ApplicationSettings.UpdatedVersion = update; } diff --git a/Duplicati/Server/WebServer/RESTMethods/SystemInfo.cs b/Duplicati/Server/WebServer/RESTMethods/SystemInfo.cs index 923a3ef96c..c2802ded19 100644 --- a/Duplicati/Server/WebServer/RESTMethods/SystemInfo.cs +++ b/Duplicati/Server/WebServer/RESTMethods/SystemInfo.cs @@ -70,6 +70,9 @@ private static object SystemData PasswordPlaceholder = Duplicati.Server.WebServer.Server.PASSWORD_PLACEHOLDER, ServerVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(), ServerVersionName = Duplicati.License.VersionNumbers.Version, + ServerVersionType = Duplicati.Library.AutoUpdater.UpdaterManager.SelfVersion.ReleaseType, + BaseVersionName = Duplicati.Library.AutoUpdater.UpdaterManager.BaseVersion.Displayname, + DefaultUpdateChannel = Duplicati.Library.AutoUpdater.AutoUpdateSettings.DefaultUpdateChannel, ServerTime = DateTime.Now, OSType = Library.Utility.Utility.IsClientLinux ? (Library.Utility.Utility.IsClientOSX ? "OSX" : "Linux") : "Windows", DirectorySeparator = System.IO.Path.DirectorySeparatorChar, diff --git a/Duplicati/Server/webroot/ngax/index.html b/Duplicati/Server/webroot/ngax/index.html index 0b646819b5..cf531c499e 100755 --- a/Duplicati/Server/webroot/ngax/index.html +++ b/Duplicati/Server/webroot/ngax/index.html @@ -110,7 +110,9 @@