uic: Add option for absolute Python resource imports
Add option that generates an absolute Python import. import resources.rc_resources from a path like ../resources/resources.qrc assuming the project root is .. . Add an additional option to specify the import paths, from which the project root can be determined. Task-number: PYSIDE-2191 Change-Id: Ib444eb666217b8c010dba0079b0ffe9ddbaa3414 Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io> Reviewed-by: Shyamnath Premnadh <Shyamnath.Premnadh@qt.io> (cherry picked from commit 814d66d55860a1eb204b804871d579da95eabd8f) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
23c49af8a3
commit
113f91229a
@ -13,11 +13,42 @@
|
|||||||
#include <qcoreapplication.h>
|
#include <qcoreapplication.h>
|
||||||
#include <qcommandlineoption.h>
|
#include <qcommandlineoption.h>
|
||||||
#include <qcommandlineparser.h>
|
#include <qcommandlineparser.h>
|
||||||
|
#include <qfileinfo.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
using namespace Qt::StringLiterals;
|
using namespace Qt::StringLiterals;
|
||||||
|
|
||||||
|
static const char pythonPathVar[] = "PYTHONPATH";
|
||||||
|
|
||||||
|
// From the Python paths, find the component the UI file is under
|
||||||
|
static QString pythonRoot(const QString &pythonPath, const QString &uiFileIn)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
static const Qt::CaseSensitivity fsSensitivity = Qt::CaseInsensitive;
|
||||||
|
#else
|
||||||
|
static const Qt::CaseSensitivity fsSensitivity = Qt::CaseSensitive;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (pythonPath.isEmpty() || uiFileIn.isEmpty())
|
||||||
|
return {};
|
||||||
|
const QString uiFile = QFileInfo(uiFileIn).canonicalFilePath();
|
||||||
|
if (uiFile.isEmpty())
|
||||||
|
return {};
|
||||||
|
const auto uiFileSize = uiFile.size();
|
||||||
|
const auto paths = pythonPath.split(QDir::listSeparator(), Qt::SkipEmptyParts);
|
||||||
|
for (const auto &path : paths) {
|
||||||
|
const QString canonicalPath = QFileInfo(path).canonicalFilePath();
|
||||||
|
const auto canonicalPathSize = canonicalPath.size();
|
||||||
|
if (uiFileSize > canonicalPathSize
|
||||||
|
&& uiFile.at(canonicalPathSize) == u'/'
|
||||||
|
&& uiFile.startsWith(canonicalPath, fsSensitivity)) {
|
||||||
|
return canonicalPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
int runUic(int argc, char *argv[])
|
int runUic(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
QHashSeed::setDeterministicGlobalSeed();
|
QHashSeed::setDeterministicGlobalSeed();
|
||||||
@ -90,6 +121,10 @@ int runUic(int argc, char *argv[])
|
|||||||
fromImportsOption.setDescription(u"Python: generate imports relative to '.'"_s);
|
fromImportsOption.setDescription(u"Python: generate imports relative to '.'"_s);
|
||||||
parser.addOption(fromImportsOption);
|
parser.addOption(fromImportsOption);
|
||||||
|
|
||||||
|
QCommandLineOption absoluteImportsOption(u"absolute-imports"_s);
|
||||||
|
absoluteImportsOption.setDescription(u"Python: generate absolute imports"_s);
|
||||||
|
parser.addOption(absoluteImportsOption);
|
||||||
|
|
||||||
// FIXME Qt 7: Flip the default?
|
// FIXME Qt 7: Flip the default?
|
||||||
QCommandLineOption rcPrefixOption(u"rc-prefix"_s);
|
QCommandLineOption rcPrefixOption(u"rc-prefix"_s);
|
||||||
rcPrefixOption.setDescription(uR"(Python: Generate "rc_file" instead of "file_rc" import)"_s);
|
rcPrefixOption.setDescription(uR"(Python: Generate "rc_file" instead of "file_rc" import)"_s);
|
||||||
@ -100,6 +135,11 @@ int runUic(int argc, char *argv[])
|
|||||||
useStarImportsOption.setDescription(u"Python: Use * imports"_s);
|
useStarImportsOption.setDescription(u"Python: Use * imports"_s);
|
||||||
parser.addOption(useStarImportsOption);
|
parser.addOption(useStarImportsOption);
|
||||||
|
|
||||||
|
QCommandLineOption pythonPathOption(u"python-paths"_s);
|
||||||
|
pythonPathOption.setDescription(u"Python paths for --absolute-imports."_s);
|
||||||
|
pythonPathOption.setValueName(u"pathlist"_s);
|
||||||
|
parser.addOption(pythonPathOption);
|
||||||
|
|
||||||
parser.addPositionalArgument(u"[uifile]"_s, u"Input file (*.ui), otherwise stdin."_s);
|
parser.addPositionalArgument(u"[uifile]"_s, u"Input file (*.ui), otherwise stdin."_s);
|
||||||
|
|
||||||
parser.process(app);
|
parser.process(app);
|
||||||
@ -130,10 +170,19 @@ int runUic(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
language::setLanguage(language);
|
language::setLanguage(language);
|
||||||
if (language == Language::Python) {
|
if (language == Language::Python) {
|
||||||
driver.option().fromImports = parser.isSet(fromImportsOption);
|
if (parser.isSet(fromImportsOption))
|
||||||
|
driver.option().pythonResourceImport = Option::PythonResourceImport::FromDot;
|
||||||
|
else if (parser.isSet(absoluteImportsOption))
|
||||||
|
driver.option().pythonResourceImport = Option::PythonResourceImport::Absolute;
|
||||||
driver.option().useStarImports = parser.isSet(useStarImportsOption);
|
driver.option().useStarImports = parser.isSet(useStarImportsOption);
|
||||||
if (parser.isSet(rcPrefixOption))
|
if (parser.isSet(rcPrefixOption))
|
||||||
driver.option().rcPrefix = 1;
|
driver.option().rcPrefix = 1;
|
||||||
|
QString pythonPaths;
|
||||||
|
if (parser.isSet(pythonPathOption))
|
||||||
|
pythonPaths = parser.value(pythonPathOption);
|
||||||
|
else if (qEnvironmentVariableIsSet(pythonPathVar))
|
||||||
|
pythonPaths = QString::fromUtf8(qgetenv(pythonPathVar));
|
||||||
|
driver.option().pythonRoot = pythonRoot(pythonPaths, inputFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inputFile.isEmpty()) // reading from stdin
|
if (inputFile.isEmpty()) // reading from stdin
|
||||||
|
@ -11,6 +11,12 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
struct Option
|
struct Option
|
||||||
{
|
{
|
||||||
|
enum class PythonResourceImport {
|
||||||
|
Default, // "import rc_file"
|
||||||
|
FromDot, // "from . import rc_file"
|
||||||
|
Absolute // "import path.rc_file"
|
||||||
|
};
|
||||||
|
|
||||||
unsigned int headerProtection : 1;
|
unsigned int headerProtection : 1;
|
||||||
unsigned int copyrightHeader : 1;
|
unsigned int copyrightHeader : 1;
|
||||||
unsigned int generateImplemetation : 1;
|
unsigned int generateImplemetation : 1;
|
||||||
@ -20,7 +26,6 @@ struct Option
|
|||||||
unsigned int limitXPM_LineLength : 1;
|
unsigned int limitXPM_LineLength : 1;
|
||||||
unsigned int implicitIncludes: 1;
|
unsigned int implicitIncludes: 1;
|
||||||
unsigned int idBased: 1;
|
unsigned int idBased: 1;
|
||||||
unsigned int fromImports: 1;
|
|
||||||
unsigned int forceMemberFnPtrConnectionSyntax: 1;
|
unsigned int forceMemberFnPtrConnectionSyntax: 1;
|
||||||
unsigned int forceStringConnectionSyntax: 1;
|
unsigned int forceStringConnectionSyntax: 1;
|
||||||
unsigned int useStarImports: 1;
|
unsigned int useStarImports: 1;
|
||||||
@ -34,6 +39,9 @@ struct Option
|
|||||||
QString postfix;
|
QString postfix;
|
||||||
QString translateFunction;
|
QString translateFunction;
|
||||||
QString includeFile;
|
QString includeFile;
|
||||||
|
QString pythonRoot;
|
||||||
|
|
||||||
|
PythonResourceImport pythonResourceImport = PythonResourceImport::Default;
|
||||||
|
|
||||||
Option()
|
Option()
|
||||||
: headerProtection(1),
|
: headerProtection(1),
|
||||||
@ -45,7 +53,6 @@ struct Option
|
|||||||
limitXPM_LineLength(0),
|
limitXPM_LineLength(0),
|
||||||
implicitIncludes(1),
|
implicitIncludes(1),
|
||||||
idBased(0),
|
idBased(0),
|
||||||
fromImports(0),
|
|
||||||
forceMemberFnPtrConnectionSyntax(0),
|
forceMemberFnPtrConnectionSyntax(0),
|
||||||
forceStringConnectionSyntax(0),
|
forceStringConnectionSyntax(0),
|
||||||
useStarImports(0),
|
useStarImports(0),
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#include <ui4.h>
|
#include <ui4.h>
|
||||||
|
|
||||||
|
#include <QtCore/qdir.h>
|
||||||
|
#include <QtCore/qfileinfo.h>
|
||||||
#include <QtCore/qtextstream.h>
|
#include <QtCore/qtextstream.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -54,23 +56,6 @@ static WriteImports::ClassesPerModule defaultClasses()
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change the name of a qrc file "dir/foo.qrc" file to the Python
|
|
||||||
// module name "foo_rc" according to project conventions.
|
|
||||||
static QString pythonResource(QString resource, bool prefix)
|
|
||||||
{
|
|
||||||
const qsizetype lastSlash = resource.lastIndexOf(u'/');
|
|
||||||
if (lastSlash != -1)
|
|
||||||
resource.remove(0, lastSlash + 1);
|
|
||||||
if (resource.endsWith(".qrc"_L1)) {
|
|
||||||
resource.chop(4);
|
|
||||||
if (prefix)
|
|
||||||
resource.prepend("rc_"_L1);
|
|
||||||
else
|
|
||||||
resource.append("_rc"_L1);
|
|
||||||
}
|
|
||||||
return resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helpers for WriteImports::ClassesPerModule maps
|
// Helpers for WriteImports::ClassesPerModule maps
|
||||||
static void insertClass(const QString &module, const QString &className,
|
static void insertClass(const QString &module, const QString &className,
|
||||||
WriteImports::ClassesPerModule *c)
|
WriteImports::ClassesPerModule *c)
|
||||||
@ -143,18 +128,57 @@ void WriteImports::acceptUI(DomUI *node)
|
|||||||
const auto includes = resources->elementInclude();
|
const auto includes = resources->elementInclude();
|
||||||
for (auto include : includes) {
|
for (auto include : includes) {
|
||||||
if (include->hasAttributeLocation())
|
if (include->hasAttributeLocation())
|
||||||
writeImport(pythonResource(include->attributeLocation(),
|
writeResourceImport(include->attributeLocation());
|
||||||
uic()->option().rcPrefix));
|
|
||||||
}
|
}
|
||||||
output << '\n';
|
output << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteImports::writeImport(const QString &module)
|
QString WriteImports::resourceAbsolutePath(QString resource) const
|
||||||
{
|
{
|
||||||
if (uic()->option().fromImports)
|
// If we know the project root, generate an absolute Python import
|
||||||
uic()->output() << "from . ";
|
// to the resource. options. pythonRoot is the Python path component
|
||||||
uic()->output() << "import " << module << '\n';
|
// under which the UI file is.
|
||||||
|
const auto &options = uic()->option();
|
||||||
|
if (!options.inputFile.isEmpty() && !options.pythonRoot.isEmpty()) {
|
||||||
|
resource = QDir::cleanPath(QFileInfo(options.inputFile).canonicalPath() + u'/' + resource);
|
||||||
|
if (resource.size() > options.pythonRoot.size())
|
||||||
|
resource.remove(0, options.pythonRoot.size() + 1);
|
||||||
|
}
|
||||||
|
// If nothing is known, we assume the directory pointed by "../" is the root
|
||||||
|
while (resource.startsWith(u"../"))
|
||||||
|
resource.remove(0, 3);
|
||||||
|
resource.replace(u'/', u'.');
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteImports::writeResourceImport(const QString &module)
|
||||||
|
{
|
||||||
|
const auto &options = uic()->option();
|
||||||
|
auto &str = uic()->output();
|
||||||
|
|
||||||
|
QString resource = QDir::cleanPath(module);
|
||||||
|
if (resource.endsWith(u".qrc"))
|
||||||
|
resource.chop(4);
|
||||||
|
const qsizetype basePos = resource.lastIndexOf(u'/') + 1;
|
||||||
|
// Change the name of a qrc file "dir/foo.qrc" file to the Python
|
||||||
|
// module name "foo_rc" according to project conventions.
|
||||||
|
if (options.rcPrefix)
|
||||||
|
resource.insert(basePos, u"rc_");
|
||||||
|
else
|
||||||
|
resource.append(u"_rc");
|
||||||
|
|
||||||
|
switch (options.pythonResourceImport) {
|
||||||
|
case Option::PythonResourceImport::Default:
|
||||||
|
str << "import " << QStringView{resource}.sliced(basePos) << '\n';
|
||||||
|
break;
|
||||||
|
case Option::PythonResourceImport::FromDot:
|
||||||
|
str << "from . import " << QStringView{resource}.sliced(basePos) << '\n';
|
||||||
|
break;
|
||||||
|
case Option::PythonResourceImport::Absolute:
|
||||||
|
str << "import " << resourceAbsolutePath(resource) << '\n';
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteImports::doAdd(const QString &className, const DomCustomWidget *dcw)
|
void WriteImports::doAdd(const QString &className, const DomCustomWidget *dcw)
|
||||||
|
@ -31,7 +31,8 @@ private:
|
|||||||
void addPythonCustomWidget(const QString &className, const DomCustomWidget *dcw);
|
void addPythonCustomWidget(const QString &className, const DomCustomWidget *dcw);
|
||||||
bool addQtClass(const QString &className);
|
bool addQtClass(const QString &className);
|
||||||
void addEnumBaseClass(const QString &v);
|
void addEnumBaseClass(const QString &v);
|
||||||
void writeImport(const QString &module);
|
void writeResourceImport(const QString &module);
|
||||||
|
QString resourceAbsolutePath(QString resource) const;
|
||||||
|
|
||||||
QHash<QString, QString> m_classToModule;
|
QHash<QString, QString> m_classToModule;
|
||||||
// Module->class (modules sorted)
|
// Module->class (modules sorted)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user