Changed the default for auto-update to be notify instead of install.

Added the --auto-update option to the commandline to allow automatic updates.
Added a new Duplicati.Library.AutoUpdater.exe tool to work with updates, especially handy if the update breaks the install and for manual handling of updates.
This commit is contained in:
Kenneth Skovhede
2014-08-17 15:45:44 +02:00
parent 80ea4f5763
commit ef3a62bf72
8 changed files with 181 additions and 15 deletions
@@ -157,6 +157,10 @@
<Project>{CCD76347-7DC7-4B42-B7E1-E500E624CAC3}</Project>
<Name>Duplicati.Library.Backend.OneDrive</Name>
</ProjectReference>
<ProjectReference Include="..\Library\Localization\Duplicati.Library.Localization.csproj">
<Project>{B68F2214-951F-4F78-8488-66E1ED3F50BF}</Project>
<Name>Duplicati.Library.Localization</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="Duplicati.snk" />
+30 -2
View File
@@ -21,6 +21,7 @@ using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using Duplicati.Library.Localization.Short;
namespace Duplicati.CommandLine
{
@@ -230,10 +231,36 @@ namespace Duplicati.CommandLine
Console.WriteLine(string.Format("Failed to delete temp file: {0}", path));
});
var autoupdate = Library.Utility.Utility.ParseBoolOption(options, "auto-update");
options.Remove("auto-update");
if (knownCommands.ContainsKey(command))
{
return knownCommands[command](cargs, options, filter);
var res = knownCommands[command](cargs, options, filter);
if (autoupdate)
{
var update = Library.AutoUpdater.UpdaterManager.LastUpdateCheckVersion;
if (update == null)
update = Library.AutoUpdater.UpdaterManager.CheckForUpdate();
if (update != null && update.Version != Library.AutoUpdater.UpdaterManager.SelfVersion.Version)
{
Console.WriteLine("Found update \"{0}\", downloading ...", update.Displayname);
long lastpg = 0;
Library.AutoUpdater.UpdaterManager.DownloadAndUnpackUpdate(update, f => {
var npg = (long)(f*100);
if (Math.Abs(npg - lastpg) >= 5 || (npg == 100 && lastpg != 100))
{
lastpg = npg;
Console.WriteLine("Downloading {0}% ...", npg);
}
});
Console.WriteLine("Update \"{0}\" ({1}) installed, using on next launch", update.Displayname, update.Version);
}
}
return res;
}
else
{
@@ -281,6 +308,7 @@ namespace Duplicati.CommandLine
new Library.Interface.CommandLineArgument("exclude", Library.Interface.CommandLineArgument.ArgumentType.String, Strings.Program.ExcludeShort, Strings.Program.ExcludeLong),
new Library.Interface.CommandLineArgument("control-files", Library.Interface.CommandLineArgument.ArgumentType.Boolean, Strings.Program.ControlFilesOptionShort, Strings.Program.ControlFilesOptionLong, "false"),
new Library.Interface.CommandLineArgument("quiet-console", Library.Interface.CommandLineArgument.ArgumentType.Boolean, Strings.Program.QuietConsoleOptionShort, Strings.Program.QuietConsoleOptionLong, "false"),
new Library.Interface.CommandLineArgument("auto-update", Library.Interface.CommandLineArgument.ArgumentType.Boolean, LC.L("Toggle automatic updates"), LC.L("Set this option if you prefer to have the commandline version automatically update"), "false"),
});
}
}
@@ -29,8 +29,7 @@ namespace Duplicati.Library.AutoUpdater
private const string UPDATE_README = "AutoUpdateFolderReadme.txt";
private const string UPDATE_INSTALL_FILE = "AutoUpdateInstallIDTemplate.txt";
private const string UPDATEURL_ENVNAME_TEMPLATE = "AUTOUPDATER_{0}_URLS";
internal const string UPDATEURL_ENVNAME_TEMPLATE = "AUTOUPDATER_{0}_URLS";
static AutoUpdateSettings()
{
@@ -6,11 +6,12 @@
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{7E119745-1F62-43F0-936C-F312A1912C0B}</ProjectGuid>
<OutputType>Library</OutputType>
<OutputType>Exe</OutputType>
<RootNamespace>Duplicati.Library.AutoUpdater</RootNamespace>
<AssemblyName>Duplicati.Library.AutoUpdater</AssemblyName>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\..\GUI\Duplicati.GUI.TrayIcon\Duplicati.snk</AssemblyOriginatorKeyFile>
<StartupObject>Duplicati.Library.AutoUpdater.Program</StartupObject>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -43,6 +44,7 @@
<Compile Include="FileEntry.cs" />
<Compile Include="SignatureReadingStream.cs" />
<Compile Include="AutoUpdateSettings.cs" />
<Compile Include="Program.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
+123
View File
@@ -0,0 +1,123 @@
// Copyright (C) 2014, Kenneth Skovhede
// http://www.hexad.dk, opensource@hexad.dk
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.Linq;
using System.Collections.Generic;
namespace Duplicati.Library.AutoUpdater
{
public static class Program
{
public static int Main(string[] args)
{
return Duplicati.Library.AutoUpdater.UpdaterManager.RunFromMostRecent(typeof(Program).GetMethod("RealMain"), args, AutoUpdateStrategy.Never);
}
public static int RealMain(string[] _args)
{
var args = new List<string>(_args);
Duplicati.Library.Utility.CommandLineParser.ExtractOptions(args);
if (args.Count == 0)
{
WriteUsage();
return 100;
}
else if (args.Count != 1)
{
Console.WriteLine("Invalid number of arguments, got {0}:{1}{1}{2}{1}{1}", args.Count, Environment.NewLine, string.Join(Environment.NewLine, args));
return 100;
}
var cmd = args[0].ToLowerInvariant().Trim();
switch (cmd)
{
case "help":
WriteUsage();
return 0;
case "list":
{
var versions = UpdaterManager.FindInstalledVersions();
var selfdir = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
if (string.Equals(Library.Utility.Utility.AppendDirSeparator(selfdir), Library.Utility.Utility.AppendDirSeparator(UpdaterManager.InstalledBaseDir)))
versions = versions.Union(new KeyValuePair<string, UpdateInfo>[] { new KeyValuePair<string, UpdateInfo>(selfdir, UpdaterManager.SelfVersion) });
Console.WriteLine(string.Join(Environment.NewLine, versions.Select(x => string.Format(" {0} {1} ({2})", (x.Value.Version == UpdaterManager.SelfVersion.Version ? "*" : "-"), x.Value.Displayname, x.Value.Version))));
return 0;
}
case "check":
{
var update = UpdaterManager.CheckForUpdate();
if (update == null)
Console.WriteLine("No updates found");
else if (update.Version == UpdaterManager.SelfVersion.Version)
Console.WriteLine("You are running the latest version: {0}", update.Displayname);
else
Console.WriteLine("New version is available: {0}", update.Displayname);
return 0;
}
case "install":
{
var update = UpdaterManager.CheckForUpdate();
if (update == null || update.Version == UpdaterManager.SelfVersion.Version)
{
Console.WriteLine("You are running the latest version: {0} ({1})", UpdaterManager.SelfVersion.Displayname, System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);
return 0;
}
Console.WriteLine("Downloading update \"{0}\" ...", update.Displayname);
long lastpg = 0;
UpdaterManager.DownloadAndUnpackUpdate(update, f => {
var npg = (long)(f*100);
if (Math.Abs(npg - lastpg) >= 5 || (npg == 100 && lastpg != 100))
{
lastpg = npg;
Console.WriteLine("Downloading {0}% ...", npg);
}
});
Console.WriteLine("New version \"{0}\" installed!", update.Displayname);
return 0;
}
default:
Console.WriteLine("Unknown command: \"{0}\"", args[0]);
Console.WriteLine();
Console.WriteLine("Try the command \"{0}\" instead", "help");
return 100;
}
}
private static void WriteUsage()
{
Console.WriteLine("Usage:{0}\t{1}{2} [LIST|CHECK|INSTALL|HELP]", Environment.NewLine, Duplicati.Library.Utility.Utility.IsMono ? "mono " : "", System.IO.Path.GetFileName(System.Reflection.Assembly.GetExecutingAssembly().Location));
Console.WriteLine();
Console.WriteLine("Environment variables:");
Console.WriteLine();
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();
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("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();
}
}
}
@@ -38,7 +38,7 @@ namespace Duplicati.Library.AutoUpdater
private static readonly string[] MANIFEST_URLS = AutoUpdateSettings.URLs;
private static readonly string APPNAME = AutoUpdateSettings.AppName;
private static readonly string INSTALLDIR;
internal static readonly string INSTALLDIR;
private static readonly string INSTALLED_BASE_DIR = string.IsNullOrWhiteSpace(System.Environment.GetEnvironmentVariable(string.Format(INSTALLDIR_ENVNAME_TEMPLATE, APPNAME))) ?
System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location)
@@ -50,16 +50,16 @@ namespace Duplicati.Library.AutoUpdater
private static KeyValuePair<string, UpdateInfo>? m_hasUpdateInstalled;
private static readonly UpdateInfo SelfVersion;
public static readonly UpdateInfo SelfVersion;
public static event Action<Exception> OnError;
private const string DATETIME_FORMAT = "yyyymmddhhMMss";
private const string INSTALLDIR_ENVNAME_TEMPLATE = "AUTOUPDATER_{0}_INSTALL_ROOT";
private const string SKIPUPDATE_ENVNAME_TEMPLATE = "AUTOUPDATER_{0}_SKIP_UPDATE";
internal const string SKIPUPDATE_ENVNAME_TEMPLATE = "AUTOUPDATER_{0}_SKIP_UPDATE";
private const string RUN_UPDATED_FOLDER_PATH = "AUTOUPDATER_LOAD_UPDATE";
private const string SLEEP_ENVNAME_TEMPLATE = "AUTOUPDATER_{0}_SLEEP";
private const string UPDATE_STRATEGY_ENVNAME_TEMPLATE = "AUTOUPDATER_{0}_POLICY";
internal const string UPDATE_STRATEGY_ENVNAME_TEMPLATE = "AUTOUPDATER_{0}_POLICY";
private const string UPDATE_MANIFEST_FILENAME = "autoupdate.manifest";
private const string README_FILE = "README.txt";
private const string INSTALL_FILE = "installation.txt";
@@ -71,6 +71,11 @@ namespace Duplicati.Library.AutoUpdater
/// <value>The original directory that this application was installed into</value>
public static string InstalledBaseDir { get { return INSTALLED_BASE_DIR; } }
/// <summary>
/// Gets the last version found from an update
/// </summary>
public static UpdateInfo LastUpdateCheckVersion { get; private set; }
static UpdaterManager()
{
string installdir = null;
@@ -197,7 +202,7 @@ namespace Duplicati.Library.AutoUpdater
using(var tmpfile = new Library.Utility.TempFile())
{
System.Net.WebClient wc = new System.Net.WebClient();
wc.Headers.Add(System.Net.HttpRequestHeader.UserAgent, string.Format("{0} v{1}", APPNAME, SelfVersion.Version));
wc.Headers.Add(System.Net.HttpRequestHeader.UserAgent, string.Format("{0} v{1}{2}", APPNAME, SelfVersion.Version, string.IsNullOrWhiteSpace(InstallID) ? "" : " -" + InstallID));
wc.Headers.Add("X-Install-ID", InstallID);
wc.DownloadFile(url, tmpfile);
@@ -214,6 +219,7 @@ namespace Duplicati.Library.AutoUpdater
if (string.Equals(SelfVersion.ReleaseType, "Debug", StringComparison.InvariantCultureIgnoreCase) && !string.Equals(update.ReleaseType, SelfVersion.ReleaseType, StringComparison.CurrentCultureIgnoreCase))
return null;
LastUpdateCheckVersion = update;
return update;
}
}
@@ -856,7 +862,7 @@ namespace Duplicati.Library.AutoUpdater
}
}
public static int RunFromMostRecent(System.Reflection.MethodInfo method, string[] cmdargs, AutoUpdateStrategy defaultstrategy = AutoUpdateStrategy.InstallDuring)
public static int RunFromMostRecent(System.Reflection.MethodInfo method, string[] cmdargs, AutoUpdateStrategy defaultstrategy = AutoUpdateStrategy.CheckDuring)
{
// If the update is disabled, go straight in
if (DISABLE_UPDATE_DOMAIN)
+4 -4
View File
@@ -226,10 +226,6 @@
<Project>{2C838169-B187-4B09-8768-1C24C2521C8D}</Project>
<Name>Duplicati.Library.SQLiteHelper</Name>
</ProjectReference>
<ProjectReference Include="..\Library\AutoUpdater\Duplicati.Library.AutoUpdater.csproj">
<Project>{7E119745-1F62-43F0-936C-F312A1912C0B}</Project>
<Name>Duplicati.Library.AutoUpdater</Name>
</ProjectReference>
<ProjectReference Include="..\Library\Backend\OneDrive\Duplicati.Library.Backend.OneDrive.csproj">
<Project>{CCD76347-7DC7-4B42-B7E1-E500E624CAC3}</Project>
<Name>Duplicati.Library.Backend.OneDrive</Name>
@@ -242,6 +238,10 @@
<Project>{B68F2214-951F-4F78-8488-66E1ED3F50BF}</Project>
<Name>Duplicati.Library.Localization</Name>
</ProjectReference>
<ProjectReference Include="..\Library\AutoUpdater\Duplicati.Library.AutoUpdater.csproj">
<Project>{7E119745-1F62-43F0-936C-F312A1912C0B}</Project>
<Name>Duplicati.Library.AutoUpdater</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Strings\DuplicatiRunner.resx">
@@ -42,5 +42,9 @@
<Project>{19E661D2-C5DA-4F35-B3EE-7586E5734B5F}</Project>
<Name>Duplicati.Server</Name>
</ProjectReference>
<ProjectReference Include="..\..\Library\AutoUpdater\Duplicati.Library.AutoUpdater.csproj">
<Project>{7E119745-1F62-43F0-936C-F312A1912C0B}</Project>
<Name>Duplicati.Library.AutoUpdater</Name>
</ProjectReference>
</ItemGroup>
</Project>