/**************************************************************************** ** ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "pkgconfigjs.h" #include #include #include #include namespace qbs { namespace Internal { namespace { template QVariantList convert(const C &c, F &&f) { QVariantList result; result.reserve(int(c.size())); std::transform(c.begin(), c.end(), std::back_inserter(result), f); return result; } QVariantMap variablesMapToMap(const PcPackage::VariablesMap &variables) { QVariantMap result; for (const auto &item: variables) result.insert(QString::fromStdString(item.first), QString::fromStdString(item.second)); return result; } QVariantMap packageToMap(const PcPackage &package) { QVariantMap result; result[QStringLiteral("isBroken")] = false; result[QStringLiteral("filePath")] = QString::fromStdString(package.filePath); result[QStringLiteral("baseFileName")] = QString::fromStdString(package.baseFileName); result[QStringLiteral("name")] = QString::fromStdString(package.name); result[QStringLiteral("version")] = QString::fromStdString(package.version); result[QStringLiteral("description")] = QString::fromStdString(package.description); result[QStringLiteral("url")] = QString::fromStdString(package.url); const auto flagToMap = [](const PcPackage::Flag &flag) { QVariantMap result; const auto value = QString::fromStdString(flag.value); result[QStringLiteral("type")] = QVariant::fromValue(qint32(flag.type)); result[QStringLiteral("value")] = value; return result; }; const auto requiredVersionToMap = [](const PcPackage::RequiredVersion &version) { using Type = PcPackage::RequiredVersion::ComparisonType; QVariantMap result; result[QStringLiteral("name")] = QString::fromStdString(version.name); const auto versionString = QString::fromStdString(version.version); const auto qbsVersion = Version::fromString(QString::fromStdString(version.version)); const auto nextQbsVersion = Version( qbsVersion.majorVersion(), qbsVersion.minorVersion(), qbsVersion.patchLevel() + 1); switch (version.comparison) { case Type::LessThan: result[QStringLiteral("versionBelow")] = versionString; break; case Type::GreaterThan: result[QStringLiteral("versionAtLeast")] = nextQbsVersion.toString(); break; case Type::LessThanEqual: result[QStringLiteral("versionBelow")] = nextQbsVersion.toString(); break; case Type::GreaterThanEqual: result[QStringLiteral("versionAtLeast")] = versionString; break; case Type::Equal: result[QStringLiteral("version")] = versionString; break; case Type::NotEqual: result[QStringLiteral("versionBelow")] = versionString; result[QStringLiteral("versionAtLeast")] = nextQbsVersion.toString(); break; case Type::AlwaysMatch: break; } return result; }; result[QStringLiteral("libs")] = convert(package.libs, flagToMap); result[QStringLiteral("libsPrivate")] = convert(package.libsPrivate, flagToMap); result[QStringLiteral("cflags")] = convert(package.cflags, flagToMap); result[QStringLiteral("requires")] = convert(package.requiresPublic, requiredVersionToMap); result[QStringLiteral("requiresPrivate")] = convert(package.requiresPrivate, requiredVersionToMap); result[QStringLiteral("conflicts")] = convert(package.conflicts, requiredVersionToMap); result[QStringLiteral("variables")] = variablesMapToMap(package.variables); return result; }; QVariantMap brokenPackageToMap(const PcBrokenPackage &package) { QVariantMap result; result[QStringLiteral("isBroken")] = true; result[QStringLiteral("filePath")] = QString::fromStdString(package.filePath); result[QStringLiteral("baseFileName")] = QString::fromStdString(package.baseFileName); result[QStringLiteral("errorText")] = QString::fromStdString(package.errorText); return result; } QVariantMap packageVariantToMap(const PcPackageVariant &package) { return package.visit([](const auto &value) { using T = std::decay_t; if constexpr (std::is_same_v) return packageToMap(value); else return brokenPackageToMap(value); }); } PcPackage::VariablesMap envToVariablesMap(const QProcessEnvironment &env) { PcPackage::VariablesMap result; const auto keys = env.keys(); for (const auto &key : keys) result[key.toStdString()] = env.value(key).toStdString(); return result; } PcPackage::VariablesMap variablesFromQVariantMap(const QVariantMap &map) { PcPackage::VariablesMap result; for (auto it = map.cbegin(), end = map.cend(); it != end; ++it) result[it.key().toStdString()] = it.value().toString().toStdString(); return result; } std::vector stringListToStdVector(const QStringList &list) { return transformed>(list, [](const auto &s) { return s.toStdString(); }); } } // namespace void PkgConfigJs::declareEnums(JSContext *ctx, JSValue classObj) { DECLARE_ENUM(ctx, classObj, LibraryName); DECLARE_ENUM(ctx, classObj, LibraryPath); DECLARE_ENUM(ctx, classObj, StaticLibraryName); DECLARE_ENUM(ctx, classObj, Framework); DECLARE_ENUM(ctx, classObj, FrameworkPath); DECLARE_ENUM(ctx, classObj, LinkerFlag); DECLARE_ENUM(ctx, classObj, IncludePath); DECLARE_ENUM(ctx, classObj, SystemIncludePath); DECLARE_ENUM(ctx, classObj, Define); DECLARE_ENUM(ctx, classObj, CompilerFlag); } JSValue PkgConfigJs::ctor(JSContext *ctx, JSValue, JSValue, int argc, JSValue *argv, int) { try { QVariantMap options; if (argc > 0) options = fromArg(ctx, "PkgConfig constructor", 1, argv[0]).toMap(); JSValue obj = createObject(ctx, options); return obj; } catch (const PcException &e) { return throwError(ctx, QString::fromUtf8(e.what())); } catch (const QString &error) { return throwError(ctx, error); } } PkgConfigJs::PkgConfigJs(JSContext *ctx, const QVariantMap &options) : m_pkgConfig(std::make_unique( convertOptions(ScriptEngine::engineForContext(ctx)->environment(), options))) { for (const auto &package : m_pkgConfig->packages()) { m_packages.insert( QString::fromStdString(package.getBaseFileName()), packageVariantToMap(package)); } } PkgConfig::Options PkgConfigJs::convertOptions(const QProcessEnvironment &env, const QVariantMap &map) { PkgConfig::Options result; result.libDirs = stringListToStdVector(map.value(QStringLiteral("libDirs")).toStringList()); result.extraPaths = stringListToStdVector(map.value(QStringLiteral("extraPaths")).toStringList()); result.sysroot = map.value(QStringLiteral("sysroot")).toString().toStdString(); result.topBuildDir = map.value(QStringLiteral("topBuildDir")).toString().toStdString(); result.allowSystemLibraryPaths = map.value(QStringLiteral("allowSystemLibraryPaths"), false).toBool(); const auto systemLibraryPaths = map.value(QStringLiteral("systemLibraryPaths")).toStringList(); result.systemLibraryPaths.reserve(systemLibraryPaths.size()); std::transform( systemLibraryPaths.begin(), systemLibraryPaths.end(), std::back_inserter(result.systemLibraryPaths), [](const QString &str){ return str.toStdString(); }); result.disableUninstalled = map.value(QStringLiteral("disableUninstalled"), true).toBool(); result.staticMode = map.value(QStringLiteral("staticMode"), false).toBool(); result.definePrefix = map.value(QStringLiteral("definePrefix"), false).toBool(); result.globalVariables = variablesFromQVariantMap(map.value(QStringLiteral("globalVariables")).toMap()); result.systemVariables = envToVariablesMap(env); return result; } void PkgConfigJs::setupMethods(JSContext *ctx, JSValue obj) { setupMethod(ctx, obj, "packages", &PkgConfigJs::jsPackages, 0); } } // namespace Internal } // namespace qbs void initializeJsExtensionPkgConfig(qbs::Internal::ScriptEngine *engine, JSValue extensionObject) { qbs::Internal::PkgConfigJs::registerClass(engine, extensionObject); }