some work on nodejs integration

This commit is contained in:
Martin Rotter 2022-02-02 10:06:45 +01:00
parent 87b2fb546a
commit c360450e62
15 changed files with 233 additions and 24 deletions

View File

@ -55,6 +55,8 @@ set(SOURCES
exceptions/networkexception.h
exceptions/scriptexception.cpp
exceptions/scriptexception.h
exceptions/processexception.cpp
exceptions/processexception.h
gui/dialogs/formabout.cpp
gui/dialogs/formabout.h
gui/dialogs/formaddaccount.cpp

View File

@ -3,6 +3,7 @@
#include "core/filterutils.h"
#include "definitions/definitions.h"
#include "exceptions/applicationexception.h"
#include "miscellaneous/iofactory.h"
#include "miscellaneous/textfactory.h"
@ -88,5 +89,10 @@ QDateTime FilterUtils::parseDateTime(const QString& dat) const {
}
QString FilterUtils::runExecutableGetOutput(const QString& executable, const QStringList& arguments) const {
try {
return IOFactory::startProcessGetOutput(executable, arguments);
}
catch (const ApplicationException& ex) {
return ex.message();
}
}

View File

@ -275,7 +275,7 @@
#elif defined(Q_OS_OPENBSD)
#define OS_ID "OpenBSD"
#elif defined(Q_OS_OS2)
#define OS_ID "OS/2"
#define OS_ID "OS2"
#elif defined(Q_OS_OSX)
#define OS_ID "macOS"
#elif defined(Q_OS_WIN)

View File

@ -0,0 +1,14 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#include "exceptions/processexception.h"
ProcessException::ProcessException(int exit_code, QProcess::ExitStatus exit_status, const QString& message)
: ApplicationException(message), m_exitStatus(exit_status), m_exitCode(exit_code) {}
QProcess::ExitStatus ProcessException::exitStatus() const {
return m_exitStatus;
}
int ProcessException::exitCode() const {
return m_exitCode;
}

View File

@ -0,0 +1,22 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#ifndef PROCESSEXCEPTION_H
#define PROCESSEXCEPTION_H
#include "exceptions/applicationexception.h"
#include <QProcess>
class ProcessException : public ApplicationException {
public:
ProcessException(int exit_code, QProcess::ExitStatus exit_status, const QString& message = QString());
QProcess::ExitStatus exitStatus() const;
int exitCode() const;
private:
QProcess::ExitStatus m_exitStatus;
int m_exitCode;
};
#endif // PROCESSEXCEPTION_H

View File

@ -3,9 +3,12 @@
#include "gui/settings/settingsnodejs.h"
#include "definitions/definitions.h"
#include "exceptions/applicationexception.h"
#include "miscellaneous/application.h"
#include "miscellaneous/nodejs.h"
#include <QDir>
SettingsNodejs::SettingsNodejs(Settings* settings, QWidget* parent) : SettingsPanel(settings, parent) {
m_ui.setupUi(this);
@ -22,6 +25,13 @@ SettingsNodejs::SettingsNodejs(Settings* settings, QWidget* parent) : SettingsPa
"it uses subfolder placed in your \"user data\" folder.").arg(APP_NAME),
false);
connect(m_ui.m_tbNodeExecutable->lineEdit(), &BaseLineEdit::textChanged,
this, &SettingsNodejs::testNodejs);
connect(m_ui.m_tbNpmExecutable->lineEdit(), &BaseLineEdit::textChanged,
this, &SettingsNodejs::testNpm);
connect(m_ui.m_tbPackageFolder->lineEdit(), &BaseLineEdit::textChanged,
this, &SettingsNodejs::testPackageFolder);
// FOR ME: npm install --prefix "složka"
// NODE_PATH="složka" node.exe....
}
@ -30,6 +40,45 @@ QString SettingsNodejs::title() const {
return QSL("Node.js");
}
void SettingsNodejs::loadSettings() {}
void SettingsNodejs::loadSettings() {
m_ui.m_tbNodeExecutable->lineEdit()->setText(qApp->nodejs()->nodeJsExecutable());
m_ui.m_tbNpmExecutable->lineEdit()->setText(qApp->nodejs()->npmExecutable());
m_ui.m_tbPackageFolder->lineEdit()->setText(qApp->nodejs()->packageFolder());
}
void SettingsNodejs::saveSettings() {}
void SettingsNodejs::testNodejs() {
try {
QString node_version = qApp->nodejs()->nodejsVersion(m_ui.m_tbNodeExecutable->lineEdit()->text());
m_ui.m_tbNodeExecutable->setStatus(WidgetWithStatus::StatusType::Ok,
tr("Node.js has version %1.").arg(node_version));
}
catch (const ApplicationException& ex) {
m_ui.m_tbNodeExecutable->setStatus(WidgetWithStatus::StatusType::Error,
tr("Node.js: %1.").arg(ex.message()));
}
}
void SettingsNodejs::testNpm() {
try {
QString npm_version = qApp->nodejs()->npmVersion(m_ui.m_tbNpmExecutable->lineEdit()->text());
m_ui.m_tbNpmExecutable->setStatus(WidgetWithStatus::StatusType::Ok,
tr("NPM has version %1.").arg(npm_version));
}
catch (const ApplicationException& ex) {
m_ui.m_tbNpmExecutable->setStatus(WidgetWithStatus::StatusType::Error,
tr("NPM: %1.").arg(ex.message()));
}
}
void SettingsNodejs::testPackageFolder() {
QString folder = qApp->replaceDataUserDataFolderPlaceholder(m_ui.m_tbPackageFolder->lineEdit()->text());
m_ui.m_tbPackageFolder->setStatus(WidgetWithStatus::StatusType::Ok,
QDir().exists(folder)
? tr("Package folder is OK.")
: tr("Package folder will be created!"));
}

