Skip to content

Commit

Permalink
Implemented two new build channels: beta and canary.
Browse files Browse the repository at this point in the history
Updated build system to allow building various types of releases.
  • Loading branch information
kenkendk committed Mar 11, 2016
1 parent 40e4b5b commit e0237b5
Show file tree
Hide file tree
Showing 25 changed files with 262 additions and 44 deletions.
21 changes: 21 additions & 0 deletions Duplicati/Library/AutoUpdater/AutoUpdateSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down Expand Up @@ -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<ReleaseType>(channelstring, true, out rt))
rt = ReleaseType.Stable;

return rt;
}
}

public static string AppName
{
Expand Down
3 changes: 2 additions & 1 deletion Duplicati/Library/AutoUpdater/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
2 changes: 2 additions & 0 deletions Duplicati/Library/AutoUpdater/UpdateInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ public enum ReleaseType
{
Unknown,
Stable,
Beta,
Experimental,
Canary,
Nightly,
Debug
}
Expand Down
53 changes: 50 additions & 3 deletions Duplicati/Library/AutoUpdater/UpdaterManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ public static class UpdaterManager

public static readonly UpdateInfo SelfVersion;

public static readonly UpdateInfo BaseVersion;

public static event Action<Exception> OnError;

private const string DATETIME_FORMAT = "yyyymmddhhMMss";
Expand Down Expand Up @@ -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));
Expand All @@ -116,6 +119,14 @@ static UpdaterManager()
{
}

try
{
baseVersion = ReadInstalledManifest(InstalledBaseDir);
}
catch
{
}

if (selfVersion == null)
selfVersion = new UpdateInfo() {
Displayname = "Current",
Expand All @@ -129,7 +140,11 @@ static UpdaterManager()
#endif
};

if (baseVersion == null)
baseVersion = selfVersion;

SelfVersion = selfVersion;
BaseVersion = baseVersion;
}

public static Version TryParseVersion(string str)
Expand Down Expand Up @@ -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("(?<prefix>.+)(?<channel>{0})(?<filename>/([^/]+).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())
Expand All @@ -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<ReleaseType>(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;
}
Expand Down
16 changes: 15 additions & 1 deletion Duplicati/Server/Database/ApplicationSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, string> m_values;
Expand All @@ -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;
}
}

Expand Down Expand Up @@ -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();
}
}
}
}

6 changes: 5 additions & 1 deletion Duplicati/Server/UpdatePollThread.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,11 @@ private void Run()

