Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for command line arguments to be passed on to python script (-py option) #19

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 25 additions & 7 deletions scribus/plugins/scriptplugin/scriptercore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -227,6 +228,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())
Expand All @@ -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)
Expand Down Expand Up @@ -357,7 +375,7 @@ void ScripterCore::slotRunPythonScript()
{
if (!ScQApp->pythonScript.isNull())
{
slotRunScriptFile(ScQApp->pythonScript, true);
slotRunScriptFile(ScQApp->pythonScript, ScQApp->pythonScriptArgs, true);
FinishScriptRun();
}
}
Expand Down
3 changes: 2 additions & 1 deletion scribus/plugins/scriptplugin/scriptercore.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
180 changes: 104 additions & 76 deletions scribus/scribusapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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"
Expand All @@ -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"
Expand All @@ -108,6 +112,7 @@ ScribusQApp::ScribusQApp( int & argc, char ** argv ) : QApplication(argc, argv),
m_scDLMgr = 0;
m_ScCore = NULL;
initDLMgr();

}

ScribusQApp::~ScribusQApp()
Expand Down Expand Up @@ -151,18 +156,36 @@ 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
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)) {
lang = args[argi];
}
else if (arg == ARG_VERSION || arg == ARG_VERSION_SHORT) {
header=true;
Expand All @@ -175,8 +198,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
Expand All @@ -187,104 +210,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()
Expand Down Expand Up @@ -485,7 +498,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") );
Expand All @@ -498,7 +511,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("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);


#if defined(_WIN32) && !defined(_CONSOLE)
printArgLine(ts, ARG_CONSOLE_SHORT, ARG_CONSOLE, tr("Display a console window") );
Expand Down Expand Up @@ -558,6 +574,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();
Expand Down
3 changes: 3 additions & 0 deletions scribus/scribusapp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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
Expand Down