Merge branch 'feature/add_single_result_code'

# Conflicts:
#	Duplicati/Library/Modules/Builtin/Strings.cs
This commit is contained in:
Kenneth Skovhede
2017-01-23 23:32:30 +01:00
7 changed files with 150 additions and 94 deletions
+5 -1
View File
@@ -573,8 +573,12 @@ namespace Duplicati.CommandLine
if (result.PartialBackup)
return 50;
//Completed with errors = 3
if (result.ParsedResult == Library.Interface.ParsedResultType.Error)
return 3;
//Completed with warnings = 2
if (result.Warnings.Count() > 0 || result.Errors.Count() > 0)
if (result.ParsedResult == Library.Interface.ParsedResultType.Warning)
return 2;
//Success, but no upload = 1
@@ -20,6 +20,15 @@ using System.Collections.Generic;
namespace Duplicati.Library.Interface
{
public enum ParsedResultType
{
Unknown,
Success,
Warning,
Error,
Fatal
}
public interface IBasicResults
{
DateTime BeginTime { get; }
@@ -29,6 +38,7 @@ namespace Duplicati.Library.Interface
IEnumerable<string> Errors { get; }
IEnumerable<string> Warnings { get; }
IEnumerable<string> Messages { get; }
ParsedResultType ParsedResult { get; }
}
public interface IBackendStatstics
+46 -6
View File
@@ -20,6 +20,7 @@ using Duplicati.Library.Interface;
using System.Collections.Generic;
using Duplicati.Library.Main.Database;
using Duplicati.Library.Logging;
using System.Linq;
namespace Duplicati.Library.Main
{
@@ -244,7 +245,20 @@ namespace Duplicati.Library.Main
m_verboseErrors = value;
}
}
public virtual ParsedResultType ParsedResult
{
get
{
if (Errors != null && Errors.Any())
return ParsedResultType.Error;
else if (Warnings != null && Warnings.Any())
return ParsedResultType.Warning;
else
return ParsedResultType.Success;
}
}
public DateTime EndTime { get; set; }
public DateTime BeginTime { get; set; }
public TimeSpan Duration { get { return EndTime.Ticks == 0 ? new TimeSpan(0) : EndTime - BeginTime; } }
@@ -754,7 +768,7 @@ namespace Duplicati.Library.Main
}
}
internal class BackupResults : BasicResults, IBackupResults
{
public long DeletedFiles { get; internal set; }
@@ -777,13 +791,26 @@ namespace Duplicati.Library.Main
public long DeletedSymlinks { get; internal set; }
public bool PartialBackup { get; internal set; }
public bool Dryrun { get; internal set; }
public override OperationMode MainOperation { get { return OperationMode.Backup; } }
public ICompactResults CompactResults { get; internal set; }
public IDeleteResults DeleteResults { get; internal set; }
public IRepairResults RepairResults { get; internal set; }
public ITestResults TestResults { get; internal set; }
public IRepairResults RepairResults { get; internal set; }
public ITestResults TestResults { get; internal set; }
public override ParsedResultType ParsedResult
{
get
{
if ((Errors != null && Errors.Any()) || FilesWithError > 0)
return ParsedResultType.Error;
else if ((Warnings != null && Warnings.Any()) || PartialBackup)
return ParsedResultType.Warning;
else
return ParsedResultType.Success;
}
}
}
internal class RestoreResults : BasicResults, Library.Interface.IRestoreResults
@@ -800,6 +827,19 @@ namespace Duplicati.Library.Main
public override OperationMode MainOperation { get { return OperationMode.Restore; } }
public IRecreateDatabaseResults RecreateDatabaseResults { get; internal set; }
public override ParsedResultType ParsedResult
{
get
{
if (Errors != null && Errors.Any())
return ParsedResultType.Error;
else if ((Warnings != null && Warnings.Any()) || FilesRestored == 0)
return ParsedResultType.Warning;
else
return ParsedResultType.Success;
}
}
}
internal class ListResultFile : Duplicati.Library.Interface.IListResultFile
@@ -51,29 +51,13 @@ namespace Duplicati.Library.Modules.Builtin
/// <summary>
/// The default mail level
/// </summary>
private const ReportLevels DEFAULT_LEVEL = ReportLevels.All;
private const string DEFAULT_LEVEL = "all";
/// <summary>
/// The default mail body
/// The default message body
/// </summary>
private readonly string DEFAULT_MESSAGE = string.Format("Duplicati %OPERATIONNAME% report for %backup-name%{0}{0}%RESULT%", Environment.NewLine);
/// <summary>
/// The default mail sender
/// </summary>
private const string DEFAULT_SENDER = "no-reply";
#endregion
/// <summary>
/// The allowed mail levels
/// </summary>
[Flags]
private enum ReportLevels
{
Success = 0x1,
Warning = 0x2,
Error = 0x4,
All = Success | Warning | Error
}
#region Private variables
/// <summary>
@@ -116,7 +100,7 @@ namespace Duplicati.Library.Modules.Builtin
/// <summary>
/// The XMPP send level
/// </summary>
private ReportLevels m_level;
private string[] m_levels;
/// <summary>
/// True to send all operations
/// </summary>
@@ -161,7 +145,7 @@ namespace Duplicati.Library.Modules.Builtin
new CommandLineArgument(OPTION_MESSAGE, CommandLineArgument.ArgumentType.String, Strings.SendJabberMessage.SendxmppmessageShort, Strings.SendJabberMessage.SendxmppmessageLong, DEFAULT_MESSAGE),
new CommandLineArgument(OPTION_USERNAME, CommandLineArgument.ArgumentType.String, Strings.SendJabberMessage.SendxmppusernameShort, Strings.SendJabberMessage.SendxmppusernameLong),
new CommandLineArgument(OPTION_PASSWORD, CommandLineArgument.ArgumentType.String, Strings.SendJabberMessage.SendxmpppasswordShort, Strings.SendJabberMessage.SendxmpppasswordLong),
new CommandLineArgument(OPTION_SENDLEVEL, CommandLineArgument.ArgumentType.Enumeration, Strings.SendJabberMessage.SendxmpplevelShort, Strings.SendJabberMessage.SendxmpplevelLong(ReportLevels.Success.ToString(), ReportLevels.Warning.ToString(), ReportLevels.Error.ToString(), ReportLevels.All.ToString()), DEFAULT_LEVEL.ToString(), null, Enum.GetNames(typeof(ReportLevels))),
new CommandLineArgument(OPTION_SENDLEVEL, CommandLineArgument.ArgumentType.Enumeration, Strings.SendJabberMessage.SendxmpplevelShort, Strings.SendJabberMessage.SendxmpplevelLong(ParsedResultType.Success.ToString(), ParsedResultType.Warning.ToString(), ParsedResultType.Error.ToString(), ParsedResultType.Fatal.ToString(), "All"), DEFAULT_LEVEL, null, Enum.GetNames(typeof(ParsedResultType)).Union(new string[] { "All" } ).ToArray()),
new CommandLineArgument(OPTION_SENDALL, CommandLineArgument.ArgumentType.Boolean, Strings.SendJabberMessage.SendxmppanyoperationShort, Strings.SendJabberMessage.SendxmppanyoperationLong),
});
}
@@ -183,23 +167,23 @@ namespace Duplicati.Library.Modules.Builtin
commandlineOptions.TryGetValue(OPTION_MESSAGE, out m_body);
m_options = commandlineOptions;
m_level = 0;
string tmp;
commandlineOptions.TryGetValue(OPTION_SENDLEVEL, out tmp);
if (!string.IsNullOrEmpty(tmp))
foreach(var s in tmp.Split(new string[] {","}, StringSplitOptions.RemoveEmptyEntries))
{
if (string.IsNullOrEmpty(s))
continue;
m_levels =
tmp
.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)
.Where(x => !string.IsNullOrWhiteSpace(x))
.Select(x => x.Trim())
.ToArray();
ReportLevels m;
if (Enum.TryParse(s.Trim(), true, out m))
m_level |= m;
}
if (m_level == 0)
m_level = DEFAULT_LEVEL;
if (m_levels == null || m_levels.Length == 0)
m_levels =
DEFAULT_LEVEL
.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)
.Where(x => !string.IsNullOrWhiteSpace(x))
.Select(x => x.Trim())
.ToArray();
m_sendAll = Utility.Utility.ParseBoolOption(commandlineOptions, OPTION_SENDALL);
@@ -240,20 +224,20 @@ namespace Duplicati.Library.Modules.Builtin
if (string.Equals(m_operationname, "Backup", StringComparison.InvariantCultureIgnoreCase))
{
ReportLevels level;
ParsedResultType level;
if (result is Exception)
level = ReportLevels.Error;
else if (result != null && result is Library.Interface.IBackupResults && (result as Library.Interface.IBackupResults).Errors.Count() > 0)
level = ReportLevels.Warning;
level = ParsedResultType.Fatal;
else if (result != null && result is Library.Interface.IBasicResults)
level = ((IBasicResults)result).ParsedResult;
else
level = ReportLevels.Success;
level = ParsedResultType.Error;
m_parsedresultlevel = level.ToString();
if (m_level != ReportLevels.All)
if (!m_levels.Any(x => string.Equals(x, "all", StringComparison.OrdinalIgnoreCase)))
{
//Check if this level should send mail
if ((m_level & level) == 0)
if (!m_levels.Any(x => string.Equals(x, level.ToString(), StringComparison.OrdinalIgnoreCase)))
return;
}
}
+24 -37
View File
@@ -68,7 +68,7 @@ namespace Duplicati.Library.Modules.Builtin
/// <summary>
/// The default mail level
/// </summary>
private const MailLevels DEFAULT_LEVEL = MailLevels.All;
private const string DEFAULT_LEVEL = "all";
/// <summary>
/// The default mail body
/// </summary>
@@ -79,20 +79,7 @@ namespace Duplicati.Library.Modules.Builtin
private const string DEFAULT_SENDER = "no-reply";
#endregion
/// <summary>
/// The allowed mail levels
/// </summary>
[Flags]
private enum MailLevels
{
Success = 0x1,
Warning = 0x2,
Error = 0x4,
All = Success | Warning | Error
}
#region Private variables
/// <summary>
/// The cached name of the operation
/// </summary>
@@ -145,7 +132,7 @@ namespace Duplicati.Library.Modules.Builtin
/// <summary>
/// The mail send level
/// </summary>
private MailLevels m_level;
private string[] m_levels;
/// <summary>
/// True to send all operations
/// </summary>
@@ -193,7 +180,7 @@ namespace Duplicati.Library.Modules.Builtin
new CommandLineArgument(OPTION_SERVER, CommandLineArgument.ArgumentType.String, Strings.SendMail.OptionServerShort, Strings.SendMail.OptionServerLong),
new CommandLineArgument(OPTION_USERNAME, CommandLineArgument.ArgumentType.String, Strings.SendMail.OptionUsernameShort, Strings.SendMail.OptionUsernameLong),
new CommandLineArgument(OPTION_PASSWORD, CommandLineArgument.ArgumentType.String, Strings.SendMail.OptionPasswordShort, Strings.SendMail.OptionPasswordLong),
new CommandLineArgument(OPTION_SENDLEVEL, CommandLineArgument.ArgumentType.String, Strings.SendMail.OptionSendlevelShort, Strings.SendMail.OptionSendlevelLong(MailLevels.Success.ToString(), MailLevels.Warning.ToString(), MailLevels.Error.ToString(), MailLevels.All.ToString()), DEFAULT_LEVEL.ToString(), null, Enum.GetNames(typeof(MailLevels))),
new CommandLineArgument(OPTION_SENDLEVEL, CommandLineArgument.ArgumentType.String, Strings.SendMail.OptionSendlevelShort, Strings.SendMail.OptionSendlevelLong(ParsedResultType.Success.ToString(), ParsedResultType.Warning.ToString(), ParsedResultType.Error.ToString(), ParsedResultType.Fatal.ToString(), "All"), DEFAULT_LEVEL, null, Enum.GetNames(typeof(ParsedResultType)).Union(new string [] { "All" }).ToArray()),
new CommandLineArgument(OPTION_SENDALL, CommandLineArgument.ArgumentType.Boolean, Strings.SendMail.OptionSendallShort, Strings.SendMail.OptionSendallLong),
});
}
@@ -218,24 +205,24 @@ namespace Duplicati.Library.Modules.Builtin
commandlineOptions.TryGetValue(OPTION_BODY, out m_body);
m_options = commandlineOptions;
m_level = 0;
string tmp;
commandlineOptions.TryGetValue(OPTION_SENDLEVEL, out tmp);
if (!string.IsNullOrEmpty(tmp))
foreach(var s in tmp.Split(new string[] {","}, StringSplitOptions.RemoveEmptyEntries))
{
if (string.IsNullOrEmpty(s))
continue;
MailLevels m;
if (Enum.TryParse(s.Trim(), true, out m))
m_level |= m;
}
if (m_level == 0)
m_level = DEFAULT_LEVEL;
m_levels =
tmp
.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)
.Where(x => !string.IsNullOrWhiteSpace(x))
.Select(x => x.Trim())
.ToArray();
if (m_levels == null || m_levels.Length == 0)
m_levels =
DEFAULT_LEVEL
.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)
.Where(x => !string.IsNullOrWhiteSpace(x))
.Select(x => x.Trim())
.ToArray();
m_sendAll = Utility.Utility.ParseBoolOption(commandlineOptions, OPTION_SENDALL);
if (string.IsNullOrEmpty(m_subject))
@@ -279,20 +266,20 @@ namespace Duplicati.Library.Modules.Builtin
if (string.Equals(m_operationname, "Backup", StringComparison.InvariantCultureIgnoreCase))
{
MailLevels level;
ParsedResultType level;
if (result is Exception)
level = MailLevels.Error;
else if (result != null && result is Library.Interface.IBackupResults && (result as Library.Interface.IBackupResults).Errors.Count() > 0)
level = MailLevels.Warning;
level = ParsedResultType.Fatal;
else if (result != null && result is Library.Interface.IBasicResults)
level = ((IBasicResults)result).ParsedResult;
else
level = MailLevels.Success;
level = ParsedResultType.Error;
m_parsedresultlevel = level.ToString();
if (m_level != MailLevels.All)
if (!m_levels.Any(x => string.Equals(x, "all", StringComparison.OrdinalIgnoreCase)))
{
//Check if this level should send mail
if ((m_level & level) == 0)
if (!m_levels.Any(x => string.Equals(x, level.ToString(), StringComparison.OrdinalIgnoreCase)))
return;
}
}
+3 -3
View File
@@ -87,7 +87,7 @@ sender@example.com
Mail Sender <sender>
Mail Sender <sender@example.com>"); } }
public static string OptionSenderShort { get { return LC.L(@"Email sender"); } }
public static string OptionSendlevelLong(string success, string warning, string error, string all) { return LC.L(@"You can specify one of ""{0}"", ""{1}"", ""{2}"". You can supply multiple options with a comma separator, e.g. ""{0},{1}"". The special value ""{3}"" is a shorthand for ""{0},{1},{2}"" and will cause all backup operations to send an email.", success, warning, error, all); }
public static string OptionSendlevelLong(string success, string warning, string error, string fatal, string all) { return LC.L(@"You can specify one of ""{0}"", ""{1}"", ""{2}"", ""{3}"". You can supply multiple options with a comma separator, e.g. ""{0},{1}"". The special value ""{4}"" is a shorthand for ""{0},{1},{2},{3}"" and will cause all backup operations to send an email.", success, warning, error, fatal, all); }
public static string OptionSendlevelShort { get { return LC.L(@"The messages to send"); } }
public static string OptionServerLong { get { return LC.L(@"A url for the SMTP server, e.g. smtp://example.com:25. Multiple servers can be supplied in a prioritized list, separated with semicolon. If a server fails, the next server in the list is tried, until the message has been sent.
If no server is supplied, a DNS lookup is performed to find the first recipient's MX record, and all SMTP servers are tried in their priority order until the message is sent.
@@ -121,8 +121,8 @@ All command line options are also reported within %value%, e.g. %volsize%. Any u
public static string SendxmpppasswordShort { get { return LC.L(@"The XMPP password"); } }
public static string SendxmpppasswordLong { get { return LC.L(@"The password for the account that will send the message"); } }
public static string SendxmpplevelShort { get { return LC.L(@"The messages to send"); } }
public static string SendxmpplevelLong(string success, string warning, string error, string all) { return LC.L(@"You can specify one of ""{0}"", ""{1}"", ""{2}"".
You can supply multiple options with a comma separator, e.g. ""{0},{1}"". The special value ""{3}"" is a shorthand for ""{0},{1},{2}"" and will cause all backup operations to send a message.", success, warning, error, all); }
public static string SendxmpplevelLong(string success, string warning, string error, string fatal, string all) { return LC.L(@"You can specify one of ""{0}"", ""{1}"", ""{2}"", ""{3}"".
You can supply multiple options with a comma separator, e.g. ""{0},{1}"". The special value ""{4}"" is a shorthand for ""{0},{1},{2},{3}"" and will cause all backup operations to send a message.", success, warning, error, fatal, all); }
public static string SendxmppanyoperationShort { get { return LC.L(@"Send messages for all operations"); } }
public static string SendxmppanyoperationLong { get { return LC.L(@"By default, messages will only be sent after a Backup operation. Use this option to send messages for all operations"); } }
public static string DisplayName { get { return LC.L(@"XMPP report module"); } }
+38 -7
View File
@@ -600,7 +600,7 @@ namespace Duplicati.Server
if (r.BackendStatistics is Duplicati.Library.Interface.IParsedBackendStatistics)
UpdateMetadata(backup, (Duplicati.Library.Interface.IParsedBackendStatistics)r.BackendStatistics);
}
if (o is Duplicati.Library.Interface.IBackupResults)
{
var r = (Duplicati.Library.Interface.IBackupResults)o;
@@ -609,21 +609,22 @@ namespace Duplicati.Server
backup.Metadata["SourceSizeString"] = Duplicati.Library.Utility.Utility.FormatSizeString(r.SizeOfExaminedFiles);
backup.Metadata["LastBackupStarted"] = Library.Utility.Utility.SerializeDateTime(((Duplicati.Library.Interface.IBasicResults)o).BeginTime.ToUniversalTime());
backup.Metadata["LastBackupFinished"] = Library.Utility.Utility.SerializeDateTime(((Duplicati.Library.Interface.IBasicResults)o).EndTime.ToUniversalTime());
if (r.FilesWithError > 0 || r.Warnings.Any())
if (r.FilesWithError > 0 || r.Warnings.Any() || r.Errors.Any())
{
Program.DataConnection.RegisterNotification(
NotificationType.Error,
backup.IsTemporary ?
NotificationType.Error,
backup.IsTemporary ?
"Warning" : string.Format("Warning while running {0}", backup.Name),
r.FilesWithError > 0 ?
r.FilesWithError > 0 ?
string.Format("Errors affected {0} file(s) ", r.FilesWithError) :
string.Format("Got {0} warning(s) ", r.Warnings.Count())
,
null,
backup.ID,
"backup:show-log",
(n, a) => {
(n, a) =>
{
var existing = (a.Where(x => x.BackupID == backup.ID)).FirstOrDefault();
if (existing == null)
return n;
@@ -636,6 +637,36 @@ namespace Duplicati.Server
);
}
}
else if (o is Duplicati.Library.Interface.IBasicResults)
{
var r = (Duplicati.Library.Interface.IBasicResults)o;
if (r.ParsedResult != Library.Interface.ParsedResultType.Success)
{
var type = r.ParsedResult == Library.Interface.ParsedResultType.Warning
? NotificationType.Warning
: NotificationType.Error;
var title = r.ParsedResult == Library.Interface.ParsedResultType.Warning
? (backup.IsTemporary ?
"Warning" : string.Format("Warning while running {0}", backup.Name))
: (backup.IsTemporary ?
"Error" : string.Format("Error while running {0}", backup.Name));
var message = r.ParsedResult == Library.Interface.ParsedResultType.Warning
? string.Format("Got {0} warning(s) ", r.Warnings.Count())
: string.Format("Got {0} error(s) ", r.Errors.Count());
Program.DataConnection.RegisterNotification(
type,
title,
message,
null,
backup.ID,
"backup:show-log",
(n, a) => n
);
}
}
if (!backup.IsTemporary)
Program.DataConnection.SetMetadata(backup.Metadata, long.Parse(backup.ID), null);