try
{
var update = Duplicati.Library.AutoUpdater.UpdaterManager.CheckForUpdate();
Library.AutoUpdater.ReleaseType rt;
if (!Enum.TryParse<Library.AutoUpdater.ReleaseType>(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;
}
Expand Down
3 changes: 3 additions & 0 deletions Duplicati/Server/WebServer/RESTMethods/SystemInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 3 additions & 1 deletion Duplicati/Server/webroot/ngax/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@
<div class="container">
<div class="header">
<div class="logo">
<a href="#/" class="home">{{appName}}</a>
<a href="#/" class="home">{{brandingService.appName}}</a>
<div class="build-suffix" ng-hide="systemInfo.ServerVersionType == 'stable' || systemInfo.ServerVersionType == ''"> &gt; {{systemInfo.ServerVersionType}}</div>
<div class="powered-by">{{brandingService.appSubtitle}}</div>
</div>

<div class="donate" ng-hide="systemInfo.SuppressDonationMessages">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
backupApp.controller('AboutController', function($scope, $location, BrandingService, ServerStatus, AppService, SystemInfo, AppUtils) {
$scope.appName = BrandingService.appName;
$scope.brandingService = BrandingService.watch($scope);
$scope.Page = 'general';
$scope.sysinfo = SystemInfo.watch($scope);
$scope.state = ServerStatus.watch($scope);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
backupApp.controller('AppController', function($scope, BrandingService, ServerStatus, SystemInfo) {
$scope.appName = BrandingService.appName;
$scope.brandingService = BrandingService.watch($scope);
$scope.state = ServerStatus.watch($scope);
$scope.systemInfo = SystemInfo.watch($scope);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ backupApp.controller('SystemSettingsController', function($scope, $location, App
$scope.allowRemoteAccess = data.data['server-listen-interface'] != 'loopback';
$scope.startupDelayDurationValue = data.data['startup-delay'].substr(0, data.data['startup-delay'].length - 1);
$scope.startupDelayDurationMultiplier = data.data['startup-delay'].substr(-1);
$scope.updateChannel = data.data['update-channel'];
$scope.advancedOptions = AppUtils.serializeAdvancedOptionsToArray(data.data);

}, AppUtils.connectionError);
Expand All @@ -33,7 +34,8 @@ backupApp.controller('SystemSettingsController', function($scope, $location, App
'server-passphrase': $scope.requireRemotePassword ? $scope.remotePassword : '',

'server-listen-interface': $scope.allowRemoteAccess ? any : 'loopback',
'startup-delay': $scope.startupDelayDurationValue + '' + $scope.startupDelayDurationMultiplier
'startup-delay': $scope.startupDelayDurationValue + '' + $scope.startupDelayDurationMultiplier,
'update-channel': $scope.updateChannel
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
backupApp.controller('UpdateChangelogController', function($scope, BrandingService, ServerStatus, AppService, AppUtils, SystemInfo) {
$scope.appName = BrandingService.appName;
$scope.brandingService = BrandingService.watch($scope);
$scope.systeminfo = SystemInfo.watch($scope);
$scope.serverstate = ServerStatus.watch($scope);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
backupApp.service('BrandingService', function() {
this.appName = "Duplicati";

var state = { 'appName': 'Duplicati', 'appSubtitle': null };
this.state = state;

this.watch = function(scope, m) {
scope.$on('brandingservicechanged', function() {
if (m) m();

$timeout(function() {
scope.$digest();
});
});

if (m) $timeout(m);
return state;
};
});
18 changes: 18 additions & 0 deletions Duplicati/Server/webroot/ngax/styles/styles2.css
Original file line number Diff line number Diff line change
Expand Up @@ -581,4 +581,22 @@ ul.notification {
font-style: italic;
}

.settings div.sublabel {
clear: both;
padding: 0 31px;
font-style: italic;
}

.logo div.build-suffix {
display: inline;
font-size: 16px;
}

.logo div.powered-by {
font-size: 16px;
margin: 0px;
line-height: 16px;
padding: 0px;
margin-top: -25px;
margin-left: 10px
}
8 changes: 4 additions & 4 deletions Duplicati/Server/webroot/ngax/templates/about.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div ng-controller="AboutController">
<h1>About {{appName}}</h1>
<h1>About {{brandingService.appName}}</h1>
<ul class="tabs">
<li ng-class="{active: Page=='general'}"><a href ng-click="Page='general'">General</a></li>
<li ng-class="{active: Page=='changelog'}"><a href ng-click="Page='changelog'">Changelog</a></li>
Expand All @@ -8,10 +8,10 @@ <h1>About {{appName}}</h1>
</ul>

<div ng-show="Page == 'general'">
<div>{{appName}} was primarily developed by <a href="mailto:[email protected]">Kenneth Skovhede</a> and <a href="mailto:[email protected]">Rene Stach</a>. {{appName}} can be downloaded from <a href="http://www.duplicati.com" target="blank">duplicati.com</a>. {{appName}} is licensed under the <a href="https://www.gnu.org/licenses/lgpl.html">GNU Lesser General Public License</a>.</div>
<div>{{brandingService.appName}} was primarily developed by <a href="mailto:[email protected]">Kenneth Skovhede</a> and <a href="mailto:[email protected]">Rene Stach</a>. {{brandingService.appName}} can be downloaded from <a href="http://www.duplicati.com" target="blank">duplicati.com</a>. {{brandingService.appName}} is licensed under the <a href="https://www.gnu.org/licenses/lgpl.html">GNU Lesser General Public License</a>.</div>

<div>&nbsp;</div>
<div>You are currently running {{appName}} {{sysinfo.ServerVersionName || 'unknown'}}</div>
<div>You are currently running {{brandingService.appName}} {{sysinfo.ServerVersionName || 'unknown'}}</div>

<div ng-show="state.updatedVersion != null &amp;&amp; !state.updateReady &amp;&amp; state.updaterState == 'Waiting'">
Update <a href ng-click="doShowUpdateChangelog()">{{state.updatedVersion}}</a> is available, <a href ng-click="doStartUpdateDownload()">download now</a>
Expand All @@ -36,7 +36,7 @@ <h1>About {{appName}}</h1>
</div>

<div ng-show="Page == 'licenses'" class="licenses">
{{appName}} is using the following third party libraries:
{{brandingService.appName}} is using the following third party libraries:
<ul>
<li ng-show="Licenses == null">Loading ...</li>
<li ng-repeat="item in Licenses" class="licenseentry">
Expand Down
37 changes: 37 additions & 0 deletions Duplicati/Server/webroot/ngax/templates/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,43 @@ <h2>Donation messages</h2>
<a href ng-click="suppressDonationMessages()" ng-show="!SystemInfo.SuppressDonationMessages">Donation messages are visible, click to hide</a>
<a href ng-click="displayDonationMessages()" ng-show="SystemInfo.SuppressDonationMessages">Donation messages are hidden, click to show</a>
</div>

<h2>Update channel</h2>
<div class="input checkbox">
<input type="radio" class="checkbox" id="updateChannelDefault" value="" name="updateChannel" ng-model="updateChannel" />
<label for="updateChannelDefault">Default ({{SystemInfo.DefaultUpdateChannel}})</label>
<div class="sublabel" class="">Same as the base install version: {{SystemInfo.BaseVersionName}}</div>
</div>

<!--
<div class="input checkbox">
<input type="radio" class="checkbox" id="updateChannelStable" value="stable" name="updateChannel" ng-model="updateChannel" />
<label for="updateChannelStable">Stable</label>
<div class="sublabel" class="">Official releases</div>
</div>
-->
<div class="input checkbox">
<input type="radio" class="checkbox" id="updateChannelBeta" value="beta" name="updateChannel" ng-model="updateChannel" />
<label for="updateChannelBeta">Beta</label>
<div class="sublabel">Try out the new features we are working on. Don't use with important data.</div>
</div>
<div class="input checkbox">
<input type="radio" class="checkbox" id="updateChannelExperimental" value="experimental" name="updateChannel" ng-model="updateChannel" />
<label for="updateChannelExperimental">Experimental</label>
<div class="sublabel">Specific builds for developers only.</div>
</div>
<div class="input checkbox">
<input type="radio" class="checkbox" id="updateChannelCanary" value="experimental" name="updateChannel" ng-model="updateChannel" />
<label for="updateChannelCanary">Canary</label>
<div class="sublabel">Individual builds for developers only.</div>
</div>
<!--
<div class="input checkbox">
<input type="radio" class="checkbox" id="updateChannelNightly" value="nightly" name="updateChannel" ng-model="updateChannel" />
<label for="updateChannelNightly">Nightly</label>
<div class="sublabel">Regular builds for developers only</div>
</div>
-->

<h2>Default options</h2>
<div class="input textarea" ng-show="ShowAdvancedTextArea">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div ng-controller="UpdateChangelogController">
<h1>Changelog for {{appName}} {{Version || '-unknown-'}}</h1>
<h1>Changelog for {{brandingService.appName}} {{Version || '-unknown-'}}</h1>

<div>
Current version is {{systeminfo.ServerVersionName}} ({{systeminfo.ServerVersion}})
Expand Down
3 changes: 3 additions & 0 deletions Updates/beta.manifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"ReleaseType": "Beta",
}
Loading

0 comments on commit e0237b5

Please sign in to comment.