Skip to content

Commit

Permalink
[GRASS] better module lookup
Browse files Browse the repository at this point in the history
  • Loading branch information
blazek committed Feb 9, 2016
1 parent 65afdcf commit 58beed2
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 116 deletions.
88 changes: 1 addition & 87 deletions src/plugins/grass/qgsgrassmodule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,98 +41,12 @@ extern "C"
#include <grass/glocale.h>
}

//#include <gdal.h> // to collect version information

//bool QgsGrassModule::mExecPathInited = 0;
//QStringList QgsGrassModule::mExecPath;

QString QgsGrassModule::findExec( QString file )
{
QgsDebugMsg( "called." );

// Init mExecPath
// Windows searches first in current directory
// TODO verify if/why applicationDirPath() is necessary
#if 0
if ( !mExecPathInited )
{
QString path = getenv( "PATH" );
QgsDebugMsg( "path = " + path );


#ifdef Q_OS_WIN
mExecPath = path.split( ";" );
mExecPath.prepend( QgsGrass::shortPath( QgsApplication::applicationDirPath() ) );
#elif defined(Q_OS_MACX)
mExecPath = path.split( ":" );
mExecPath.prepend( QgsApplication::applicationDirPath() + "/bin" );
mExecPath.prepend( QgsApplication::applicationDirPath() + "/grass/bin" );
#else
mExecPath = path.split( ":" );
mExecPath.prepend( QgsApplication::applicationDirPath() );
#endif
mExecPathInited = true;
}
#endif

if ( QFile::exists( file ) )
{
return file; // full path
}

#ifdef Q_OS_WIN
// On windows try .bat first
Q_FOREACH ( const QString& path, QgsGrass::grassModulesPaths() )
{
QString full = path + "/" + file + ".bat";
if ( QFile::exists( full ) )
{
return full;
}
}

// .exe next
Q_FOREACH ( const QString& path, QgsGrass::grassModulesPaths() )
{
QString full = path + "/" + file + ".exe";
if ( QFile::exists( full ) )
{
return full;
}
}

// and then try if it's a script (w/o extension)
#endif

// Search for module
Q_FOREACH ( const QString& path, QgsGrass::grassModulesPaths() )
{
QString full = path + "/" + file;
if ( QFile::exists( full ) )
{
QgsDebugMsg( "found " + full );
return full;
}
else
{
QgsDebugMsg( "not found " + full );
}
}

return QString();
}

bool QgsGrassModule::inExecPath( QString file )
{
return !findExec( file ).isNull();
}

