AbstractProcessStep: Provide API for running TaskTree

As an alternative to calling AbstractProcessStep::doRun().

Change-Id: I53142b7470a3e2aed0e219300fb3e0b4621630db
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Jarek Kobus
2022-12-06 06:49:30 +01:00
parent c022f53b88
commit acd55c0677
2 changed files with 76 additions and 29 deletions

View File

@@ -75,6 +75,7 @@ public:
AbstractProcessStep *q; AbstractProcessStep *q;
std::unique_ptr<QtcProcess> m_process; std::unique_ptr<QtcProcess> m_process;
std::unique_ptr<TaskTree> m_taskTree;
ProcessParameters m_param; ProcessParameters m_param;
ProcessParameters *m_displayedParams = &m_param; ProcessParameters *m_displayedParams = &m_param;
std::function<CommandLine()> m_commandLineProvider; std::function<CommandLine()> m_commandLineProvider;
@@ -146,7 +147,7 @@ void AbstractProcessStep::setWorkingDirectoryProvider(const std::function<FilePa
bool AbstractProcessStep::init() bool AbstractProcessStep::init()
{ {
if (d->m_process) if (d->m_process || d->m_taskTree)
return false; return false;
if (!setupProcessParameters(processParameters())) if (!setupProcessParameters(processParameters()))
@@ -168,6 +169,24 @@ void AbstractProcessStep::setupOutputFormatter(OutputFormatter *formatter)
*/ */
void AbstractProcessStep::doRun() void AbstractProcessStep::doRun()
{
if (!checkWorkingDirectory())
return;
if (!d->m_param.effectiveCommand().isExecutableFile()) {
processStartupFailed();
return;
}
setupStreams();
d->m_process.reset(new QtcProcess);
setupProcess(d->m_process.get());
connect(d->m_process.get(), &QtcProcess::done, this, &AbstractProcessStep::handleProcessDone);
d->m_process->start();
}
bool AbstractProcessStep::checkWorkingDirectory()
{ {
const FilePath wd = d->m_param.effectiveWorkingDirectory(); const FilePath wd = d->m_param.effectiveWorkingDirectory();
if (!wd.exists()) { if (!wd.exists()) {
@@ -175,53 +194,67 @@ void AbstractProcessStep::doRun()
emit addOutput(tr("Could not create directory \"%1\"").arg(wd.toUserOutput()), emit addOutput(tr("Could not create directory \"%1\"").arg(wd.toUserOutput()),
OutputFormat::ErrorMessage); OutputFormat::ErrorMessage);
finish(ProcessResult::StartFailed); finish(ProcessResult::StartFailed);
return; return false;
} }
} }
return true;
}
const CommandLine effectiveCommand(d->m_param.effectiveCommand(), void AbstractProcessStep::setupStreams()
d->m_param.effectiveArguments(), {
CommandLine::Raw);
if (!effectiveCommand.executable().isExecutableFile()) {
processStartupFailed();
return;
}
d->stdoutStream = std::make_unique<QTextDecoder>(buildEnvironment().hasKey("VSLANG") d->stdoutStream = std::make_unique<QTextDecoder>(buildEnvironment().hasKey("VSLANG")
? QTextCodec::codecForName("UTF-8") : QTextCodec::codecForLocale()); ? QTextCodec::codecForName("UTF-8") : QTextCodec::codecForLocale());
d->stderrStream = std::make_unique<QTextDecoder>(QTextCodec::codecForLocale()); d->stderrStream = std::make_unique<QTextDecoder>(QTextCodec::codecForLocale());
}
d->m_process.reset(new QtcProcess); void AbstractProcessStep::setupProcess(QtcProcess *process)
d->m_process->setUseCtrlCStub(HostOsInfo::isWindowsHost()); {
d->m_process->setWorkingDirectory(wd); process->setUseCtrlCStub(HostOsInfo::isWindowsHost());
process->setWorkingDirectory(d->m_param.effectiveWorkingDirectory());
// Enforce PWD in the environment because some build tools use that. // Enforce PWD in the environment because some build tools use that.
// PWD can be different from getcwd in case of symbolic links (getcwd resolves symlinks). // PWD can be different from getcwd in case of symbolic links (getcwd resolves symlinks).
// For example Clang uses PWD for paths in debug info, see QTCREATORBUG-23788 // For example Clang uses PWD for paths in debug info, see QTCREATORBUG-23788
Environment envWithPwd = d->m_param.environment(); Environment envWithPwd = d->m_param.environment();
envWithPwd.set("PWD", d->m_process->workingDirectory().path()); envWithPwd.set("PWD", process->workingDirectory().path());
d->m_process->setEnvironment(envWithPwd); process->setEnvironment(envWithPwd);
d->m_process->setCommand(effectiveCommand); process->setCommand({d->m_param.effectiveCommand(), d->m_param.effectiveArguments(),
CommandLine::Raw});
if (d->m_lowPriority && ProjectExplorerPlugin::projectExplorerSettings().lowBuildPriority) if (d->m_lowPriority && ProjectExplorerPlugin::projectExplorerSettings().lowBuildPriority)
d->m_process->setLowPriority(); process->setLowPriority();
connect(d->m_process.get(), &QtcProcess::readyReadStandardOutput, this, [this] { connect(process, &QtcProcess::readyReadStandardOutput, this, [this, process] {
emit addOutput(d->stdoutStream->toUnicode(d->m_process->readAllStandardOutput()), emit addOutput(d->stdoutStream->toUnicode(process->readAllStandardOutput()),
OutputFormat::Stdout, DontAppendNewline); OutputFormat::Stdout, DontAppendNewline);
}); });
connect(d->m_process.get(), &QtcProcess::readyReadStandardError, this, [this] { connect(process, &QtcProcess::readyReadStandardError, this, [this, process] {
emit addOutput(d->stderrStream->toUnicode(d->m_process->readAllStandardError()), emit addOutput(d->stderrStream->toUnicode(process->readAllStandardError()),
OutputFormat::Stderr, DontAppendNewline); OutputFormat::Stderr, DontAppendNewline);
}); });
connect(d->m_process.get(), &QtcProcess::started, this, [this] { connect(process, &QtcProcess::started, this, [this] {
ProcessParameters *params = displayedParameters(); ProcessParameters *params = displayedParameters();
emit addOutput(tr("Starting: \"%1\" %2") emit addOutput(tr("Starting: \"%1\" %2")
.arg(params->effectiveCommand().toUserOutput(), params->prettyArguments()), .arg(params->effectiveCommand().toUserOutput(), params->prettyArguments()),
OutputFormat::NormalMessage); OutputFormat::NormalMessage);
}); });
connect(d->m_process.get(), &QtcProcess::done, }
this, &AbstractProcessStep::handleProcessDone);
d->m_process->start(); void AbstractProcessStep::runTaskTree(const Tasking::Group &recipe)
{
setupStreams();
d->m_taskTree.reset(new TaskTree(recipe));
connect(d->m_taskTree.get(), &TaskTree::progressValueChanged, this, [this](int value) {
emit progress(qRound(double(value) * 100 / d->m_taskTree->progressMaximum()), {});
});
connect(d->m_taskTree.get(), &TaskTree::done, this, [this] {
emit finished(true);
d->m_taskTree.release()->deleteLater();
});
connect(d->m_taskTree.get(), &TaskTree::errorOccurred, this, [this] {
emit finished(false);
d->m_taskTree.release()->deleteLater();
});
d->m_taskTree->start();
} }
void AbstractProcessStep::setLowPriority() void AbstractProcessStep::setLowPriority()
@@ -231,7 +264,14 @@ void AbstractProcessStep::setLowPriority()
void AbstractProcessStep::doCancel() void AbstractProcessStep::doCancel()
{ {
d->cleanUp(-1, QProcess::CrashExit); if (d->m_process) {
d->cleanUp(-1, QProcess::CrashExit);
}
if (d->m_taskTree) {
d->m_taskTree.reset();
emit addOutput(tr("The build step was ended forcefully."), OutputFormat::ErrorMessage);
emit finished(false);
}
} }
ProcessParameters *AbstractProcessStep::processParameters() ProcessParameters *AbstractProcessStep::processParameters()
@@ -311,7 +351,7 @@ void AbstractProcessStep::processStartupFailed()
.arg(params->effectiveCommand().toUserOutput(), params->prettyArguments()), .arg(params->effectiveCommand().toUserOutput(), params->prettyArguments()),
OutputFormat::ErrorMessage); OutputFormat::ErrorMessage);
QString err = d->m_process ? d->m_process->errorString() : QString(); const QString err = d->m_process ? d->m_process->errorString() : QString();
if (!err.isEmpty()) if (!err.isEmpty())
emit addOutput(err, OutputFormat::ErrorMessage); emit addOutput(err, OutputFormat::ErrorMessage);
finish(ProcessResult::StartFailed); finish(ProcessResult::StartFailed);

View File

@@ -10,6 +10,8 @@
namespace Utils { namespace Utils {
class CommandLine; class CommandLine;
enum class ProcessResult; enum class ProcessResult;
class QtcProcess;
namespace Tasking { class Group; }
} }
namespace ProjectExplorer { namespace ProjectExplorer {
@@ -48,9 +50,14 @@ protected:
virtual void finish(Utils::ProcessResult result); virtual void finish(Utils::ProcessResult result);
private: bool checkWorkingDirectory();
void processStartupFailed(); void setupProcess(Utils::QtcProcess *process);
void runTaskTree(const Utils::Tasking::Group &recipe);
ProcessParameters *displayedParameters() const; ProcessParameters *displayedParameters() const;
private:
void setupStreams();
void processStartupFailed();
void handleProcessDone(); void handleProcessDone();
class Private; class Private;