From 7e08a58fb50d28ba96aedd5f5cd79a9479b4a0ad Mon Sep 17 00:00:00 2001 From: Christoph Cullmann Date: Mon, 24 Jan 2022 19:07:37 +0000 Subject: [PATCH] improve QProcess handling ensure we take executables from PATH for execution instead possibly from current working directory or the working directory set for the QProcess --- addons/compiler-explorer/compiledbreader.cpp | 4 +- addons/externaltools/katetoolrunner.cpp | 9 +++- addons/gdbplugin/debugview.cpp | 17 +++++++- addons/git-blame/commitfilesview.cpp | 17 +++++--- addons/git-blame/kategitblameplugin.cpp | 8 +++- addons/kate-ctags/gotosymbolmodel.cpp | 15 +++++-- addons/project/comparebranchesview.cpp | 4 +- addons/project/filehistorywidget.cpp | 14 +++++-- addons/project/git/gitutils.cpp | 41 +++++++++++++++---- addons/project/gitwidget.cpp | 19 +++++++-- addons/project/kateprojectindex.cpp | 9 +++- .../kateprojectinfoviewcodeanalysis.cpp | 9 +++- addons/project/kateprojectworker.cpp | 32 +++++++++++---- addons/project/stashdialog.cpp | 20 ++++----- addons/project/stashdialog.h | 2 +- addons/replicode/replicodeview.cpp | 9 ++++ addons/xmlcheck/plugin_katexmlcheck.cpp | 8 ++++ kate/katefileactions.cpp | 17 ++++---- kate/katefileactions.h | 4 +- kate/katemwmodonhddialog.cpp | 6 ++- kate/katemwmodonhddialog.h | 1 + kate/kateviewspace.cpp | 7 +++- shared/gitprocess.h | 16 +++++++- 23 files changed, 217 insertions(+), 71 deletions(-) diff --git a/addons/compiler-explorer/compiledbreader.cpp b/addons/compiler-explorer/compiledbreader.cpp index 74e83638e..ab9ebc483 100644 --- a/addons/compiler-explorer/compiledbreader.cpp +++ b/addons/compiler-explorer/compiledbreader.cpp @@ -21,7 +21,9 @@ std::optional getDotGitPath(const QString &repo) { /* This call is intentionally blocking because we need git path for everything else */ QProcess git; - setupGitProcess(git, repo, {QStringLiteral("rev-parse"), QStringLiteral("--absolute-git-dir")}); + if (!setupGitProcess(git, repo, {QStringLiteral("rev-parse"), QStringLiteral("--absolute-git-dir")})) { + return std::nullopt; + } git.start(QProcess::ReadOnly); if (git.waitForStarted() && git.waitForFinished(-1)) { if (git.exitStatus() != QProcess::NormalExit || git.exitCode() != 0) { diff --git a/addons/externaltools/katetoolrunner.cpp b/addons/externaltools/katetoolrunner.cpp index 10a5d7226..e14940ad7 100644 --- a/addons/externaltools/katetoolrunner.cpp +++ b/addons/externaltools/katetoolrunner.cpp @@ -14,6 +14,7 @@ #include #include #include +#include KateToolRunner::KateToolRunner(std::unique_ptr tool, KTextEditor::View *view, QObject *parent) : QObject(parent) @@ -40,6 +41,12 @@ KateExternalTool *KateToolRunner::tool() const void KateToolRunner::run() { + // always only execute the tool from PATH + const auto fullExecutable = QStandardPaths::findExecutable(m_tool->executable); + if (fullExecutable.isEmpty()) { + return; + } + if (!m_tool->workingDir.isEmpty()) { m_process->setWorkingDirectory(m_tool->workingDir); } else if (m_view) { @@ -72,7 +79,7 @@ void KateToolRunner::run() }); const QStringList args = KShell::splitArgs(m_tool->arguments); - m_process->start(m_tool->executable, args); + m_process->start(fullExecutable, args); } void KateToolRunner::waitForFinished() diff --git a/addons/gdbplugin/debugview.cpp b/addons/gdbplugin/debugview.cpp index 9505daa25..d8c868d7a 100644 --- a/addons/gdbplugin/debugview.cpp +++ b/addons/gdbplugin/debugview.cpp @@ -12,7 +12,9 @@ #include "debugview.h" #include +#include #include +#include #include #include @@ -48,7 +50,20 @@ void DebugView::runDebugger(const GDBTargetConf &conf, const QStringList &ioFifo if (conf.executable.isEmpty()) { return; } + m_targetConf = conf; + + // no chance if no debugger configured + if (m_targetConf.gdbCmd.isEmpty()) { + return; + } + + // only run debugger from PATH or the absolute executable path we specified + const auto fullExecutable = QFileInfo(m_targetConf.gdbCmd).isAbsolute() ? m_targetConf.gdbCmd : QStandardPaths::findExecutable(m_targetConf.gdbCmd); + if (fullExecutable.isEmpty()) { + return; + } + if (ioFifos.size() == 3) { m_ioPipeString = QStringLiteral("< %1 1> %2 2> %3").arg(ioFifos[0], ioFifos[1], ioFifos[2]); } @@ -69,7 +84,7 @@ void DebugView::runDebugger(const GDBTargetConf &conf, const QStringList &ioFifo connect(&m_debugProcess, static_cast(&QProcess::finished), this, &DebugView::slotDebugFinished); - m_debugProcess.start(m_targetConf.gdbCmd, QStringList()); + m_debugProcess.start(fullExecutable, QStringList()); m_nextCommands << QStringLiteral("set pagination off"); m_state = ready; diff --git a/addons/git-blame/commitfilesview.cpp b/addons/git-blame/commitfilesview.cpp index 26e484a4a..667b423b2 100644 --- a/addons/git-blame/commitfilesview.cpp +++ b/addons/git-blame/commitfilesview.cpp @@ -263,7 +263,9 @@ static void createFileTree(QStandardItem *parent, const QString &basePath, const static std::optional getGitCmdOutput(const QString &workDir, const QStringList &args) { QProcess git; - setupGitProcess(git, workDir, args); + if (!setupGitProcess(git, workDir, args)) { + return {}; + } git.start(QProcess::ReadOnly); if (git.waitForStarted() && git.waitForFinished(-1)) { if (git.exitStatus() != QProcess::NormalExit || git.exitCode() != 0) { @@ -365,9 +367,12 @@ void CommitDiffTreeView::openCommit(const QString &hash, const QString &filePath m_commitHash = hash; QProcess *git = new QProcess(this); - setupGitProcess(*git, - QFileInfo(filePath).absolutePath(), - {QStringLiteral("show"), hash, QStringLiteral("--numstat"), QStringLiteral("--pretty=oneline"), QStringLiteral("-z")}); + if (!setupGitProcess(*git, + QFileInfo(filePath).absolutePath(), + {QStringLiteral("show"), hash, QStringLiteral("--numstat"), QStringLiteral("--pretty=oneline"), QStringLiteral("-z")})) { + delete git; + return; + } connect(git, &QProcess::finished, this, [this, git, filePath](int e, QProcess::ExitStatus s) { git->deleteLater(); if (e != 0 || s != QProcess::NormalExit) { @@ -440,7 +445,9 @@ void CommitDiffTreeView::showDiff(const QModelIndex &idx) { const QString file = idx.data(FileItem::Path).toString(); QProcess git; - setupGitProcess(git, m_gitDir, {QStringLiteral("show"), m_commitHash, QStringLiteral("--"), file}); + if (!setupGitProcess(git, m_gitDir, {QStringLiteral("show"), m_commitHash, QStringLiteral("--"), file})) { + return; + } git.start(QProcess::ReadOnly); if (git.waitForStarted() && git.waitForFinished(-1)) { diff --git a/addons/git-blame/kategitblameplugin.cpp b/addons/git-blame/kategitblameplugin.cpp index d0354cc75..ae0f8c106 100644 --- a/addons/git-blame/kategitblameplugin.cpp +++ b/addons/git-blame/kategitblameplugin.cpp @@ -255,7 +255,9 @@ void KateGitBlamePluginView::startBlameProcess(const QUrl &url) QDir dir{url.toLocalFile()}; dir.cdUp(); - setupGitProcess(m_blameInfoProc, dir.absolutePath(), {QStringLiteral("blame"), QStringLiteral("-p"), QStringLiteral("./%1").arg(fileName)}); + if (!setupGitProcess(m_blameInfoProc, dir.absolutePath(), {QStringLiteral("blame"), QStringLiteral("-p"), QStringLiteral("./%1").arg(fileName)})) { + return; + } m_blameInfoProc.start(QIODevice::ReadOnly); m_blameUrl = url; } @@ -270,7 +272,9 @@ void KateGitBlamePluginView::startShowProcess(const QUrl &url, const QString &ha QDir dir{url.toLocalFile()}; dir.cdUp(); - setupGitProcess(m_showProc, dir.absolutePath(), {QStringLiteral("show"), hash, QStringLiteral("--numstat")}); + if (!setupGitProcess(m_showProc, dir.absolutePath(), {QStringLiteral("show"), hash, QStringLiteral("--numstat")})) { + return; + } m_showProc.start(QIODevice::ReadOnly); } diff --git a/addons/kate-ctags/gotosymbolmodel.cpp b/addons/kate-ctags/gotosymbolmodel.cpp index 6c547e379..0c116090f 100644 --- a/addons/kate-ctags/gotosymbolmodel.cpp +++ b/addons/kate-ctags/gotosymbolmodel.cpp @@ -8,6 +8,7 @@ #include #include #include +#include GotoSymbolModel::GotoSymbolModel(QObject *parent) : QAbstractTableModel(parent) @@ -58,16 +59,24 @@ void GotoSymbolModel::refresh(const QString &filePath) m_rows.clear(); endResetModel(); + // only use ctags from PATH + static const auto fullExecutablePath = QStandardPaths::findExecutable(QStringLiteral("ctags")); + if (fullExecutablePath.isEmpty()) { + beginResetModel(); + m_rows.append(SymbolItem{i18n("CTags executable not found."), -1, QIcon()}); + endResetModel(); + return; + } + QProcess p; - p.start(QStringLiteral("ctags"), {QStringLiteral("-x"), QStringLiteral("--_xformat=%{name}%{signature}\t%{kind}\t%{line}"), filePath}); + p.start(fullExecutablePath, {QStringLiteral("-x"), QStringLiteral("--_xformat=%{name}%{signature}\t%{kind}\t%{line}"), filePath}); QByteArray out; if (p.waitForFinished()) { out = p.readAllStandardOutput(); } else { - qWarning() << "Ctags failed"; beginResetModel(); - m_rows.append(SymbolItem{i18n("CTags executable not found."), -1, QIcon()}); + m_rows.append(SymbolItem{i18n("CTags executable failed to execute."), -1, QIcon()}); endResetModel(); return; } diff --git a/addons/project/comparebranchesview.cpp b/addons/project/comparebranchesview.cpp index 48d1d2633..7cf585f66 100644 --- a/addons/project/comparebranchesview.cpp +++ b/addons/project/comparebranchesview.cpp @@ -158,7 +158,9 @@ void CompareBranchesView::showDiff(const QModelIndex &idx) { auto file = idx.data(Qt::UserRole).toString().remove(m_gitDir + QLatin1Char('/')); QProcess git; - setupGitProcess(git, m_gitDir, {QStringLiteral("diff"), QStringLiteral("%1...%2").arg(m_fromBr).arg(m_toBr), QStringLiteral("--"), file}); + if (!setupGitProcess(git, m_gitDir, {QStringLiteral("diff"), QStringLiteral("%1...%2").arg(m_fromBr).arg(m_toBr), QStringLiteral("--"), file})) { + return; + } git.start(QProcess::ReadOnly); if (git.waitForStarted() && git.waitForFinished(-1)) { diff --git a/addons/project/filehistorywidget.cpp b/addons/project/filehistorywidget.cpp index 626016a6b..14857e178 100644 --- a/addons/project/filehistorywidget.cpp +++ b/addons/project/filehistorywidget.cpp @@ -231,9 +231,12 @@ FileHistoryWidget::~FileHistoryWidget() // git log --format=%H%n%aN%n%aE%n%at%n%ct%n%P%n%B --author-date-order void FileHistoryWidget::getFileHistory(const QString &file) { - setupGitProcess(m_git, - QFileInfo(file).absolutePath(), - {QStringLiteral("log"), QStringLiteral("--format=%H%n%aN%n%aE%n%at%n%ct%n%P%n%B"), QStringLiteral("-z"), file}); + if (!setupGitProcess(m_git, + QFileInfo(file).absolutePath(), + {QStringLiteral("log"), QStringLiteral("--format=%H%n%aN%n%aE%n%at%n%ct%n%P%n%B"), QStringLiteral("-z"), file})) { + Q_EMIT errorMessage(i18n("Failed to get file history: git executable not found in PATH"), true); + return; + } connect(&m_git, &QProcess::readyReadStandardOutput, this, [this] { auto commits = parseCommits(m_git.readAllStandardOutput().split(0x00)); @@ -258,7 +261,10 @@ void FileHistoryWidget::itemClicked(const QModelIndex &idx) const auto commit = idx.data(CommitListModel::CommitRole).value(); - setupGitProcess(git, fi.absolutePath(), {QStringLiteral("show"), QString::fromUtf8(commit.hash), QStringLiteral("--"), m_file}); + if (!setupGitProcess(git, fi.absolutePath(), {QStringLiteral("show"), QString::fromUtf8(commit.hash), QStringLiteral("--"), m_file})) { + return; + } + git.start(QProcess::ReadOnly); if (git.waitForStarted() && git.waitForFinished(-1)) { if (git.exitStatus() != QProcess::NormalExit || git.exitCode() != 0) { diff --git a/addons/project/git/gitutils.cpp b/addons/project/git/gitutils.cpp index ea8dd8823..8b494c16f 100644 --- a/addons/project/git/gitutils.cpp +++ b/addons/project/git/gitutils.cpp @@ -15,7 +15,10 @@ bool GitUtils::isGitRepo(const QString &repo) { QProcess git; - setupGitProcess(git, repo, {QStringLiteral("rev-parse"), QStringLiteral("--is-inside-work-tree")}); + if (!setupGitProcess(git, repo, {QStringLiteral("rev-parse"), QStringLiteral("--is-inside-work-tree")})) { + return false; + } + git.start(QProcess::ReadOnly); if (git.waitForStarted() && git.waitForFinished(-1)) { return git.readAll().trimmed() == "true"; @@ -27,7 +30,10 @@ std::optional GitUtils::getDotGitPath(const QString &repo) { /* This call is intentionally blocking because we need git path for everything else */ QProcess git; - setupGitProcess(git, repo, {QStringLiteral("rev-parse"), QStringLiteral("--absolute-git-dir")}); + if (!setupGitProcess(git, repo, {QStringLiteral("rev-parse"), QStringLiteral("--absolute-git-dir")})) { + return std::nullopt; + } + git.start(QProcess::ReadOnly); if (git.waitForStarted() && git.waitForFinished(-1)) { if (git.exitStatus() != QProcess::NormalExit || git.exitCode() != 0) { @@ -57,7 +63,10 @@ QString GitUtils::getCurrentBranchName(const QString &repo) for (int i = 0; i < 3; ++i) { QProcess git; - setupGitProcess(git, repo, argsList[i]); + if (!setupGitProcess(git, repo, argsList[i])) { + return QString(); + } + git.start(QProcess::ReadOnly); if (git.waitForStarted() && git.waitForFinished(-1)) { if (git.exitStatus() == QProcess::NormalExit && git.exitCode() == 0) { @@ -73,7 +82,10 @@ QString GitUtils::getCurrentBranchName(const QString &repo) GitUtils::CheckoutResult GitUtils::checkoutBranch(const QString &repo, const QString &branch) { QProcess git; - setupGitProcess(git, repo, {QStringLiteral("checkout"), branch}); + if (!setupGitProcess(git, repo, {QStringLiteral("checkout"), branch})) { + return CheckoutResult{}; + } + git.start(QProcess::ReadOnly); CheckoutResult res; res.branch = branch; @@ -91,7 +103,11 @@ GitUtils::CheckoutResult GitUtils::checkoutNewBranch(const QString &repo, const if (!fromBranch.isEmpty()) { args.append(fromBranch); } - setupGitProcess(git, repo, args); + + if (!setupGitProcess(git, repo, args)) { + return CheckoutResult{}; + } + git.start(QProcess::ReadOnly); CheckoutResult res; res.branch = newBranch; @@ -132,7 +148,10 @@ QVector GitUtils::getAllBranchesAndTags(const QString &repo, R args.append(QStringLiteral("--sort=-taggerdate")); } - setupGitProcess(git, repo, args); + if (!setupGitProcess(git, repo, args)) { + return {}; + } + git.start(QProcess::ReadOnly); QVector branches; if (git.waitForStarted() && git.waitForFinished(-1)) { @@ -166,7 +185,10 @@ std::pair GitUtils::getLastCommitMessage(const QString &repo) { // git log -1 --pretty=%B QProcess git; - setupGitProcess(git, repo, {QStringLiteral("log"), QStringLiteral("-1"), QStringLiteral("--pretty=%B")}); + if (!setupGitProcess(git, repo, {QStringLiteral("log"), QStringLiteral("-1"), QStringLiteral("--pretty=%B")})) { + return {}; + } + git.start(QProcess::ReadOnly); if (git.waitForStarted() && git.waitForFinished(-1)) { if (git.exitCode() != 0 || git.exitStatus() != QProcess::NormalExit) { @@ -197,7 +219,10 @@ GitUtils::Result GitUtils::deleteBranches(const QStringList &branches, const QSt args << branches; QProcess git; - setupGitProcess(git, repo, args); + if (!setupGitProcess(git, repo, args)) { + return {}; + } + git.start(QProcess::ReadOnly); if (git.waitForStarted() && git.waitForFinished(-1)) { QString out = QString::fromLatin1(git.readAllStandardError()) + QString::fromLatin1(git.readAllStandardOutput()); diff --git a/addons/project/gitwidget.cpp b/addons/project/gitwidget.cpp index 2b19781c0..77499dad8 100644 --- a/addons/project/gitwidget.cpp +++ b/addons/project/gitwidget.cpp @@ -514,8 +514,9 @@ void GitWidget::launchExternalDiffTool(const QString &file, bool staged) args.append(file); QProcess git; - setupGitProcess(git, m_gitPath, args); - git.startDetached(); + if (setupGitProcess(git, m_gitPath, args)) { + git.startDetached(); + } } void GitWidget::commitChanges(const QString &msg, const QString &desc, bool signOff, bool amend) @@ -745,7 +746,12 @@ void GitWidget::branchCompareFiles(const QString &from, const QString &to) auto args = QStringList{QStringLiteral("diff"), QStringLiteral("%1...%2").arg(from).arg(to), QStringLiteral("--name-status")}; QProcess git; - setupGitProcess(git, m_gitPath, args); + + // early out if we can't find git + if (!setupGitProcess(git, m_gitPath, args)) { + return; + } + git.start(QProcess::ReadOnly); if (git.waitForStarted() && git.waitForFinished(-1)) { if (git.exitStatus() != QProcess::NormalExit || git.exitCode() != 0) { @@ -767,7 +773,12 @@ void GitWidget::branchCompareFiles(const QString &from, const QString &to) // get --num-stat args = QStringList{QStringLiteral("diff"), QStringLiteral("%1...%2").arg(from).arg(to), QStringLiteral("--numstat"), QStringLiteral("-z")}; - setupGitProcess(git, m_gitPath, args); + + // early out if we can't find git + if (!setupGitProcess(git, m_gitPath, args)) { + return; + } + git.start(QProcess::ReadOnly); if (git.waitForStarted() && git.waitForFinished(-1)) { if (git.exitStatus() != QProcess::NormalExit || git.exitCode() != 0) { diff --git a/addons/project/kateprojectindex.cpp b/addons/project/kateprojectindex.cpp index a7d9ec9c1..9fc5b64cb 100644 --- a/addons/project/kateprojectindex.cpp +++ b/addons/project/kateprojectindex.cpp @@ -9,6 +9,7 @@ #include #include +#include /** * include ctags reading @@ -73,6 +74,12 @@ void KateProjectIndex::loadCtags(const QStringList &files, const QVariantMap &ct */ m_ctagsIndexFile->close(); + // only use ctags from PATH + static const auto fullExecutablePath = QStandardPaths::findExecutable(QStringLiteral("ctags")); + if (fullExecutablePath.isEmpty()) { + return; + } + /** * try to run ctags for all files in this project * output to our ctags index file @@ -85,7 +92,7 @@ void KateProjectIndex::loadCtags(const QStringList &files, const QVariantMap &ct for (const QVariant &optVariant : opts) { args << optVariant.toString(); } - ctags.start(QStringLiteral("ctags"), args); + ctags.start(fullExecutablePath, args); if (!ctags.waitForStarted()) { return; } diff --git a/addons/project/kateprojectinfoviewcodeanalysis.cpp b/addons/project/kateprojectinfoviewcodeanalysis.cpp index 21cd26a84..23b82c45e 100644 --- a/addons/project/kateprojectinfoviewcodeanalysis.cpp +++ b/addons/project/kateprojectinfoviewcodeanalysis.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -134,14 +135,18 @@ void KateProjectInfoViewCodeAnalysis::slotStartStopClicked() connect(m_analyzer, &QProcess::readyRead, this, &KateProjectInfoViewCodeAnalysis::slotReadyRead); connect(m_analyzer, static_cast(&QProcess::finished), this, &KateProjectInfoViewCodeAnalysis::finished); - m_analyzer->start(m_analysisTool->path(), m_analysisTool->arguments()); + // ensure we only run the code analyzer from PATH + const QString fullExecutable = QStandardPaths::findExecutable(m_analysisTool->path()); + if (!fullExecutable.isEmpty()) { + m_analyzer->start(fullExecutable, m_analysisTool->arguments()); + } if (m_messageWidget) { delete m_messageWidget; m_messageWidget = nullptr; } - if (!m_analyzer->waitForStarted()) { + if (fullExecutable.isEmpty() || !m_analyzer->waitForStarted()) { m_messageWidget = new KMessageWidget(this); m_messageWidget->setCloseButtonVisible(true); m_messageWidget->setMessageType(KMessageWidget::Warning); diff --git a/addons/project/kateprojectworker.cpp b/addons/project/kateprojectworker.cpp index d1979d1ec..831dae89b 100644 --- a/addons/project/kateprojectworker.cpp +++ b/addons/project/kateprojectworker.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -442,10 +443,12 @@ QVector KateProjectWorker::filesFromGit(const QDir &dir, bool recursive QVector KateProjectWorker::gitFiles(const QDir &dir, bool recursive, const QStringList &args) { + QVector files; QProcess git; - setupGitProcess(git, dir.absolutePath(), args); + if (!setupGitProcess(git, dir.absolutePath(), args)) { + return files; + } git.start(QProcess::ReadOnly); - QVector files; if (!git.waitForStarted() || !git.waitForFinished(-1)) { return files; } @@ -466,13 +469,18 @@ QVector KateProjectWorker::gitFiles(const QDir &dir, bool recursive, co QVector KateProjectWorker::filesFromMercurial(const QDir &dir, bool recursive) { + // only use version control from PATH QVector files; + static const auto fullExecutablePath = QStandardPaths::findExecutable(QStringLiteral("hg")); + if (fullExecutablePath.isEmpty()) { + return files; + } QProcess hg; hg.setWorkingDirectory(dir.absolutePath()); QStringList args; args << QStringLiteral("manifest") << QStringLiteral("."); - hg.start(QStringLiteral("hg"), args, QProcess::ReadOnly); + hg.start(fullExecutablePath, args, QProcess::ReadOnly); if (!hg.waitForStarted() || !hg.waitForFinished(-1)) { return files; } @@ -493,7 +501,12 @@ QVector KateProjectWorker::filesFromMercurial(const QDir &dir, bool rec QVector KateProjectWorker::filesFromSubversion(const QDir &dir, bool recursive) { + // only use version control from PATH QVector files; + static const auto fullExecutablePath = QStandardPaths::findExecutable(QStringLiteral("svn")); + if (fullExecutablePath.isEmpty()) { + return files; + } QProcess svn; svn.setWorkingDirectory(dir.absolutePath()); @@ -504,7 +517,7 @@ QVector KateProjectWorker::filesFromSubversion(const QDir &dir, bool re } else { args << QStringLiteral("--depth=files"); } - svn.start(QStringLiteral("svn"), args, QProcess::ReadOnly); + svn.start(fullExecutablePath, args, QProcess::ReadOnly); if (!svn.waitForStarted() || !svn.waitForFinished(-1)) { return files; } @@ -555,18 +568,21 @@ QVector KateProjectWorker::filesFromSubversion(const QDir &dir, bool re QVector KateProjectWorker::filesFromDarcs(const QDir &dir, bool recursive) { + // only use version control from PATH QVector files; + static const auto fullExecutablePath = QStandardPaths::findExecutable(QStringLiteral("darcs")); + if (fullExecutablePath.isEmpty()) { + return files; + } - const QString cmd = QStringLiteral("darcs"); QString root; - { QProcess darcs; darcs.setWorkingDirectory(dir.absolutePath()); QStringList args; args << QStringLiteral("list") << QStringLiteral("repo"); - darcs.start(cmd, args, QProcess::ReadOnly); + darcs.start(fullExecutablePath, args, QProcess::ReadOnly); if (!darcs.waitForStarted() || !darcs.waitForFinished(-1)) { return files; @@ -590,7 +606,7 @@ QVector KateProjectWorker::filesFromDarcs(const QDir &dir, bool recursi darcs.setWorkingDirectory(dir.absolutePath()); args << QStringLiteral("list") << QStringLiteral("files") << QStringLiteral("--no-directories") << QStringLiteral("--pending"); - darcs.start(cmd, args, QProcess::ReadOnly); + darcs.start(fullExecutablePath, args, QProcess::ReadOnly); if (!darcs.waitForStarted() || !darcs.waitForFinished(-1)) { return files; diff --git a/addons/project/stashdialog.cpp b/addons/project/stashdialog.cpp index c623182a8..bddedf709 100644 --- a/addons/project/stashdialog.cpp +++ b/addons/project/stashdialog.cpp @@ -32,6 +32,8 @@ #include +#include + constexpr int StashIndexRole = Qt::UserRole + 2; class StashFilterModel final : public QSortFilterProxyModel @@ -218,11 +220,10 @@ void StashDialog::slotReturnPressed() hide(); } -QProcess *StashDialog::gitp() +QProcess *StashDialog::gitp(const QStringList &arguments) { auto git = new QProcess(this); - git->setProgram(QStringLiteral("git")); - git->setWorkingDirectory(m_gitPath); + setupGitProcess(*git, m_gitPath, arguments); return git; } @@ -242,7 +243,7 @@ void StashDialog::stash(bool keepIndex, bool includeUntracked) args.append(m_lineEdit.text()); } - auto git = gitp(); + auto git = gitp(args); connect(git, &QProcess::finished, this, [this, git](int exitCode, QProcess::ExitStatus es) { if (es != QProcess::NormalExit || exitCode != 0) { qWarning() << git->errorString(); @@ -253,14 +254,12 @@ void StashDialog::stash(bool keepIndex, bool includeUntracked) Q_EMIT done(); git->deleteLater(); }); - git->setArguments(args); git->start(QProcess::ReadOnly); } void StashDialog::getStashList() { - auto git = gitp(); - git->setArguments({QStringLiteral("stash"), QStringLiteral("list")}); + auto git = gitp({QStringLiteral("stash"), QStringLiteral("list")}); git->start(QProcess::ReadOnly); QList stashList; @@ -293,11 +292,11 @@ void StashDialog::getStashList() void StashDialog::popStash(const QByteArray &index, const QString &command) { - auto git = gitp(); QStringList args{QStringLiteral("stash"), command}; if (!index.isEmpty()) { args.append(QString::fromUtf8(index)); } + auto git = gitp(args); connect(git, &QProcess::finished, this, [this, command, git](int exitCode, QProcess::ExitStatus es) { if (es != QProcess::NormalExit || exitCode != 0) { @@ -320,7 +319,6 @@ void StashDialog::popStash(const QByteArray &index, const QString &command) Q_EMIT done(); git->deleteLater(); }); - git->setArguments(args); git->start(QProcess::ReadOnly); } @@ -339,9 +337,8 @@ void StashDialog::showStash(const QByteArray &index) if (index.isEmpty()) { return; } - auto git = gitp(); - QStringList args{QStringLiteral("stash"), QStringLiteral("show"), QStringLiteral("-p"), QString::fromUtf8(index)}; + auto git = gitp({QStringLiteral("stash"), QStringLiteral("show"), QStringLiteral("-p"), QString::fromUtf8(index)}); connect(git, &QProcess::finished, this, [this, git](int exitCode, QProcess::ExitStatus es) { if (es != QProcess::NormalExit || exitCode != 0) { @@ -353,6 +350,5 @@ void StashDialog::showStash(const QByteArray &index) git->deleteLater(); }); - git->setArguments(args); git->start(QProcess::ReadOnly); } diff --git a/addons/project/stashdialog.h b/addons/project/stashdialog.h index a18d42ab9..417690757 100644 --- a/addons/project/stashdialog.h +++ b/addons/project/stashdialog.h @@ -56,7 +56,7 @@ protected Q_SLOTS: void slotReturnPressed() override; private: - QProcess *gitp(); + QProcess *gitp(const QStringList &arguments); void stash(bool keepIndex, bool includeUntracked); void getStashList(); void popStash(const QByteArray &index, const QString &command = QStringLiteral("pop")); diff --git a/addons/replicode/replicodeview.cpp b/addons/replicode/replicodeview.cpp index 0199f46ce..7f70ee1ea 100644 --- a/addons/replicode/replicodeview.cpp +++ b/addons/replicode/replicodeview.cpp @@ -8,7 +8,9 @@ #include "replicodeconfig.h" #include "replicodesettings.h" + #include +#include #include #include @@ -116,7 +118,14 @@ void ReplicodeView::runReplicode() } KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("Replicode")); + QString executorPath = config.readEntry("replicodePath", QString()); + + // ensure we only call replicode from PATH if not given as absolute path already + if (!executorPath.isEmpty() && !QFileInfo(executorPath).isAbsolute()) { + executorPath = QStandardPaths::findExecutable(executorPath); + } + if (executorPath.isEmpty()) { QMessageBox::warning(m_mainWindow->window(), i18nc("@title:window", "Replicode Executable Not Found"), diff --git a/addons/xmlcheck/plugin_katexmlcheck.cpp b/addons/xmlcheck/plugin_katexmlcheck.cpp index f1d52f3a7..3971550cd 100644 --- a/addons/xmlcheck/plugin_katexmlcheck.cpp +++ b/addons/xmlcheck/plugin_katexmlcheck.cpp @@ -304,10 +304,18 @@ bool PluginKateXMLCheckView::slotValidate() s << kv->document()->text(); s.flush(); + // ensure we only execute xmllint from PATH or application package QString exe = QStandardPaths::findExecutable(QStringLiteral("xmllint")); if (exe.isEmpty()) { exe = QStandardPaths::locate(QStandardPaths::ApplicationsLocation, QStringLiteral("xmllint")); } + if (exe.isEmpty()) { + KMessageBox::error(nullptr, + i18n("Error: Failed to find xmllint. Please make " + "sure that xmllint is installed. It is part of libxml2.")); + return false; + } + // qDebug() << "exe=" < #include #include +#include #include void KateFileActions::copyFilePathToClipboard(KTextEditor::Document *doc) @@ -137,17 +138,13 @@ void KateFileActions::deleteDocumentFile(QWidget *parent, KTextEditor::Document } } -QStringList KateFileActions::supportedDiffTools() +QVector> KateFileActions::supportedDiffTools() { - // LATER: check for program existence and set some boolean value accordingly - // Can this be even done in an easy way when we don't use the absolute path to the executable? - // See https://stackoverflow.com/questions/42444055/how-to-check-if-a-program-exists-in-path-using-qt - - QStringList resultList; - resultList.push_back(QStringLiteral("kdiff3")); - resultList.push_back(QStringLiteral("kompare")); - resultList.push_back(QStringLiteral("meld")); - + // query once if the tools are there in the path and store that + // we will disable the actions for the tools not found + static QVector> resultList{{QStringLiteral("kdiff3"), QStandardPaths::findExecutable(QStringLiteral("kdiff3"))}, + {QStringLiteral("kompare"), QStandardPaths::findExecutable(QStringLiteral("kompare"))}, + {QStringLiteral("meld"), QStandardPaths::findExecutable(QStringLiteral("meld"))}}; return resultList; } diff --git a/kate/katefileactions.h b/kate/katefileactions.h index 524d81097..77cc5b0bf 100644 --- a/kate/katefileactions.h +++ b/kate/katefileactions.h @@ -51,9 +51,9 @@ void openFilePropertiesDialog(KTextEditor::Document *document); void deleteDocumentFile(QWidget *parent, KTextEditor::Document *document); /** - * @returns a list of supported diff tools (names of the executables) + * @returns a list of supported diff tools (names of the executables + paths to them, empty if not found in PATH) */ -QStringList supportedDiffTools(); +QVector> supportedDiffTools(); /** * Runs an external program to compare the underlying files of two given documents. diff --git a/kate/katemwmodonhddialog.cpp b/kate/katemwmodonhddialog.cpp index e0041d858..d7c79e4d4 100644 --- a/kate/katemwmodonhddialog.cpp +++ b/kate/katemwmodonhddialog.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,7 @@ public: KateMwModOnHdDialog::KateMwModOnHdDialog(DocVector docs, QWidget *parent, const char *name) : QDialog(parent) + , m_fullDiffPath(QStandardPaths::findExecutable(QStringLiteral("diff"))) , m_proc(nullptr) , m_diffFile(nullptr) , m_blockAddDocument(false) @@ -108,6 +110,7 @@ KateMwModOnHdDialog::KateMwModOnHdDialog(DocVector docs, QWidget *parent, const "file for the selected document, and shows the difference with the " "default application. Requires diff(1).")); hb->addWidget(btnDiff); + btnDiff->setEnabled(!m_fullDiffPath.isEmpty()); connect(btnDiff, &QPushButton::clicked, this, &KateMwModOnHdDialog::slotDiff); // Dialog buttons @@ -288,9 +291,10 @@ void KateMwModOnHdDialog::slotDiff() m_diffFile->open(); // Start a KProcess that creates a diff + // We use the full path to don't launch some random "diff" in current working directory m_proc = new KProcess(this); m_proc->setOutputChannelMode(KProcess::MergedChannels); - *m_proc << QStringLiteral("diff") << QStringLiteral("-ub") << QStringLiteral("-") << doc->url().toLocalFile(); + *m_proc << m_fullDiffPath << QStringLiteral("-ub") << QStringLiteral("-") << doc->url().toLocalFile(); connect(m_proc, &KProcess::readyRead, this, &KateMwModOnHdDialog::slotDataAvailable); connect(m_proc, static_cast(&KProcess::finished), this, &KateMwModOnHdDialog::slotPDone); diff --git a/kate/katemwmodonhddialog.h b/kate/katemwmodonhddialog.h index 11c09eab7..6fa245726 100644 --- a/kate/katemwmodonhddialog.h +++ b/kate/katemwmodonhddialog.h @@ -51,6 +51,7 @@ private: class QTreeWidget *twDocuments; class QDialogButtonBox *dlgButtons; class QPushButton *btnDiff; + QString m_fullDiffPath; KProcess *m_proc; QTemporaryFile *m_diffFile; QStringList m_stateTexts; diff --git a/kate/kateviewspace.cpp b/kate/kateviewspace.cpp index dba2fb973..af3bb8d34 100644 --- a/kate/kateviewspace.cpp +++ b/kate/kateviewspace.cpp @@ -678,8 +678,11 @@ void KateViewSpace::showContextMenu(int idx, const QPoint &globalPos) if (mCompareWithActive->isEnabled()) { for (auto &&diffTool : KateFileActions::supportedDiffTools()) { - QAction *compareAction = mCompareWithActive->addAction(diffTool); - compareAction->setData(diffTool); + QAction *compareAction = mCompareWithActive->addAction(diffTool.first); + + // we use the full path to safely execute the tool, disable action if no full path => tool not found + compareAction->setData(diffTool.second); + compareAction->setEnabled(!diffTool.second.isEmpty()); } } diff --git a/shared/gitprocess.h b/shared/gitprocess.h index 47b98b696..b0d79fac6 100644 --- a/shared/gitprocess.h +++ b/shared/gitprocess.h @@ -7,6 +7,7 @@ #pragma once #include +#include /** * small helper function to setup a QProcess based "git" command. @@ -17,10 +18,20 @@ * @param process process to setup for git * @param workingDirectory working directory to use for process * @param arguments arguments to pass to git + * @return could set setup the process or did that fail, e.g. because the git executable is not available? */ -inline void setupGitProcess(QProcess &process, const QString &workingDirectory, const QStringList &arguments) +inline bool setupGitProcess(QProcess &process, const QString &workingDirectory, const QStringList &arguments) { - process.setProgram(QStringLiteral("git")); + // only use git from PATH + static const auto gitExecutable = QStandardPaths::findExecutable(QStringLiteral("git")); + if (gitExecutable.isEmpty()) { + // ensure we have no valid QProcess setup + process.setProgram(QString()); + return false; + } + + // setup program and arguments, ensure we do run git in the right working directory + process.setProgram(gitExecutable); process.setWorkingDirectory(workingDirectory); process.setArguments(arguments); @@ -37,4 +48,5 @@ inline void setupGitProcess(QProcess &process, const QString &workingDirectory, QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert(QStringLiteral("GIT_OPTIONAL_LOCKS"), QStringLiteral("0")); process.setProcessEnvironment(env); + return true; } -- GitLab