diff options
author | Kenneth Skovhede <kenneth@hexad.dk> | 2014-10-14 16:45:49 +0400 |
---|---|---|
committer | Kenneth Skovhede <kenneth@hexad.dk> | 2014-10-14 16:45:49 +0400 |
commit | c2fc930411ddbcd15072acc9d68f7c6be06ea451 (patch) | |
tree | 1464e18f89e269164ae036fd9592ea7f6e9d12c8 /Duplicati | |
parent | d5dd9391f3bf01238ef6191b72e921602e63fa3d (diff) |
Implemented storing backup task info in the backup data
Diffstat (limited to 'Duplicati')
-rw-r--r-- | Duplicati/Server/Database/Connection.cs | 14 | ||||
-rw-r--r-- | Duplicati/Server/Duplicati.Server.csproj | 1 | ||||
-rw-r--r-- | Duplicati/Server/Runner.cs | 52 | ||||
-rw-r--r-- | Duplicati/Server/Serializable/ImportExportStructure.cs | 33 | ||||
-rw-r--r-- | Duplicati/Server/SpecialFolders.cs | 28 | ||||
-rw-r--r-- | Duplicati/Server/WebServer/ControlHandler.cs | 25 | ||||
-rw-r--r-- | Duplicati/Server/WebServer/ControlMethods/GetBackup.cs | 30 | ||||
-rw-r--r-- | Duplicati/Server/webroot/greeno/index.html | 12 | ||||
-rw-r--r-- | Duplicati/Server/webroot/greeno/scripts/editdialog.js | 3 |
9 files changed, 145 insertions, 53 deletions
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 @@ <Compile Include="LogWriteHandler.cs" />
<Compile Include="Database\Notification.cs" />
<Compile Include="Database\TempFile.cs" />
+ <Compile Include="Serializable\ImportExportStructure.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
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<string, string>();
@@ -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<string, string> 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<string, string> 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<string, string>(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<string, string>(x, n);
+ } catch {
+ }
+
+ if (x.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString()) && x.Length > 1)
+ return new KeyValuePair<string, string>(x, x.Substring(0, x.Length - 1).Substring(x.Substring(0, x.Length - 1).LastIndexOf("/") + 1));
+ else
+ return new KeyValuePair<string, string>(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<string, string> 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<string, string>()))
using(var m2 = m.Decrypt(fs))
using(var sr = new System.IO.StreamReader(m2))
- ipx = Serializer.Deserialize<ImportExportStructure>(sr);
+ ipx = Serializer.Deserialize<Serializable.ImportExportStructure>(sr);
}
else
{
using(var sr = new System.IO.StreamReader(fs))
- ipx = Serializer.Deserialize<ImportExportStructure>(sr);
+ ipx = Serializer.Deserialize<Serializable.ImportExportStructure>(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<string, string> 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<string, string>(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<string, string>(x, n);
- } catch {
- }
-
- if (x.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString()) && x.Length > 1)
- return new KeyValuePair<string, string>(x, x.Substring(0, x.Length - 1).Substring(x.Substring(0, x.Length - 1).LastIndexOf("/") + 1));
- else
- return new KeyValuePair<string, string>(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 @@ </div> <div id="edit-tab-sourcedata"> + + <div class="input-wrapper"> + <div class="edit-dialog-label" title="Choose if the backup configuration should be stored">Store configuration</div> + <select id="store-task-config" name="store-task-config"> + <option value="false">Don't store setup</option> + <option value="true">Store this backup job setup</option> + <option value="all">Store all backup job setups</option> + </select> + </div> + + <div class="clearfix"></div> + <div id="source-folder-paths" class="empty"> <div id="source-folder-droptarget"></div> <div id="source-folder-paths-hint" class="hint-text">Click the "Browse" button to add folders</div> 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(); } } }; |