Update issue #678

Status: Fixed

The CLI now returns error codes.

git-svn-id: https://duplicati.googlecode.com/svn/trunk@1420 59da171f-624f-0410-aa54-27559c288bec
This commit is contained in:
kenneth@hexad.dk
2012-08-07 19:36:49 +00:00
parent 03758e68ec
commit d83eb730f2
4 changed files with 81 additions and 22 deletions
+56 -21
View File
@@ -27,7 +27,7 @@ namespace Duplicati.CommandLine
{
private static readonly string[] COMMANDS_AS_ARGUMENTS = new string[] { "delete-all-but-n-full", "delete-all-but-n", "delete-older-than" };
static void Main(string[] args)
static int Main(string[] args)
{
bool verboseErrors = false;
try
@@ -70,7 +70,7 @@ namespace Duplicati.CommandLine
cargs.RemoveAt(0);
UnitTest.RunTest(cargs.ToArray(), options);
return;
return 0;
}
#endif
@@ -91,7 +91,7 @@ namespace Duplicati.CommandLine
if (options.ContainsKey(internaloption))
{
Console.WriteLine(Strings.Program.InternalOptionUsedError, internaloption);
return;
return 200;
}
//After checking for internal options, we set the filter option
@@ -104,7 +104,7 @@ namespace Duplicati.CommandLine
{
case "purge-signature-cache":
Library.Main.Interface.PurgeSignatureCache(options);
return;
return 0;
}
}
@@ -116,7 +116,7 @@ namespace Duplicati.CommandLine
Help.PrintUsage(cargs[1], options);
return;
return 0;
}
@@ -158,7 +158,7 @@ namespace Duplicati.CommandLine
if (cargs.Count != 1)
{
PrintWrongNumberOfArguments(cargs, 1);
return;
return 200;
}
Console.WriteLine(string.Join("\r\n", new List<string>(Duplicati.Library.Main.Interface.ListCurrentFiles(target, options)).ToArray()));
@@ -170,7 +170,7 @@ namespace Duplicati.CommandLine
if (cargs.Count != 1)
{
PrintWrongNumberOfArguments(cargs, 1);
return;
return 200;
}
Console.WriteLine(string.Join("\r\n", Duplicati.Library.Main.Interface.ListSourceFolders(target, options) ?? new string[0]));
@@ -182,7 +182,7 @@ namespace Duplicati.CommandLine
if (cargs.Count != 1)
{
PrintWrongNumberOfArguments(cargs, 1);
return;
return 200;
}
List<KeyValuePair<Duplicati.Library.Main.RSync.RSyncDir.PatchFileType, string>> files = Duplicati.Library.Main.Interface.ListActualSignatureFiles(cargs[0], options);
@@ -248,7 +248,7 @@ namespace Duplicati.CommandLine
if (cargs.Count != 1)
{
PrintWrongNumberOfArguments(cargs, 1);
return;
return 200;
}
List<Duplicati.Library.Main.ManifestEntry> entries = Duplicati.Library.Main.Interface.ParseFileList(cargs[0], options);
@@ -281,7 +281,7 @@ namespace Duplicati.CommandLine
if (!int.TryParse(target, out n) || n < 0)
{
Console.WriteLine(string.Format(Strings.Program.IntegerParseError, target));
return;
return 200;
}
options["delete-all-but-n-full"] = n.ToString();
@@ -292,7 +292,7 @@ namespace Duplicati.CommandLine
if (cargs.Count != 1)
{
PrintWrongNumberOfArguments(cargs, 1);
return;
return 200;
}
if (source.Trim().ToLower() == "delete-all-but-n")
@@ -309,7 +309,7 @@ namespace Duplicati.CommandLine
catch (Exception ex)
{
Console.WriteLine(string.Format(Strings.Program.TimeParseError, target, ex.Message));
return;
return 200;
}
options["delete-older-than"] = target;
@@ -320,7 +320,7 @@ namespace Duplicati.CommandLine
if (cargs.Count != 1)
{
PrintWrongNumberOfArguments(cargs, 1);
return;
return 200;
}
Console.WriteLine(Duplicati.Library.Main.Interface.DeleteOlderThan(cargs[0], options));
@@ -332,7 +332,7 @@ namespace Duplicati.CommandLine
if (cargs.Count != 1)
{
PrintWrongNumberOfArguments(cargs, 1);
return;
return 200;
}
Console.WriteLine(Duplicati.Library.Main.Interface.Cleanup(cargs[0], options));
@@ -344,7 +344,7 @@ namespace Duplicati.CommandLine
if (cargs.Count != 1)
{
PrintWrongNumberOfArguments(cargs, 1);
return;
return 200;
}
Duplicati.Library.Main.Interface.CreateFolder(cargs[0], options);
@@ -357,7 +357,7 @@ namespace Duplicati.CommandLine
if (cargs.Count != 1)
{
PrintWrongNumberOfArguments(cargs, 1);
return;
return 200;
}
List<KeyValuePair<string, DateTime>> results = Duplicati.Library.Main.Interface.FindLastFileVersion(cargs[0], options);
@@ -372,7 +372,7 @@ namespace Duplicati.CommandLine
if (cargs.Count != 1)
{
PrintWrongNumberOfArguments(cargs, 1);
return;
return 200;
}
List<KeyValuePair<Duplicati.Library.Main.BackupEntryBase, Exception>> results = Duplicati.Library.Main.Interface.VerifyBackup(cargs[0], options);
@@ -412,7 +412,7 @@ namespace Duplicati.CommandLine
if (cargs.Count != 2)
{
PrintWrongNumberOfArguments(cargs, 2);
return;
return 200;
}
Console.WriteLine(Duplicati.Library.Main.Interface.Restore(source, target.Split(System.IO.Path.PathSeparator), options));
@@ -422,11 +422,33 @@ namespace Duplicati.CommandLine
if (cargs.Count != 2)
{
PrintWrongNumberOfArguments(cargs, 2);
return;
}
return 200;
}
Console.WriteLine(Duplicati.Library.Main.Interface.Backup(source.Split(System.IO.Path.PathSeparator), target, options));
string result = Duplicati.Library.Main.Interface.Backup(source.Split(System.IO.Path.PathSeparator), target, options);
Console.WriteLine(result);
Dictionary<string, string> tmp = ParseDuplicatiOutput(result);
//Interrupted = 50
if (tmp.ContainsKey("PartialBackup"))
return 50;
//Completed with warnings = 2
if (tmp.ContainsKey("NumberOfWarnings"))
return 2;
//Success, but no upload = 1
if (tmp.ContainsKey("BytesUploaded"))
{
long s;
if (long.TryParse(tmp["BytesUploaded"], out s) && s == 0)
return 1;
}
}
//Normal operation = 0
return 0;
}
catch (Exception ex)
{
@@ -452,9 +474,22 @@ namespace Duplicati.CommandLine
Console.Error.WriteLine(Strings.Program.UnhandledInnerException, ex.ToString());
}
}
//Error = 100
return 100;
}
}
public static Dictionary<string, string> ParseDuplicatiOutput(string output)
{
System.Text.RegularExpressions.Regex re = new System.Text.RegularExpressions.Regex("(?<key>[^\\:]+)\\:(?<value>[^\\n]*)", System.Text.RegularExpressions.RegexOptions.Singleline);
Dictionary<string, string> res = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
foreach (System.Text.RegularExpressions.Match m in re.Matches(output))
res[m.Groups["key"].Value.Trim()] = m.Groups["value"].Value.Trim();
return res;
}
private static void PrintWrongNumberOfArguments(List<string> args, int expected)
{
Console.WriteLine(Strings.Program.WrongNumberOfCommandsError_v2, args.Count, expected, args.Count == 0 ? "" : "\"" + string.Join("\", \"", args.ToArray()) + "\"");
+15 -1
View File
@@ -23,7 +23,7 @@ See duplicati.commandline.exe help <topic> for more information.
Formats: date, time, size, encryption, compression
Advanced options: advanced, filter, <option> (e.g. --auto-cleanup)
Advanced options: advanced, returncodes, filter, <option> (e.g. --auto-cleanup)
http://www.duplicati.com/ Version: %VERSION%
@@ -383,3 +383,17 @@ Options:
Duplicati offers more options than listed in the other topics. Those additional options should only be used with care. For normal operation none of them should ever be required. Here is a complete list of options supported by Duplicati:
%MAINOPTIONS%
# =============================================================================
> duplicati.commandline.exe help returncodes
> duplicati.commandline.exe help exitcodes
> duplicati.commandline.exe help statuscodes
Duplicati reports the following return/exit codes:
0 - Success
1 - Successful backup, but no files were changed
2 - Successful backup, with warnings
50 - Backup uploaded some files, but did not finish
100 - An error occurred
200 - Invalid commandline arguments found
@@ -41,6 +41,7 @@ namespace Duplicati.Library.Main
private long m_tooLargeFiles;
private long m_filesWithError;
private bool m_full = false;
private bool m_partialBackup = false;
private string m_typeReason = null;
public BackupStatistics(DuplicatiOperationMode operationMode)
@@ -150,6 +151,12 @@ namespace Duplicati.Library.Main
set { m_filesWithError = value; }
}
public bool PartialBackup
{
get { return m_partialBackup; }
set { m_partialBackup = true; }
}
public void SetTypeReason(string reason)
{
m_typeReason = reason;
@@ -178,6 +185,8 @@ namespace Duplicati.Library.Main
sb.Append("Unprocessed : " + this.UnprocessedFiles.ToString(System.Globalization.CultureInfo.InvariantCulture) + "\r\n");
sb.Append("TooLargeFiles : " + this.FilesTooLarge.ToString(System.Globalization.CultureInfo.InvariantCulture) + "\r\n");
sb.Append("FilesWithError : " + this.FilesWithError.ToString(System.Globalization.CultureInfo.InvariantCulture) + "\r\n");
if (m_partialBackup)
sb.Append("PartialBackup : true" + "\r\n");
sb.Append(base.ToString());
return sb.ToString();
+1
View File
@@ -861,6 +861,7 @@ namespace Duplicati.Library.Main
Logging.Log.WriteMessage(string.Format(Strings.Interface.PartialUploadMessage, backend.ManifestUploads, ex.Message), Logging.LogMessageType.Warning);
bs.LogError(string.Format(Strings.Interface.PartialUploadMessage, backend.ManifestUploads, ex.Message), ex);
bs.PartialBackup = true;
}
finally
{