QStringList QgsGrassModule::execArguments( QString module )
{
QString exe;
QStringList arguments;

exe = QgsGrassModule::findExec( module );
exe = QgsGrass::findModule( module );
if ( exe.isNull() )
{
return arguments;
Expand Down
12 changes: 0 additions & 12 deletions src/plugins/grass/qgsgrassmodule.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,6 @@ class QgsGrassModule : public QWidget, private Ui::QgsGrassModuleBase
// ! Options widget
QgsGrassModuleOptions *options() { return mOptions; }

// ! List of directories in PATH variable + current directory on Windows
//static QStringList mExecPath;
//static bool mExecPathInited;

// ! Find in exec path
// returns full path or null string
// appends automaticaly .exe on Windows
static QString findExec( QString file );

// ! Check if file is in mExecPath
static bool inExecPath( QString file );

// ! Get executable + arguments. Executable is returned as first string.
// On Window if the module is script the executable will be path to shell
// Returns empty list if not found.
Expand Down
81 changes: 64 additions & 17 deletions src/providers/grass/qgsgrass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ bool QgsGrass::init( void )
mGrassModulesPaths << gisbase() + "/bin";
mGrassModulesPaths << gisbase() + "/scripts";
mGrassModulesPaths << QgsApplication::pkgDataPath() + "/grass/scripts";
mGrassModulesPaths << qgisGrassModulePath();

// On windows the GRASS libraries are in
// QgsApplication::prefixPath(), we have to add them
Expand Down Expand Up @@ -1543,9 +1544,7 @@ QStringList QgsGrass::grassObjects( const QgsGrassObject& mapsetObject, QgsGrass
{
#if GRASS_VERSION_MAJOR >= 7
QString cmd = gisbase() + "/scripts/t.list";
#ifdef Q_OS_WIN
cmd += ".py";
#endif

QStringList arguments;

// Running t.list module is quite slow (about 500ms) -> check first if temporal db exists.
Expand All @@ -1560,19 +1559,27 @@ QStringList QgsGrass::grassObjects( const QgsGrassObject& mapsetObject, QgsGrass
arguments << "type=" + QgsGrassObject::elementShort( type );

int timeout = -1; // What timeout to use? It can take long time on network or database
QByteArray data = runModule( mapsetObject.gisdbase(), mapsetObject.location(), mapsetObject.mapset(), cmd, arguments, timeout, false );
Q_FOREACH ( QString fullName, QString::fromLocal8Bit( data ).split( '\n' ) )
try
{
fullName = fullName.trimmed();
if ( !fullName.isEmpty() )
QByteArray data = runModule( mapsetObject.gisdbase(), mapsetObject.location(), mapsetObject.mapset(), cmd, arguments, timeout, false );
Q_FOREACH ( QString fullName, QString::fromLocal8Bit( data ).split( '\n' ) )
{
QStringList nameMapset = fullName.split( "@" );
if ( nameMapset.value( 1 ) == mapsetObject.mapset() || nameMapset.value( 1 ).isEmpty() )
fullName = fullName.trimmed();
if ( !fullName.isEmpty() )
{
list << nameMapset.value( 0 );
QStringList nameMapset = fullName.split( "@" );
if ( nameMapset.value( 1 ) == mapsetObject.mapset() || nameMapset.value( 1 ).isEmpty() )
{
list << nameMapset.value( 0 );
}
}
}
}
catch ( QgsGrass::Exception &e )
{
// TODO: notify somehow user
QgsDebugMsg( QString( "Cannot run %1: %2" ).arg( cmd ).arg( e.what() ) );
}
}
#endif
}
Expand Down Expand Up @@ -1958,6 +1965,47 @@ bool QgsGrass::mapRegion( QgsGrassObject::Type type, QString gisdbase,
return true;
}

QString QgsGrass::findModule( QString module )
{
QgsDebugMsg( "called." );
if ( QFile::exists( module ) )
{
return module; // full path
}

QStringList extensions;
#ifdef Q_OS_WIN
// On windows try .bat first
extensions << ".bat" << ".py" << ".exe";
#endif
// and then try if it's a module without extension (standard on UNIX)
extensions << "";

QStringList paths;
// Try first full path
paths << "";
paths << QgsGrass::grassModulesPaths();

// Extensions first to prefer .bat over .exe on Windows
Q_FOREACH ( const QString& ext, extensions )
{
Q_FOREACH ( const QString& path, paths )
{
QString full = path + "/" + module + ext;
if ( QFile::exists( full ) )
{
QgsDebugMsg( "found " + full );
return full;
}
else
{
QgsDebugMsg( "not found " + full );
}
}
}
return QString();
}

QProcess *QgsGrass::startModule( const QString& gisdbase, const QString& location,
const QString& mapset, const QString& moduleName, const QStringList& arguments,
QTemporaryFile &gisrcFile, bool qgisModule )
Expand All @@ -1970,12 +2018,12 @@ QProcess *QgsGrass::startModule( const QString& gisdbase, const QString& locati
{
module += QString::number( QgsGrass::versionMajor() );
}
#ifdef Q_OS_WIN
if ( !module.endsWith( ".exe", Qt::CaseInsensitive ) && !module.endsWith( ".py", Qt::CaseInsensitive ) )

QString modulePath = findModule( module );
if ( modulePath.isEmpty() )
{
module += ".exe";
throw QgsGrass::Exception( QObject::tr( "Cannot find module %1" ).arg( module ) );
}
#endif

// We have to set GISRC file, uff
if ( !gisrcFile.open() )
Expand Down Expand Up @@ -2008,9 +2056,8 @@ QProcess *QgsGrass::startModule( const QString& gisdbase, const QString& locati

process->setEnvironment( environment );

QgsDebugMsg( module + " " + arguments.join( " " ) );
//process->start( module, arguments, QProcess::Unbuffered );
process->start( module, arguments );
QgsDebugMsg( modulePath + " " + arguments.join( " " ) );
process->start( modulePath, arguments );
if ( !process->waitForStarted() )
{
throw QgsGrass::Exception( error );
Expand Down
6 changes: 6 additions & 0 deletions src/providers/grass/qgsgrass.h
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,12 @@ class GRASS_LIB_EXPORT QgsGrass : public QObject
// ! Get current gisrc path
static QString gisrcFilePath();

/** Find a module trying to append .bat, .py and .exe on Windows. The module may be a full path
* without extension or just a module name in which case it is searched in grassModulesPaths().
* @param module module name or path to module without extension
* @return full path including extension or empty string */
static QString findModule( QString module );

/** Start a GRASS module in any gisdbase/location/mapset.
* @param mapset if empty a first mapset owned by user will be used, if no mapset is owned
* by user, exception is thrown.
Expand Down

0 comments on commit 58beed2

Please sign in to comment.