View File

@ -17,6 +17,11 @@ class SettingsNodejs : public SettingsPanel {
virtual void loadSettings();
virtual void saveSettings();
private slots:
void testNodejs();
void testNpm();
void testPackageFolder();
private:
Ui::SettingsNodejs m_ui;
};

View File

@ -22,15 +22,18 @@
<property name="text">
<string>Node.js executable</string>
</property>
<property name="buddy">
<cstring>m_tbNodeExecutable</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="LineEditWithStatus" name="widget" native="true"/>
<widget class="LineEditWithStatus" name="m_tbNodeExecutable" native="true"/>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<widget class="QPushButton" name="m_btnNodeExecutable">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -49,15 +52,18 @@
<property name="text">
<string>NPM executable</string>
</property>
<property name="buddy">
<cstring>m_tbNpmExecutable</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="LineEditWithStatus" name="widget_2" native="true"/>
<widget class="LineEditWithStatus" name="m_tbNpmExecutable" native="true"/>
</item>
<item>
<widget class="QPushButton" name="pushButton_2">
<widget class="QPushButton" name="m_btnNpmExecutable">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -76,15 +82,18 @@
<property name="text">
<string>Package folder </string>
</property>
<property name="buddy">
<cstring>m_tbPackageFolder</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="LineEditWithStatus" name="widget_4" native="true"/>
<widget class="LineEditWithStatus" name="m_tbPackageFolder" native="true"/>
</item>
<item>
<widget class="QPushButton" name="pushButton_4">
<widget class="QPushButton" name="m_btnPackageFolder">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>

View File

@ -68,7 +68,7 @@ Application::Application(const QString& id, int& argc, char** argv)
m_database = new DatabaseFactory(this);
m_downloadManager = nullptr;
m_notifications = new NotificationFactory(this);
m_nodejs = new NodeJs(this);
m_nodejs = new NodeJs(m_settings, this);
m_shouldRestart = false;
determineFirstRuns();

View File

@ -4,6 +4,7 @@
#include "definitions/definitions.h"
#include "exceptions/ioexception.h"
#include "exceptions/processexception.h"
#include <QDataStream>
#include <QDir>
@ -113,9 +114,7 @@ QString IOFactory::startProcessGetOutput(const QString& executable,
return proc.readAllStandardOutput();
}
else {
QString err = proc.readAllStandardError().simplified();
return err;
throw ProcessException(proc.exitCode(), proc.exitStatus(), proc.readAllStandardError().simplified());
}
}

View File

