View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0013311 | Scribus | Integration | public | 2015-08-19 15:22 | 2015-11-22 13:52 |
Reporter | berteh | Assigned To | cbradney | ||
Priority | normal | Severity | minor | Reproducibility | always |
Status | closed | Resolution | fixed | ||
Product Version | 1.5.1svn | ||||
Fixed in Version | 1.5.1svn | ||||
Summary | 0013311: support for command line arguments to be passed on to python script (-py option) | ||||
Description | adding 1 option to pass arguments to python script run in Scribus from command line (to be used with -py and -g), after discussions and testing with a-l-e and luzpaz. -py, --python-script <filename> Run filename in Python scripter --python-arg-<argumentname> [value] Argument passed on to python script, with an optional value, no effect without -py -g, --no-gui Do not start GUI -- Explicit end of command line options | ||||
Steps To Reproduce | [New : edited the 4th of sept 2015] apply "cmdline_--python-arg_name_value__clean.patch", compile, then call any scribus python script that will get the additional arguments passed from the command line: simple use: ./scribus -g -py ~/cmdtest.py --python-arg -someflag1 --python-arg --somearg1 value1 ~/some1.sla or more complex (with -- to distinguish that last parameter(s) are file(s) to be opened by scribus before running the script, and not arguments to be passed to the script.) ./scribus -g -py ~/cmdtest.py --python-arg -somearg1 value1 --python-arg --someflag1 -- ~/some1.sla help is in the standard usage info: ./scribus -h Usage: scribus [options] [files] Options: (...) -py, --python-script <filename> Run filename in Python scripter -pa, --python-arg <name> [value] Argument passed on to python script, with an optional value, no effect without -py -- Explicit end of command line options | ||||
Tags | No tags attached. | ||||
Patch | Yes | ||||
|
command-line-arguments-for-python-script.patch (30,923 bytes)
From d019992c0798595d3d422672a21e3441b3cc6838 Mon Sep 17 00:00:00 2001 From: berteh <berteh@gmail.com> Date: Wed, 5 Aug 2015 16:00:45 +0200 Subject: [PATCH 1/7] added command-line arguments to be passed to python script, some fix needed in scriptercore.cpp#283. --- scribus/plugins/scriptplugin/scriptercore.cpp | 30 +++++++++++++++++++++++---- scribus/plugins/scriptplugin/scriptercore.h | 3 ++- scribus/scribusapp.cpp | 22 ++++++++++++++++++-- scribus/scribusapp.h | 2 ++ 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/scribus/plugins/scriptplugin/scriptercore.cpp b/scribus/plugins/scriptplugin/scriptercore.cpp index 3903617..c27517b 100644 --- a/scribus/plugins/scriptplugin/scriptercore.cpp +++ b/scribus/plugins/scriptplugin/scriptercore.cpp @@ -9,6 +9,7 @@ for which a new license (GPL+exception) is in place. #include <QGlobalStatic> #include <QWidget> #include <QString> +#include <QStringList> #include <QApplication> #include <QMessageBox> #include <QTextCodec> @@ -37,7 +38,7 @@ for which a new license (GPL+exception) is in place. #include "prefscontext.h" #include "prefstable.h" #include "prefsmanager.h" -#include "scribusapp.h" // need it to acces ScQApp->pythonScript +#include "scribusapp.h" // need it to acces ScQApp->pythonScript & ScQApp->pythonScriptArgs ScripterCore::ScripterCore(QWidget* parent) { @@ -228,6 +229,12 @@ void ScripterCore::RecentScript(QString fn) void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter) { + QStringList arguments = QStringList(); + slotRunScriptFileArgs(fileName, arguments, inMainInterpreter); +} + +void ScripterCore::slotRunScriptFileArgs(QString fileName, QStringList arguments, bool inMainInterpreter) +{ // Prevent two scripts to be run concurrently or face crash! if (ScCore->primaryMainWindow()->scriptIsRunning()) return; @@ -252,16 +259,31 @@ void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter) // Init the scripter module in the sub-interpreter initscribus(ScCore->primaryMainWindow()); } + + // handle additional arguments + bool argsExtra = !(arguments.isEmpty()); + int argsc = 0; + if (argsExtra) + { + argsc = arguments.size(); + //std::cout << tr("running script with %1 arguments").arg(argsc).toLocal8Bit().data() << std::endl; + } // Make sure sys.argv[0] is the path to the script - char* comm[2]; + char* comm[2+argsc]; comm[0] = na.data(); + // and tell the script if it's running in the main intepreter or // a subinterpreter using the second argument, ie sys.argv[1] if (inMainInterpreter) comm[1] = const_cast<char*>("ext"); else comm[1] = const_cast<char*>("sub"); - PySys_SetArgv(2, comm); + for (int j = 0; j < argsc; ++j) + { + comm[2+j] = arguments.at(j).toLocal8Bit().data() ; // TODO fix here: some copy is needed, otherwise all comm[>2] point to same (last) value for j. + } + PySys_SetArgv(2+argsc, comm); + // call python script PyObject* m = PyImport_AddModule((char*)"__main__"); if (m == NULL) @@ -357,7 +379,7 @@ void ScripterCore::slotRunPythonScript() { if (!ScQApp->pythonScript.isNull()) { - slotRunScriptFile(ScQApp->pythonScript, true); + slotRunScriptFileArgs(ScQApp->pythonScript, ScQApp->pythonScriptArgs, true); FinishScriptRun(); } } diff --git a/scribus/plugins/scriptplugin/scriptercore.h b/scribus/plugins/scriptplugin/scriptercore.h index 1e929f4..b8e2edf 100644 --- a/scribus/plugins/scriptplugin/scriptercore.h +++ b/scribus/plugins/scriptplugin/scriptercore.h @@ -39,8 +39,9 @@ public slots: void StdScript(QString filebasename); void RecentScript(QString fn); void slotRunScriptFile(QString fileName, bool inMainInterpreter = false); + void slotRunScriptFileArgs(QString fileName, QStringList arguments, bool inMainInterpreter = false); void slotRunPythonScript(); // needed for running python script from CLI - void slotRunScript(const QString Script); + void slotRunScript(const QString script); void slotInteractiveScript(bool); void slotExecute(); /*! \brief Show docstring of the script to the user. diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index fec4055..9c52c04 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -32,6 +32,7 @@ for which a new license (GPL+exception) is in place. #include <QLibraryInfo> #include <QLocale> #include <QString> +#include <QStringList> #include <QTextCodec> #include <QTextStream> #include <QTranslator> @@ -71,6 +72,8 @@ for which a new license (GPL+exception) is in place. #define ARG_UPGRADECHECK "--upgradecheck" #define ARG_TESTS "--tests" #define ARG_PYTHONSCRIPT "--python-script" +#define ARG_SCRIPTARG_PREFIX "--python-arg" // directly followed by <param name> <param value> +#define ARG_SCRIPTFLAG_PREFIX "--python-flag" // directly followed by <param name> #define ARG_VERSION_SHORT "-v" #define ARG_HELP_SHORT "-h" @@ -108,6 +111,7 @@ ScribusQApp::ScribusQApp( int & argc, char ** argv ) : QApplication(argc, argv), m_scDLMgr = 0; m_ScCore = NULL; initDLMgr(); + } ScribusQApp::~ScribusQApp() @@ -213,6 +217,8 @@ void ScribusQApp::parseCommandLine() std::exit(EXIT_SUCCESS); useGUI = true; //We are going to run something other than command line help + QString qtARG_SCRIPTARG_PREFIX = QString(ARG_SCRIPTARG_PREFIX); + QString qtARG_SCRIPTFLAG_PREFIX = QString(ARG_SCRIPTFLAG_PREFIX); for(int i = 1; i < argsc; i++) { arg = args[i]; @@ -267,7 +273,17 @@ void ScribusQApp::parseCommandLine() } else { ++i; } - } else { + } else if (arg.startsWith(qtARG_SCRIPTARG_PREFIX)) { + QString arg_name = arg.mid(qtARG_SCRIPTARG_PREFIX.size()); + QString arg_value = QFile::decodeName(args[++i].toLocal8Bit()); + //std::cout << tr("got one script argument: %1 with value %2").arg(arg_name).arg(arg_value).toLocal8Bit().data() << std::endl; + pythonScriptArgs.append(arg_name); + pythonScriptArgs.append(arg_value); + } else if (arg.startsWith(qtARG_SCRIPTFLAG_PREFIX)) { + QString arg_name = arg.mid(qtARG_SCRIPTFLAG_PREFIX.size()); + //std::cout << tr("got one script flag: %1 ").arg(arg_name).toLocal8Bit().data() << std::endl; + pythonScriptArgs.append(arg_name); + } else { // (last) positional argument fileName = QFile::decodeName(args[i].toLocal8Bit()); if (!QFileInfo(fileName).exists()) { showHeader(); @@ -498,7 +514,9 @@ void ScribusQApp::showUsage() printArgLine(ts, ARG_UPGRADECHECK_SHORT, ARG_UPGRADECHECK, tr("Download a file from the Scribus website and show the latest available version") ); printArgLine(ts, ARG_VERSION_SHORT, ARG_VERSION, tr("Output version information and exit") ); printArgLine(ts, ARG_PYTHONSCRIPT_SHORT, qPrintable(QString("%1 <%2>").arg(ARG_PYTHONSCRIPT).arg(tr("filename"))), tr("Run filename in Python scripter") ); - printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); + ts << (QString(" %1<%2> <%3> ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script with its value, no effect without -py"); endl(ts); + ts << (QString(" %1<%2> ").arg(ARG_SCRIPTFLAG_PREFIX).arg(tr("flagname"))) << tr("Argument passed on to python script with no value, no effect without -py"); endl(ts); + printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); #if defined(_WIN32) && !defined(_CONSOLE) printArgLine(ts, ARG_CONSOLE_SHORT, ARG_CONSOLE, tr("Display a console window") ); diff --git a/scribus/scribusapp.h b/scribus/scribusapp.h index 2857306..7fc9f7f 100644 --- a/scribus/scribusapp.h +++ b/scribus/scribusapp.h @@ -23,6 +23,7 @@ for which a new license (GPL+exception) is in place. #define SCRIBUSAPP_H #include <QApplication> #include <QString> +#include <QStringList> #include "scribusapi.h" @@ -71,6 +72,7 @@ class SCRIBUS_API ScribusQApp : public QApplication const QString& currGUILanguage() { return GUILang; } ScDLManager* dlManager() { return m_scDLMgr; } QString pythonScript; // script to be run in python from CLI + QStringList pythonScriptArgs; // command line arguments and flags for script from CLI private: ScribusCore* m_ScCore; From f4c7e635c738fb35114f9ffd6112c0e38990d55a Mon Sep 17 00:00:00 2001 From: berteh <berteh@gmail.com> Date: Wed, 5 Aug 2015 17:05:56 +0200 Subject: [PATCH 2/7] help message layout --- scribus/scribusapp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index 9c52c04..77be088 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -514,8 +514,8 @@ void ScribusQApp::showUsage() printArgLine(ts, ARG_UPGRADECHECK_SHORT, ARG_UPGRADECHECK, tr("Download a file from the Scribus website and show the latest available version") ); printArgLine(ts, ARG_VERSION_SHORT, ARG_VERSION, tr("Output version information and exit") ); printArgLine(ts, ARG_PYTHONSCRIPT_SHORT, qPrintable(QString("%1 <%2>").arg(ARG_PYTHONSCRIPT).arg(tr("filename"))), tr("Run filename in Python scripter") ); - ts << (QString(" %1<%2> <%3> ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script with its value, no effect without -py"); endl(ts); - ts << (QString(" %1<%2> ").arg(ARG_SCRIPTFLAG_PREFIX).arg(tr("flagname"))) << tr("Argument passed on to python script with no value, no effect without -py"); endl(ts); + ts << (QString(" %1<%2> <%3> ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script with its value, no effect without -py"); endl(ts); + ts << (QString(" %1<%2> ").arg(ARG_SCRIPTFLAG_PREFIX).arg(tr("flagname"))) << tr("Argument passed on to python script with no value, no effect without -py"); endl(ts); printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); #if defined(_WIN32) && !defined(_CONSOLE) From 35e17efbc051678d5d78f4958a08ac6bc7079bc0 Mon Sep 17 00:00:00 2001 From: berteh <berteh@gmail.com> Date: Wed, 5 Aug 2015 17:07:11 +0200 Subject: [PATCH 3/7] use QStringList to call python script with arguments --- scribus/plugins/scriptplugin/scriptercore.cpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/scribus/plugins/scriptplugin/scriptercore.cpp b/scribus/plugins/scriptplugin/scriptercore.cpp index c27517b..f6456c4 100644 --- a/scribus/plugins/scriptplugin/scriptercore.cpp +++ b/scribus/plugins/scriptplugin/scriptercore.cpp @@ -234,6 +234,7 @@ void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter) } void ScripterCore::slotRunScriptFileArgs(QString fileName, QStringList arguments, bool inMainInterpreter) +/** run "filename" python script with the additional arguments provided in "arguments" */ { // Prevent two scripts to be run concurrently or face crash! if (ScCore->primaryMainWindow()->scriptIsRunning()) @@ -260,29 +261,24 @@ void ScripterCore::slotRunScriptFileArgs(QString fileName, QStringList arguments initscribus(ScCore->primaryMainWindow()); } - // handle additional arguments - bool argsExtra = !(arguments.isEmpty()); - int argsc = 0; - if (argsExtra) - { - argsc = arguments.size(); - //std::cout << tr("running script with %1 arguments").arg(argsc).toLocal8Bit().data() << std::endl; - } // Make sure sys.argv[0] is the path to the script - char* comm[2+argsc]; - comm[0] = na.data(); + arguments.prepend(na.data()); // and tell the script if it's running in the main intepreter or // a subinterpreter using the second argument, ie sys.argv[1] if (inMainInterpreter) - comm[1] = const_cast<char*>("ext"); + arguments.insert(1,QString("ext")); else - comm[1] = const_cast<char*>("sub"); - for (int j = 0; j < argsc; ++j) + arguments.insert(1,QString("sub")); + + //convert arguments (QListString) to char** for Python bridge + /* typically arguments == ['path/to/script.py','ext','--argument1','valueforarg1','--flag']*/ + char *comm[arguments.size()]; + for (int i = 0; i < arguments.size(); i++) { - comm[2+j] = arguments.at(j).toLocal8Bit().data() ; // TODO fix here: some copy is needed, otherwise all comm[>2] point to same (last) value for j. + comm[i] = arguments.at(i).mid(0).toLocal8Bit().data(); // TODO fix here: unexpected border effects. all comm[*] point to same (last) value for i... despite mid() that should create a copy. } - PySys_SetArgv(2+argsc, comm); + PySys_SetArgv(arguments.size(), comm); // call python script PyObject* m = PyImport_AddModule((char*)"__main__"); From 50fca9e4feffa2337a1c8de5f0e99f9bf23bb248 Mon Sep 17 00:00:00 2001 From: berteh <berteh@gmail.com> Date: Wed, 5 Aug 2015 18:31:30 +0200 Subject: [PATCH 4/7] fix arguments passing from command line to python script --- scribus/plugins/scriptplugin/scriptercore.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scribus/plugins/scriptplugin/scriptercore.cpp b/scribus/plugins/scriptplugin/scriptercore.cpp index f6456c4..41b2949 100644 --- a/scribus/plugins/scriptplugin/scriptercore.cpp +++ b/scribus/plugins/scriptplugin/scriptercore.cpp @@ -276,7 +276,8 @@ void ScripterCore::slotRunScriptFileArgs(QString fileName, QStringList arguments char *comm[arguments.size()]; for (int i = 0; i < arguments.size(); i++) { - comm[i] = arguments.at(i).mid(0).toLocal8Bit().data(); // TODO fix here: unexpected border effects. all comm[*] point to same (last) value for i... despite mid() that should create a copy. + comm[i] = new char[arguments.at(i).toLocal8Bit().size()+1]; //+1 to allow adding '\0'. may be useless, don't know how to check. + strcpy(comm[i],arguments.at(i).toLocal8Bit().data()+'\0'); } PySys_SetArgv(arguments.size(), comm); From b90f29c7bdb9908c4addb31b8486c8ec8197650d Mon Sep 17 00:00:00 2001 From: berteh <berteh@gmail.com> Date: Thu, 6 Aug 2015 11:32:17 +0200 Subject: [PATCH 5/7] add dash to prefix for command line arguments to python script --- scribus/scribusapp.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index 77be088..46b7508 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -72,8 +72,8 @@ for which a new license (GPL+exception) is in place. #define ARG_UPGRADECHECK "--upgradecheck" #define ARG_TESTS "--tests" #define ARG_PYTHONSCRIPT "--python-script" -#define ARG_SCRIPTARG_PREFIX "--python-arg" // directly followed by <param name> <param value> -#define ARG_SCRIPTFLAG_PREFIX "--python-flag" // directly followed by <param name> +#define ARG_SCRIPTARG_PREFIX "--python-arg-" // directly followed by <param name> <param value> +#define ARG_SCRIPTFLAG_PREFIX "--python-flag-" // directly followed by <param name> #define ARG_VERSION_SHORT "-v" #define ARG_HELP_SHORT "-h" @@ -274,13 +274,13 @@ void ScribusQApp::parseCommandLine() ++i; } } else if (arg.startsWith(qtARG_SCRIPTARG_PREFIX)) { - QString arg_name = arg.mid(qtARG_SCRIPTARG_PREFIX.size()); + QString arg_name = arg.mid(qtARG_SCRIPTARG_PREFIX.size()-1); //-1 to get the dash from prefix QString arg_value = QFile::decodeName(args[++i].toLocal8Bit()); //std::cout << tr("got one script argument: %1 with value %2").arg(arg_name).arg(arg_value).toLocal8Bit().data() << std::endl; pythonScriptArgs.append(arg_name); pythonScriptArgs.append(arg_value); } else if (arg.startsWith(qtARG_SCRIPTFLAG_PREFIX)) { - QString arg_name = arg.mid(qtARG_SCRIPTFLAG_PREFIX.size()); + QString arg_name = arg.mid(qtARG_SCRIPTFLAG_PREFIX.size()-1); //-1 to get the dash from prefix //std::cout << tr("got one script flag: %1 ").arg(arg_name).toLocal8Bit().data() << std::endl; pythonScriptArgs.append(arg_name); } else { // (last) positional argument @@ -514,8 +514,8 @@ void ScribusQApp::showUsage() printArgLine(ts, ARG_UPGRADECHECK_SHORT, ARG_UPGRADECHECK, tr("Download a file from the Scribus website and show the latest available version") ); printArgLine(ts, ARG_VERSION_SHORT, ARG_VERSION, tr("Output version information and exit") ); printArgLine(ts, ARG_PYTHONSCRIPT_SHORT, qPrintable(QString("%1 <%2>").arg(ARG_PYTHONSCRIPT).arg(tr("filename"))), tr("Run filename in Python scripter") ); - ts << (QString(" %1<%2> <%3> ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script with its value, no effect without -py"); endl(ts); - ts << (QString(" %1<%2> ").arg(ARG_SCRIPTFLAG_PREFIX).arg(tr("flagname"))) << tr("Argument passed on to python script with no value, no effect without -py"); endl(ts); + ts << (QString(" %1<%2> <%3> ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script with its value, no effect without -py"); endl(ts); + ts << (QString(" %1<%2> ").arg(ARG_SCRIPTFLAG_PREFIX).arg(tr("flagname"))) << tr("Argument passed on to python script with no value, no effect without -py"); endl(ts); printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); #if defined(_WIN32) && !defined(_CONSOLE) From 9aa5b6951f2ef8fd187a2c9e99fe491dcb95fffb Mon Sep 17 00:00:00 2001 From: berteh <berteh@gmail.com> Date: Thu, 6 Aug 2015 15:30:32 +0200 Subject: [PATCH 6/7] command line arguments for script unified into --python-arg- ; added command-line double dash for options end --- scribus/scribusapp.cpp | 67 +++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index 46b7508..6be0cbc 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -72,8 +72,8 @@ for which a new license (GPL+exception) is in place. #define ARG_UPGRADECHECK "--upgradecheck" #define ARG_TESTS "--tests" #define ARG_PYTHONSCRIPT "--python-script" -#define ARG_SCRIPTARG_PREFIX "--python-arg-" // directly followed by <param name> <param value> -#define ARG_SCRIPTFLAG_PREFIX "--python-flag-" // directly followed by <param name> +#define ARG_SCRIPTARG_PREFIX "--python-arg-" // directly followed by <param name> <param value> +#define CMD_OPTIONS_END "--" // end of command line options #define ARG_VERSION_SHORT "-v" #define ARG_HELP_SHORT "-h" @@ -218,8 +218,8 @@ void ScribusQApp::parseCommandLine() useGUI = true; //We are going to run something other than command line help QString qtARG_SCRIPTARG_PREFIX = QString(ARG_SCRIPTARG_PREFIX); - QString qtARG_SCRIPTFLAG_PREFIX = QString(ARG_SCRIPTFLAG_PREFIX); - for(int i = 1; i < argsc; i++) { + int i = 1; + for( ; i < argsc; i++) { //handle all options (not positional parameters) arg = args[i]; if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++i < argsc)) { @@ -247,7 +247,7 @@ void ScribusQApp::parseCommandLine() if (!QFileInfo(prefsUserFile).exists()) { showHeader(); if (prefsUserFile.left(1) == "-" || prefsUserFile.left(2) == "--") { - std::cout << tr("Invalid argument: ").toLocal8Bit().data() << prefsUserFile.toLocal8Bit().data() << std::endl; + std::cout << tr("Invalid option: ").toLocal8Bit().data() << prefsUserFile.toLocal8Bit().data() << std::endl; } else { std::cout << tr("File %1 does not exist, aborting.").arg(prefsUserFile).toLocal8Bit().data() << std::endl; } @@ -264,7 +264,7 @@ void ScribusQApp::parseCommandLine() if (!QFileInfo(pythonScript).exists()) { showHeader(); if (pythonScript.left(1) == "-" || pythonScript.left(2) == "--") { - std::cout << tr("Invalid argument: ").toLocal8Bit().data() << pythonScript.toLocal8Bit().data() << std::endl; + std::cout << tr("Invalid option: ").toLocal8Bit().data() << pythonScript.toLocal8Bit().data() << std::endl; } else { std::cout << tr("File %1 does not exist, aborting.").arg(pythonScript).toLocal8Bit().data() << std::endl; } @@ -273,32 +273,32 @@ void ScribusQApp::parseCommandLine() } else { ++i; } + } else if (arg == CMD_OPTIONS_END) { //double dash, indicates end of command line options, see http://unix.stackexchange.com/questions/11376/what-does-double-dash-mean-also-known-as-bare-double-dash + i++; + break; } else if (arg.startsWith(qtARG_SCRIPTARG_PREFIX)) { - QString arg_name = arg.mid(qtARG_SCRIPTARG_PREFIX.size()-1); //-1 to get the dash from prefix - QString arg_value = QFile::decodeName(args[++i].toLocal8Bit()); - //std::cout << tr("got one script argument: %1 with value %2").arg(arg_name).arg(arg_value).toLocal8Bit().data() << std::endl; - pythonScriptArgs.append(arg_name); - pythonScriptArgs.append(arg_value); - } else if (arg.startsWith(qtARG_SCRIPTFLAG_PREFIX)) { - QString arg_name = arg.mid(qtARG_SCRIPTFLAG_PREFIX.size()-1); //-1 to get the dash from prefix - //std::cout << tr("got one script flag: %1 ").arg(arg_name).toLocal8Bit().data() << std::endl; - pythonScriptArgs.append(arg_name); - } else { // (last) positional argument - fileName = QFile::decodeName(args[i].toLocal8Bit()); - if (!QFileInfo(fileName).exists()) { - showHeader(); - if (fileName.left(1) == "-" || fileName.left(2) == "--") { - std::cout << tr("Invalid argument: %1").arg(fileName).toLocal8Bit().data() << std::endl; - } else { - std::cout << tr("File %1 does not exist, aborting.").arg(fileName).toLocal8Bit().data() << std::endl; - } - showUsage(); - std::exit(EXIT_FAILURE); + pythonScriptArgs.append( arg.mid(qtARG_SCRIPTARG_PREFIX.size()-1) ); //-1 to get the dash from prefix + if (!args[i+1].startsWith("-")) { + pythonScriptArgs.append( QFile::decodeName(args[++i].toLocal8Bit()) ); } - else - { - filesToLoad.append(fileName); + } else { //argument is not a known option, but either positional parameter or invalid. + break; + } + } + //remaining arguments, if any + for ( ; i<argsc; i++) { + fileName = QFile::decodeName(args[i].toLocal8Bit()); + if (!QFileInfo(fileName).exists()) { + showHeader(); + if (fileName.left(1) == "-" || fileName.left(2) == "--") { + std::cout << tr("Invalid argument: %1").arg(fileName).toLocal8Bit().data() << std::endl; + } else { + std::cout << tr("File %1 does not exist, aborting.").arg(fileName).toLocal8Bit().data() << std::endl; } + showUsage(); + std::exit(EXIT_FAILURE); + } else { + filesToLoad.append(fileName); } } } @@ -501,7 +501,7 @@ void ScribusQApp::showUsage() QFile f; f.open(stderr, QIODevice::WriteOnly); QTextStream ts(&f); - ts << tr("Usage: scribus [option ... ] [file]") ; endl(ts); + ts << tr("Usage: scribus [options] [files]") ; endl(ts); endl(ts); ts << tr("Options:") ; endl(ts); printArgLine(ts, ARG_FONTINFO_SHORT, ARG_FONTINFO, tr("Show information on the console when fonts are being loaded") ); printArgLine(ts, ARG_HELP_SHORT, ARG_HELP, tr("Print help (this message) and exit") ); @@ -514,9 +514,10 @@ void ScribusQApp::showUsage() printArgLine(ts, ARG_UPGRADECHECK_SHORT, ARG_UPGRADECHECK, tr("Download a file from the Scribus website and show the latest available version") ); printArgLine(ts, ARG_VERSION_SHORT, ARG_VERSION, tr("Output version information and exit") ); printArgLine(ts, ARG_PYTHONSCRIPT_SHORT, qPrintable(QString("%1 <%2>").arg(ARG_PYTHONSCRIPT).arg(tr("filename"))), tr("Run filename in Python scripter") ); - ts << (QString(" %1<%2> <%3> ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script with its value, no effect without -py"); endl(ts); - ts << (QString(" %1<%2> ").arg(ARG_SCRIPTFLAG_PREFIX).arg(tr("flagname"))) << tr("Argument passed on to python script with no value, no effect without -py"); endl(ts); - printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); + ts << (QString(" %1<%2> [%3] ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script, with an optional value, no effect without -py"); endl(ts); + printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); + ts << (QString(" %1").arg(CMD_OPTIONS_END,-39)) << tr("Explicit end of command line options"); endl(ts); + #if defined(_WIN32) && !defined(_CONSOLE) printArgLine(ts, ARG_CONSOLE_SHORT, ARG_CONSOLE, tr("Display a console window") ); From 6752a35215de21ff5b0b1e3530245f55c43bb655 Mon Sep 17 00:00:00 2001 From: berteh <berteh@gmail.com> Date: Wed, 19 Aug 2015 17:09:19 +0200 Subject: [PATCH 7/7] polishing code for command line arguments for python script: overloading --- scribus/plugins/scriptplugin/scriptercore.cpp | 6 ++--- scribus/plugins/scriptplugin/scriptercore.h | 2 +- scribus/scribusapp.cpp | 32 +++++++++++++-------------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/scribus/plugins/scriptplugin/scriptercore.cpp b/scribus/plugins/scriptplugin/scriptercore.cpp index 41b2949..f1f4594 100644 --- a/scribus/plugins/scriptplugin/scriptercore.cpp +++ b/scribus/plugins/scriptplugin/scriptercore.cpp @@ -230,10 +230,10 @@ void ScripterCore::RecentScript(QString fn) void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter) { QStringList arguments = QStringList(); - slotRunScriptFileArgs(fileName, arguments, inMainInterpreter); + slotRunScriptFile(fileName, arguments, inMainInterpreter); } -void ScripterCore::slotRunScriptFileArgs(QString fileName, QStringList arguments, bool inMainInterpreter) +void ScripterCore::slotRunScriptFile(QString fileName, QStringList arguments, bool inMainInterpreter) /** run "filename" python script with the additional arguments provided in "arguments" */ { // Prevent two scripts to be run concurrently or face crash! @@ -376,7 +376,7 @@ void ScripterCore::slotRunPythonScript() { if (!ScQApp->pythonScript.isNull()) { - slotRunScriptFileArgs(ScQApp->pythonScript, ScQApp->pythonScriptArgs, true); + slotRunScriptFile(ScQApp->pythonScript, ScQApp->pythonScriptArgs, true); FinishScriptRun(); } } diff --git a/scribus/plugins/scriptplugin/scriptercore.h b/scribus/plugins/scriptplugin/scriptercore.h index b8e2edf..72e5461 100644 --- a/scribus/plugins/scriptplugin/scriptercore.h +++ b/scribus/plugins/scriptplugin/scriptercore.h @@ -39,7 +39,7 @@ public slots: void StdScript(QString filebasename); void RecentScript(QString fn); void slotRunScriptFile(QString fileName, bool inMainInterpreter = false); - void slotRunScriptFileArgs(QString fileName, QStringList arguments, bool inMainInterpreter = false); + void slotRunScriptFile(QString fileName, QStringList arguments, bool inMainInterpreter = false); void slotRunPythonScript(); // needed for running python script from CLI void slotRunScript(const QString script); void slotInteractiveScript(bool); diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index 6be0cbc..8870934 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -218,11 +218,11 @@ void ScribusQApp::parseCommandLine() useGUI = true; //We are going to run something other than command line help QString qtARG_SCRIPTARG_PREFIX = QString(ARG_SCRIPTARG_PREFIX); - int i = 1; - for( ; i < argsc; i++) { //handle all options (not positional parameters) - arg = args[i]; + int argi = 1; + for( ; argi < argsc; argi++) { //handle options (not positional parameters) + arg = args[argi]; - if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++i < argsc)) { + if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++argi < argsc)) { continue; } else if ( arg == ARG_CONSOLE || arg == ARG_CONSOLE_SHORT ) { continue; @@ -238,12 +238,12 @@ void ScribusQApp::parseCommandLine() showFontInfo=true; } else if (arg == ARG_PROFILEINFO || arg == ARG_PROFILEINFO_SHORT) { showProfileInfo=true; - } else if ((arg == ARG_DISPLAY || arg==ARG_DISPLAY_SHORT || arg==ARG_DISPLAY_QT) && ++i < argsc) { + } else if ((arg == ARG_DISPLAY || arg==ARG_DISPLAY_SHORT || arg==ARG_DISPLAY_QT) && ++argi < argsc) { // allow setting of display, QT expect the option -display <display_name> so we discard the // last argument. FIXME: Qt only understands -display not --display and -d , we need to work // around this. } else if (arg == ARG_PREFS || arg == ARG_PREFS_SHORT) { - prefsUserFile = QFile::decodeName(args[i + 1].toLocal8Bit()); + prefsUserFile = QFile::decodeName(args[argi + 1].toLocal8Bit()); if (!QFileInfo(prefsUserFile).exists()) { showHeader(); if (prefsUserFile.left(1) == "-" || prefsUserFile.left(2) == "--") { @@ -254,40 +254,40 @@ void ScribusQApp::parseCommandLine() showUsage(); std::exit(EXIT_FAILURE); } else { - ++i; + ++argi; } } else if (strncmp(arg.toLocal8Bit().data(),"-psn_",4) == 0) { // Andreas Vox: Qt/Mac has -psn_blah flags that must be accepted. } else if (arg == ARG_PYTHONSCRIPT || arg == ARG_PYTHONSCRIPT_SHORT) { - pythonScript = QFile::decodeName(args[i + 1].toLocal8Bit()); + pythonScript = QFile::decodeName(args[argi + 1].toLocal8Bit()); if (!QFileInfo(pythonScript).exists()) { showHeader(); if (pythonScript.left(1) == "-" || pythonScript.left(2) == "--") { - std::cout << tr("Invalid option: ").toLocal8Bit().data() << pythonScript.toLocal8Bit().data() << std::endl; + std::cout << tr("Invalid argument: ").toLocal8Bit().data() << pythonScript.toLocal8Bit().data() << std::endl; } else { std::cout << tr("File %1 does not exist, aborting.").arg(pythonScript).toLocal8Bit().data() << std::endl; } showUsage(); std::exit(EXIT_FAILURE); } else { - ++i; + ++argi; } } else if (arg == CMD_OPTIONS_END) { //double dash, indicates end of command line options, see http://unix.stackexchange.com/questions/11376/what-does-double-dash-mean-also-known-as-bare-double-dash - i++; + argi++; break; } else if (arg.startsWith(qtARG_SCRIPTARG_PREFIX)) { pythonScriptArgs.append( arg.mid(qtARG_SCRIPTARG_PREFIX.size()-1) ); //-1 to get the dash from prefix - if (!args[i+1].startsWith("-")) { - pythonScriptArgs.append( QFile::decodeName(args[++i].toLocal8Bit()) ); + if (!args[argi+1].startsWith("-")) { + pythonScriptArgs.append( QFile::decodeName(args[++argi].toLocal8Bit()) ); } } else { //argument is not a known option, but either positional parameter or invalid. break; } } - //remaining arguments, if any - for ( ; i<argsc; i++) { - fileName = QFile::decodeName(args[i].toLocal8Bit()); + //remaining (positional) arguments, if any + for ( ; argi<argsc; argi++) { + fileName = QFile::decodeName(args[argi].toLocal8Bit()); if (!QFileInfo(fileName).exists()) { showHeader(); if (fileName.left(1) == "-" || fileName.left(2) == "--") { |
|
cmdtest.py (1,071 bytes)
#!/usr/bin/env python # -*- coding: utf-8 -*- import sys import sys, scribus, traceback def main(argv): print "\nYES! main is reached in cmdtest script\ncheck out the arguments it's got:", " ".join(argv) if scribus.haveDoc(): print "\nthis script could modify the current document ", scribus.getDocName(), " automatically" else: print "\nno document is currently open in scribus" def main_wrapper(argv): try: if scribus.haveDoc(): scribus.setRedraw(False) #scribus.statusMessage("ĥeadless test") #scribus.progressReset() main(argv) except Exception: print "error: "+traceback.format_exc() finally: # Exit neatly even if the script terminated with an exception, # so we leave the progress bar and status bar blank and make sure # drawing is enabled. if scribus.haveDoc(): scribus.setRedraw(True) scribus.statusMessage('') scribus.progressReset() if __name__ == '__main__': main_wrapper(sys.argv) |
|
History and discussions at https://github.com/scribusproject/scribus/pull/19 |
|
Berteh! Fantastic. I've submitted this to the Mailing list to get more feedback from the community. The more testers the better. Thanks so much for the contribution! |
|
storydeptharg.py (2,426 bytes)
#!/usr/bin/env python # -*- coding: utf-8 -*- """ Return the depth of the text in the file sample.txt Run with the command line scribus -g -py storydeptharg.py --python-arg-storyfile sample.txt depthtemplate.sla sample.txt is the text file to measure. depthtemplate.sla is a document with a single, empty text frame. Tested with scribus 1.5.0 Author: William Bader 11Aug14 wb initial version 15Dec14 wb get the file name from STORYFILE 19Aug15 wb get the file name from the command line """ # check that the script is running from inside scribus try: from scribus import * except ImportError: print 'This script only runs from within Scribus.' sys.exit(1) # get the os module try: import os except ImportError: print 'Could not import the os module.' sys.exit(1) # get the sys module try: import sys except ImportError: print 'Could not import the sys module.' sys.exit(1) def main(argv): # The first text frame of the current document defines the style try: storyfile = "" i = 1; while i < len(argv): if argv[i] == "-storyfile": storyfile = argv[i+1] i = i + 1 if storyfile == "": print 'Warning: -storyfile not given, checking environment' storyfile = os.environ['STORYFILE'] except: print 'Error: Pass the story file with the --python-arg-storyfile argument or the STORYFILE environment variable' return try: storytext = open(storyfile, 'r').read() except: print 'Error: Story file "', storyfile, '" not found.' return try: deselectAll() selectObject('Text1') except: print 'Error: The document does not have an object called Text1.' return try: setText(storytext) except: print 'Error: The document does not have a text frame.' return try: ov = textOverflows() width, depth = getSize() if ov: baddepth = depth gooddepth = 100 else: baddepth = 0 gooddepth = depth while baddepth < gooddepth: trydepth = (baddepth + gooddepth) / 2 sizeObject(width, trydepth) tryov = textOverflows() if tryov: baddepth = trydepth + 0.0001 else: baddepth = baddepth + 0.0001 gooddepth = trydepth sizeObject(width, gooddepth) print 'The depth is ', str(gooddepth) except: print 'Error: not a text frame.' # start the script if __name__ == '__main__': if haveDoc(): main(sys.argv) else: print 'Error: You need to have a document open before you can run this script succesfully.' |
|
It works for me. I uploaded a slightly longer test script. The script calculates the length of text. Put the text in a normal file. Create a Scribus document with an empty text frame. Run the command scribus -g -py storydeptharg.py --python-arg-storyfile sample.txt depthtemplate.sla If I print the arguments, I get an extra argv[1] of "ext". i 0 storydeptharg.py i 1 ext i 2 -storyfile i 3 sample.txt In an earlier version of the script, I passed arguments through environment variables. |
|
I read the patches. argv[1] is "ext" when the script is running in the main interpreter and "sub" when the script is running in a subinterpreter. |
|
indeed william. that's legacy from scribus and i was not brave enough to remove it in case it was needed elsewhere... My guess is on distinguishing between scripts in scripter consoles and others, but it's only a quick guess. Shall the script author handle it, or can we safely remove that "artificial" argument addition by scribus? |
|
I think that it is OK to leave it as long as it is documented. I've never checked the command line on a script, but if that parameter was there before, removing it might break old scripts. |
|
one way to handle this extra argument in the script is to remove it: #handle arguments #discard argv[1] if it is 'ext' or 'sub', that is added by Scribus when calling an external script if (sys.argv[1] == 'ext' or sys.argv[1] == 'sub'): del sys.argv[1] args = parser.parse_args() |
|
Any comments from the devs? |
|
It may be less overwhelming to see the diffs side-by-side: https://github.com/scribusproject/scribus/pull/19/files |
|
Jean, any comments on this patch ? |
|
Thanks Kunda for the pushes! Is there anything I can do to help have this patch accepted? |
|
berteh : keep your irc client open and connected to #scribus chan on freenode, and talk to jghali or MrB when they're there (in the evening). |
|
ok, thanks JLuc. |
|
Jean and I have reviewed. Qt doesn't require things like : QStringList arguments = QStringList(); As for the Python side.. we'd prefer syntax of --python-arg name value, instead of --python-arg-name value. Possible? thanks Craig |
|
thanks for the review Jean & Craig! syntax --python-arg name value is indeed possible. It would just prevent to pass some argument with a name that indicates a "header" attribute in Scribus command-line parsing, namely: version, help, availlang, upgradecheck and tests. indeed: the command below would pass the "-v" to scribus and display it's version, and not pass it to the script (for instance to set some "verbosity" level), as the "-v" is a header argument (scribusapp.cpp l.217). scribus -g -py ~/myScribusScript.py --python-arg -v 6 -pa --title "title from command line" ~/all*.sla If that restriction is fine by you, then kindly use the modified patch attached (that adds short "-pa" as well, since it's now easy to handle ;) - cmdline_--python-arg_name_value.patch The examples provided earlier would become: simple use: ./scribus -g -py ~/cmdtest.py --python-arg -flag1 --python-arg -arg1 value1 ~/some1.sla or more complex (with -- to distinguish that last parameter(s) are file(s) to be opened by scribus before running the script, and not arguments to be passed to the script.) ./scribus -g -py ~/cmdtest.py --python-arg -arg1 value1 --python-arg -flag1 -- ~/some1.sla A possible workaround to that restriction is to assume the argument name must start with a dash at the script call, and omit that dash in the scribus command line, thus not detecting it as a scribus (short) header argument. The dash would then be added automatically before the name that is passed to the script. scribus -g -py ~/myScribusScript.py --python-arg v 6 -pa -title "title from command line" ~/all*.sla I like this last option less as it seems not clean, and enforces the use of dashes in the script arguments... but if you want it i can implement that instead. Berteh. |
|
cmdline_--python-arg_name_value.patch (36,615 bytes)
From d019992c0798595d3d422672a21e3441b3cc6838 Mon Sep 17 00:00:00 2001 From: berteh <berteh@gmail.com> Date: Wed, 5 Aug 2015 16:00:45 +0200 Subject: [PATCH 1/9] added command-line arguments to be passed to python script, some fix needed in scriptercore.cpp#283. --- scribus/plugins/scriptplugin/scriptercore.cpp | 30 +++++++++++++++++++++++---- scribus/plugins/scriptplugin/scriptercore.h | 3 ++- scribus/scribusapp.cpp | 22 ++++++++++++++++++-- scribus/scribusapp.h | 2 ++ 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/scribus/plugins/scriptplugin/scriptercore.cpp b/scribus/plugins/scriptplugin/scriptercore.cpp index 3903617..c27517b 100644 --- a/scribus/plugins/scriptplugin/scriptercore.cpp +++ b/scribus/plugins/scriptplugin/scriptercore.cpp @@ -9,6 +9,7 @@ for which a new license (GPL+exception) is in place. #include <QGlobalStatic> #include <QWidget> #include <QString> +#include <QStringList> #include <QApplication> #include <QMessageBox> #include <QTextCodec> @@ -37,7 +38,7 @@ for which a new license (GPL+exception) is in place. #include "prefscontext.h" #include "prefstable.h" #include "prefsmanager.h" -#include "scribusapp.h" // need it to acces ScQApp->pythonScript +#include "scribusapp.h" // need it to acces ScQApp->pythonScript & ScQApp->pythonScriptArgs ScripterCore::ScripterCore(QWidget* parent) { @@ -228,6 +229,12 @@ void ScripterCore::RecentScript(QString fn) void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter) { + QStringList arguments = QStringList(); + slotRunScriptFileArgs(fileName, arguments, inMainInterpreter); +} + +void ScripterCore::slotRunScriptFileArgs(QString fileName, QStringList arguments, bool inMainInterpreter) +{ // Prevent two scripts to be run concurrently or face crash! if (ScCore->primaryMainWindow()->scriptIsRunning()) return; @@ -252,16 +259,31 @@ void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter) // Init the scripter module in the sub-interpreter initscribus(ScCore->primaryMainWindow()); } + + // handle additional arguments + bool argsExtra = !(arguments.isEmpty()); + int argsc = 0; + if (argsExtra) + { + argsc = arguments.size(); + //std::cout << tr("running script with %1 arguments").arg(argsc).toLocal8Bit().data() << std::endl; + } // Make sure sys.argv[0] is the path to the script - char* comm[2]; + char* comm[2+argsc]; comm[0] = na.data(); + // and tell the script if it's running in the main intepreter or // a subinterpreter using the second argument, ie sys.argv[1] if (inMainInterpreter) comm[1] = const_cast<char*>("ext"); else comm[1] = const_cast<char*>("sub"); - PySys_SetArgv(2, comm); + for (int j = 0; j < argsc; ++j) + { + comm[2+j] = arguments.at(j).toLocal8Bit().data() ; // TODO fix here: some copy is needed, otherwise all comm[>2] point to same (last) value for j. + } + PySys_SetArgv(2+argsc, comm); + // call python script PyObject* m = PyImport_AddModule((char*)"__main__"); if (m == NULL) @@ -357,7 +379,7 @@ void ScripterCore::slotRunPythonScript() { if (!ScQApp->pythonScript.isNull()) { - slotRunScriptFile(ScQApp->pythonScript, true); + slotRunScriptFileArgs(ScQApp->pythonScript, ScQApp->pythonScriptArgs, true); FinishScriptRun(); } } diff --git a/scribus/plugins/scriptplugin/scriptercore.h b/scribus/plugins/scriptplugin/scriptercore.h index 1e929f4..b8e2edf 100644 --- a/scribus/plugins/scriptplugin/scriptercore.h +++ b/scribus/plugins/scriptplugin/scriptercore.h @@ -39,8 +39,9 @@ public slots: void StdScript(QString filebasename); void RecentScript(QString fn); void slotRunScriptFile(QString fileName, bool inMainInterpreter = false); + void slotRunScriptFileArgs(QString fileName, QStringList arguments, bool inMainInterpreter = false); void slotRunPythonScript(); // needed for running python script from CLI - void slotRunScript(const QString Script); + void slotRunScript(const QString script); void slotInteractiveScript(bool); void slotExecute(); /*! \brief Show docstring of the script to the user. diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index fec4055..9c52c04 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -32,6 +32,7 @@ for which a new license (GPL+exception) is in place. #include <QLibraryInfo> #include <QLocale> #include <QString> +#include <QStringList> #include <QTextCodec> #include <QTextStream> #include <QTranslator> @@ -71,6 +72,8 @@ for which a new license (GPL+exception) is in place. #define ARG_UPGRADECHECK "--upgradecheck" #define ARG_TESTS "--tests" #define ARG_PYTHONSCRIPT "--python-script" +#define ARG_SCRIPTARG_PREFIX "--python-arg" // directly followed by <param name> <param value> +#define ARG_SCRIPTFLAG_PREFIX "--python-flag" // directly followed by <param name> #define ARG_VERSION_SHORT "-v" #define ARG_HELP_SHORT "-h" @@ -108,6 +111,7 @@ ScribusQApp::ScribusQApp( int & argc, char ** argv ) : QApplication(argc, argv), m_scDLMgr = 0; m_ScCore = NULL; initDLMgr(); + } ScribusQApp::~ScribusQApp() @@ -213,6 +217,8 @@ void ScribusQApp::parseCommandLine() std::exit(EXIT_SUCCESS); useGUI = true; //We are going to run something other than command line help + QString qtARG_SCRIPTARG_PREFIX = QString(ARG_SCRIPTARG_PREFIX); + QString qtARG_SCRIPTFLAG_PREFIX = QString(ARG_SCRIPTFLAG_PREFIX); for(int i = 1; i < argsc; i++) { arg = args[i]; @@ -267,7 +273,17 @@ void ScribusQApp::parseCommandLine() } else { ++i; } - } else { + } else if (arg.startsWith(qtARG_SCRIPTARG_PREFIX)) { + QString arg_name = arg.mid(qtARG_SCRIPTARG_PREFIX.size()); + QString arg_value = QFile::decodeName(args[++i].toLocal8Bit()); + //std::cout << tr("got one script argument: %1 with value %2").arg(arg_name).arg(arg_value).toLocal8Bit().data() << std::endl; + pythonScriptArgs.append(arg_name); + pythonScriptArgs.append(arg_value); + } else if (arg.startsWith(qtARG_SCRIPTFLAG_PREFIX)) { + QString arg_name = arg.mid(qtARG_SCRIPTFLAG_PREFIX.size()); + //std::cout << tr("got one script flag: %1 ").arg(arg_name).toLocal8Bit().data() << std::endl; + pythonScriptArgs.append(arg_name); + } else { // (last) positional argument fileName = QFile::decodeName(args[i].toLocal8Bit()); if (!QFileInfo(fileName).exists()) { showHeader(); @@ -498,7 +514,9 @@ void ScribusQApp::showUsage() printArgLine(ts, ARG_UPGRADECHECK_SHORT, ARG_UPGRADECHECK, tr("Download a file from the Scribus website and show the latest available version") ); printArgLine(ts, ARG_VERSION_SHORT, ARG_VERSION, tr("Output version information and exit") ); printArgLine(ts, ARG_PYTHONSCRIPT_SHORT, qPrintable(QString("%1 <%2>").arg(ARG_PYTHONSCRIPT).arg(tr("filename"))), tr("Run filename in Python scripter") ); - printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); + ts << (QString(" %1<%2> <%3> ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script with its value, no effect without -py"); endl(ts); + ts << (QString(" %1<%2> ").arg(ARG_SCRIPTFLAG_PREFIX).arg(tr("flagname"))) << tr("Argument passed on to python script with no value, no effect without -py"); endl(ts); + printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); #if defined(_WIN32) && !defined(_CONSOLE) printArgLine(ts, ARG_CONSOLE_SHORT, ARG_CONSOLE, tr("Display a console window") ); diff --git a/scribus/scribusapp.h b/scribus/scribusapp.h index 2857306..7fc9f7f 100644 --- a/scribus/scribusapp.h +++ b/scribus/scribusapp.h @@ -23,6 +23,7 @@ for which a new license (GPL+exception) is in place. #define SCRIBUSAPP_H #include <QApplication> #include <QString> +#include <QStringList> #include "scribusapi.h" @@ -71,6 +72,7 @@ class SCRIBUS_API ScribusQApp : public QApplication const QString& currGUILanguage() { return GUILang; } ScDLManager* dlManager() { return m_scDLMgr; } QString pythonScript; // script to be run in python from CLI + QStringList pythonScriptArgs; // command line arguments and flags for script from CLI private: ScribusCore* m_ScCore; From f4c7e635c738fb35114f9ffd6112c0e38990d55a Mon Sep 17 00:00:00 2001 From: berteh <berteh@gmail.com> Date: Wed, 5 Aug 2015 17:05:56 +0200 Subject: [PATCH 2/9] help message layout --- scribus/scribusapp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index 9c52c04..77be088 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -514,8 +514,8 @@ void ScribusQApp::showUsage() printArgLine(ts, ARG_UPGRADECHECK_SHORT, ARG_UPGRADECHECK, tr("Download a file from the Scribus website and show the latest available version") ); printArgLine(ts, ARG_VERSION_SHORT, ARG_VERSION, tr("Output version information and exit") ); printArgLine(ts, ARG_PYTHONSCRIPT_SHORT, qPrintable(QString("%1 <%2>").arg(ARG_PYTHONSCRIPT).arg(tr("filename"))), tr("Run filename in Python scripter") ); - ts << (QString(" %1<%2> <%3> ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script with its value, no effect without -py"); endl(ts); - ts << (QString(" %1<%2> ").arg(ARG_SCRIPTFLAG_PREFIX).arg(tr("flagname"))) << tr("Argument passed on to python script with no value, no effect without -py"); endl(ts); + ts << (QString(" %1<%2> <%3> ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script with its value, no effect without -py"); endl(ts); + ts << (QString(" %1<%2> ").arg(ARG_SCRIPTFLAG_PREFIX).arg(tr("flagname"))) << tr("Argument passed on to python script with no value, no effect without -py"); endl(ts); printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); #if defined(_WIN32) && !defined(_CONSOLE) From 35e17efbc051678d5d78f4958a08ac6bc7079bc0 Mon Sep 17 00:00:00 2001 From: berteh <berteh@gmail.com> Date: Wed, 5 Aug 2015 17:07:11 +0200 Subject: [PATCH 3/9] use QStringList to call python script with arguments --- scribus/plugins/scriptplugin/scriptercore.cpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/scribus/plugins/scriptplugin/scriptercore.cpp b/scribus/plugins/scriptplugin/scriptercore.cpp index c27517b..f6456c4 100644 --- a/scribus/plugins/scriptplugin/scriptercore.cpp +++ b/scribus/plugins/scriptplugin/scriptercore.cpp @@ -234,6 +234,7 @@ void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter) } void ScripterCore::slotRunScriptFileArgs(QString fileName, QStringList arguments, bool inMainInterpreter) +/** run "filename" python script with the additional arguments provided in "arguments" */ { // Prevent two scripts to be run concurrently or face crash! if (ScCore->primaryMainWindow()->scriptIsRunning()) @@ -260,29 +261,24 @@ void ScripterCore::slotRunScriptFileArgs(QString fileName, QStringList arguments initscribus(ScCore->primaryMainWindow()); } - // handle additional arguments - bool argsExtra = !(arguments.isEmpty()); - int argsc = 0; - if (argsExtra) - { - argsc = arguments.size(); - //std::cout << tr("running script with %1 arguments").arg(argsc).toLocal8Bit().data() << std::endl; - } // Make sure sys.argv[0] is the path to the script - char* comm[2+argsc]; - comm[0] = na.data(); + arguments.prepend(na.data()); // and tell the script if it's running in the main intepreter or // a subinterpreter using the second argument, ie sys.argv[1] if (inMainInterpreter) - comm[1] = const_cast<char*>("ext"); + arguments.insert(1,QString("ext")); else - comm[1] = const_cast<char*>("sub"); - for (int j = 0; j < argsc; ++j) + arguments.insert(1,QString("sub")); + + //convert arguments (QListString) to char** for Python bridge + /* typically arguments == ['path/to/script.py','ext','--argument1','valueforarg1','--flag']*/ + char *comm[arguments.size()]; + for (int i = 0; i < arguments.size(); i++) { - comm[2+j] = arguments.at(j).toLocal8Bit().data() ; // TODO fix here: some copy is needed, otherwise all comm[>2] point to same (last) value for j. + comm[i] = arguments.at(i).mid(0).toLocal8Bit().data(); // TODO fix here: unexpected border effects. all comm[*] point to same (last) value for i... despite mid() that should create a copy. } - PySys_SetArgv(2+argsc, comm); + PySys_SetArgv(arguments.size(), comm); // call python script PyObject* m = PyImport_AddModule((char*)"__main__"); From 50fca9e4feffa2337a1c8de5f0e99f9bf23bb248 Mon Sep 17 00:00:00 2001 From: berteh <berteh@gmail.com> Date: Wed, 5 Aug 2015 18:31:30 +0200 Subject: [PATCH 4/9] fix arguments passing from command line to python script --- scribus/plugins/scriptplugin/scriptercore.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scribus/plugins/scriptplugin/scriptercore.cpp b/scribus/plugins/scriptplugin/scriptercore.cpp index f6456c4..41b2949 100644 --- a/scribus/plugins/scriptplugin/scriptercore.cpp +++ b/scribus/plugins/scriptplugin/scriptercore.cpp @@ -276,7 +276,8 @@ void ScripterCore::slotRunScriptFileArgs(QString fileName, QStringList arguments char *comm[arguments.size()]; for (int i = 0; i < arguments.size(); i++) { - comm[i] = arguments.at(i).mid(0).toLocal8Bit().data(); // TODO fix here: unexpected border effects. all comm[*] point to same (last) value for i... despite mid() that should create a copy. + comm[i] = new char[arguments.at(i).toLocal8Bit().size()+1]; //+1 to allow adding '\0'. may be useless, don't know how to check. + strcpy(comm[i],arguments.at(i).toLocal8Bit().data()+'\0'); } PySys_SetArgv(arguments.size(), comm); From b90f29c7bdb9908c4addb31b8486c8ec8197650d Mon Sep 17 00:00:00 2001 From: berteh <berteh@gmail.com> Date: Thu, 6 Aug 2015 11:32:17 +0200 Subject: [PATCH 5/9] add dash to prefix for command line arguments to python script --- scribus/scribusapp.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index 77be088..46b7508 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -72,8 +72,8 @@ for which a new license (GPL+exception) is in place. #define ARG_UPGRADECHECK "--upgradecheck" #define ARG_TESTS "--tests" #define ARG_PYTHONSCRIPT "--python-script" -#define ARG_SCRIPTARG_PREFIX "--python-arg" // directly followed by <param name> <param value> -#define ARG_SCRIPTFLAG_PREFIX "--python-flag" // directly followed by <param name> +#define ARG_SCRIPTARG_PREFIX "--python-arg-" // directly followed by <param name> <param value> +#define ARG_SCRIPTFLAG_PREFIX "--python-flag-" // directly followed by <param name> #define ARG_VERSION_SHORT "-v" #define ARG_HELP_SHORT "-h" @@ -274,13 +274,13 @@ void ScribusQApp::parseCommandLine() ++i; } } else if (arg.startsWith(qtARG_SCRIPTARG_PREFIX)) { - QString arg_name = arg.mid(qtARG_SCRIPTARG_PREFIX.size()); + QString arg_name = arg.mid(qtARG_SCRIPTARG_PREFIX.size()-1); //-1 to get the dash from prefix QString arg_value = QFile::decodeName(args[++i].toLocal8Bit()); //std::cout << tr("got one script argument: %1 with value %2").arg(arg_name).arg(arg_value).toLocal8Bit().data() << std::endl; pythonScriptArgs.append(arg_name); pythonScriptArgs.append(arg_value); } else if (arg.startsWith(qtARG_SCRIPTFLAG_PREFIX)) { - QString arg_name = arg.mid(qtARG_SCRIPTFLAG_PREFIX.size()); + QString arg_name = arg.mid(qtARG_SCRIPTFLAG_PREFIX.size()-1); //-1 to get the dash from prefix //std::cout << tr("got one script flag: %1 ").arg(arg_name).toLocal8Bit().data() << std::endl; pythonScriptArgs.append(arg_name); } else { // (last) positional argument @@ -514,8 +514,8 @@ void ScribusQApp::showUsage() printArgLine(ts, ARG_UPGRADECHECK_SHORT, ARG_UPGRADECHECK, tr("Download a file from the Scribus website and show the latest available version") ); printArgLine(ts, ARG_VERSION_SHORT, ARG_VERSION, tr("Output version information and exit") ); printArgLine(ts, ARG_PYTHONSCRIPT_SHORT, qPrintable(QString("%1 <%2>").arg(ARG_PYTHONSCRIPT).arg(tr("filename"))), tr("Run filename in Python scripter") ); - ts << (QString(" %1<%2> <%3> ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script with its value, no effect without -py"); endl(ts); - ts << (QString(" %1<%2> ").arg(ARG_SCRIPTFLAG_PREFIX).arg(tr("flagname"))) << tr("Argument passed on to python script with no value, no effect without -py"); endl(ts); + ts << (QString(" %1<%2> <%3> ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script with its value, no effect without -py"); endl(ts); + ts << (QString(" %1<%2> ").arg(ARG_SCRIPTFLAG_PREFIX).arg(tr("flagname"))) << tr("Argument passed on to python script with no value, no effect without -py"); endl(ts); printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); #if defined(_WIN32) && !defined(_CONSOLE) From 9aa5b6951f2ef8fd187a2c9e99fe491dcb95fffb Mon Sep 17 00:00:00 2001 From: berteh <berteh@gmail.com> Date: Thu, 6 Aug 2015 15:30:32 +0200 Subject: [PATCH 6/9] command line arguments for script unified into --python-arg- ; added command-line double dash for options end --- scribus/scribusapp.cpp | 67 +++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index 46b7508..6be0cbc 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -72,8 +72,8 @@ for which a new license (GPL+exception) is in place. #define ARG_UPGRADECHECK "--upgradecheck" #define ARG_TESTS "--tests" #define ARG_PYTHONSCRIPT "--python-script" -#define ARG_SCRIPTARG_PREFIX "--python-arg-" // directly followed by <param name> <param value> -#define ARG_SCRIPTFLAG_PREFIX "--python-flag-" // directly followed by <param name> +#define ARG_SCRIPTARG_PREFIX "--python-arg-" // directly followed by <param name> <param value> +#define CMD_OPTIONS_END "--" // end of command line options #define ARG_VERSION_SHORT "-v" #define ARG_HELP_SHORT "-h" @@ -218,8 +218,8 @@ void ScribusQApp::parseCommandLine() useGUI = true; //We are going to run something other than command line help QString qtARG_SCRIPTARG_PREFIX = QString(ARG_SCRIPTARG_PREFIX); - QString qtARG_SCRIPTFLAG_PREFIX = QString(ARG_SCRIPTFLAG_PREFIX); - for(int i = 1; i < argsc; i++) { + int i = 1; + for( ; i < argsc; i++) { //handle all options (not positional parameters) arg = args[i]; if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++i < argsc)) { @@ -247,7 +247,7 @@ void ScribusQApp::parseCommandLine() if (!QFileInfo(prefsUserFile).exists()) { showHeader(); if (prefsUserFile.left(1) == "-" || prefsUserFile.left(2) == "--") { - std::cout << tr("Invalid argument: ").toLocal8Bit().data() << prefsUserFile.toLocal8Bit().data() << std::endl; + std::cout << tr("Invalid option: ").toLocal8Bit().data() << prefsUserFile.toLocal8Bit().data() << std::endl; } else { std::cout << tr("File %1 does not exist, aborting.").arg(prefsUserFile).toLocal8Bit().data() << std::endl; } @@ -264,7 +264,7 @@ void ScribusQApp::parseCommandLine() if (!QFileInfo(pythonScript).exists()) { showHeader(); if (pythonScript.left(1) == "-" || pythonScript.left(2) == "--") { - std::cout << tr("Invalid argument: ").toLocal8Bit().data() << pythonScript.toLocal8Bit().data() << std::endl; + std::cout << tr("Invalid option: ").toLocal8Bit().data() << pythonScript.toLocal8Bit().data() << std::endl; } else { std::cout << tr("File %1 does not exist, aborting.").arg(pythonScript).toLocal8Bit().data() << std::endl; } @@ -273,32 +273,32 @@ void ScribusQApp::parseCommandLine() } else { ++i; } + } else if (arg == CMD_OPTIONS_END) { //double dash, indicates end of command line options, see http://unix.stackexchange.com/questions/11376/what-does-double-dash-mean-also-known-as-bare-double-dash + i++; + break; } else if (arg.startsWith(qtARG_SCRIPTARG_PREFIX)) { - QString arg_name = arg.mid(qtARG_SCRIPTARG_PREFIX.size()-1); //-1 to get the dash from prefix - QString arg_value = QFile::decodeName(args[++i].toLocal8Bit()); - //std::cout << tr("got one script argument: %1 with value %2").arg(arg_name).arg(arg_value).toLocal8Bit().data() << std::endl; - pythonScriptArgs.append(arg_name); - pythonScriptArgs.append(arg_value); - } else if (arg.startsWith(qtARG_SCRIPTFLAG_PREFIX)) { - QString arg_name = arg.mid(qtARG_SCRIPTFLAG_PREFIX.size()-1); //-1 to get the dash from prefix - //std::cout << tr("got one script flag: %1 ").arg(arg_name).toLocal8Bit().data() << std::endl; - pythonScriptArgs.append(arg_name); - } else { // (last) positional argument - fileName = QFile::decodeName(args[i].toLocal8Bit()); - if (!QFileInfo(fileName).exists()) { - showHeader(); - if (fileName.left(1) == "-" || fileName.left(2) == "--") { - std::cout << tr("Invalid argument: %1").arg(fileName).toLocal8Bit().data() << std::endl; - } else { - std::cout << tr("File %1 does not exist, aborting.").arg(fileName).toLocal8Bit().data() << std::endl; - } - showUsage(); - std::exit(EXIT_FAILURE); + pythonScriptArgs.append( arg.mid(qtARG_SCRIPTARG_PREFIX.size()-1) ); //-1 to get the dash from prefix + if (!args[i+1].startsWith("-")) { + pythonScriptArgs.append( QFile::decodeName(args[++i].toLocal8Bit()) ); } - else - { - filesToLoad.append(fileName); + } else { //argument is not a known option, but either positional parameter or invalid. + break; + } + } + //remaining arguments, if any + for ( ; i<argsc; i++) { + fileName = QFile::decodeName(args[i].toLocal8Bit()); + if (!QFileInfo(fileName).exists()) { + showHeader(); + if (fileName.left(1) == "-" || fileName.left(2) == "--") { + std::cout << tr("Invalid argument: %1").arg(fileName).toLocal8Bit().data() << std::endl; + } else { + std::cout << tr("File %1 does not exist, aborting.").arg(fileName).toLocal8Bit().data() << std::endl; } + showUsage(); + std::exit(EXIT_FAILURE); + } else { + filesToLoad.append(fileName); } } } @@ -501,7 +501,7 @@ void ScribusQApp::showUsage() QFile f; f.open(stderr, QIODevice::WriteOnly); QTextStream ts(&f); - ts << tr("Usage: scribus [option ... ] [file]") ; endl(ts); + ts << tr("Usage: scribus [options] [files]") ; endl(ts); endl(ts); ts << tr("Options:") ; endl(ts); printArgLine(ts, ARG_FONTINFO_SHORT, ARG_FONTINFO, tr("Show information on the console when fonts are being loaded") ); printArgLine(ts, ARG_HELP_SHORT, ARG_HELP, tr("Print help (this message) and exit") ); @@ -514,9 +514,10 @@ void ScribusQApp::showUsage() printArgLine(ts, ARG_UPGRADECHECK_SHORT, ARG_UPGRADECHECK, tr("Download a file from the Scribus website and show the latest available version") ); printArgLine(ts, ARG_VERSION_SHORT, ARG_VERSION, tr("Output version information and exit") ); printArgLine(ts, ARG_PYTHONSCRIPT_SHORT, qPrintable(QString("%1 <%2>").arg(ARG_PYTHONSCRIPT).arg(tr("filename"))), tr("Run filename in Python scripter") ); - ts << (QString(" %1<%2> <%3> ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script with its value, no effect without -py"); endl(ts); - ts << (QString(" %1<%2> ").arg(ARG_SCRIPTFLAG_PREFIX).arg(tr("flagname"))) << tr("Argument passed on to python script with no value, no effect without -py"); endl(ts); - printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); + ts << (QString(" %1<%2> [%3] ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script, with an optional value, no effect without -py"); endl(ts); + printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); + ts << (QString(" %1").arg(CMD_OPTIONS_END,-39)) << tr("Explicit end of command line options"); endl(ts); + #if defined(_WIN32) && !defined(_CONSOLE) printArgLine(ts, ARG_CONSOLE_SHORT, ARG_CONSOLE, tr("Display a console window") ); From 6752a35215de21ff5b0b1e3530245f55c43bb655 Mon Sep 17 00:00:00 2001 From: berteh <berteh@gmail.com> Date: Wed, 19 Aug 2015 17:09:19 +0200 Subject: [PATCH 7/9] polishing code for command line arguments for python script: overloading --- scribus/plugins/scriptplugin/scriptercore.cpp | 6 ++--- scribus/plugins/scriptplugin/scriptercore.h | 2 +- scribus/scribusapp.cpp | 32 +++++++++++++-------------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/scribus/plugins/scriptplugin/scriptercore.cpp b/scribus/plugins/scriptplugin/scriptercore.cpp index 41b2949..f1f4594 100644 --- a/scribus/plugins/scriptplugin/scriptercore.cpp +++ b/scribus/plugins/scriptplugin/scriptercore.cpp @@ -230,10 +230,10 @@ void ScripterCore::RecentScript(QString fn) void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter) { QStringList arguments = QStringList(); - slotRunScriptFileArgs(fileName, arguments, inMainInterpreter); + slotRunScriptFile(fileName, arguments, inMainInterpreter); } -void ScripterCore::slotRunScriptFileArgs(QString fileName, QStringList arguments, bool inMainInterpreter) +void ScripterCore::slotRunScriptFile(QString fileName, QStringList arguments, bool inMainInterpreter) /** run "filename" python script with the additional arguments provided in "arguments" */ { // Prevent two scripts to be run concurrently or face crash! @@ -376,7 +376,7 @@ void ScripterCore::slotRunPythonScript() { if (!ScQApp->pythonScript.isNull()) { - slotRunScriptFileArgs(ScQApp->pythonScript, ScQApp->pythonScriptArgs, true); + slotRunScriptFile(ScQApp->pythonScript, ScQApp->pythonScriptArgs, true); FinishScriptRun(); } } diff --git a/scribus/plugins/scriptplugin/scriptercore.h b/scribus/plugins/scriptplugin/scriptercore.h index b8e2edf..72e5461 100644 --- a/scribus/plugins/scriptplugin/scriptercore.h +++ b/scribus/plugins/scriptplugin/scriptercore.h @@ -39,7 +39,7 @@ public slots: void StdScript(QString filebasename); void RecentScript(QString fn); void slotRunScriptFile(QString fileName, bool inMainInterpreter = false); - void slotRunScriptFileArgs(QString fileName, QStringList arguments, bool inMainInterpreter = false); + void slotRunScriptFile(QString fileName, QStringList arguments, bool inMainInterpreter = false); void slotRunPythonScript(); // needed for running python script from CLI void slotRunScript(const QString script); void slotInteractiveScript(bool); diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index 6be0cbc..8870934 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -218,11 +218,11 @@ void ScribusQApp::parseCommandLine() useGUI = true; //We are going to run something other than command line help QString qtARG_SCRIPTARG_PREFIX = QString(ARG_SCRIPTARG_PREFIX); - int i = 1; - for( ; i < argsc; i++) { //handle all options (not positional parameters) - arg = args[i]; + int argi = 1; + for( ; argi < argsc; argi++) { //handle options (not positional parameters) + arg = args[argi]; - if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++i < argsc)) { + if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++argi < argsc)) { continue; } else if ( arg == ARG_CONSOLE || arg == ARG_CONSOLE_SHORT ) { continue; @@ -238,12 +238,12 @@ void ScribusQApp::parseCommandLine() showFontInfo=true; } else if (arg == ARG_PROFILEINFO || arg == ARG_PROFILEINFO_SHORT) { showProfileInfo=true; - } else if ((arg == ARG_DISPLAY || arg==ARG_DISPLAY_SHORT || arg==ARG_DISPLAY_QT) && ++i < argsc) { + } else if ((arg == ARG_DISPLAY || arg==ARG_DISPLAY_SHORT || arg==ARG_DISPLAY_QT) && ++argi < argsc) { // allow setting of display, QT expect the option -display <display_name> so we discard the // last argument. FIXME: Qt only understands -display not --display and -d , we need to work // around this. } else if (arg == ARG_PREFS || arg == ARG_PREFS_SHORT) { - prefsUserFile = QFile::decodeName(args[i + 1].toLocal8Bit()); + prefsUserFile = QFile::decodeName(args[argi + 1].toLocal8Bit()); if (!QFileInfo(prefsUserFile).exists()) { showHeader(); if (prefsUserFile.left(1) == "-" || prefsUserFile.left(2) == "--") { @@ -254,40 +254,40 @@ void ScribusQApp::parseCommandLine() showUsage(); std::exit(EXIT_FAILURE); } else { - ++i; + ++argi; } } else if (strncmp(arg.toLocal8Bit().data(),"-psn_",4) == 0) { // Andreas Vox: Qt/Mac has -psn_blah flags that must be accepted. } else if (arg == ARG_PYTHONSCRIPT || arg == ARG_PYTHONSCRIPT_SHORT) { - pythonScript = QFile::decodeName(args[i + 1].toLocal8Bit()); + pythonScript = QFile::decodeName(args[argi + 1].toLocal8Bit()); if (!QFileInfo(pythonScript).exists()) { showHeader(); if (pythonScript.left(1) == "-" || pythonScript.left(2) == "--") { - std::cout << tr("Invalid option: ").toLocal8Bit().data() << pythonScript.toLocal8Bit().data() << std::endl; + std::cout << tr("Invalid argument: ").toLocal8Bit().data() << pythonScript.toLocal8Bit().data() << std::endl; } else { std::cout << tr("File %1 does not exist, aborting.").arg(pythonScript).toLocal8Bit().data() << std::endl; } showUsage(); std::exit(EXIT_FAILURE); } else { - ++i; + ++argi; } } else if (arg == CMD_OPTIONS_END) { //double dash, indicates end of command line options, see http://unix.stackexchange.com/questions/11376/what-does-double-dash-mean-also-known-as-bare-double-dash - i++; + argi++; break; } else if (arg.startsWith(qtARG_SCRIPTARG_PREFIX)) { pythonScriptArgs.append( arg.mid(qtARG_SCRIPTARG_PREFIX.size()-1) ); //-1 to get the dash from prefix - if (!args[i+1].startsWith("-")) { - pythonScriptArgs.append( QFile::decodeName(args[++i].toLocal8Bit()) ); + if (!args[argi+1].startsWith("-")) { + pythonScriptArgs.append( QFile::decodeName(args[++argi].toLocal8Bit()) ); } } else { //argument is not a known option, but either positional parameter or invalid. break; } } - //remaining arguments, if any - for ( ; i<argsc; i++) { - fileName = QFile::decodeName(args[i].toLocal8Bit()); + //remaining (positional) arguments, if any + for ( ; argi<argsc; argi++) { + fileName = QFile::decodeName(args[argi].toLocal8Bit()); if (!QFileInfo(fileName).exists()) { showHeader(); if (fileName.left(1) == "-" || fileName.left(2) == "--") { From 83db1fc71a4ade3cd478c1b762229c9d9be8e6c3 Mon Sep 17 00:00:00 2001 From: berteh <berteh@gmail.com> Date: Thu, 3 Sep 2015 22:21:32 +0200 Subject: [PATCH 8/9] modified syntax to --python-arg <name> [value], per Craig request --- scribus/plugins/scriptplugin/scriptercore.cpp | 3 +-- scribus/scribusapp.cpp | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/scribus/plugins/scriptplugin/scriptercore.cpp b/scribus/plugins/scriptplugin/scriptercore.cpp index f1f4594..cf41110 100644 --- a/scribus/plugins/scriptplugin/scriptercore.cpp +++ b/scribus/plugins/scriptplugin/scriptercore.cpp @@ -229,8 +229,7 @@ void ScripterCore::RecentScript(QString fn) void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter) { - QStringList arguments = QStringList(); - slotRunScriptFile(fileName, arguments, inMainInterpreter); + slotRunScriptFile(fileName, QStringList(), inMainInterpreter); } void ScripterCore::slotRunScriptFile(QString fileName, QStringList arguments, bool inMainInterpreter) diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index 8870934..951889c 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -72,8 +72,8 @@ for which a new license (GPL+exception) is in place. #define ARG_UPGRADECHECK "--upgradecheck" #define ARG_TESTS "--tests" #define ARG_PYTHONSCRIPT "--python-script" -#define ARG_SCRIPTARG_PREFIX "--python-arg-" // directly followed by <param name> <param value> -#define CMD_OPTIONS_END "--" // end of command line options +#define ARG_SCRIPTARG "--python-arg" +#define CMD_OPTIONS_END "--" #define ARG_VERSION_SHORT "-v" #define ARG_HELP_SHORT "-h" @@ -89,6 +89,7 @@ for which a new license (GPL+exception) is in place. #define ARG_UPGRADECHECK_SHORT "-u" #define ARG_TESTS_SHORT "-T" #define ARG_PYTHONSCRIPT_SHORT "-py" +#define ARG_SCRIPTARG_SHORT "-pa" // Qt wants -display not --display or -d #define ARG_DISPLAY_QT "-display" @@ -217,12 +218,17 @@ void ScribusQApp::parseCommandLine() std::exit(EXIT_SUCCESS); useGUI = true; //We are going to run something other than command line help - QString qtARG_SCRIPTARG_PREFIX = QString(ARG_SCRIPTARG_PREFIX); int argi = 1; for( ; argi < argsc; argi++) { //handle options (not positional parameters) arg = args[argi]; - if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++argi < argsc)) { + if (arg == ARG_SCRIPTARG || arg == ARG_SCRIPTARG_SHORT) { //needs to be first to give precedence to script argument name over scribus' + pythonScriptArgs.append(args[++argi]); // arg name + if (!args[argi+1].startsWith("-")) { // arg value + pythonScriptArgs.append( QFile::decodeName(args[++argi].toLocal8Bit()) ); + } + } + else if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++argi < argsc)) { continue; } else if ( arg == ARG_CONSOLE || arg == ARG_CONSOLE_SHORT ) { continue; @@ -276,11 +282,6 @@ void ScribusQApp::parseCommandLine() } else if (arg == CMD_OPTIONS_END) { //double dash, indicates end of command line options, see http://unix.stackexchange.com/questions/11376/what-does-double-dash-mean-also-known-as-bare-double-dash argi++; break; - } else if (arg.startsWith(qtARG_SCRIPTARG_PREFIX)) { - pythonScriptArgs.append( arg.mid(qtARG_SCRIPTARG_PREFIX.size()-1) ); //-1 to get the dash from prefix - if (!args[argi+1].startsWith("-")) { - pythonScriptArgs.append( QFile::decodeName(args[++argi].toLocal8Bit()) ); - } } else { //argument is not a known option, but either positional parameter or invalid. break; } @@ -514,7 +515,7 @@ void ScribusQApp::showUsage() printArgLine(ts, ARG_UPGRADECHECK_SHORT, ARG_UPGRADECHECK, tr("Download a file from the Scribus website and show the latest available version") ); printArgLine(ts, ARG_VERSION_SHORT, ARG_VERSION, tr("Output version information and exit") ); printArgLine(ts, ARG_PYTHONSCRIPT_SHORT, qPrintable(QString("%1 <%2>").arg(ARG_PYTHONSCRIPT).arg(tr("filename"))), tr("Run filename in Python scripter") ); - ts << (QString(" %1<%2> [%3] ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script, with an optional value, no effect without -py"); endl(ts); + printArgLine(ts, ARG_SCRIPTARG_SHORT, qPrintable(QString("%1 <%2> [%3]").arg(ARG_SCRIPTARG).arg(tr("name")).arg(tr("value"))), tr("Argument passed on to python script, with an optional value, no effect without -py") ); printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); ts << (QString(" %1").arg(CMD_OPTIONS_END,-39)) << tr("Explicit end of command line options"); endl(ts); From 697424b382e8b1eabe485de262573d28d383c46a Mon Sep 17 00:00:00 2001 From: berteh <berteh@gmail.com> Date: Thu, 3 Sep 2015 22:35:22 +0200 Subject: [PATCH 9/9] revert 'option' to 'argument' in CLI feedback --- scribus/scribusapp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index 951889c..21d7ecc 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -253,7 +253,7 @@ void ScribusQApp::parseCommandLine() if (!QFileInfo(prefsUserFile).exists()) { showHeader(); if (prefsUserFile.left(1) == "-" || prefsUserFile.left(2) == "--") { - std::cout << tr("Invalid option: ").toLocal8Bit().data() << prefsUserFile.toLocal8Bit().data() << std::endl; + std::cout << tr("Invalid argument: ").toLocal8Bit().data() << prefsUserFile.toLocal8Bit().data() << std::endl; } else { std::cout << tr("File %1 does not exist, aborting.").arg(prefsUserFile).toLocal8Bit().data() << std::endl; } |
|
diff view of changes between the 2 patches: https://github.com/berteh/scribus/commit/83db1fc71a4ade3cd478c1b762229c9d9be8e6c3?diff=split diff view of the new patch (in full): https://github.com/scribusproject/scribus/pull/19/files?diff=split |
|
Do we need arg and flag types? +#define ARG_SCRIPTARG_PREFIX "--python-arg" // directly followed by <param name> <param value> +#define ARG_SCRIPTFLAG_PREFIX "--python-flag" // directly followed by <param name> I don't get why if we have a flag and an arg command line option, Scribus cannot just use the full values without messing with existing options. eg when --python-flag is used, the next parameter is the flag, and when --python-arg is used, the next two parameters are the arg/value pair. Another Qt one: QString qtARG_SCRIPTARG_PREFIX = QString(ARG_SCRIPTARG_PREFIX); should just be QString qtARG_SCRIPTARG_PREFIX(ARG_SCRIPTARG_PREFIX); unless the #define causes issues. formatting issue: + } else if (arg.startsWith(qtARG_SCRIPTFLAG_PREFIX)) { should be + } + else if (arg.startsWith(qtARG_SCRIPTFLAG_PREFIX)) + { |
|
ghostscript has a similar issue where you sometimes need to pass information to the postscript interpreter. They have a -c option that takes everything that follows until a delimiter (or to the end of the command line if no delimiter is present). http://ghostscript.com/doc/current/Use.htm#General_switches It is similar to the --python-arg ... -- suggestion, except that most gs scripts place the -c ... sequence last, so you can usually get away without worrying about the delimiter. I think that all of the suggestions so far are fine because the arguments will probably be generated by scripts, so the syntax and verbosity is not a big issue. The syntax "--python-arg -xyz ... --" might be slightly easier to script because it is easier to write "--python-arg $flag --" without worrying if $flag is empty, while "--python-flag$arg" or "--python-flag $flag" both require a conditional in the script to test if $flag is empty. |
|
@cbradney: the 3 items you mention are not in the final code of the patch, but only in its history (they have been changed by later commits in the same patch), I re-up a "clean" patch with only the final changes... or you can see it online at https://github.com/scribusproject/scribus/pull/19/files?diff=split on 1) only --python-arg, -pa and -- are added, nothing about a "flag" anymore, for the reason you mention. on 2) and 3) qtARG_SCRIPTFLAG_PREFIX is completely removed from code nevertheless the issue stands on the "header" arguments: -h, -v (a.o.) get a "preferred" treatment in current code, they are detected before all other command-line arguments, to simply issue a command-line feedback and exit (scribusapp.cpp l.217). Do you want me to merge all arguments parsing (headers and non headers) into a single loop for parsing arguments? I could then solve "precedence" issues... but then adding "-h" after "--python-arg" would NOT display scribus help. @william: yes indeed a single combination of "some-args-start" and "some-args-stop" delimiter passing all in-between to the script would be possible, but others (namely aoloe) preferred not having that mechanism, see https://github.com/scribusproject/scribus/pull/19#issuecomment-128313027 (and that would still not solve the issue of "headers" arguments above, by the way) |
|
cmdline_--python-arg_name_value__clean.patch (11,126 bytes)
diff --git a/scribus/plugins/scriptplugin/scriptercore.cpp b/scribus/plugins/scriptplugin/scriptercore.cpp index 3903617..cf41110 100644 --- a/scribus/plugins/scriptplugin/scriptercore.cpp +++ b/scribus/plugins/scriptplugin/scriptercore.cpp @@ -9,6 +9,7 @@ for which a new license (GPL+exception) is in place. #include <QGlobalStatic> #include <QWidget> #include <QString> +#include <QStringList> #include <QApplication> #include <QMessageBox> #include <QTextCodec> @@ -37,7 +38,7 @@ for which a new license (GPL+exception) is in place. #include "prefscontext.h" #include "prefstable.h" #include "prefsmanager.h" -#include "scribusapp.h" // need it to acces ScQApp->pythonScript +#include "scribusapp.h" // need it to acces ScQApp->pythonScript & ScQApp->pythonScriptArgs ScripterCore::ScripterCore(QWidget* parent) { @@ -228,6 +229,12 @@ void ScripterCore::RecentScript(QString fn) void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter) { + slotRunScriptFile(fileName, QStringList(), inMainInterpreter); +} + +void ScripterCore::slotRunScriptFile(QString fileName, QStringList arguments, bool inMainInterpreter) +/** run "filename" python script with the additional arguments provided in "arguments" */ +{ // Prevent two scripts to be run concurrently or face crash! if (ScCore->primaryMainWindow()->scriptIsRunning()) return; @@ -252,16 +259,27 @@ void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter) // Init the scripter module in the sub-interpreter initscribus(ScCore->primaryMainWindow()); } + // Make sure sys.argv[0] is the path to the script - char* comm[2]; - comm[0] = na.data(); + arguments.prepend(na.data()); + // and tell the script if it's running in the main intepreter or // a subinterpreter using the second argument, ie sys.argv[1] if (inMainInterpreter) - comm[1] = const_cast<char*>("ext"); + arguments.insert(1,QString("ext")); else - comm[1] = const_cast<char*>("sub"); - PySys_SetArgv(2, comm); + arguments.insert(1,QString("sub")); + + //convert arguments (QListString) to char** for Python bridge + /* typically arguments == ['path/to/script.py','ext','--argument1','valueforarg1','--flag']*/ + char *comm[arguments.size()]; + for (int i = 0; i < arguments.size(); i++) + { + comm[i] = new char[arguments.at(i).toLocal8Bit().size()+1]; //+1 to allow adding '\0'. may be useless, don't know how to check. + strcpy(comm[i],arguments.at(i).toLocal8Bit().data()+'\0'); + } + PySys_SetArgv(arguments.size(), comm); + // call python script PyObject* m = PyImport_AddModule((char*)"__main__"); if (m == NULL) @@ -357,7 +375,7 @@ void ScripterCore::slotRunPythonScript() { if (!ScQApp->pythonScript.isNull()) { - slotRunScriptFile(ScQApp->pythonScript, true); + slotRunScriptFile(ScQApp->pythonScript, ScQApp->pythonScriptArgs, true); FinishScriptRun(); } } diff --git a/scribus/plugins/scriptplugin/scriptercore.h b/scribus/plugins/scriptplugin/scriptercore.h index 1e929f4..72e5461 100644 --- a/scribus/plugins/scriptplugin/scriptercore.h +++ b/scribus/plugins/scriptplugin/scriptercore.h @@ -39,8 +39,9 @@ public slots: void StdScript(QString filebasename); void RecentScript(QString fn); void slotRunScriptFile(QString fileName, bool inMainInterpreter = false); + void slotRunScriptFile(QString fileName, QStringList arguments, bool inMainInterpreter = false); void slotRunPythonScript(); // needed for running python script from CLI - void slotRunScript(const QString Script); + void slotRunScript(const QString script); void slotInteractiveScript(bool); void slotExecute(); /*! \brief Show docstring of the script to the user. diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index fec4055..21d7ecc 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -32,6 +32,7 @@ for which a new license (GPL+exception) is in place. #include <QLibraryInfo> #include <QLocale> #include <QString> +#include <QStringList> #include <QTextCodec> #include <QTextStream> #include <QTranslator> @@ -71,6 +72,8 @@ for which a new license (GPL+exception) is in place. #define ARG_UPGRADECHECK "--upgradecheck" #define ARG_TESTS "--tests" #define ARG_PYTHONSCRIPT "--python-script" +#define ARG_SCRIPTARG "--python-arg" +#define CMD_OPTIONS_END "--" #define ARG_VERSION_SHORT "-v" #define ARG_HELP_SHORT "-h" @@ -86,6 +89,7 @@ for which a new license (GPL+exception) is in place. #define ARG_UPGRADECHECK_SHORT "-u" #define ARG_TESTS_SHORT "-T" #define ARG_PYTHONSCRIPT_SHORT "-py" +#define ARG_SCRIPTARG_SHORT "-pa" // Qt wants -display not --display or -d #define ARG_DISPLAY_QT "-display" @@ -108,6 +112,7 @@ ScribusQApp::ScribusQApp( int & argc, char ** argv ) : QApplication(argc, argv), m_scDLMgr = 0; m_ScCore = NULL; initDLMgr(); + } ScribusQApp::~ScribusQApp() @@ -213,10 +218,17 @@ void ScribusQApp::parseCommandLine() std::exit(EXIT_SUCCESS); useGUI = true; //We are going to run something other than command line help - for(int i = 1; i < argsc; i++) { - arg = args[i]; - - if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++i < argsc)) { + int argi = 1; + for( ; argi < argsc; argi++) { //handle options (not positional parameters) + arg = args[argi]; + + if (arg == ARG_SCRIPTARG || arg == ARG_SCRIPTARG_SHORT) { //needs to be first to give precedence to script argument name over scribus' + pythonScriptArgs.append(args[++argi]); // arg name + if (!args[argi+1].startsWith("-")) { // arg value + pythonScriptArgs.append( QFile::decodeName(args[++argi].toLocal8Bit()) ); + } + } + else if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++argi < argsc)) { continue; } else if ( arg == ARG_CONSOLE || arg == ARG_CONSOLE_SHORT ) { continue; @@ -232,12 +244,12 @@ void ScribusQApp::parseCommandLine() showFontInfo=true; } else if (arg == ARG_PROFILEINFO || arg == ARG_PROFILEINFO_SHORT) { showProfileInfo=true; - } else if ((arg == ARG_DISPLAY || arg==ARG_DISPLAY_SHORT || arg==ARG_DISPLAY_QT) && ++i < argsc) { + } else if ((arg == ARG_DISPLAY || arg==ARG_DISPLAY_SHORT || arg==ARG_DISPLAY_QT) && ++argi < argsc) { // allow setting of display, QT expect the option -display <display_name> so we discard the // last argument. FIXME: Qt only understands -display not --display and -d , we need to work // around this. } else if (arg == ARG_PREFS || arg == ARG_PREFS_SHORT) { - prefsUserFile = QFile::decodeName(args[i + 1].toLocal8Bit()); + prefsUserFile = QFile::decodeName(args[argi + 1].toLocal8Bit()); if (!QFileInfo(prefsUserFile).exists()) { showHeader(); if (prefsUserFile.left(1) == "-" || prefsUserFile.left(2) == "--") { @@ -248,13 +260,13 @@ void ScribusQApp::parseCommandLine() showUsage(); std::exit(EXIT_FAILURE); } else { - ++i; + ++argi; } } else if (strncmp(arg.toLocal8Bit().data(),"-psn_",4) == 0) { // Andreas Vox: Qt/Mac has -psn_blah flags that must be accepted. } else if (arg == ARG_PYTHONSCRIPT || arg == ARG_PYTHONSCRIPT_SHORT) { - pythonScript = QFile::decodeName(args[i + 1].toLocal8Bit()); + pythonScript = QFile::decodeName(args[argi + 1].toLocal8Bit()); if (!QFileInfo(pythonScript).exists()) { showHeader(); if (pythonScript.left(1) == "-" || pythonScript.left(2) == "--") { @@ -265,24 +277,29 @@ void ScribusQApp::parseCommandLine() showUsage(); std::exit(EXIT_FAILURE); } else { - ++i; + ++argi; } - } else { - fileName = QFile::decodeName(args[i].toLocal8Bit()); - if (!QFileInfo(fileName).exists()) { - showHeader(); - if (fileName.left(1) == "-" || fileName.left(2) == "--") { - std::cout << tr("Invalid argument: %1").arg(fileName).toLocal8Bit().data() << std::endl; - } else { - std::cout << tr("File %1 does not exist, aborting.").arg(fileName).toLocal8Bit().data() << std::endl; - } - showUsage(); - std::exit(EXIT_FAILURE); - } - else - { - filesToLoad.append(fileName); + } else if (arg == CMD_OPTIONS_END) { //double dash, indicates end of command line options, see http://unix.stackexchange.com/questions/11376/what-does-double-dash-mean-also-known-as-bare-double-dash + argi++; + break; + } else { //argument is not a known option, but either positional parameter or invalid. + break; + } + } + //remaining (positional) arguments, if any + for ( ; argi<argsc; argi++) { + fileName = QFile::decodeName(args[argi].toLocal8Bit()); + if (!QFileInfo(fileName).exists()) { + showHeader(); + if (fileName.left(1) == "-" || fileName.left(2) == "--") { + std::cout << tr("Invalid argument: %1").arg(fileName).toLocal8Bit().data() << std::endl; + } else { + std::cout << tr("File %1 does not exist, aborting.").arg(fileName).toLocal8Bit().data() << std::endl; } + showUsage(); + std::exit(EXIT_FAILURE); + } else { + filesToLoad.append(fileName); } } } @@ -485,7 +502,7 @@ void ScribusQApp::showUsage() QFile f; f.open(stderr, QIODevice::WriteOnly); QTextStream ts(&f); - ts << tr("Usage: scribus [option ... ] [file]") ; endl(ts); + ts << tr("Usage: scribus [options] [files]") ; endl(ts); endl(ts); ts << tr("Options:") ; endl(ts); printArgLine(ts, ARG_FONTINFO_SHORT, ARG_FONTINFO, tr("Show information on the console when fonts are being loaded") ); printArgLine(ts, ARG_HELP_SHORT, ARG_HELP, tr("Print help (this message) and exit") ); @@ -498,7 +515,10 @@ void ScribusQApp::showUsage() printArgLine(ts, ARG_UPGRADECHECK_SHORT, ARG_UPGRADECHECK, tr("Download a file from the Scribus website and show the latest available version") ); printArgLine(ts, ARG_VERSION_SHORT, ARG_VERSION, tr("Output version information and exit") ); printArgLine(ts, ARG_PYTHONSCRIPT_SHORT, qPrintable(QString("%1 <%2>").arg(ARG_PYTHONSCRIPT).arg(tr("filename"))), tr("Run filename in Python scripter") ); + printArgLine(ts, ARG_SCRIPTARG_SHORT, qPrintable(QString("%1 <%2> [%3]").arg(ARG_SCRIPTARG).arg(tr("name")).arg(tr("value"))), tr("Argument passed on to python script, with an optional value, no effect without -py") ); printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); + ts << (QString(" %1").arg(CMD_OPTIONS_END,-39)) << tr("Explicit end of command line options"); endl(ts); + #if defined(_WIN32) && !defined(_CONSOLE) printArgLine(ts, ARG_CONSOLE_SHORT, ARG_CONSOLE, tr("Display a console window") ); diff --git a/scribus/scribusapp.h b/scribus/scribusapp.h index 2857306..7fc9f7f 100644 --- a/scribus/scribusapp.h +++ b/scribus/scribusapp.h @@ -23,6 +23,7 @@ for which a new license (GPL+exception) is in place. #define SCRIBUSAPP_H #include <QApplication> #include <QString> +#include <QStringList> #include "scribusapi.h" @@ -71,6 +72,7 @@ class SCRIBUS_API ScribusQApp : public QApplication const QString& currGUILanguage() { return GUILang; } ScDLManager* dlManager() { return m_scDLMgr; } QString pythonScript; // script to be run in python from CLI + QStringList pythonScriptArgs; // command line arguments and flags for script from CLI private: ScribusCore* m_ScCore; |
|
is there anyway someone can edit the "steps to reproduce" of this bug report to the following (I cannot) apply "cmdline_--python-arg_name_value__clean.patch", compile, then call any scribus python script that will get the additional arguments passed from the command line: simple use: ./scribus -g -py ~/cmdtest.py --python-arg -someflag1 --python-arg --somearg1 value1 ~/some1.sla or more complex (with -- to distinguish that last parameter(s) are file(s) to be opened by scribus before running the script, and not arguments to be passed to the script.) ./scribus -g -py ~/cmdtest.py --python-arg -somearg1 value1 --python-arg --someflag1 -- ~/some1.sla help is in the standard usage info: ./scribus -h Usage: scribus [options] [files] Options: (...) -py, --python-script <filename> Run filename in Python scripter -pa, --python-arg <name> [value] Argument passed on to python script, with an optional value, no effect without -py -- Explicit end of command line options |
|
Done berteh. I prefer --python-arg arg1 or --python-arg -arg1 to --python-arg-arg1 As for conflicts with standard scribus args, i could very well accept to have to mention these standard options before any python-arg Thanks MrB and Berteh for all these thoughts and works for improving use. |
|
i'm fine with "--python-arg -l --python-arg --items=12". but i still somehow prefer "--python-arg-h" since it does not seem to have any side effects (except maybe, that it's harder for the user to understand that it's a parameter of the script and not a scribus parameter) i would indeed avoid a start and stop mechanism. i'd prefer long, unambiguous, easy to parse commands to short and easy to type ones. (i don't really see those arguments as to typed in a terminal but rather generated by a script) after having read the comment about GS, i thing that it would not be that bad to just use the same wa other software have already implemented (using solutions that work and possibly already known to our users) |
|
It should be --python-arg <argname> <argvalue> (or -pa) @berteh: Feel free to rewrite the command line parsing to remove precedence. I would not expect -h after --python-arg to show the help (however if after --python-arg, I would also then expect "-h" to be passed in, and not just "h" as both argname and argvalue should not use -). I don't like start/stop markers (wont accept a patch for that) I don't like --python-arg-blah (wont accept a patch for that) I guess we would accept forcing --python-arg to be last and then having all arg/values at the end. scribus -h --python-arg abc 123 should show the help though and ignore --python-arg (or any other parameter passed in) |
|
cmdline --python-arg name value__compatible-header-arguments.patch (14,494 bytes)
diff --git a/scribus/plugins/scriptplugin/scriptercore.cpp b/scribus/plugins/scriptplugin/scriptercore.cpp index 3903617..cf41110 100644 --- a/scribus/plugins/scriptplugin/scriptercore.cpp +++ b/scribus/plugins/scriptplugin/scriptercore.cpp @@ -9,6 +9,7 @@ for which a new license (GPL+exception) is in place. #include <QGlobalStatic> #include <QWidget> #include <QString> +#include <QStringList> #include <QApplication> #include <QMessageBox> #include <QTextCodec> @@ -37,7 +38,7 @@ for which a new license (GPL+exception) is in place. #include "prefscontext.h" #include "prefstable.h" #include "prefsmanager.h" -#include "scribusapp.h" // need it to acces ScQApp->pythonScript +#include "scribusapp.h" // need it to acces ScQApp->pythonScript & ScQApp->pythonScriptArgs ScripterCore::ScripterCore(QWidget* parent) { @@ -228,6 +229,12 @@ void ScripterCore::RecentScript(QString fn) void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter) { + slotRunScriptFile(fileName, QStringList(), inMainInterpreter); +} + +void ScripterCore::slotRunScriptFile(QString fileName, QStringList arguments, bool inMainInterpreter) +/** run "filename" python script with the additional arguments provided in "arguments" */ +{ // Prevent two scripts to be run concurrently or face crash! if (ScCore->primaryMainWindow()->scriptIsRunning()) return; @@ -252,16 +259,27 @@ void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter) // Init the scripter module in the sub-interpreter initscribus(ScCore->primaryMainWindow()); } + // Make sure sys.argv[0] is the path to the script - char* comm[2]; - comm[0] = na.data(); + arguments.prepend(na.data()); + // and tell the script if it's running in the main intepreter or // a subinterpreter using the second argument, ie sys.argv[1] if (inMainInterpreter) - comm[1] = const_cast<char*>("ext"); + arguments.insert(1,QString("ext")); else - comm[1] = const_cast<char*>("sub"); - PySys_SetArgv(2, comm); + arguments.insert(1,QString("sub")); + + //convert arguments (QListString) to char** for Python bridge + /* typically arguments == ['path/to/script.py','ext','--argument1','valueforarg1','--flag']*/ + char *comm[arguments.size()]; + for (int i = 0; i < arguments.size(); i++) + { + comm[i] = new char[arguments.at(i).toLocal8Bit().size()+1]; //+1 to allow adding '\0'. may be useless, don't know how to check. + strcpy(comm[i],arguments.at(i).toLocal8Bit().data()+'\0'); + } + PySys_SetArgv(arguments.size(), comm); + // call python script PyObject* m = PyImport_AddModule((char*)"__main__"); if (m == NULL) @@ -357,7 +375,7 @@ void ScripterCore::slotRunPythonScript() { if (!ScQApp->pythonScript.isNull()) { - slotRunScriptFile(ScQApp->pythonScript, true); + slotRunScriptFile(ScQApp->pythonScript, ScQApp->pythonScriptArgs, true); FinishScriptRun(); } } diff --git a/scribus/plugins/scriptplugin/scriptercore.h b/scribus/plugins/scriptplugin/scriptercore.h index 1e929f4..72e5461 100644 --- a/scribus/plugins/scriptplugin/scriptercore.h +++ b/scribus/plugins/scriptplugin/scriptercore.h @@ -39,8 +39,9 @@ public slots: void StdScript(QString filebasename); void RecentScript(QString fn); void slotRunScriptFile(QString fileName, bool inMainInterpreter = false); + void slotRunScriptFile(QString fileName, QStringList arguments, bool inMainInterpreter = false); void slotRunPythonScript(); // needed for running python script from CLI - void slotRunScript(const QString Script); + void slotRunScript(const QString script); void slotInteractiveScript(bool); void slotExecute(); /*! \brief Show docstring of the script to the user. diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index fec4055..6a43590 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -32,6 +32,7 @@ for which a new license (GPL+exception) is in place. #include <QLibraryInfo> #include <QLocale> #include <QString> +#include <QStringList> #include <QTextCodec> #include <QTextStream> #include <QTranslator> @@ -71,6 +72,8 @@ for which a new license (GPL+exception) is in place. #define ARG_UPGRADECHECK "--upgradecheck" #define ARG_TESTS "--tests" #define ARG_PYTHONSCRIPT "--python-script" +#define ARG_SCRIPTARG "--python-arg" +#define CMD_OPTIONS_END "--" #define ARG_VERSION_SHORT "-v" #define ARG_HELP_SHORT "-h" @@ -86,6 +89,7 @@ for which a new license (GPL+exception) is in place. #define ARG_UPGRADECHECK_SHORT "-u" #define ARG_TESTS_SHORT "-T" #define ARG_PYTHONSCRIPT_SHORT "-py" +#define ARG_SCRIPTARG_SHORT "-pa" // Qt wants -display not --display or -d #define ARG_DISPLAY_QT "-display" @@ -108,6 +112,7 @@ ScribusQApp::ScribusQApp( int & argc, char ** argv ) : QApplication(argc, argv), m_scDLMgr = 0; m_ScCore = NULL; initDLMgr(); + } ScribusQApp::~ScribusQApp() @@ -151,18 +156,30 @@ void ScribusQApp::parseCommandLine() int testargsc; #endif showFontInfo=false; - showProfileInfo=false; + showProfileInfo=false; + bool neversplash = false; - //Parse for command line information options, and lang + //Parse for command line options // Qt5 port: do this in a Qt compatible manner QStringList args = arguments(); int argsc = args.count(); - for(int i = 1; i < argsc; i++) - { - arg = args[i]; - if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++i < argsc)) { - lang = args[i]; + //Init translations + initLang(); + + useGUI = true; + int argi = 1; + for( ; argi < argsc; argi++) { //handle options (not positional parameters) + arg = args[argi]; + + if (arg == ARG_SCRIPTARG || arg == ARG_SCRIPTARG_SHORT) { //needs to be first to give precedence to script argument name over scribus' options + pythonScriptArgs.append(args[++argi]); // arg name + if (!args[argi+1].startsWith("-")) { // arg value + pythonScriptArgs.append( QFile::decodeName(args[++argi].toLocal8Bit()) ); + } + } + else if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++argi < argsc)) { + lang = args[argi]; } else if (arg == ARG_VERSION || arg == ARG_VERSION_SHORT) { header=true; @@ -175,8 +192,8 @@ void ScribusQApp::parseCommandLine() else if (arg == ARG_TESTS || arg == ARG_TESTS_SHORT) { header=true; runtests=true; - testargsc = argc() - i; - testargsv = argv() + i; + testargsc = argc() - argi; + testargsv = argv() + argi; break; } #endif @@ -187,104 +204,94 @@ void ScribusQApp::parseCommandLine() header=true; runUpgradeCheck=true; } - } - //Init translations - initLang(); - //Show command line help - if (header) - showHeader(); - if (version) - showVersion(); - if (availlangs) - showAvailLangs(); - if (usage) - showUsage(); -#ifdef WITH_TESTS - if (runtests) - RunTests::runTests(testargsc, testargsv); -#endif - if (runUpgradeCheck) - { - UpgradeChecker uc; - uc.fetch(); - } - //Dont run the GUI init process called from main.cpp, and return - if (header) - std::exit(EXIT_SUCCESS); - useGUI = true; - //We are going to run something other than command line help - for(int i = 1; i < argsc; i++) { - arg = args[i]; - - if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++i < argsc)) { + else if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++argi < argsc)) { continue; - } else if ( arg == ARG_CONSOLE || arg == ARG_CONSOLE_SHORT ) { + } + else if ( arg == ARG_CONSOLE || arg == ARG_CONSOLE_SHORT ) { continue; } else if (arg == ARG_NOSPLASH || arg == ARG_NOSPLASH_SHORT) { showSplash = false; } else if (arg == ARG_NEVERSPLASH || arg == ARG_NEVERSPLASH_SHORT) { showSplash = false; - neverSplash(true); + neversplash = true; } else if (arg == ARG_NOGUI || arg == ARG_NOGUI_SHORT) { useGUI=false; } else if (arg == ARG_FONTINFO || arg == ARG_FONTINFO_SHORT) { showFontInfo=true; } else if (arg == ARG_PROFILEINFO || arg == ARG_PROFILEINFO_SHORT) { showProfileInfo=true; - } else if ((arg == ARG_DISPLAY || arg==ARG_DISPLAY_SHORT || arg==ARG_DISPLAY_QT) && ++i < argsc) { + } else if ((arg == ARG_DISPLAY || arg==ARG_DISPLAY_SHORT || arg==ARG_DISPLAY_QT) && ++argi < argsc) { // allow setting of display, QT expect the option -display <display_name> so we discard the // last argument. FIXME: Qt only understands -display not --display and -d , we need to work // around this. } else if (arg == ARG_PREFS || arg == ARG_PREFS_SHORT) { - prefsUserFile = QFile::decodeName(args[i + 1].toLocal8Bit()); + prefsUserFile = QFile::decodeName(args[argi + 1].toLocal8Bit()); if (!QFileInfo(prefsUserFile).exists()) { - showHeader(); - if (prefsUserFile.left(1) == "-" || prefsUserFile.left(2) == "--") { - std::cout << tr("Invalid argument: ").toLocal8Bit().data() << prefsUserFile.toLocal8Bit().data() << std::endl; - } else { - std::cout << tr("File %1 does not exist, aborting.").arg(prefsUserFile).toLocal8Bit().data() << std::endl; - } - showUsage(); + showError(prefsUserFile); std::exit(EXIT_FAILURE); } else { - ++i; + ++argi; } } else if (strncmp(arg.toLocal8Bit().data(),"-psn_",4) == 0) { // Andreas Vox: Qt/Mac has -psn_blah flags that must be accepted. } else if (arg == ARG_PYTHONSCRIPT || arg == ARG_PYTHONSCRIPT_SHORT) { - pythonScript = QFile::decodeName(args[i + 1].toLocal8Bit()); + pythonScript = QFile::decodeName(args[argi + 1].toLocal8Bit()); if (!QFileInfo(pythonScript).exists()) { - showHeader(); - if (pythonScript.left(1) == "-" || pythonScript.left(2) == "--") { - std::cout << tr("Invalid argument: ").toLocal8Bit().data() << pythonScript.toLocal8Bit().data() << std::endl; - } else { - std::cout << tr("File %1 does not exist, aborting.").arg(pythonScript).toLocal8Bit().data() << std::endl; - } - showUsage(); + showError(pythonScript); std::exit(EXIT_FAILURE); } else { - ++i; + ++argi; } + } else if (arg == CMD_OPTIONS_END) { //double dash, indicates end of command line options, see http://unix.stackexchange.com/questions/11376/what-does-double-dash-mean-also-known-as-bare-double-dash + argi++; + break; + } else { //argument is not a known option, but either positional parameter or invalid. + break; + } + } + // parse for remaining (positional) arguments, if any + for ( ; argi<argsc; argi++) { + fileName = QFile::decodeName(args[argi].toLocal8Bit()); + if (!QFileInfo(fileName).exists()) { + showError(fileName); + std::exit(EXIT_FAILURE); } else { - fileName = QFile::decodeName(args[i].toLocal8Bit()); - if (!QFileInfo(fileName).exists()) { - showHeader(); - if (fileName.left(1) == "-" || fileName.left(2) == "--") { - std::cout << tr("Invalid argument: %1").arg(fileName).toLocal8Bit().data() << std::endl; - } else { - std::cout << tr("File %1 does not exist, aborting.").arg(fileName).toLocal8Bit().data() << std::endl; - } - showUsage(); - std::exit(EXIT_FAILURE); - } - else - { - filesToLoad.append(fileName); - } + filesToLoad.append(fileName); } } + + + //Show command line info + if (header) { + useGUI = false; + showHeader(); + } + if (version) + showVersion(); + if (availlangs) + showAvailLangs(); + if (usage) + showUsage(); +#ifdef WITH_TESTS + if (runtests) + RunTests::runTests(testargsc, testargsv); +#endif + if (runUpgradeCheck) + { + UpgradeChecker uc; + uc.fetch(); + } + //Dont run the GUI init process called from main.cpp, and return + if (header) { + std::exit(EXIT_SUCCESS); + } + //proceed + if(neversplash) { + neverSplash(true); + } + } int ScribusQApp::init() @@ -485,7 +492,7 @@ void ScribusQApp::showUsage() QFile f; f.open(stderr, QIODevice::WriteOnly); QTextStream ts(&f); - ts << tr("Usage: scribus [option ... ] [file]") ; endl(ts); + ts << tr("Usage: scribus [options] [files]") ; endl(ts); endl(ts); ts << tr("Options:") ; endl(ts); printArgLine(ts, ARG_FONTINFO_SHORT, ARG_FONTINFO, tr("Show information on the console when fonts are being loaded") ); printArgLine(ts, ARG_HELP_SHORT, ARG_HELP, tr("Print help (this message) and exit") ); @@ -498,7 +505,10 @@ void ScribusQApp::showUsage() printArgLine(ts, ARG_UPGRADECHECK_SHORT, ARG_UPGRADECHECK, tr("Download a file from the Scribus website and show the latest available version") ); printArgLine(ts, ARG_VERSION_SHORT, ARG_VERSION, tr("Output version information and exit") ); printArgLine(ts, ARG_PYTHONSCRIPT_SHORT, qPrintable(QString("%1 <%2>").arg(ARG_PYTHONSCRIPT).arg(tr("filename"))), tr("Run filename in Python scripter") ); + printArgLine(ts, ARG_SCRIPTARG_SHORT, qPrintable(QString("%1 <%2> [%3]").arg(ARG_SCRIPTARG).arg(tr("name")).arg(tr("value"))), tr("Argument passed on to python script, with an optional value, no effect without -py") ); printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); + ts << (QString(" %1").arg(CMD_OPTIONS_END,-39)) << tr("Explicit end of command line options"); endl(ts); + #if defined(_WIN32) && !defined(_CONSOLE) printArgLine(ts, ARG_CONSOLE_SHORT, ARG_CONSOLE, tr("Display a console window") ); @@ -558,6 +568,18 @@ void ScribusQApp::showHeader() endl(ts); } +void ScribusQApp::showError(QString arg) +{ + showHeader(); + if (arg.left(1) == "-" || arg.left(2) == "--") { + std::cout << tr("Invalid argument: %1").arg(arg).toLocal8Bit().data() << std::endl; + } else { + std::cout << tr("File %1 does not exist, aborting.").arg(arg).toLocal8Bit().data() << std::endl; + } + showUsage(); + std::cout << tr("Scribus Version").toLocal8Bit().data() << " " << VERSION << std::endl; +} + void ScribusQApp::neverSplash(bool splashOff) { QString prefsDir = ScPaths::getApplicationDataDir(); diff --git a/scribus/scribusapp.h b/scribus/scribusapp.h index 2857306..0add48f 100644 --- a/scribus/scribusapp.h +++ b/scribus/scribusapp.h @@ -23,6 +23,7 @@ for which a new license (GPL+exception) is in place. #define SCRIBUSAPP_H #include <QApplication> #include <QString> +#include <QStringList> #include "scribusapi.h" @@ -71,10 +72,12 @@ class SCRIBUS_API ScribusQApp : public QApplication const QString& currGUILanguage() { return GUILang; } ScDLManager* dlManager() { return m_scDLMgr; } QString pythonScript; // script to be run in python from CLI + QStringList pythonScriptArgs; // command line arguments and flags for script from CLI private: ScribusCore* m_ScCore; void showHeader(); + void showError(QString arg); void showVersion(); /*! \author Franz Schmid |
|
@cbradney new patch (cmdline --python-arg name value__compatible-header-arguments.patch) includes the removal of precedence of header arguments. It supports --python-arg <name> <value> (or -pa), and indeed if you pass "-h" as <name>, the script receives "-h". scribus -h --python-arg abc 123 does indeed show scribus help and exit (precedence is only removed in the parsing, not in the effect of the argument itself) online view at https://github.com/scribusproject/scribus/pull/19/files?diff=split thanks for your guidance. |
|
Thanks, resolved in r20372 :) |
|
Hello i've documented the command-line scripting option along with this argument passing feature. Can you have a look and correct mistakes when necessary ? http://wiki.scribus.net/canvas/Command_line_scripts |
|
BTW i dont understand the 'depth computation' example. What is that 'depth' exactly ? maybe the heigth of the actual text, whether it fits or not in the frame ? |
|
It think i've understood. See http://wiki.scribus.net/canvas/Command_line_scripts |
|
Lets make a super sexy and practical page showing great usecases for this function. |
|
The documentation at http://wiki.scribus.net/canvas/Command_line_scripts looks good. I didn't realize that you would use the script. It is not the most common use case. To explain, I am trying to build pages from blocks of text. Each block is in a text file. First I run each block of text through the script to find the depth, then I do some calculations with the depths to position the blocks to fill pages, and then I build a document. The command line option lets you do things similar to the Scribus Generator http://wiki.scribus.net/canvas/Scribus_Generator . The Scribus Generator is easier if you are doing text replacement (like making form letters). The command line is easier if you are performing actions that need to be scripted (like assembling a document or exporting a document to PDF). |
|
Thanks JLuc for the doc. the usage of the argument is different though: you've got to repeat "-pa" or "--python-arg" for each argument, such as in: scribus -py somescript.py --python-arg -v -pa -w 500 -pa -h 200 mydoc.sla Sorry if that was not clear before. I'll apply for a wiki access to updated this... and the Scribus Generator page too, to add about the new functions (advanced tweaks & merge all pages). |
|
It works fine when there is exactly 2 command line arguments after -pa but there 2 issues. 1) when -pa is used with 0 or 1 argument, an assert happens : ASSERT failure in QList<T>::operator[]: "index out of range", file /localbin/Qt5.5.0/5.5/gcc_64/include/QtCore/qlist.h, line 518 Plantage de Scribus ------------- Plantage de Scribus suite au signal 0000006 2) when -pa is used with 3 or more than 3 arguments, no assert but a scribus error message : it misses a filename on the command line ("Le fichier 3 n'existe pas, annulation. Usage: scribus [options] [files]...") scribus151svn -ns -g -py hello_or_not.py --python-arg --> assert scribus151svn -ns -g -py hello_or_not.py --python-arg first --> assert scribus151svn -ns -g -py hello_or_not.py --python-arg first hello --> OK ! scribus151svn -ns -g -py hello_or_not.py --python-arg first hello third --> scribus error etc These tests are made with the "conditional hello world" script on the wiki page : http://wiki.scribus.net/canvas/Command_line_scripts#Hello_world_script_with_arguments |
|
Beside : your script expects a filename to be opened to be able to work, but there is no command to open the document in the script : scribus opens it, not the script. How can scribus know where do the arguments for the script stop ? How can a script tell scribus "i've finished with my arguments and i dont need the following one which are filenames to open" ? I wonder all the more when there is no -- separator. |
|
Hi JLuc. the 1 assert you spotted should generate a nice error message. I'll correct it, thanks. the 2d assert you spotted should be valid, it's a bug, I'll correct it, thanks. the 4th test is the (expected) standard scribus error message, no change from the current behaviour, nothing to do with the script args parsing... but I agree with you that this message could use a better wording, and even more so in the french translation seemingly. On your last matter of the filename: it is indeed scribus that should open the sla if you provide it in this way, and that's the purpose (so you can use the same script via the command-line and via the script menu). If you want the script to get a document, you pass it using a "-pa"... but then don't expect scribus to open it! Scribus knows where the last argument for the script stops either because you provide a name *and value* for the last -pa... or by using an explicit "--" if you provide no value for your last -pa. This double dash is explained in http://unix.stackexchange.com/questions/11376/what-does-double-dash-mean-also-known-as-bare-double-dash and requested by aoloe in https://github.com/scribusproject/scribus/pull/19#issuecomment-128341739 . It basically marks the end of the options and the beginning of the positional arguments. so, all of the following are valid: scribus151svn -ns -g -py hello_or_not.py -pa first hello -pa --second hello2 file-to-open-in-scribus.sla scribus151svn -ns -g -py hello_or_not.py -pa first hello -pa --second -- file-to-open-in-scribus.sla scribus151svn -ns -g -py hello_or_not.py -pa first hello -pa --input file-the script-gets-not-opened-in-scribus.sla file-to-open-in-scribus.sla and even (if you make a script that works on all documents currently open in scribus): scribus151svn -ns -g -py hello_or_not.py -pa first hello -pa --second -- files-to-open-in-scribus/*.sla |
|
OK fine ! (i previously wrongly understood that the code for -- wasnt merged) I think i got the whole picture and will improve the wiki page accordingly. |
|
kindly re-open to fix bug detected by JLuc. correcting patch is at https://github.com/scribusproject/scribus/commit/e93952802113a2f86ddeb86e99e360a7a34b90cc.patch |
|
Applied with some changes: fyi "and" in an "if" condition is not accepted by all compilers. Probably a typedef specific to gcc. |
|
export_to_pdf.py (2,522 bytes)
#!/usr/bin/env python # -*- coding: utf-8 -*- """ Convert a document to a PDF Run with a command like scribus -g -py export_to_pdf.py -pa -version 13 -pa -bleedr 2 -pa -compress 1 -pa -info 'test title' -pa -file 'test.pdf' -- testdoc.sla You can set any "pdf" attribute with "-pa -attribute value". Tested with scribus 1.5.1 r20382 Author: William Bader, Director of Research and Development, SCS, http://www.newspapersystems.com 15Sep15 wb initial version """ # check that the script is running from inside scribus try: from scribus import * except ImportError: print 'This script only runs from within Scribus.' sys.exit(1) # get the os module try: import os except ImportError: print 'Could not import the os module.' sys.exit(1) def main(argv): pdf = scribus.PDFfile() pdf.pages=[1] pdf.version = 13 pdf.file = 'newfile.pdf' i = 1 while i < len(argv): if (len(argv[i]) > 0) and (argv[i][0] == '-'): name = argv[i][1:] try: pdf_attr = getattr(pdf, name) if i < len(argv): i = i + 1 value = argv[i] else: value = '' if callable(pdf_attr): print 'Error: "', name, '" is not a settable attribute.' else: if isinstance(pdf_attr, float): try: setattr(pdf, name, float(value)) except: print 'Error: Could not set "', name, '", "', value, '" is not a valid real number.' elif isinstance(pdf_attr, int): # Integers and booleans try: if value.lower() in [ 'true', 't', 'yes', 'y', 'si', 's' ]: setattr(pdf, name, 1) elif value.lower() in [ 'false', 'f', 'no', 'n' ]: setattr(pdf, name, 0) else: setattr(pdf, name, int(value)) except: print 'Error: Could not set "', name, '", "', value, '" is not a valid integer.' elif isinstance(pdf_attr, basestring): # Should this differentiate str and unicode, or will the assignment do the conversion? try: setattr(pdf, name, value) except: print 'Error: Could not set "', name, '", "', value, '" is not a valid string.' else: print 'Error: Could not set "', name, ', type "', type(pdf_attr), '" not supported.' print name, ' is ', str(getattr(pdf, name)), '.' except: print 'Error: Ignoring unrecognized pdf attribute "', name, '".' i = i + 1 pdf.save() # start the script if __name__ == '__main__': if haveDoc(): main(sys.argv) else: print 'Error: You need to have a document open before you can run this script successfully.' |
|
I attached an export_to_pdf.py script that I think is a good example of something useful. It exports a document to a PDF, and you can specify settings for "pdf" class attributes on the command line, for example, scribus -g -py export_to_pdf.py -pa -version 13 -pa -bleedr 2 -pa -compress 1 -pa -info 'test title' -pa -file 'test.pdf' -- testdoc.sla It uses getattr(), isinstance() and setattr() to access pdf class variables by their string name, so it does not need a hard-coded list of names. |
|
hi william i guess it was in the air :-) i created a very similar script yesterday evening: https://github.com/aoloe/scribus-script-sample/blob/master/to-pdf-with-placeholder/to-pdf-with-placeholder.py also, as written above, jluc is collecting samples and drafting a documentation in the wiki: http://wiki.scribus.net/canvas/Command_line_scripts |
|
Thanks Jean for the patch. Thanks William & Ale for the nice scripts. and most of all thanks JLuc for the extensive documentation! I added a few lines in the wiki to highlight (and get rid) of the "parasite" arguments Scribus introduces, so that getops or other argparse can be used: if __name__ == '__main__': if (sys.argv[1] == 'ext' or sys.argv[1] == 'sub'): #discard argv[1] if it is 'ext' or 'sub', that is added by Scribus when calling an external script del sys.argv[1] main(sys.argv) Would be useful if you handle them explicitely in your "example" scripts so that they don't come as a surprise to the next one. |
|
hi berteh, i'm no python expert, but from what i've seen, the standard way of getting rid of extra arguments in argv seems to be sys.argv[1:] (normally used for removing the scrip name). in our case we should probably pass sys.argv[2:] to main. on the other hand, i have opened a ticket (0013351) for getting rid of the extra argument before the new functionality starts to be used. if nobody knows what the sub/ext is good for, i really think that we should drop it. |
|
detect-missing-arg_bug-fix.patch (2,501 bytes)
From e93952802113a2f86ddeb86e99e360a7a34b90cc Mon Sep 17 00:00:00 2001 From: berteh <berteh@gmail.com> Date: Mon, 14 Sep 2015 10:35:18 +0200 Subject: [PATCH] detect missing argument --- scribus/scribusapp.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index 6a43590..a1f4c52 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -173,9 +173,15 @@ void ScribusQApp::parseCommandLine() arg = args[argi]; if (arg == ARG_SCRIPTARG || arg == ARG_SCRIPTARG_SHORT) { //needs to be first to give precedence to script argument name over scribus' options - pythonScriptArgs.append(args[++argi]); // arg name - if (!args[argi+1].startsWith("-")) { // arg value - pythonScriptArgs.append( QFile::decodeName(args[++argi].toLocal8Bit()) ); + if (++argi<argsc and (args[argi] != CMD_OPTIONS_END)) { + pythonScriptArgs.append(args[argi]); // script argument + } else { + std::cout << tr("Invalid argument use: '%1' requires to be followed by <argument> [value]").arg(arg).toLocal8Bit().data() << std::endl; + showUsage(); + std::exit(EXIT_FAILURE); + } + if (++argi<argsc and !args[argi].startsWith("-")) { // arg value + pythonScriptArgs.append( QFile::decodeName(args[argi].toLocal8Bit()) ); } } else if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++argi < argsc)) { @@ -505,7 +511,7 @@ void ScribusQApp::showUsage() printArgLine(ts, ARG_UPGRADECHECK_SHORT, ARG_UPGRADECHECK, tr("Download a file from the Scribus website and show the latest available version") ); printArgLine(ts, ARG_VERSION_SHORT, ARG_VERSION, tr("Output version information and exit") ); printArgLine(ts, ARG_PYTHONSCRIPT_SHORT, qPrintable(QString("%1 <%2>").arg(ARG_PYTHONSCRIPT).arg(tr("filename"))), tr("Run filename in Python scripter") ); - printArgLine(ts, ARG_SCRIPTARG_SHORT, qPrintable(QString("%1 <%2> [%3]").arg(ARG_SCRIPTARG).arg(tr("name")).arg(tr("value"))), tr("Argument passed on to python script, with an optional value, no effect without -py") ); + printArgLine(ts, ARG_SCRIPTARG_SHORT, qPrintable(QString("%1 <%2> [%3]").arg(ARG_SCRIPTARG).arg(tr("argument")).arg(tr("value"))), tr("Argument passed on to python script, with an optional value, no effect without -py") ); printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); ts << (QString(" %1").arg(CMD_OPTIONS_END,-39)) << tr("Explicit end of command line options"); endl(ts); |
|
uploaded patch to fix the bug detecte by JLuc (detect-missing-arg_bug-fix.patch), as it main not stay available on github. No need to do anything with it, as jghali kindly applied alreay. |
Date Modified | Username | Field | Change |
---|---|---|---|
2015-08-19 15:22 | berteh | New Issue | |
2015-08-19 15:22 | berteh | File Added: command-line-arguments-for-python-script.patch | |
2015-08-19 15:23 | berteh | File Added: cmdtest.py | |
2015-08-19 15:24 | berteh | Note Added: 0036069 | |
2015-08-19 20:58 | Kunda | Note Added: 0036070 | |
2015-08-20 03:29 | william | File Added: storydeptharg.py | |
2015-08-20 03:41 | william | Note Added: 0036071 | |
2015-08-20 05:34 | william | Note Added: 0036072 | |
2015-08-20 09:40 | berteh | Note Added: 0036073 | |
2015-08-20 16:26 | william | Note Added: 0036074 | |
2015-08-21 10:56 | berteh | Note Added: 0036075 | |
2015-08-21 18:11 | Kunda | Note Added: 0036076 | |
2015-08-25 01:18 | Kunda | Summary | add support for command line arguments to be passed on to python script (-py option) => [PATCH] support for command line arguments to be passed on to python script (-py option) |
2015-08-27 22:44 | Kunda | Note Added: 0036107 | |
2015-08-29 13:43 | Kunda | Note Added: 0036117 | |
2015-08-31 00:32 | Kunda | Relationship added | related to 0000238 |
2015-09-01 12:33 | Kunda | Sticky Issue | No => Yes |
2015-09-02 07:24 | berteh | Note Added: 0036132 | |
2015-09-02 07:47 | JLuc | Note Added: 0036134 | |
2015-09-02 09:19 | berteh | Note Added: 0036135 | |
2015-09-03 19:24 | cbradney | Note Added: 0036140 | |
2015-09-03 20:27 | berteh | Note Added: 0036143 | |
2015-09-03 20:28 | berteh | File Added: cmdline_--python-arg_name_value.patch | |
2015-09-03 20:28 | berteh | Note Edited: 0036143 | |
2015-09-03 20:36 | berteh | File Deleted: cmdline_--python-arg_name_value.patch | |
2015-09-03 20:36 | berteh | File Added: cmdline_--python-arg_name_value.patch | |
2015-09-03 20:39 | berteh | Note Added: 0036144 | |
2015-09-03 20:40 | berteh | Note Edited: 0036143 | |
2015-09-03 20:40 | cbradney | Note Added: 0036145 | |
2015-09-03 21:24 | william | Note Added: 0036148 | |
2015-09-04 06:09 | berteh | Note Added: 0036149 | |
2015-09-04 06:09 | berteh | File Added: cmdline_--python-arg_name_value__clean.patch | |
2015-09-04 06:12 | berteh | Note Edited: 0036149 | |
2015-09-04 06:12 | berteh | Note Edited: 0036149 | |
2015-09-04 06:15 | berteh | Note Edited: 0036149 | |
2015-09-04 06:24 | berteh | Note Added: 0036150 | |
2015-09-04 10:20 | JLuc | Steps to Reproduce Updated | |
2015-09-04 10:23 | JLuc | Note Added: 0036151 | |
2015-09-04 10:23 | JLuc | Note Edited: 0036151 | |
2015-09-07 14:10 | ale | Note Added: 0036161 | |
2015-09-07 19:49 | cbradney | Note Added: 0036165 | |
2015-09-10 19:09 | berteh | File Added: cmdline --python-arg name value__compatible-header-arguments.patch | |
2015-09-10 19:15 | berteh | Note Added: 0036184 | |
2015-09-10 20:08 | cbradney | Note Added: 0036185 | |
2015-09-10 20:08 | cbradney | Status | new => resolved |
2015-09-10 20:08 | cbradney | Fixed in Version | => 1.5.1svn |
2015-09-10 20:08 | cbradney | Resolution | open => fixed |
2015-09-10 20:08 | cbradney | Assigned To | => cbradney |
2015-09-11 11:42 | Kunda | Sticky Issue | Yes => No |
2015-09-13 08:00 | JLuc | Note Added: 0036203 | |
2015-09-13 08:00 | JLuc | Note Edited: 0036203 | |
2015-09-13 08:01 | JLuc | Note Added: 0036204 | |
2015-09-13 08:16 | JLuc | Note Added: 0036205 | |
2015-09-13 13:05 | Kunda | Note Added: 0036206 | |
2015-09-13 15:10 | william | Note Added: 0036207 | |
2015-09-13 19:37 | berteh | Note Added: 0036208 | |
2015-09-13 20:00 | JLuc | Note Added: 0036209 | |
2015-09-13 20:35 | JLuc | Note Added: 0036210 | |
2015-09-13 20:35 | JLuc | Note Edited: 0036210 | |
2015-09-13 20:36 | JLuc | Note Edited: 0036210 | |
2015-09-13 20:56 | berteh | Note Added: 0036211 | |
2015-09-13 21:34 | JLuc | Note Added: 0036212 | |
2015-09-14 08:39 | berteh | Note Added: 0036213 | |
2015-09-14 08:39 | berteh | Status | resolved => feedback |
2015-09-14 08:39 | berteh | Resolution | fixed => reopened |
2015-09-14 14:57 | jghali | Note Added: 0036217 | |
2015-09-14 14:57 | jghali | Status | feedback => resolved |
2015-09-14 14:57 | jghali | Resolution | reopened => fixed |
2015-09-15 01:21 | william | File Added: export_to_pdf.py | |
2015-09-15 01:35 | william | Note Added: 0036239 | |
2015-09-15 06:15 | ale | Note Added: 0036240 | |
2015-09-15 06:53 | berteh | Note Added: 0036241 | |
2015-09-15 07:08 | ale | Note Added: 0036242 | |
2015-09-17 07:42 | berteh | File Added: detect-missing-arg_bug-fix.patch | |
2015-09-17 07:44 | berteh | Note Added: 0036252 | |
2015-09-17 18:50 | cbradney | Relationship added | has duplicate 0008968 |
2015-10-03 20:18 | cbradney | Status | resolved => closed |
2015-11-22 13:52 | jghali | Summary | [PATCH] support for command line arguments to be passed on to python script (-py option) => support for command line arguments to be passed on to python script (-py option) |