| 1 | // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. | 
| 2 | // | 
| 3 | // SPDX-License-Identifier: GPL-3.0-or-later | 
| 4 |  | 
| 5 | #include "config.h" | 
| 6 | #include "environment.h" | 
| 7 | #include "processutil.h" | 
| 8 |  | 
| 9 | #include <QRegularExpression> | 
| 10 | #include <QDir> | 
| 11 | #include <QDebug> | 
| 12 | #include <QDirIterator> | 
| 13 |  | 
| 14 | #include <iostream> | 
| 15 | namespace environment { | 
| 16 |  | 
| 17 | const QString RK_Major{"Major" }; | 
| 18 | const QString RK_Minor{"Minor" }; | 
| 19 | const QString RK_Revision{"Revision" }; | 
| 20 | const QString RK_Build{"Build" }; | 
| 21 |  | 
| 22 | namespace language { | 
| 23 |  | 
| 24 | Version completion(Category category, Kit kit, const Version &version) | 
| 25 | { | 
| 26 |     qInfo() << __FUNCTION__ << version.major.value(); | 
| 27 |     Version ret = version; | 
| 28 |     if (category == User) { | 
| 29 |         if (kit == Python) { | 
| 30 |             QString program = "python" ; | 
| 31 |             if (version.major) { | 
| 32 |                 program += QString::number(version.major.value()); | 
| 33 |             } | 
| 34 |             ProcessUtil::execute(program, {"-V" }, [&](const QByteArray &data){ | 
| 35 |                 QRegularExpression regExp {"Python\\s(?<"  + RK_Major +">[0-9])"  | 
| 36 |                             + "\\.(?<" + RK_Minor +">[0-9])"  | 
| 37 |                             + "\\.(?<" + RK_Revision +">[0-9])"  | 
| 38 |                             + "(\\.(?<" + RK_Build + ">[0-9]))?" }; | 
| 39 |                 auto matchs = regExp.match(data); | 
| 40 |                 if (matchs.hasMatch()) { | 
| 41 |                     auto major = matchs.captured(RK_Major); | 
| 42 |                     auto minor = matchs.captured(RK_Minor); | 
| 43 |                     auto revsion = matchs.captured(RK_Revision); | 
| 44 |                     auto build = matchs.captured(RK_Build); | 
| 45 |                     if (!major.isNull()) { | 
| 46 |                         ret.major = major.toInt(); | 
| 47 |                     } | 
| 48 |                     if (!minor.isNull()) { | 
| 49 |                         ret.minor = minor.toInt(); | 
| 50 |                     } | 
| 51 |                     if (!revsion.isNull()) { | 
| 52 |                         ret.revision = revsion.toInt(); | 
| 53 |                     } | 
| 54 |                     if (!build.isNull()) { | 
| 55 |                         ret.revision = build.toInt(); | 
| 56 |                     } | 
| 57 |                 } | 
| 58 |             }); | 
| 59 |         } | 
| 60 |     } | 
| 61 |     return ret; | 
| 62 | } | 
| 63 |  | 
| 64 | Program search(Category category, Kit kit, const Version &version) | 
| 65 | { | 
| 66 |     qInfo() << __FUNCTION__; | 
| 67 |     Program ret; | 
| 68 |     if (category == User) { | 
| 69 |         if (kit == Python) { | 
| 70 |             Version executeVersion = completion(category, kit, version); | 
| 71 |             if (executeVersion.major.value() == 3) { | 
| 72 |                 QString program = "python" ; | 
| 73 |                 if (executeVersion.major) { | 
| 74 |                     program + QString::number(executeVersion.major.value()); | 
| 75 |                 } | 
| 76 |                 ret.pkgsPath = QDir::homePath() + QDir::separator() | 
| 77 |                         + ".local"  + QDir::separator() | 
| 78 |                         + "lib"  + QDir::separator() | 
| 79 |                         + QString("python" ) + QString::number(executeVersion.major.value()) | 
| 80 |                         + "."  | 
| 81 |                         + QString::number(executeVersion.minor.value()) | 
| 82 |                         + QDir::separator() | 
| 83 |                         + "site-packages" ; | 
| 84 |             } | 
| 85 |         } | 
| 86 |     } | 
| 87 |     return ret; | 
| 88 | } | 
| 89 |  | 
| 90 | QProcessEnvironment get(Category category, Kit kit, const Version &version) | 
| 91 | { | 
| 92 |     QProcess process; | 
| 93 |     auto procEnv = process.processEnvironment(); | 
| 94 |     if (category == Category::User) { | 
| 95 |         if (kit == Kit::Python) { | 
| 96 |             Program program = search(category, kit, version); | 
| 97 |             if (program.binsPath) { | 
| 98 |                 QString runtimeBinPath = program.binsPath.value(); | 
| 99 |                 QString PATH_EnvValue = procEnv.value("PATH" ); | 
| 100 |                 procEnv.remove("PATH" ); | 
| 101 |                 procEnv.insert("PATH" , runtimeBinPath + ":"  + PATH_EnvValue); | 
| 102 |             } | 
| 103 |             if (program.pkgsPath) { | 
| 104 |                 QString userPythonPkgPath = program.pkgsPath.value(); | 
| 105 |                 procEnv.remove("PYTHONPATH" ); | 
| 106 |                 procEnv.insert("PYTHONPATH" , userPythonPkgPath); | 
| 107 |             } | 
| 108 |         } | 
| 109 |     } | 
| 110 |     return procEnv; | 
| 111 | } | 
| 112 |  | 
| 113 | Version::Version() | 
| 114 | { | 
| 115 |  | 
| 116 | } | 
| 117 |  | 
| 118 | Version::Version(int major) | 
| 119 |     : major(major) | 
| 120 | { | 
| 121 |  | 
| 122 | } | 
| 123 |  | 
| 124 | Version::Version(const Version &version) | 
| 125 |     : major(version.major) | 
| 126 |     , minor(version.minor) | 
| 127 |     , revision(version.revision) | 
| 128 |     , build(version.build) | 
| 129 | { | 
| 130 |  | 
| 131 | } | 
| 132 |  | 
| 133 | Version &Version::operator =(const Version &version) | 
| 134 | { | 
| 135 |     this->major = version.major; | 
| 136 |     this->minor = version.minor; | 
| 137 |     this->revision = version.revision; | 
| 138 |     this->build = version.build; | 
| 139 |     return *this; | 
| 140 | } | 
| 141 |  | 
| 142 | } // language | 
| 143 |  | 
| 144 | /*! | 
| 145 |  * @brief package::native::path | 
| 146 |  *  get local install offline packge path | 
| 147 |  * @param category use package name to search | 
| 148 |  * @return if Category is empty return install top path, else return package name path | 
| 149 |  */ | 
| 150 | QString package::native::path(const Category::type_value &category) | 
| 151 | { | 
| 152 |     QString envPath = QString(LIBRARY_INSTALL_PREFIX) | 
| 153 |             + QDir::separator() + "tools"  | 
| 154 |             + QDir::separator() + "env" ; | 
| 155 |     if (category.isEmpty()) { | 
| 156 |         return envPath; | 
| 157 |     } else { | 
| 158 |         QDirIterator sameItera(envPath, QDir::Files|QDir::NoDotAndDotDot); | 
| 159 |         while (sameItera.hasNext()) { | 
| 160 |             sameItera.next(); | 
| 161 |             QFileInfo info = sameItera.fileInfo(); | 
| 162 |             if (category == info.fileName()) { | 
| 163 |                 return info.filePath(); | 
| 164 |             } | 
| 165 |         } | 
| 166 |         QDirIterator containsItera(envPath, QDir::Files|QDir::NoDotAndDotDot); | 
| 167 |         while (containsItera.hasNext()) { | 
| 168 |             containsItera.next(); | 
| 169 |             QFileInfo info = containsItera.fileInfo(); | 
| 170 |             if (info.fileName().contains(category)) { | 
| 171 |                 return info.filePath(); | 
| 172 |             } | 
| 173 |         } | 
| 174 |     } | 
| 175 |     return envPath; | 
| 176 | } | 
| 177 |  | 
| 178 | /*! | 
| 179 |  * \brief environment::package::native::installed | 
| 180 |  *  Determine whether the current offline package is installed | 
| 181 |  * \return if install return true, else return false | 
| 182 |  */ | 
| 183 | bool environment::package::native::installed() | 
| 184 | { | 
| 185 |     QDir dir(path()); | 
| 186 |     if (dir.exists()) | 
| 187 |         return true; | 
| 188 |     return false; | 
| 189 | } | 
| 190 |  | 
| 191 | } // environment | 
| 192 |  |