@ -2,4 +2,48 @@
#include "miscellaneous/nodejs.h"
NodeJs::NodeJs(QObject* parent) : QObject{parent} {}
#include "exceptions/applicationexception.h"
#include "miscellaneous/iofactory.h"
#include "miscellaneous/settings.h"
#include <QDir>
NodeJs::NodeJs(Settings* settings, QObject* parent) : QObject(parent), m_settings(settings) {}
QString NodeJs::nodeJsExecutable() const {
return QDir::toNativeSeparators(m_settings->value(GROUP(Node), SETTING(Node::NodeJsExecutable)).toString());
}
void NodeJs::setNodeJsExecutable(const QString& exe) const {
m_settings->setValue(GROUP(Node), Node::NodeJsExecutable, exe);
}
QString NodeJs::npmExecutable() const {
return QDir::toNativeSeparators(m_settings->value(GROUP(Node), SETTING(Node::NpmExecutable)).toString());
}
void NodeJs::setNpmExecutable(const QString& exe) const {
m_settings->setValue(GROUP(Node), Node::NpmExecutable, exe);
}
QString NodeJs::packageFolder() const {
return QDir::toNativeSeparators(m_settings->value(GROUP(Node), SETTING(Node::PackageFolder)).toString());
}
void NodeJs::setPackageFolder(const QString& path) {}
QString NodeJs::nodejsVersion(const QString& nodejs_exe) const {
if (nodejs_exe.simplified().isEmpty()) {
throw ApplicationException(tr("file not found"));
}
return IOFactory::startProcessGetOutput(nodejs_exe, { QSL("--version") }).simplified();
}
QString NodeJs::npmVersion(const QString& npm_exe) const {
if (npm_exe.simplified().isEmpty()) {
throw ApplicationException(tr("file not found"));
}
return IOFactory::startProcessGetOutput(npm_exe, { QSL("--version") }).simplified();
}

View File

@ -5,11 +5,28 @@
#include <QObject>
class Settings;
class NodeJs : public QObject {
Q_OBJECT
public:
explicit NodeJs(QObject* parent = nullptr);
explicit NodeJs(Settings* settings, QObject* parent = nullptr);
QString nodeJsExecutable() const;
void setNodeJsExecutable(const QString& exe) const;
QString npmExecutable() const;
void setNpmExecutable(const QString& exe) const;
QString packageFolder() const;
void setPackageFolder(const QString& path);
QString nodejsVersion(const QString& nodejs_exe) const;
QString npmVersion(const QString& npm_exe) const;
private:
Settings* m_settings;
};
#endif // NODEJS_H

View File

@ -15,6 +15,30 @@
DKEY WebEngineAttributes::ID = "web_engine_attributes";
#endif
// Node.js.
DKEY Node::ID = "nodejs";
DKEY Node::NodeJsExecutable = QSL("nodejs_executable_") + OS_ID;
#if defined(Q_OS_WIN) || defined(Q_OS_OS2)
DVALUE(QString) Node::NodeJsExecutableDef = "node.exe";
#else
DVALUE(QString) Node::NodeJsExecutableDef = "node";
#endif
DKEY Node::NpmExecutable = QSL("npm_executable_") + OS_ID;
#if defined(Q_OS_WIN)
DVALUE(QString) Node::NpmExecutableDef = "npm.cmd";
#elif defined(Q_OS_OS2)
DVALUE(QString) Node::NpmExecutableDef = "npm.exe";
#else
DVALUE(QString) Node::NpmExecutableDef = "npm";
#endif
DKEY Node::PackageFolder = QSL("package_folder") + OS_ID;
DVALUE(QString) Node::PackageFolderDef = QSL(USER_DATA_PLACEHOLDER) + "/node-packages-" + OS_ID;
// Cookies.
DKEY Cookies::ID = "cookies";

View File

@ -16,8 +16,8 @@
#include <QNetworkProxy>
#include <QStringList>
#define KEY extern const char*
#define DKEY const char*
#define KEY extern const QString
#define DKEY const QString
#define VALUE(x) extern const x
#define NON_CONST_VALUE(x) extern x
#define DVALUE(x) const x
@ -36,6 +36,19 @@ namespace Cookies {
KEY ID;
}
namespace Node {
KEY ID;
KEY NodeJsExecutable;
VALUE(QString) NodeJsExecutableDef;
KEY NpmExecutable;
VALUE(QString) NpmExecutableDef;
KEY PackageFolder;
VALUE(QString) PackageFolderDef;
}
namespace AdBlock {
KEY ID;

View File

@ -298,6 +298,7 @@ QProcess* AdBlockManager::startServer(int port) {
auto pe = proc->processEnvironment();
if (!pe.contains(QSL("NODE_PATH"))) {
try {
const QString system_node_prefix = IOFactory::startProcessGetOutput(
#if defined(Q_OS_WIN)
QSL("npm.cmd")
@ -311,6 +312,10 @@ QProcess* AdBlockManager::startServer(int port) {
pe.insert(QSL("NODE_PATH"), system_node_prefix.simplified());
}
}
catch (const ApplicationException& ex) {
qWarningNN << LOGSEC_ADBLOCK << "Failed to get NPM root path:" << QUOTE_W_SPACE_DOT(ex.message());
}
}
proc->setProcessEnvironment(pe);
proc->setProcessChannelMode(QProcess::ProcessChannelMode::ForwardedErrorChannel);