diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt index 90e724793..4049d0cdf 100644 --- a/src/base/CMakeLists.txt +++ b/src/base/CMakeLists.txt @@ -49,6 +49,7 @@ search/searchdownloadhandler.h search/searchhandler.h search/searchpluginmanager.h utils/bytearray.h +utils/foreignapps.h utils/fs.h utils/gzip.h utils/misc.h @@ -117,6 +118,7 @@ search/searchdownloadhandler.cpp search/searchhandler.cpp search/searchpluginmanager.cpp utils/bytearray.cpp +utils/foreignapps.cpp utils/fs.cpp utils/gzip.cpp utils/misc.cpp diff --git a/src/base/base.pri b/src/base/base.pri index c84c49c93..1357fc754 100644 --- a/src/base/base.pri +++ b/src/base/base.pri @@ -64,6 +64,7 @@ HEADERS += \ $$PWD/types.h \ $$PWD/unicodestrings.h \ $$PWD/utils/bytearray.h \ + $$PWD/utils/foreignapps.h \ $$PWD/utils/fs.h \ $$PWD/utils/gzip.h \ $$PWD/utils/misc.h \ @@ -127,6 +128,7 @@ SOURCES += \ $$PWD/torrentfilter.cpp \ $$PWD/tristatebool.cpp \ $$PWD/utils/bytearray.cpp \ + $$PWD/utils/foreignapps.cpp \ $$PWD/utils/fs.cpp \ $$PWD/utils/gzip.cpp \ $$PWD/utils/misc.cpp \ diff --git a/src/base/search/searchdownloadhandler.cpp b/src/base/search/searchdownloadhandler.cpp index e3d853e5b..33f267db2 100644 --- a/src/base/search/searchdownloadhandler.cpp +++ b/src/base/search/searchdownloadhandler.cpp @@ -30,8 +30,8 @@ #include +#include "../utils/foreignapps.h" #include "../utils/fs.h" -#include "../utils/misc.h" #include "searchpluginmanager.h" SearchDownloadHandler::SearchDownloadHandler(const QString &siteUrl, const QString &url, SearchPluginManager *manager) @@ -48,7 +48,7 @@ SearchDownloadHandler::SearchDownloadHandler(const QString &siteUrl, const QStri url }; // Launch search - m_downloadProcess->start(Utils::Misc::pythonExecutable(), params, QIODevice::ReadOnly); + m_downloadProcess->start(Utils::ForeignApps::Python::pythonExecutable(), params, QIODevice::ReadOnly); } void SearchDownloadHandler::downloadProcessFinished(int exitcode) diff --git a/src/base/search/searchhandler.cpp b/src/base/search/searchhandler.cpp index efb14a29e..d1fb72157 100644 --- a/src/base/search/searchhandler.cpp +++ b/src/base/search/searchhandler.cpp @@ -32,8 +32,8 @@ #include #include +#include "../utils/foreignapps.h" #include "../utils/fs.h" -#include "../utils/misc.h" #include "searchpluginmanager.h" namespace @@ -70,7 +70,7 @@ SearchHandler::SearchHandler(const QString &pattern, const QString &category, co }; // Launch search - m_searchProcess->setProgram(Utils::Misc::pythonExecutable()); + m_searchProcess->setProgram(Utils::ForeignApps::Python::pythonExecutable()); m_searchProcess->setArguments(params + m_pattern.split(" ")); #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) diff --git a/src/base/search/searchpluginmanager.cpp b/src/base/search/searchpluginmanager.cpp index de0a4b577..448793245 100644 --- a/src/base/search/searchpluginmanager.cpp +++ b/src/base/search/searchpluginmanager.cpp @@ -46,6 +46,7 @@ #include "base/net/downloadmanager.h" #include "base/preferences.h" #include "base/profile.h" +#include "base/utils/foreignapps.h" #include "base/utils/fs.h" #include "base/utils/misc.h" #include "searchdownloadhandler.h" @@ -63,7 +64,7 @@ namespace QPointer SearchPluginManager::m_instance = nullptr; SearchPluginManager::SearchPluginManager() - : m_updateUrl(QString("http://searchplugins.qbittorrent.org/%1/engines/").arg(Utils::Misc::pythonVersion() >= 3 ? "nova3" : "nova")) + : m_updateUrl(QString("http://searchplugins.qbittorrent.org/%1/engines/").arg(Utils::ForeignApps::Python::pythonVersion() >= 3 ? "nova3" : "nova")) { Q_ASSERT(!m_instance); // only one instance is allowed m_instance = this; @@ -322,7 +323,7 @@ QString SearchPluginManager::pluginsLocation() QString SearchPluginManager::engineLocation() { QString folder = "nova"; - if (Utils::Misc::pythonVersion() >= 3) + if (Utils::ForeignApps::Python::pythonVersion() >= 3) folder = "nova3"; const QString location = Utils::Fs::expandPathAbs(specialFolderLocation(SpecialFolder::Data) + folder); QDir locationDir(location); @@ -370,7 +371,7 @@ void SearchPluginManager::updateNova() // create nova directory if necessary QDir searchDir(engineLocation()); - QString novaFolder = Utils::Misc::pythonVersion() >= 3 ? "searchengine/nova3" : "searchengine/nova"; + QString novaFolder = Utils::ForeignApps::Python::pythonVersion() >= 3 ? "searchengine/nova3" : "searchengine/nova"; QFile packageFile(searchDir.absoluteFilePath("__init__.py")); packageFile.open(QIODevice::WriteOnly | QIODevice::Text); packageFile.close(); @@ -436,7 +437,7 @@ void SearchPluginManager::update() QStringList params; params << Utils::Fs::toNativePath(engineLocation() + "/nova2.py"); params << "--capabilities"; - nova.start(Utils::Misc::pythonExecutable(), params, QIODevice::ReadOnly); + nova.start(Utils::ForeignApps::Python::pythonExecutable(), params, QIODevice::ReadOnly); nova.waitForStarted(); nova.waitForFinished(); diff --git a/src/base/utils/foreignapps.cpp b/src/base/utils/foreignapps.cpp new file mode 100644 index 000000000..6a26197b9 --- /dev/null +++ b/src/base/utils/foreignapps.cpp @@ -0,0 +1,133 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2018 Mike Tzou + * Copyright (C) 2006 Christophe Dumez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#include "foreignapps.h" + +#include +#include +#include + +#include "base/logger.h" + +/** + * Detects the python version. + */ +int Utils::ForeignApps::Python::pythonVersion() +{ + static int version = -1; + if (version < 0) { + QString versionComplete = pythonVersionComplete().trimmed(); + QStringList splitted = versionComplete.split('.'); + if (splitted.size() > 1) { + int highVer = splitted.at(0).toInt(); + if ((highVer == 2) || (highVer == 3)) + version = highVer; + } + } + return version; +} + +/** + * Detects the python executable by calling "python --version". + */ +QString Utils::ForeignApps::Python::pythonExecutable() +{ + static QString executable; + if (executable.isEmpty()) { + QProcess pythonProc; +#if defined(Q_OS_UNIX) + /* + * On Unix-Like Systems python2 and python3 should always exist + * http://legacy.python.org/dev/peps/pep-0394/ + */ + pythonProc.start("python3", {"--version"}, QIODevice::ReadOnly); + if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) { + executable = "python3"; + return executable; + } + pythonProc.start("python2", {"--version"}, QIODevice::ReadOnly); + if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) { + executable = "python2"; + return executable; + } +#endif + // Look for "python" in Windows and in UNIX if "python2" and "python3" are + // not detected. + pythonProc.start("python", {"--version"}, QIODevice::ReadOnly); + if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) + executable = "python"; + else + Logger::instance()->addMessage(QCoreApplication::translate("misc", "Python not detected"), Log::INFO); + } + return executable; +} + +/** + * Returns the complete python version + * eg 2.7.9 + * Make sure to have setup python first + */ +QString Utils::ForeignApps::Python::pythonVersionComplete() +{ + static QString version; + if (version.isEmpty()) { + if (pythonExecutable().isEmpty()) + return version; + QProcess pythonProc; + pythonProc.start(pythonExecutable(), {"--version"}, QIODevice::ReadOnly); + if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) { + QByteArray output = pythonProc.readAllStandardOutput(); + if (output.isEmpty()) + output = pythonProc.readAllStandardError(); + + // Software 'Anaconda' installs its own python interpreter + // and `python --version` returns a string like this: + // `Python 3.4.3 :: Anaconda 2.3.0 (64-bit)` + const QList outSplit = output.split(' '); + if (outSplit.size() > 1) { + version = outSplit.at(1).trimmed(); + Logger::instance()->addMessage(QCoreApplication::translate("misc", "Python version: %1").arg(version), Log::INFO); + } + + // If python doesn't report a 3-piece version e.g. 3.6.1 + // then fill the missing pieces with zero + const QStringList verSplit = version.split('.', QString::SkipEmptyParts); + if (verSplit.size() < 3) { + for (int i = verSplit.size(); i < 3; ++i) { + if (version.endsWith('.')) + version.append('0'); + else + version.append(".0"); + } + Logger::instance()->addMessage(QCoreApplication::translate("misc", "Normalized Python version: %1").arg(version), Log::INFO); + } + } + } + return version; +} diff --git a/src/base/utils/foreignapps.h b/src/base/utils/foreignapps.h new file mode 100644 index 000000000..40c2eeddd --- /dev/null +++ b/src/base/utils/foreignapps.h @@ -0,0 +1,45 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2018 Mike Tzou + * Copyright (C) 2006 Christophe Dumez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#pragma once + +#include + +namespace Utils +{ + namespace ForeignApps + { + namespace Python + { + int pythonVersion(); + QString pythonExecutable(); + QString pythonVersionComplete(); + } + } +} diff --git a/src/base/utils/misc.cpp b/src/base/utils/misc.cpp index 000d937db..aa9159bd4 100644 --- a/src/base/utils/misc.cpp +++ b/src/base/utils/misc.cpp @@ -237,105 +237,7 @@ QPoint Utils::Misc::screenCenter(const QWidget *w) QRect r = desktop->availableGeometry(scrn); return QPoint(r.x() + (r.width() - w->frameSize().width()) / 2, r.y() + (r.height() - w->frameSize().height()) / 2); } - -#endif - -/** - * Detects the python version. - */ -int Utils::Misc::pythonVersion() -{ - static int version = -1; - if (version < 0) { - QString versionComplete = pythonVersionComplete().trimmed(); - QStringList splitted = versionComplete.split('.'); - if (splitted.size() > 1) { - int highVer = splitted.at(0).toInt(); - if ((highVer == 2) || (highVer == 3)) - version = highVer; - } - } - return version; -} - -/** - * Detects the python executable by calling "python --version". - */ -QString Utils::Misc::pythonExecutable() -{ - static QString executable; - if (executable.isEmpty()) { - QProcess pythonProc; -#if defined(Q_OS_UNIX) - /* - * On Unix-Like Systems python2 and python3 should always exist - * http://legacy.python.org/dev/peps/pep-0394/ - */ - pythonProc.start("python3", {"--version"}, QIODevice::ReadOnly); - if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) { - executable = "python3"; - return executable; - } - pythonProc.start("python2", {"--version"}, QIODevice::ReadOnly); - if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) { - executable = "python2"; - return executable; - } #endif - // Look for "python" in Windows and in UNIX if "python2" and "python3" are - // not detected. - pythonProc.start("python", {"--version"}, QIODevice::ReadOnly); - if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) - executable = "python"; - else - Logger::instance()->addMessage(QCoreApplication::translate("misc", "Python not detected"), Log::INFO); - } - return executable; -} - -/** - * Returns the complete python version - * eg 2.7.9 - * Make sure to have setup python first - */ -QString Utils::Misc::pythonVersionComplete() -{ - static QString version; - if (version.isEmpty()) { - if (pythonExecutable().isEmpty()) - return version; - QProcess pythonProc; - pythonProc.start(pythonExecutable(), {"--version"}, QIODevice::ReadOnly); - if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) { - QByteArray output = pythonProc.readAllStandardOutput(); - if (output.isEmpty()) - output = pythonProc.readAllStandardError(); - - // Software 'Anaconda' installs its own python interpreter - // and `python --version` returns a string like this: - // `Python 3.4.3 :: Anaconda 2.3.0 (64-bit)` - const QList outSplit = output.split(' '); - if (outSplit.size() > 1) { - version = outSplit.at(1).trimmed(); - Logger::instance()->addMessage(QCoreApplication::translate("misc", "Python version: %1").arg(version), Log::INFO); - } - - // If python doesn't report a 3-piece version e.g. 3.6.1 - // then fill the missing pieces with zero - const QStringList verSplit = version.split('.', QString::SkipEmptyParts); - if (verSplit.size() < 3) { - for (int i = verSplit.size(); i < 3; ++i) { - if (version.endsWith('.')) - version.append('0'); - else - version.append(".0"); - } - Logger::instance()->addMessage(QCoreApplication::translate("misc", "Normalized Python version: %1").arg(version), Log::INFO); - } - } - } - return version; -} QString Utils::Misc::unitString(Utils::Misc::SizeUnit unit) { diff --git a/src/base/utils/misc.h b/src/base/utils/misc.h index 8af5c54fc..028bc146a 100644 --- a/src/base/utils/misc.h +++ b/src/base/utils/misc.h @@ -80,10 +80,6 @@ namespace Utils QString boostVersionString(); QString libtorrentVersionString(); - int pythonVersion(); - QString pythonExecutable(); - QString pythonVersionComplete(); - QString unitString(SizeUnit unit); // return the best user friendly storage unit (B, KiB, MiB, GiB, TiB) diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index a4263b9fe..9bd284725 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -66,6 +66,7 @@ #include "base/rss/rss_folder.h" #include "base/rss/rss_session.h" #include "base/settingsstorage.h" +#include "base/utils/foreignapps.h" #include "base/utils/fs.h" #include "base/utils/misc.h" #include "aboutdialog.h" @@ -1742,7 +1743,7 @@ void MainWindow::on_actionRSSReader_triggered() void MainWindow::on_actionSearchWidget_triggered() { if (!m_hasPython && m_ui->actionSearchWidget->isChecked()) { - int pythonVersion = Utils::Misc::pythonVersion(); + int pythonVersion = Utils::ForeignApps::Python::pythonVersion(); // Check if python is already in PATH if (pythonVersion > 0) @@ -1751,14 +1752,14 @@ void MainWindow::on_actionSearchWidget_triggered() .arg("PATH", qgetenv("PATH").constData()), Log::INFO); #ifdef Q_OS_WIN else if (addPythonPathToEnv()) - pythonVersion = Utils::Misc::pythonVersion(); + pythonVersion = Utils::ForeignApps::Python::pythonVersion(); #endif bool res = false; if ((pythonVersion == 2) || (pythonVersion == 3)) { // Check Python minimum requirement: 2.7.9 / 3.3.0 - QString version = Utils::Misc::pythonVersionComplete(); + QString version = Utils::ForeignApps::Python::pythonVersionComplete(); QStringList splitted = version.split('.'); if (splitted.size() > 2) { int middleVer = splitted.at(1).toInt(); @@ -2085,7 +2086,7 @@ void MainWindow::pythonDownloadSuccess(const QString &url, const QString &filePa m_hasPython = addPythonPathToEnv(); if (m_hasPython) { // Make it print the version to Log - Utils::Misc::pythonVersion(); + Utils::ForeignApps::Python::pythonVersion(); m_ui->actionSearchWidget->setChecked(true); displaySearchTab(true); } diff --git a/src/gui/search/searchwidget.cpp b/src/gui/search/searchwidget.cpp index efac66a5f..45894debd 100644 --- a/src/gui/search/searchwidget.cpp +++ b/src/gui/search/searchwidget.cpp @@ -56,8 +56,8 @@ #include "base/preferences.h" #include "base/search/searchpluginmanager.h" #include "base/search/searchhandler.h" +#include "base/utils/foreignapps.h" #include "base/utils/fs.h" -#include "base/utils/misc.h" #include "addnewtorrentdialog.h" #include "guiiconprovider.h" #include "mainwindow.h" @@ -285,7 +285,7 @@ void SearchWidget::giveFocusToSearchInput() // Function called when we click on search button void SearchWidget::on_searchButton_clicked() { - if (Utils::Misc::pythonVersion() < 0) { + if (Utils::ForeignApps::Python::pythonVersion() < 0) { m_mainWindow->showNotificationBaloon(tr("Search Engine"), tr("Please install Python to use the Search Engine.")); return; }