From 1b7e1349ca64e4ae7ecb10e6b7153ab15faf8bee Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Mon, 17 Jun 2024 09:32:04 +0200 Subject: [PATCH] Adding option for enabling argument parsing in scripts --- .../Library/Modules/Builtin/RunScript.cs | 39 +++++++++++-------- Duplicati/Library/Modules/Builtin/Strings.cs | 2 + .../Modules/Builtin/run-script-example.bat | 8 ++++ .../Modules/Builtin/run-script-example.sh | 8 ++++ 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/Duplicati/Library/Modules/Builtin/RunScript.cs b/Duplicati/Library/Modules/Builtin/RunScript.cs index 02577d47a..27fcf7901 100644 --- a/Duplicati/Library/Modules/Builtin/RunScript.cs +++ b/Duplicati/Library/Modules/Builtin/RunScript.cs @@ -55,6 +55,7 @@ namespace Duplicati.Library.Modules.Builtin private const string FINISH_OPTION = "run-script-after"; private const string REQUIRED_OPTION = "run-script-before-required"; private const string TIMEOUT_OPTION = "run-script-timeout"; + private const string ENABLE_ARGUMENTS_OPTION = "run-script-with-arguments"; /// /// Option used to set the log level for mail reports /// @@ -72,6 +73,7 @@ namespace Duplicati.Library.Modules.Builtin private string m_startScript = null; private string m_finishScript = null; private int m_timeout = 0; + private bool m_enableArguments = false; private string m_operationName; private string m_remoteurl; @@ -86,7 +88,7 @@ namespace Duplicati.Library.Modules.Builtin /// /// The log storage /// - private Utility.FileBackedStringList m_logstorage; + private FileBackedStringList m_logstorage; #region IGenericModule implementation @@ -95,10 +97,10 @@ namespace Duplicati.Library.Modules.Builtin commandlineOptions.TryGetValue(STARTUP_OPTION, out m_startScript); commandlineOptions.TryGetValue(REQUIRED_OPTION, out m_requiredScript); commandlineOptions.TryGetValue(FINISH_OPTION, out m_finishScript); + m_enableArguments = Utility.Utility.ParseBoolOption(commandlineOptions, ENABLE_ARGUMENTS_OPTION); - string tmpResultFormat; ResultExportFormat resultFormat; - if (!commandlineOptions.TryGetValue(RESULT_FORMAT_OPTION, out tmpResultFormat)) + if (!commandlineOptions.TryGetValue(RESULT_FORMAT_OPTION, out var tmpResultFormat)) { resultFormat = ResultExportFormat.Duplicati; } @@ -109,8 +111,7 @@ namespace Duplicati.Library.Modules.Builtin resultFormatSerializer = ResultFormatSerializerProvider.GetSerializer(resultFormat); - string t; - if (!commandlineOptions.TryGetValue(TIMEOUT_OPTION, out t)) + if (!commandlineOptions.TryGetValue(TIMEOUT_OPTION, out var t)) t = DEFAULT_TIMEOUT; m_timeout = (int)Utility.Timeparser.ParseTimeSpan(t).TotalMilliseconds; @@ -118,7 +119,7 @@ namespace Duplicati.Library.Modules.Builtin m_options = commandlineOptions; m_options.TryGetValue(OPTION_LOG_FILTER, out var logfilterstring); - var filter = Utility.FilterExpression.ParseLogFilter(logfilterstring); + var filter = FilterExpression.ParseLogFilter(logfilterstring); var logLevel = Utility.Utility.ParseEnumOption(m_options, OPTION_LOG_LEVEL, DEFAULT_LOG_LEVEL); m_logstorage = new FileBackedStringList(); @@ -148,6 +149,7 @@ namespace Duplicati.Library.Modules.Builtin new CommandLineArgument(STARTUP_OPTION, CommandLineArgument.ArgumentType.Path, Strings.RunScript.StartupoptionShort, Strings.RunScript.StartupoptionLong), new CommandLineArgument(FINISH_OPTION, CommandLineArgument.ArgumentType.Path, Strings.RunScript.FinishoptionShort, Strings.RunScript.FinishoptionLong), new CommandLineArgument(REQUIRED_OPTION, CommandLineArgument.ArgumentType.Path, Strings.RunScript.RequiredoptionShort, Strings.RunScript.RequiredoptionLong), + new CommandLineArgument(ENABLE_ARGUMENTS_OPTION, CommandLineArgument.ArgumentType.Boolean, Strings.RunScript.EnableArgumentsShort, Strings.RunScript.EnableArgumentsLong), new CommandLineArgument(RESULT_FORMAT_OPTION, CommandLineArgument.ArgumentType.Enumeration, Strings.RunScript.ResultFormatShort, @@ -169,10 +171,10 @@ namespace Duplicati.Library.Modules.Builtin public void OnStart(string operationname, ref string remoteurl, ref string[] localpath) { if (!string.IsNullOrEmpty(m_requiredScript)) - Execute(m_requiredScript, "BEFORE", operationname, ref remoteurl, ref localpath, m_timeout, true, m_options, null, null); + Execute(m_requiredScript, "BEFORE", operationname, ref remoteurl, ref localpath, m_timeout, true, m_enableArguments, m_options, null, null); if (!string.IsNullOrEmpty(m_startScript)) - Execute(m_startScript, "BEFORE", operationname, ref remoteurl, ref localpath, m_timeout, false, m_options, null, null); + Execute(m_startScript, "BEFORE", operationname, ref remoteurl, ref localpath, m_timeout, false, m_enableArguments, m_options, null, null); // Save options that might be set by a --run-script-before script so that the OnFinish method // references the same values. @@ -226,25 +228,28 @@ namespace Duplicati.Library.Modules.Builtin using (var streamWriter = new StreamWriter(tmpfile)) streamWriter.Write(resultFormatSerializer.Serialize(result, exception, m_logstorage, null)); - Execute(m_finishScript, "AFTER", m_operationName, ref m_remoteurl, ref m_localpath, m_timeout, false, m_options, tmpfile, level); + Execute(m_finishScript, "AFTER", m_operationName, ref m_remoteurl, ref m_localpath, m_timeout, false, m_enableArguments, m_options, tmpfile, level); } } #endregion - private static void Execute(string scriptpath, string eventname, string operationname, ref string remoteurl, ref string[] localpath, int timeout, bool requiredScript, IDictionary options, string datafile, ParsedResultType? level) + private static void Execute(string scriptpath, string eventname, string operationname, ref string remoteurl, ref string[] localpath, int timeout, bool requiredScript, bool enableArguments, IDictionary options, string datafile, ParsedResultType? level) { try { - var args = ARGREGEX.Matches(scriptpath); - var arguments = new List(); - if (args.Any()) + var arguments = new List() { scriptpath }; + if (enableArguments) { - arguments = args.AsEnumerable().Select(m => m.Groups["value"].Value).ToList(); - scriptpath = arguments[0]; - arguments.RemoveAt(0); + var args = ARGREGEX.Matches(scriptpath); + if (args.Any()) + { + arguments = args.AsEnumerable().Select(m => m.Groups["value"].Value).ToList(); + scriptpath = arguments[0]; + arguments.RemoveAt(0); + } } - System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo(scriptpath, arguments) + var psi = new System.Diagnostics.ProcessStartInfo(scriptpath, arguments) { WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden, CreateNoWindow = true, diff --git a/Duplicati/Library/Modules/Builtin/Strings.cs b/Duplicati/Library/Modules/Builtin/Strings.cs index 791ccb135..f895a679f 100644 --- a/Duplicati/Library/Modules/Builtin/Strings.cs +++ b/Duplicati/Library/Modules/Builtin/Strings.cs @@ -93,6 +93,8 @@ namespace Duplicati.Library.Modules.Builtin.Strings public static string StdErrorReport(string script, string message) { return LC.L(@"The script ""{0}"" reported error messages: {1}", script, message); } public static string TimeoutoptionLong { get { return LC.L(@"Sets the maximum time a script is allowed to execute. If the script has not completed within this time, it will continue to execute but the operation will continue too, and no script output will be processed."); } } public static string TimeoutoptionShort { get { return LC.L(@"Sets the script timeout"); } } + public static string EnableArgumentsShort { get { return LC.L(@"Enable script arguments"); } } + public static string EnableArgumentsLong { get { return LC.L(@"This option enables the use of script arguments. If this option is enabled, the script arguments are treated as commandline strings. Use single or double quotes to separate arguments."); } } } internal static class SendMail { diff --git a/Duplicati/Library/Modules/Builtin/run-script-example.bat b/Duplicati/Library/Modules/Builtin/run-script-example.bat index 7f879f74c..e858bbc2b 100644 --- a/Duplicati/Library/Modules/Builtin/run-script-example.bat +++ b/Duplicati/Library/Modules/Builtin/run-script-example.bat @@ -11,6 +11,7 @@ REM --run-script-before = REM --run-script-before-required = REM --run-script-timeout =