From c2fc930411ddbcd15072acc9d68f7c6be06ea451 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Tue, 14 Oct 2014 14:45:49 +0200 Subject: Implemented storing backup task info in the backup data --- Duplicati/Server/Database/Connection.cs | 14 +++++- Duplicati/Server/Duplicati.Server.csproj | 1 + Duplicati/Server/Runner.cs | 52 ++++++++++++++++++++-- .../Server/Serializable/ImportExportStructure.cs | 33 ++++++++++++++ Duplicati/Server/SpecialFolders.cs | 28 ++++++++++++ Duplicati/Server/WebServer/ControlHandler.cs | 25 +++-------- .../Server/WebServer/ControlMethods/GetBackup.cs | 30 +------------ Duplicati/Server/webroot/greeno/index.html | 12 +++++ .../Server/webroot/greeno/scripts/editdialog.js | 3 ++ 9 files changed, 145 insertions(+), 53 deletions(-) create mode 100644 Duplicati/Server/Serializable/ImportExportStructure.cs (limited to 'Duplicati') diff --git a/Duplicati/Server/Database/Connection.cs b/Duplicati/Server/Database/Connection.cs index ec5416f0d..12c5087fe 100644 --- a/Duplicati/Server/Database/Connection.cs +++ b/Duplicati/Server/Database/Connection.cs @@ -64,7 +64,18 @@ namespace Duplicati.Server.Database using(var cmd = m_connection.CreateCommand()) f(cmd); } - + + internal Serializable.ImportExportStructure PrepareBackupForExport(IBackup backup) + { + var scheduleId = GetScheduleIDsFromTags(new string[] { "ID=" + backup.ID }); + return new Serializable.ImportExportStructure() { + CreatedByVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(), + Backup = (Database.Backup)backup, + Schedule = (Database.Schedule)(scheduleId.Any() ? GetSchedule(scheduleId.First()) : null), + DisplayNames = SpecialFolders.GetSourceNames(backup) + }; + } + public string RegisterTemporaryBackup(IBackup backup) { lock(m_lock) @@ -562,6 +573,7 @@ namespace Duplicati.Server.Database foreach(var n in lst) n.Metadata = GetMetadata(long.Parse(n.ID)); + return lst; } } diff --git a/Duplicati/Server/Duplicati.Server.csproj b/Duplicati/Server/Duplicati.Server.csproj index df9b5dca3..00239723b 100644 --- a/Duplicati/Server/Duplicati.Server.csproj +++ b/Duplicati/Server/Duplicati.Server.csproj @@ -119,6 +119,7 @@ + diff --git a/Duplicati/Server/Runner.cs b/Duplicati/Server/Runner.cs index 41fa9bad5..9518aa41e 100644 --- a/Duplicati/Server/Runner.cs +++ b/Duplicati/Server/Runner.cs @@ -325,6 +325,7 @@ namespace Duplicati.Server public static Duplicati.Library.Interface.IBasicResults Run(IRunnerData data, bool fromQueue) { var backup = data.Backup; + Duplicati.Library.Utility.TempFolder tempfolder = null; if (backup.Metadata == null) backup.Metadata = new Dictionary(); @@ -342,7 +343,10 @@ namespace Duplicati.Server if (data.ExtraOptions != null) foreach(var k in data.ExtraOptions) options[k.Key] = k.Value; - + + // Log file is using the internal log-handler + // so we can display output in the GUI as well as log + // into the given file if (options.ContainsKey("log-file")) { var file = options["log-file"]; @@ -357,7 +361,49 @@ namespace Duplicati.Server Program.LogHandler.SetOperationFile(file, level); } - + + // Pack in the system or task config for easy restore + if (data.Operation == DuplicatiOperation.Backup && options.ContainsKey("store-task-config")) + { + var all_tasks = string.Equals(options["store-task-config"], "all", StringComparison.InvariantCultureIgnoreCase) || string.Equals(options["store-task-config"], "*", StringComparison.InvariantCultureIgnoreCase); + var this_task = Duplicati.Library.Utility.Utility.ParseBool(options["store-task-config"], false); + + options.Remove("store-task-config"); + + if (all_tasks || this_task) + { + if (tempfolder == null) + tempfolder = new Duplicati.Library.Utility.TempFolder(); + + var temppath = System.IO.Path.Combine(tempfolder, "task-setup.json"); + using(var tempfile = Duplicati.Library.Utility.TempFile.WrapExistingFile(temppath)) + { + object taskdata = null; + if (all_tasks) + taskdata = Program.DataConnection.Backups.Where(x => !x.IsTemporary).Select(x => Program.DataConnection.PrepareBackupForExport(Program.DataConnection.GetBackup(x.ID))); + else + taskdata = new [] { Program.DataConnection.PrepareBackupForExport(data.Backup) }; + + using(var fs = System.IO.File.OpenWrite(tempfile)) + using(var sw = new System.IO.StreamWriter(fs, System.Text.Encoding.UTF8)) + Serializer.SerializeJson(sw, taskdata, true); + + tempfile.Protected = true; + + string controlfiles = null; + options.TryGetValue("control-files", out controlfiles); + + if (string.IsNullOrWhiteSpace(controlfiles)) + controlfiles = tempfile; + else + controlfiles += System.IO.Path.PathSeparator + tempfile; + + options["control-files"] = controlfiles; + } + } + } + + using(tempfolder) using(var controller = new Duplicati.Library.Main.Controller(backup.TargetURL, options, sink)) { ((RunnerData)data).Controller = controller; @@ -372,7 +418,7 @@ namespace Duplicati.Server let p = SpecialFolders.ExpandEnvironmentVariables(n) where !string.IsNullOrWhiteSpace(p) select p).ToArray(); - + var r = controller.Backup(sources, filter); UpdateMetadata(backup, r); return r; diff --git a/Duplicati/Server/Serializable/ImportExportStructure.cs b/Duplicati/Server/Serializable/ImportExportStructure.cs new file mode 100644 index 000000000..f1e049a23 --- /dev/null +++ b/Duplicati/Server/Serializable/ImportExportStructure.cs @@ -0,0 +1,33 @@ +// 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.Collections.Generic; + +namespace Duplicati.Server.Serializable +{ + internal class ImportExportStructure + { + public string CreatedByVersion { get; set; } + public Duplicati.Server.Database.Schedule Schedule { get; set; } + public Duplicati.Server.Database.Backup Backup { get; set; } + public Dictionary DisplayNames { get; set; } + } + + +} + diff --git a/Duplicati/Server/SpecialFolders.cs b/Duplicati/Server/SpecialFolders.cs index db40ec6df..518c3b345 100644 --- a/Duplicati/Server/SpecialFolders.cs +++ b/Duplicati/Server/SpecialFolders.cs @@ -109,6 +109,34 @@ namespace Duplicati.Server Nodes = lst.ToArray(); } + + internal static Dictionary GetSourceNames(Serialization.Interface.IBackup backup) + { + var systemIO = Duplicati.Library.Snapshots.SnapshotUtility.SystemIO; + + return backup.Sources.Distinct().Select(x => { + var sp = SpecialFolders.TranslateToDisplayString(x); + if (sp != null) + return new KeyValuePair(x, sp); + + x = SpecialFolders.ExpandEnvironmentVariables(x); + try { + var nx = x; + if (nx.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString())) + nx = nx.Substring(0, nx.Length - 1); + var n = systemIO.PathGetFileName(nx); + if (!string.IsNullOrWhiteSpace(n)) + return new KeyValuePair(x, n); + } catch { + } + + if (x.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString()) && x.Length > 1) + return new KeyValuePair(x, x.Substring(0, x.Length - 1).Substring(x.Substring(0, x.Length - 1).LastIndexOf("/") + 1)); + else + return new KeyValuePair(x, x); + + }).ToDictionary(x => x.Key, x => x.Value); + } } } diff --git a/Duplicati/Server/WebServer/ControlHandler.cs b/Duplicati/Server/WebServer/ControlHandler.cs index 331d9bde1..4ea8e159c 100644 --- a/Duplicati/Server/WebServer/ControlHandler.cs +++ b/Duplicati/Server/WebServer/ControlHandler.cs @@ -665,15 +665,7 @@ namespace Duplicati.Server.WebServer } } - - private class ImportExportStructure - { - public string CreatedByVersion { get; set; } - public Duplicati.Server.Database.Schedule Schedule { get; set; } - public Duplicati.Server.Database.Backup Backup { get; set; } - public Dictionary DisplayNames { get; set; } - } - + private void ExportBackup(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw) { HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString; @@ -692,14 +684,7 @@ namespace Duplicati.Server.WebServer else { var passphrase = input["passphrase"].Value; - var scheduleId = Program.DataConnection.GetScheduleIDsFromTags(new string[] { "ID=" + bk.ID }); - - var ipx = new ImportExportStructure() { - CreatedByVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(), - Backup = (Database.Backup)bk, - Schedule = (Database.Schedule)(scheduleId.Any() ? Program.DataConnection.GetSchedule(scheduleId.First()) : null), - DisplayNames = GetSourceNames(bk) - }; + var ipx = Program.DataConnection.PrepareBackupForExport(bk); byte[] data; using(var ms = new System.IO.MemoryStream()) @@ -751,7 +736,7 @@ namespace Duplicati.Server.WebServer } else { - ImportExportStructure ipx; + Serializable.ImportExportStructure ipx; var file = request.Form.GetFile("config"); if (file == null) @@ -769,12 +754,12 @@ namespace Duplicati.Server.WebServer using(var m = new Duplicati.Library.Encryption.AESEncryption(passphrase, new Dictionary())) using(var m2 = m.Decrypt(fs)) using(var sr = new System.IO.StreamReader(m2)) - ipx = Serializer.Deserialize(sr); + ipx = Serializer.Deserialize(sr); } else { using(var sr = new System.IO.StreamReader(fs)) - ipx = Serializer.Deserialize(sr); + ipx = Serializer.Deserialize(sr); } } diff --git a/Duplicati/Server/WebServer/ControlMethods/GetBackup.cs b/Duplicati/Server/WebServer/ControlMethods/GetBackup.cs index 42ef68665..d8752e153 100644 --- a/Duplicati/Server/WebServer/ControlMethods/GetBackup.cs +++ b/Duplicati/Server/WebServer/ControlMethods/GetBackup.cs @@ -33,7 +33,7 @@ namespace Duplicati.Server.WebServer { var scheduleId = Program.DataConnection.GetScheduleIDsFromTags(new string[] { "ID=" + bk.ID }); var schedule = scheduleId.Any() ? Program.DataConnection.GetSchedule(scheduleId.First()) : null; - var sourcenames = GetSourceNames(bk); + var sourcenames = SpecialFolders.GetSourceNames(bk); //TODO: Filter out the password in both settings and the target url @@ -48,34 +48,6 @@ namespace Duplicati.Server.WebServer }); } } - - private Dictionary GetSourceNames(Duplicati.Server.Serialization.Interface.IBackup backup) - { - var systemIO = Duplicati.Library.Snapshots.SnapshotUtility.SystemIO; - - return backup.Sources.Distinct().Select(x => { - var sp = SpecialFolders.TranslateToDisplayString(x); - if (sp != null) - return new KeyValuePair(x, sp); - - x = SpecialFolders.ExpandEnvironmentVariables(x); - try { - var nx = x; - if (nx.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString())) - nx = nx.Substring(0, nx.Length - 1); - var n = systemIO.PathGetFileName(nx); - if (!string.IsNullOrWhiteSpace(n)) - return new KeyValuePair(x, n); - } catch { - } - - if (x.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString()) && x.Length > 1) - return new KeyValuePair(x, x.Substring(0, x.Length - 1).Substring(x.Substring(0, x.Length - 1).LastIndexOf("/") + 1)); - else - return new KeyValuePair(x, x); - - }).ToDictionary(x => x.Key, x => x.Value); - } } } diff --git a/Duplicati/Server/webroot/greeno/index.html b/Duplicati/Server/webroot/greeno/index.html index f26d0b901..cd1e54f87 100644 --- a/Duplicati/Server/webroot/greeno/index.html +++ b/Duplicati/Server/webroot/greeno/index.html @@ -297,6 +297,18 @@
+ +
+
Store configuration
+ +
+ +
+
Click the "Browse" button to add folders
diff --git a/Duplicati/Server/webroot/greeno/scripts/editdialog.js b/Duplicati/Server/webroot/greeno/scripts/editdialog.js index b43e5a7b9..35aa1ca57 100644 --- a/Duplicati/Server/webroot/greeno/scripts/editdialog.js +++ b/Duplicati/Server/webroot/greeno/scripts/editdialog.js @@ -417,6 +417,9 @@ $(document).ready(function() { delete dict['Backup']['Settings']['keep-versions']; delete dict['Backup']['Settings']['keep-time']; } + }, + 'store-task-config': function(dict, key, el, cfgel) { + dict['Backup']['Settings']['store-task-config'] = $(el).val(); } } }; -- cgit v1.2.3