//# //# Copyright (C) 2018-2021 QuasarApp. //# Distributed under the lgplv3 software license, see the accompanying //# Everyone is permitted to copy and distribute verbatim copies //# of this license document, but changing it is not allowed. //# #include "configparser.h" #include #include #include #include #include "dependenciesscanner.h" #include "deploycore.h" #include "filemanager.h" #include "packing.h" #include "pathutils.h" #include "pluginsparser.h" #include "quasarapp.h" #include #include #include #include #include /** * this function init packages of project * inputParamsList - list of parameters * patern : value;package * mainContainer - container for insert data, usually it is packages map. * seterFunc - this is method of item of mainConteiner for set value from inputParamsList * important : package in inputParamsList must be second. */ static QString defaultPackage = ""; template bool parsePackagesPrivate(Container& mainContainer, const QStringList &inputParamsList, Adder adder) { for (const auto& str: inputParamsList) { auto paramsList = str.split(DeployCore::getSeparator(1)); auto first = paramsList.value(0, ""); if (paramsList.size() == 1) (valueLink(mainContainer, defaultPackage, DistroModule{defaultPackage}).*adder)(first); else { bool skipError = QuasarAppUtils::Params::isEndable("allowEmptyPackages"); first = PathUtils::fullStripPath(first); if (!skipError && !mainContainer.contains(first)) { return false; } for (int i = 1; i < paramsList.size(); ++i) { (valueLink(mainContainer, first, DistroModule{first}).*adder)(paramsList[i]); } } } return true; } template void parseTargetPrivate(DeployConfig& conf, const QStringList &inputParams, Adder adder) { auto &cointainer = conf.targetsEdit(); for (const auto &iconPair: inputParams) { auto pair = iconPair.split(DeployCore::getSeparator(1), splitbehavior); if (pair.size() == 1) { QuasarAppUtils::Params::log(QString("Set new default property for all tagets: " + pair.value(0)), QuasarAppUtils::Debug); for (auto& editableTarget: cointainer) { (editableTarget.*adder)(pair.value(0)); } continue; } const auto targetsMap = conf.getTargetsListByFilter(pair.value(0)); if (pair.value(0).isEmpty() || targetsMap.isEmpty()) { QuasarAppUtils::Params::log(QString("You try sets property for the not exits target." " target: %0").arg(pair.value(0)), QuasarAppUtils::Warning); continue; } for (const auto &target: targetsMap) { QuasarAppUtils::Params::log(QString("Set new property for %0 taget."). arg(pair.value(0), pair.value(1)), QuasarAppUtils::Debug); (target->*adder)(pair.value(1)); } } } template bool enableOptionFotTargetPrivate(DeployConfig& conf, const QStringList &inputParams, Enabler enabler) { for (const auto &iconPair: inputParams) { auto pair = iconPair.split(DeployCore::getSeparator(1), splitbehavior); if (pair.size() != 1) { QuasarAppUtils::Params::log(QString("Failed parese list of option values, This option support only single leve list. " " Example: use -Option val1,val2,val3 "), QuasarAppUtils::Error); return false; } const auto targetsMap = conf.getTargetsListByFilter(pair.value(0)); if (!targetsMap.size()) { QuasarAppUtils::Params::log(QString("Not found any targets for the %0 selector"). arg(pair.value(0)), QuasarAppUtils::Warning); } for (const auto &target: targetsMap) { QuasarAppUtils::Params::log(QString("Set new property for %0 taget."). arg(pair.value(0)), QuasarAppUtils::Debug); (target->*enabler)(); } } return true; } bool ConfigParser::parseParams() { auto path = QuasarAppUtils::Params::getArg("confFile"); bool createFile = !QFile::exists(path) && QuasarAppUtils::Params::isEndable("confFile"); if (path.isEmpty() && QuasarAppUtils::Params::size() <= 0) { path = DEFAULT_COFIGURATION_FILE; } if (QFile::exists(path)) { if (!loadFromFile(path)) { QuasarAppUtils::Params::log("Failed to parse json file : " + path, QuasarAppUtils::Error); return false; } } auto distro = getDistribution(); _packing->setDistribution(distro); switch (DeployCore::getMode()) { case RunMode::Info: { QuasarAppUtils::Params::log("Print info ...", QuasarAppUtils::Info); if (!parseInfoMode()) { QuasarAppUtils::Params::log("Show info is failed!", QuasarAppUtils::Error); return false; } break; } case RunMode::Clear: { QuasarAppUtils::Params::log("Clear ...", QuasarAppUtils::Info); if (!parseClearMode()) { QuasarAppUtils::Params::log("Clear failed!", QuasarAppUtils::Error); return false; } break; } case RunMode::Init: { QuasarAppUtils::Params::log("Init ...", QuasarAppUtils::Info); if (!parseInitMode()) { QuasarAppUtils::Params::log("init is failed!", QuasarAppUtils::Error); return false; } break; } case RunMode::Deploy: { QuasarAppUtils::Params::log("Deploy ...", QuasarAppUtils::Info); if (!parseDeployMode()) { QuasarAppUtils::Params::log("Deploy failed!", QuasarAppUtils::Error); return false; } break; } case RunMode::Template: { QuasarAppUtils::Params::log("Extract defaults Templates ...", QuasarAppUtils::Info); if (!parseDeployMode()) { QuasarAppUtils::Params::log("Extract defaults Templates is failed!", QuasarAppUtils::Error); return false; } break; } } DeployCore::_config = &_config; if (createFile && !createFromDeploy(path)) { QuasarAppUtils::Params::log("Failed to create a deploy config file in " + path, QuasarAppUtils::Error); } return true; } const DeployConfig *ConfigParser::config() const { return &_config; } // FIX ME. if package contains the path separators then package rewrite to RelativeLink of configFile location QJsonValue ConfigParser::writeKeyArray(int separatorLvl, const QString ¶meter, const QString &confFileDir) const { auto list = parameter.split(DeployCore::getSeparator(separatorLvl)); if (DeployCore::isContainsArraySeparators(parameter)) { QJsonArray array; for (const auto &i: list) { array.push_back(writeKeyArray(separatorLvl + 1, i, confFileDir)); } return array; } if (list.size() && list.first().isEmpty()) { return QJsonValue(true); } auto val = list.first(); if (PathUtils::isPath(val)) { val = PathUtils::getRelativeLink( QFileInfo(confFileDir).absoluteFilePath(), QFileInfo(val).absoluteFilePath()); } return val; } void ConfigParser::writeKey(const QString& key, QJsonObject& obj, const QString& confFileDir) const { if (QuasarAppUtils::Params::isEndable(key)) { obj[key] = writeKeyArray(0, QuasarAppUtils::Params::getArg(key), confFileDir); } } QString ConfigParser::readKeyArray(int separatorLvl, const QJsonArray &array, const QString& confFileDir) const { QStringList list; for (const QJsonValue &i : array) { if (i.isArray()) { list.push_back(readKeyArray(separatorLvl + 1, i.toArray(), confFileDir)); } else { QString val = i.toString(); if (i.type() == QJsonValue::Double) { val = QString::number(i.toDouble(0), 'f'); } if (!val.isEmpty()) { if (PathUtils::isReleativePath(val)) { list.push_back(QFileInfo(confFileDir + '/' + val).absoluteFilePath()); } else { list.push_back(val); } } } } return list.join(DeployCore::getSeparator(separatorLvl)); } void ConfigParser::readKey(const QString& key, const QJsonObject& obj, const QString& confFileDir) const { if (!QuasarAppUtils::Params::isEndable(key)) { auto type = obj[key].type(); switch (type) { case QJsonValue::Array: { auto array = obj[key].toArray(); QuasarAppUtils::Params::setArg(key, readKeyArray(0, array, confFileDir)); break; } case QJsonValue::Double: { readString(key, QString::number(obj[key].toDouble(0), 'f'), confFileDir); break; } case QJsonValue::String: { readString(key, obj[key].toString(), confFileDir); break; } default: { auto value = obj[key].toBool(true); QuasarAppUtils::Params::setEnable(key, value); break; } } } } void ConfigParser::readString(const QString &key, const QString &val, const QString& confFileDir) const { if (PathUtils::isReleativePath(val)) { QuasarAppUtils::Params::setArg(key, QFileInfo(confFileDir + '/' + val).absoluteFilePath()); } else { QuasarAppUtils::Params::setArg(key, val); } } bool ConfigParser::createFromDeploy(const QString& confFile) const { QJsonObject obj; auto info = QFileInfo(confFile); const auto keys = DeployCore::helpKeys(); for (const auto &key :keys) { writeKey(key, obj, info.absolutePath()); } if (!QFile::exists(info.absolutePath()) && !QDir("/").mkpath(info.absolutePath())) { return false; } QJsonDocument doc(obj); QFile file(confFile); if (file.open(QIODevice::WriteOnly| QIODevice::Truncate)) { file.write(doc.toJson()); file.close(); return true; } return false; } bool ConfigParser::loadFromFile(const QString& confFile) { QFile file(confFile); QString confFilePath = QFileInfo(confFile).absolutePath(); if (file.open(QIODevice::ReadOnly)) { auto doc = QJsonDocument::fromJson(file.readAll()); if (!doc.isObject()) { return false; } auto obj = doc.object(); const auto keys = obj.keys(); for (const auto &key: keys) { readKey(key, obj, confFilePath); } file.close(); return true; } return false; } bool ConfigParser::initDistroStruct() { if (!initPackages()) { return false; } auto &mainDistro = _config.packagesEdit(); #ifdef Q_OS_LINUX auto binOut = QuasarAppUtils::Params::getArg("binOut"). split(DeployCore::getSeparator(0), splitbehavior); auto libOut = QuasarAppUtils::Params::getArg("libOut"). split(DeployCore::getSeparator(0), splitbehavior); #else auto binOut = QuasarAppUtils::Params::getArg("binOut"). split(DeployCore::getSeparator(0), splitbehavior); auto libOut = QuasarAppUtils::Params::getArg("libOut"). split(DeployCore::getSeparator(0), splitbehavior); #endif auto qmlOut = QuasarAppUtils::Params::getArg("qmlOut"). split(DeployCore::getSeparator(0), splitbehavior); auto trOut = QuasarAppUtils::Params::getArg("trOut"). split(DeployCore::getSeparator(0), splitbehavior); auto pluginOut = QuasarAppUtils::Params::getArg("pluginOut"). split(DeployCore::getSeparator(0), splitbehavior); auto recOut = QuasarAppUtils::Params::getArg("recOut"). split(DeployCore::getSeparator(0), splitbehavior); auto extraDataOut = QuasarAppUtils::Params::getArg("extraDataOut"). split(DeployCore::getSeparator(0), splitbehavior); auto name = QuasarAppUtils::Params::getArg("name"). split(DeployCore::getSeparator(0), splitbehavior); auto description = QuasarAppUtils::Params::getArg("description"). split(DeployCore::getSeparator(0), splitbehavior); auto deployVersion = QuasarAppUtils::Params::getArg("deployVersion"). split(DeployCore::getSeparator(0), splitbehavior); auto releaseDate = QuasarAppUtils::Params::getArg("releaseDate"). split(DeployCore::getSeparator(0), splitbehavior); auto publisher = QuasarAppUtils::Params::getArg("publisher"). split(DeployCore::getSeparator(0), splitbehavior); auto homepage = QuasarAppUtils::Params::getArg("homePage"). split(DeployCore::getSeparator(0), splitbehavior); auto prefix = QuasarAppUtils::Params::getArg("prefix"). split(DeployCore::getSeparator(0), splitbehavior); auto extraData = QuasarAppUtils::Params::getArg("extraData"). split(DeployCore::getSeparator(0), splitbehavior); auto trData = QuasarAppUtils::Params::getArg("tr"). split(DeployCore::getSeparator(0), splitbehavior); // init distro stucts for all targets if (binOut.size() && !parsePackagesPrivate(mainDistro, binOut, &DistroModule::setBinOutDir)) { packagesErrorLog("binOut"); return false; } if (libOut.size() && !parsePackagesPrivate(mainDistro, libOut, &DistroModule::setLibOutDir)) { packagesErrorLog("libOut"); return false; } if (qmlOut.size() && !parsePackagesPrivate(mainDistro, qmlOut, &DistroModule::setQmlOutDir)) { packagesErrorLog("qmlOut"); return false; } if (trOut.size() && !parsePackagesPrivate(mainDistro, trOut, &DistroModule::setTrOutDir)) { packagesErrorLog("trOut"); return false; } if (pluginOut.size() && !parsePackagesPrivate(mainDistro, pluginOut, &DistroModule::setPluginsOutDir)) { packagesErrorLog("pluginOut"); return false; } if (recOut.size() && !parsePackagesPrivate(mainDistro, recOut, &DistroModule::setResOutDir)) { packagesErrorLog("recOut"); return false; } if (extraDataOut.size() && !parsePackagesPrivate(mainDistro, extraDataOut, &DistroModule::setExtraDataOutDir)) { packagesErrorLog("extraDataOut"); return false; } if (name.size() && !parsePackagesPrivate(mainDistro, name, &DistroModule::setName)) { packagesErrorLog("name"); return false; } if (description.size() && !parsePackagesPrivate(mainDistro, description, &DistroModule::setDescription)) { packagesErrorLog("description"); return false; } if (deployVersion.size() && !parsePackagesPrivate(mainDistro, deployVersion, &DistroModule::setVersion)) { packagesErrorLog("deployVersion"); return false; } if (releaseDate.size() && !parsePackagesPrivate(mainDistro, releaseDate, &DistroModule::setReleaseData)) { packagesErrorLog("releaseDate"); return false; } if (publisher.size() && !parsePackagesPrivate(mainDistro, publisher, &DistroModule::setPublisher)) { packagesErrorLog("Publisher"); return false; } if (homepage.size() && !parsePackagesPrivate(mainDistro, homepage, &DistroModule::setHomePage)) { packagesErrorLog("homePage"); return false; } if (prefix.size() && !parsePackagesPrivate(mainDistro, prefix, &DistroModule::setPrefix)) { packagesErrorLog("prefix"); return false; } if (extraData.size() && !parsePackagesPrivate(mainDistro, extraData, &DistroModule::addExtraData)) { packagesErrorLog("extraData"); return false; } if (trData.size() && !parsePackagesPrivate(mainDistro, trData, &DistroModule::addTr)) { packagesErrorLog("tr"); return false; } return true; } bool ConfigParser::initPackages() { defaultPackage = "Application"; QSet configuredTargets; if (QuasarAppUtils::Params::isEndable("targetPackage")) { auto tar_packages_array = QuasarAppUtils::Params::getArg("targetPackage", ""). split(DeployCore::getSeparator(0)); for (auto& str: tar_packages_array) { auto paramsList = str.split(DeployCore::getSeparator(1)); auto package = PathUtils::fullStripPath(paramsList.value(0, "")); for (int i = 1; i < paramsList.size(); ++i) { auto targetPattern = paramsList.value(i); auto list = _config.getTargetsListByFilter(targetPattern); if (!list.size()) { auto warning = QString("You create the %0 package with the %1 pattern, " "but no matches were found for this pattern. "). arg(package, targetPattern); QuasarAppUtils::Params::log(warning, QuasarAppUtils::Warning); continue; } for (auto it = list.begin(); it != list.end(); ++it) { if (!configuredTargets.contains(it.key())) { configuredTargets.insert(it.key()); it.value()->setPackage(package); } } _config.packagesEdit().insert(package, DistroModule{package}); } if (paramsList.size() < 2) { defaultPackage = package; } } QuasarAppUtils::Params::log( "The default package is " + defaultPackage, QuasarAppUtils::Info); } // init default packages bool fDefaultPackage = false; for (auto it = _config.targetsEdit().begin(); it != _config.targetsEdit().end(); ++it) { if (!configuredTargets.contains(it.key())) { configuredTargets.insert(it.key()); it.value().setPackage(defaultPackage); fDefaultPackage = true; } } if (fDefaultPackage) { _config.packagesEdit().insert(defaultPackage, DistroModule{defaultPackage}); } _config.setDefaultPackage(defaultPackage); return true; } bool ConfigParser::initQmlInput() { auto qmlDir = QuasarAppUtils::Params::getArg("qmlDir"). split(DeployCore::getSeparator(0), splitbehavior); // init distro stucts for all targets _config.deployQml = qmlDir.size(); if (qmlDir.size() && !parsePackagesPrivate(_config.packagesEdit(), qmlDir, &DistroModule::addQmlInput)) { packagesErrorLog("qmlDir"); return false; } return true; } void ConfigParser::packagesErrorLog(const QString &option) { QuasarAppUtils::Params::log(QString("Failed to set the %0 option, because you are trying to set it for an uninitialized package." " Use the 'targetPackage' flag to init this package. " "Or, if you want to configure an empty package, " "use the allowEmptyPackages option to disable this error message."). arg(option), QuasarAppUtils::Error); } bool ConfigParser::parseDeployMode() { if (QuasarAppUtils::Params::isEndable("deploySystem-with-libc")) { QuasarAppUtils::Params::log("You are using a deprecated option \"deploySystem-with-libc\"." " In this version this option is no different from \"deploySystem\"." " Please use the deploySystem option.", QuasarAppUtils::Warning); QuasarAppUtils::Params::setEnable("deploySystem", true ); } if (!checkSnapPermisions()) { return false; } setTargetDir(); auto bin = QuasarAppUtils::Params::getArg("bin"). split(DeployCore::getSeparator(0), splitbehavior); if (bin.size() && !setTargets(bin)) { QuasarAppUtils::Params::log("Failed to set targets", QuasarAppUtils::Warning); } auto xData = QuasarAppUtils::Params::getArg("extraData"). split(DeployCore::getSeparator(0), splitbehavior); if (!(_config.targets().count() || xData.count())) { QuasarAppUtils::Params::log("Failed to initialize targets or extra data!", QuasarAppUtils::Error); QuasarAppUtils::Params::log("Use bin or extraData optins. And check input pathes.", QuasarAppUtils::Info); return false; } _config.depchLimit = 0; if (QuasarAppUtils::Params::isEndable("recursiveDepth")) { bool ok; _config.depchLimit = QuasarAppUtils::Params::getArg("recursiveDepth").toInt(&ok); if (!ok) { _config.depchLimit = 0; QuasarAppUtils::Params::log("Failed to set the recursive depth. The argument of the recursiveDepth option is invalid!" " Using the default value 0", QuasarAppUtils::Warning); } } initIgnoreEnvList(); initEnvirement(); initIgnoreList(); if (!initDistroStruct()) { return false; } initExtraPath(); initExtraNames(); initPlugins(); if (!initQmake()) { if (DeployCore::isSnap()) { QuasarAppUtils::Params::log("If you are using qmake from the system repository," " then you must use the classic version of CQtDeployer instead of the snap version." " This is due to the fact that the snap version" " runs in an isolated container and has limited access" " to system utilities and the environment." " For get the classic version of cqtdeployer use the cqtdeployer installer" " https://github.com/QuasarApp/CQtDeployer/releases", QuasarAppUtils::Info); } return false; } if (!initQmlInput()) { return false; } return true; } bool ConfigParser::parseInfoMode() { if ((QuasarAppUtils::Params::isEndable("v") || QuasarAppUtils::Params::isEndable("version"))) { DeployCore::printVersion(); return true; } DeployCore::help(); return true; } bool ConfigParser::parseInitMode() { auto initLvl = QuasarAppUtils::Params::getArg("init"); QString sourceUrl(":/Distro/Distributions/configures/Init.json"); if (initLvl == "multi") { sourceUrl = ":/Distro/Distributions/configures/Init multiPackage configuration.json"; } else if (initLvl == "single") { sourceUrl = ":/Distro/Distributions/configures/Init single configuration.json"; } QFile configFile(DEFAULT_COFIGURATION_FILE); QFile source(sourceUrl); if (configFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { if (source.open(QIODevice::ReadOnly)) { configFile.write(source.readAll()); source.close(); } configFile.close(); } return true; } bool ConfigParser::configureTargets() { const auto icons = QuasarAppUtils::Params::getArg("icon"). split(DeployCore::getSeparator(0), splitbehavior); const auto runScripts = QuasarAppUtils::Params::getArg("runScript"). split(DeployCore::getSeparator(0), splitbehavior); const auto disableRunScripts = QuasarAppUtils::Params::getArg("disableRunScript"). split(DeployCore::getSeparator(0), splitbehavior); const auto disableShortcuts = QuasarAppUtils::Params::getArg("disableShortCut"). split(DeployCore::getSeparator(0), splitbehavior); if (icons.size()) { parseTargetPrivate(_config, icons, &TargetInfo::setIcon); } if (runScripts.size()) { parseTargetPrivate(_config, runScripts, &TargetInfo::setRunScript); } if (disableShortcuts.size() && !enableOptionFotTargetPrivate(_config, disableShortcuts, &TargetInfo::disableShortCut)) { packagesErrorLog("disableShortCut"); return false; } if (disableRunScripts.size() && !enableOptionFotTargetPrivate(_config, disableRunScripts, &TargetInfo::disableRunScript)) { packagesErrorLog("disableRunScript"); return false; } return true; } bool ConfigParser::parseClearMode() { setTargetDir("./" + DISTRO_DIR); return true; } QSet ConfigParser::getQtPathesFromTargets() { QSet res; for (const auto &i: _config.targets()) { if (i.isValid() && !i.getQtPath().isEmpty()) { res.insert(i.getQtPath()); } } return res; } void ConfigParser::setTargetDir(const QString &target) { if (QuasarAppUtils::Params::isEndable("targetDir")) { _config.setTargetDir(QFileInfo(QuasarAppUtils::Params::getArg("targetDir")).absoluteFilePath()); } else if (target.size()) { _config.setTargetDir(QFileInfo(target).absoluteFilePath()); } else { _config.setTargetDir(QFileInfo("./" + DISTRO_DIR).absoluteFilePath()); QuasarAppUtils::Params::log("The targetDir option is not used." " CQtDeployer will use default target dir :" + _config.getTargetDir(), QuasarAppUtils::Info); } } bool ConfigParser::setTargets(const QStringList &value) { bool isfillList = false; for (const auto &i : value) { QFileInfo targetInfo = DeployCore::findItem(i); if (i.isEmpty()) continue; if (targetInfo.isFile()) { auto target = createTarget(targetInfo.absoluteFilePath()); if (!_config.targetsEdit().contains(target.target)) { _config.targetsEdit().insert(target.target, target.targetInfo); } isfillList = true; } else if (targetInfo.isDir()) { if (!setTargetsInDir(targetInfo.absoluteFilePath())) { QuasarAppUtils::Params::log(i + " does not contain executable binaries!", QuasarAppUtils::Debug); continue; } isfillList = true; } else { QuasarAppUtils::Params::log(targetInfo.absoluteFilePath() + " does not exist!", QuasarAppUtils::Debug); } } if (!isfillList) return false; return true; } bool ConfigParser::setTargetsRecursive(const QString &dir) { if (!setTargetsInDir(dir, true)) { QuasarAppUtils::Params::log("setTargetsInDir failed!", QuasarAppUtils::Debug); return false; } return true; } bool ConfigParser::setTargetsInDir(const QString &dir, bool recursive) { QDir d(dir); if (dir.isEmpty() || !d.exists()) { QuasarAppUtils::Params::log(dir + " dir not exits!", QuasarAppUtils::Debug); return false; } QuasarAppUtils::Params::log("setTargetsInDir check path: " + dir, QuasarAppUtils::Debug); QFileInfoList list; if (recursive) { list = d.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); } else { list = d.entryInfoList(QDir::Files | QDir::NoDotAndDotDot); } bool result = false; for (const auto &file : qAsConst(list)) { if (file.isDir()) { result |= setTargetsInDir(file.absoluteFilePath(), recursive); continue; } auto name = file.fileName(); auto sufix = file.completeSuffix(); if (sufix.isEmpty() || name.contains(".dll", Qt::CaseInsensitive) || name.contains(".so", Qt::CaseInsensitive) || name.contains(".exe", Qt::CaseInsensitive)) { auto target = createTarget(QDir::fromNativeSeparators(file.absoluteFilePath())); if (!_config.targetsEdit().contains(target.target)) { _config.targetsEdit().insert(target.target, target.targetInfo); } result = true; } } return result; } TargetData ConfigParser::createTarget(const QString &target) { TargetInfo libinfo; auto key = target; if (_scaner->fillLibInfo(libinfo, key)) { return {libinfo.fullPath(), libinfo}; } return {key, {}}; } QHash ConfigParser::moveTarget(TargetInfo target, const QString& newLocation) { target.setPath(QFileInfo(newLocation).absolutePath()); return {{newLocation, target}}; } void ConfigParser::initIgnoreList() { if (QuasarAppUtils::Params::isEndable("ignore")) { auto list = QuasarAppUtils::Params::getArg("ignore"). split(DeployCore::getSeparator(0)); for (const auto &i : list) { _config.ignoreList.addRule(IgnoreData(i)); } } IgnoreData ruleUnix, ruleWin; Envirement envUnix, envWin; envUnix.addEnv(Envirement::recursiveInvairement("/lib", 3)); envUnix.addEnv(Envirement::recursiveInvairement("/usr/lib", 3)); if (DeployCore::isSnap()) { envUnix.addEnv(Envirement::recursiveInvairement(DeployCore::transportPathToSnapRoot("/lib"), 3)); envUnix.addEnv(Envirement::recursiveInvairement(DeployCore::transportPathToSnapRoot("/usr/lib"), 3)); } ruleUnix.prority = SystemLib; ruleUnix.platform = Unix; ruleUnix.enfirement = envUnix; auto addRuleUnix = [&ruleUnix](const QString & lib) { ruleUnix.label = lib; return ruleUnix; }; _config.ignoreList.addRule(addRuleUnix("libc")); _config.ignoreList.addRule(addRuleUnix("libstdc++")); _config.ignoreList.addRule(addRuleUnix("ld-")); _config.ignoreList.addRule(addRuleUnix("libpthread")); _config.ignoreList.addRule(addRuleUnix("libm")); _config.ignoreList.addRule(addRuleUnix("libz")); _config.ignoreList.addRule(addRuleUnix("librt")); _config.ignoreList.addRule(addRuleUnix("libnsl")); _config.ignoreList.addRule(addRuleUnix("libdl")); _config.ignoreList.addRule(addRuleUnix("libutil")); _config.ignoreList.addRule(addRuleUnix("libresolv")); _config.ignoreList.addRule(addRuleUnix("libBrokenLocale")); _config.ignoreList.addRule(addRuleUnix("libBrokenLocale")); _config.ignoreList.addRule(addRuleUnix("libSegFault")); _config.ignoreList.addRule(addRuleUnix("libanl")); _config.ignoreList.addRule(addRuleUnix("libcrypt.so")); _config.ignoreList.addRule(addRuleUnix("/gconv/")); _config.ignoreList.addRule(addRuleUnix("libnss")); QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); auto path = env.value("PATH"); auto winPath = findWindowsPath(path); envWin.addEnv(Envirement::recursiveInvairement(winPath + "/System32", 2)); envWin.addEnv(Envirement::recursiveInvairement(winPath + "/SysWOW64", 2)); ruleWin.prority = SystemLib; ruleWin.platform = Win; ruleWin.enfirement = envWin; auto addRuleWin = [&ruleWin](const QString & lib) { ruleWin.label = lib; return ruleWin; }; // win and core libs : see https://en.wikipedia.org/wiki/Microsoft_Windows_library_files _config.ignoreList.addRule(addRuleWin("Hal.DLL")); _config.ignoreList.addRule(addRuleWin("NTDLL.DLL")); _config.ignoreList.addRule(addRuleWin("KERNEL32.DLL")); _config.ignoreList.addRule(addRuleWin("GDI32.DLL")); _config.ignoreList.addRule(addRuleWin("USER32.DLL")); _config.ignoreList.addRule(addRuleWin("COMCTL32.DLL")); _config.ignoreList.addRule(addRuleWin("COMDLG32.DLL")); _config.ignoreList.addRule(addRuleWin("WS2_32.DLL")); _config.ignoreList.addRule(addRuleWin("ADVAPI32.DLL")); _config.ignoreList.addRule(addRuleWin("NETAPI32.DLL")); _config.ignoreList.addRule(addRuleWin("OLE32.DLL")); _config.ignoreList.addRule(addRuleWin("SHSCRAP.DLL")); _config.ignoreList.addRule(addRuleWin("WINMM.DLL")); _config.ignoreList.addRule(addRuleWin("IMM32.DLL")); _config.ignoreList.addRule(addRuleWin("KernelBase.DLL")); _config.ignoreList.addRule(addRuleWin("dwmapi.DLL")); } void ConfigParser::initIgnoreEnvList() { QStringList ignoreEnvList; if (QuasarAppUtils::Params::isEndable("ignoreEnv")) { auto ignoreList = QuasarAppUtils::Params::getArg("ignoreEnv"). split(DeployCore::getSeparator(0)); for (const auto &i : ignoreList) { auto path = QFileInfo(i).absoluteFilePath(); if (path.right(1) == "/" || path.right(1) == "\\") { path.remove(path.size() - 1, 1); } ignoreEnvList.append(path); } } // forbid pathes of the snap container if (DeployCore::isSnap()) { ignoreEnvList.push_back("/lib"); ignoreEnvList.push_back("/usr/lib"); } ignoreEnvList.push_back(_config.appDir); ignoreEnvList.push_back(_config.getTargetDir()); if (QuasarAppUtils::Params::isEndable("noRecursiveiIgnoreEnv")) { _config.envirement.setIgnoreEnvList(ignoreEnvList); } else { _config.envirement.setIgnoreEnvListRecursive(ignoreEnvList, _config.depchLimit); } } QString ConfigParser::getPathFrmoQmakeLine(const QString &in) const { auto list = in.split(':'); if (list.size() > 1) { list.removeAt(0); return DeployCore::transportPathToSnapRoot( QFileInfo(list.join(':')).absoluteFilePath().remove('\r')); } return ""; } bool ConfigParser::initQmakePrivate(const QString &qmake) { QFileInfo info(qmake); QString basePath = info.absolutePath(); if (!setQmake(qmake)) { QDir dir(basePath); if (!dir.cdUp()) { QuasarAppUtils::Params::log("Failed to initialize qt directories by qmake.", QuasarAppUtils::Error); return false; } QuasarAppUtils::Params::log("Failed to execute the qmake process!" " Trying to initialize Qt directories from path: " + dir.absolutePath(), QuasarAppUtils::Warning); if (!setQtDir(dir.absolutePath())){ QuasarAppUtils::Params::log("Failed to initialize Qt directories", QuasarAppUtils::Error); return false; } } return true; } bool ConfigParser::initQmake() { if (!_config.isNeededQt()) { QuasarAppUtils::Params::log("Deploy only C/C++ libraries because" " all target applications do not depend on the Qt libraries", QuasarAppUtils::Info); return true; } auto qmake = QuasarAppUtils::Params::getArg("qmake"); QFileInfo info(qmake); if (!info.isFile() || (info.baseName() != "qmake")) { auto qtList = getQtPathesFromTargets(); if (qtList.isEmpty()) { if (!QuasarAppUtils::Params::isEndable("noCheckPATH")) { auto env = QProcessEnvironment::systemEnvironment(); auto proc = DeployCore::findProcess(env.value("PATH"), "qmake"); if (proc.isEmpty()) { QuasarAppUtils::Params::log("The deployment target requires Qt libraries," " but initialize of Qt directories is failed." " Please use the qmake option to set a path to the qmake executable.", QuasarAppUtils::Error); return false; } return initQmakePrivate(proc); } QuasarAppUtils::Params::log("Your distribution required Qt libraries " "but qmake executable cannot be found in the 'qmake' option or RPATH. " "You are using the option noCheckPATH, " "please remove this option from your deploy command to search qmake in PATH", QuasarAppUtils::Error); return false; } if (qtList.size() > 1) { QuasarAppUtils::Params::log("Your deployment targets were compiled by different qmakes, " "auto-capture of the Qt libraries is not possible. " "Please use the -qmake flag to solve this problem.", QuasarAppUtils::Error); return false; } auto qt = *qtList.begin(); if (qt.rightRef(3).compare(QString("lib"), Qt::CaseInsensitive)) { return initQmakePrivate(QFileInfo(qt + "/../bin/qmake").absoluteFilePath()); } return initQmakePrivate(QFileInfo(qt + "/qmake").absoluteFilePath()); } return initQmakePrivate(qmake); } bool ConfigParser::setQmake(const QString &value) { auto qmakeInfo = QFileInfo(QDir::fromNativeSeparators(value)); if (!(qmakeInfo.fileName().compare("qmake", Qt::CaseInsensitive) || qmakeInfo.fileName().compare("qmake.exe", Qt::CaseInsensitive))) { return false; } QProcess proc; proc.setProgram(qmakeInfo.absoluteFilePath()); proc.setProcessEnvironment(QProcessEnvironment::systemEnvironment()); proc.setArguments({"-query"}); proc.start(); if (!proc.waitForFinished(1000)) { QuasarAppUtils::Params::log("run qmake fail!"); return false; } QString qmakeData = proc.readAll(); auto list = qmakeData.split('\n'); for (const auto &value : list) { if (value.contains("QT_INSTALL_LIBS")) { _config.qtDir.setLibs(getPathFrmoQmakeLine(value)); } else if (value.contains("QT_INSTALL_LIBEXECS")) { _config.qtDir.setLibexecs(getPathFrmoQmakeLine(value)); } else if (value.contains("QT_INSTALL_BINS")) { _config.qtDir.setBins(getPathFrmoQmakeLine(value)); } else if (value.contains("QT_INSTALL_PLUGINS")) { _config.qtDir.setPlugins(getPathFrmoQmakeLine(value)); } else if (value.contains("QT_INSTALL_QML")) { _config.qtDir.setQmls(getPathFrmoQmakeLine(value)); } else if (value.contains("QT_INSTALL_TRANSLATIONS")) { _config.qtDir.setTranslations(getPathFrmoQmakeLine(value)); } else if (value.contains("QT_INSTALL_DATA")) { _config.qtDir.setResources(getPathFrmoQmakeLine(value) + "/resources"); } else if (value.contains("QMAKE_XSPEC")) { auto val = value.split(':').value(1); if (val.contains("win32")) { _config.qtDir.setQtPlatform(Platform::Win); } else { _config.qtDir.setQtPlatform(Platform::Unix); } } } _config.qtDir.setQtVersion(_config.isNeededQt()); _config.envirement.addEnv(_config.qtDir.getLibs()); _config.envirement.addEnv(_config.qtDir.getBins()); return true; } bool ConfigParser::setQtDir(const QString &value) { QFileInfo info(value); if (!QFile::exists(info.absoluteFilePath() + ("/bin"))) { QuasarAppUtils::Params::log("get qt bin failed!", QuasarAppUtils::Debug); return false; } _config.qtDir.setBins(info.absoluteFilePath() + ("/bin")); if (!QFile::exists(info.absoluteFilePath() + ("/lib"))) { QuasarAppUtils::Params::log("get qt lib failed!", QuasarAppUtils::Debug); return false; } _config.qtDir.setLibs(info.absoluteFilePath() + ("/lib")); if (!QFile::exists(info.absoluteFilePath() + ("/qml"))) { QuasarAppUtils::Params::log("get qt qml failed!", QuasarAppUtils::Debug); } else { _config.qtDir.setQmls(info.absoluteFilePath() + ("/qml")); } if (!QFile::exists(info.absoluteFilePath() + ("/plugins"))) { QuasarAppUtils::Params::log("get qt plugins failed!", QuasarAppUtils::Debug); } else { _config.qtDir.setPlugins(info.absoluteFilePath() + ("/plugins")); } #ifdef Q_OS_UNIX if (!QFile::exists(info.absoluteFilePath() + ("/libexec"))) { QuasarAppUtils::Params::log("get qt libexec failed!", QuasarAppUtils::Debug); } else { _config.qtDir.setLibexecs(info.absoluteFilePath() + ("/libexec")); } #endif #ifdef Q_OS_WIN _config.qtDir.setLibexecs(info.absoluteFilePath() + ("/bin")); #endif if (!QFile::exists(info.absoluteFilePath() + ("/translations"))) { QuasarAppUtils::Params::log("get qt translations failed!", QuasarAppUtils::Debug); } else { _config.qtDir.setTranslations(info.absoluteFilePath() + ("/translations")); } if (!QFile::exists(info.absoluteFilePath() + ("/resources"))) { QuasarAppUtils::Params::log("get qt resources failed!", QuasarAppUtils::Debug); } else { _config.qtDir.setResources(info.absoluteFilePath() + ("/resources")); } #ifdef Q_OS_UNIX _config.qtDir.setQtPlatform(Platform::Unix); #endif #ifdef Q_OS_WIN _config.qtDir.setQtPlatform(Platform::Win); #endif _config.qtDir.setQtVersion(_config.isNeededQt()); _config.envirement.addEnv(_config.qtDir.getLibs()); _config.envirement.addEnv(_config.qtDir.getBins()); return true; } void ConfigParser::initExtraPath() { auto listLibDir = QuasarAppUtils::Params::getArg("libDir"). split(DeployCore::getSeparator(0)); QDir dir; for (const auto &i : listLibDir) { QFileInfo info(DeployCore::transportPathToSnapRoot(i)); if (info.isDir()) { if (_config.targets().contains(info.absoluteFilePath())) { QuasarAppUtils::Params::log("Skip the extra library path because it is target!", QuasarAppUtils::Debug); continue; } dir.setPath(info.absoluteFilePath()); auto extraDirs = getSetDirsRecursive(QDir::fromNativeSeparators(info.absoluteFilePath()), _config.depchLimit); _config.extraPaths.addExtraPaths(extraDirs); _config.envirement.addEnv(Envirement::recursiveInvairement(dir, 0, _config.depchLimit)); } else if (i.size() > 1) { _config.extraPaths.addExtraPathsMasks({i}); QuasarAppUtils::Params::log(i + " is added as a path mask", QuasarAppUtils::Debug); } else { QuasarAppUtils::Params::log(i + " not added in path mask because" " the path mask must be large 2 characters", QuasarAppUtils::Debug); } } } void ConfigParser::initExtraNames() { const auto deployExtraNames = [this](const QStringList& listNamesMasks){ for (const auto &i : listNamesMasks) { if (i.size() > 1) { _config.allowedPaths.addtExtraNamesMasks({i}); QuasarAppUtils::Params::log(i + " is added as a filename mask", QuasarAppUtils::Debug); } else { QuasarAppUtils::Params::log(i + " not added in file mask because" " the file mask must be large 2 characters", QuasarAppUtils::Debug); } } }; auto listNamesMasks = QuasarAppUtils::Params::getArg("extraLibs"). split(DeployCore::getSeparator(0)); deployExtraNames(listNamesMasks); /* * Task https://github.com/QuasarApp/CQtDeployer/issues/422 * We need to add to extra names libraries without which qt will not work, * */ if (_config.isNeededQt()) { auto libs = DeployCore::Qt3rdpartyLibs( _config.getPlatformOfAll()); deployExtraNames(libs); } } bool ConfigParser::initPlugins() { auto listExtraPlugin = QuasarAppUtils::Params::getArg("extraPlugin"). split(DeployCore::getSeparator(0), splitbehavior); auto listEnablePlugins = QuasarAppUtils::Params::getArg("enablePlugins"). split(DeployCore::getSeparator(0), splitbehavior); auto listDisablePlugins = QuasarAppUtils::Params::getArg("disablePlugins"). split(DeployCore::getSeparator(0), splitbehavior); if (listExtraPlugin.size() && !parsePackagesPrivate(_config.packagesEdit(), listExtraPlugin, &DistroModule::addExtraPlugins)) { packagesErrorLog("extra plugins"); return false; } if (listEnablePlugins.size() && !parsePackagesPrivate(_config.packagesEdit(), listEnablePlugins, &DistroModule::addEnabledPlugins)) { packagesErrorLog("enable plugins"); return false; } if (listDisablePlugins.size() && !parsePackagesPrivate(_config.packagesEdit(), listDisablePlugins, &DistroModule::addDisabledPlugins)) { packagesErrorLog("disable plugins"); return false; } return true; } QString ConfigParser::findWindowsPath(const QString& path) const { auto list = path.split(';'); QString win_magic = "windows"; for (const auto &i: list ) { int index = i.indexOf(win_magic, 0, Qt::CaseInsensitive); if (index > 0 && i.size() == index + win_magic.size()) { return QDir::fromNativeSeparators(i); } } return "C:/" + win_magic; } QList ConfigParser::getDistribution() { QList distros; if (QuasarAppUtils::Params::isEndable("deb")) { #ifdef Q_OS_LINUX distros.push_back(new Deb(_fileManager)); #else QuasarAppUtils::Params::log("The deb option availabel only on Linux host palatforms," " please remove this options from your deploy command", QuasarAppUtils::Warning); #endif } if (QuasarAppUtils::Params::isEndable("zip")) { distros.push_back(new ZipArhive(_fileManager)); } if (QuasarAppUtils::Params::isEndable("qif")) { distros.push_back(new QIF(_fileManager)); } if (distros.isEmpty()) { distros.push_back(new DefaultDistro(_fileManager)); } return distros; } void ConfigParser::initEnvirement() { QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); auto path = env.value("PATH"); if (!DeployCore::isSnap()) { _config.envirement.addEnv(env.value("LD_LIBRARY_PATH")); _config.envirement.addEnv(path); } QStringList dirs; #ifdef Q_OS_LINUX dirs.append(getDirsRecursive(DeployCore::transportPathToSnapRoot("/lib"), 5)); dirs.append(getDirsRecursive(DeployCore::transportPathToSnapRoot("/usr/lib"), 5)); #else auto winPath = findWindowsPath(path); dirs.append(getDirsRecursive(winPath + "/System32", 2)); dirs.append(getDirsRecursive(winPath + "/SysWOW64", 2)); #endif _config.envirement.addEnv(dirs); if (_config.envirement.size() < 2) { QuasarAppUtils::Params::log("System environment is empty", QuasarAppUtils::Warning); } } bool ConfigParser::checkSnapPermisions() { if (!DeployCore::isSnap()) return true; bool system = QuasarAppUtils::Params::isEndable("deploySystem") || QuasarAppUtils::Params::isEndable("extraLibs"); if (system && !DeployCore::checkSystemBakupSnapInterface()) { QuasarAppUtils::Params::log("You use a deploySystem or extraLibs options," " but not added permision system-backup for cqtdeployer." " Please add permissions system-backup before using cqtdeployer." " Add system-backup permision from console: ", QuasarAppUtils::Error); QuasarAppUtils::Params::log( "'snap connect cqtdeployer:system-backup :system-backup'", QuasarAppUtils::Info); QuasarAppUtils::Params::log( "GUI: Open the gnome system setting >> Applications >> CQtDeployer. " "in menu rights and permisions enable system-backup.", QuasarAppUtils::Info); return false; } return true; } QStringList ConfigParser::getDirsRecursive(const QString &path, int maxDepch, int depch) { return getSetDirsRecursive(path, maxDepch, depch).values(); } QSet ConfigParser::getSetDirsRecursive(const QString &path, int maxDepch, int depch) { QDir dir(path); QSet res = {dir.path()}; if (maxDepch >= 0 && maxDepch <= depch) { return res; } auto list = dir.entryInfoList(QDir::Dirs| QDir::NoDotAndDotDot); for (const auto &subDir: list) { res.insert(subDir.absoluteFilePath()); res.unite(getSetDirsRecursive(subDir.absoluteFilePath(), maxDepch, depch + 1)); } return res; } bool ConfigParser::smartMoveTargets() { QMultiHash temp; bool result = true; QuasarAppUtils::Params::log(QString("Available Targets: "), QuasarAppUtils::Debug); for (auto i = _config.targets().cbegin(); i != _config.targets().cend(); ++i) { if (!i.value().isValid()) { internalError(); return false; } QFileInfo target(i.key()); QString targetPath = _config.getTargetDir() + "/" + i.value().getPackage(); targetPath += _config.getDistro(i.key()).getBinOutDir(); if (!_fileManager->cp(target.absoluteFilePath(), targetPath)) { result = false; } auto newTargetKey = targetPath + "/" + target.fileName(); const auto newTarget = moveTarget(i.value(), newTargetKey); temp.unite(newTarget); QuasarAppUtils::Params::log(QString("Target: " + newTarget.begin().key()), QuasarAppUtils::Debug); auto pkgKey = i.value().getPackage(); if (!_config.packagesEdit().contains(pkgKey)) { QuasarAppUtils::Params::log(QString("The target %0 belongs to package %1" " but this package is not initialized!"). arg(i.key(), pkgKey)); internalError(); return false; } valueLink(_config.packagesEdit(), pkgKey, DistroModule{pkgKey}).addTarget(newTargetKey); } _config.targetsEdit() = temp; return result && configureTargets(); } ConfigParser::ConfigParser(FileManager *filemanager, PluginsParser *pluginsParser, DependenciesScanner* scaner, Packing *pac): _fileManager(filemanager), _pluginsParser(pluginsParser), _scaner(scaner), _packing(pac) { assert(_fileManager); assert(_pluginsParser); assert(_scaner); assert(_packing); _config.appDir = QuasarAppUtils::Params::getCurrentExecutableDir(); if (_config.appDir.right(4) == "/bin") { _config.appDir = _config.appDir.left(_config.appDir.size() - 4); } QuasarAppUtils::Params::log("appDir = " + _config.appDir); }