calamares/src/libcalamares/ProcessJob.cpp
Adriaan de Groot 4ff1a0d5ea [libcalamares] another convenience for running commands
Back targetEnvCommand() with a more general runCommand()
that takes an argument selecting the location to run
the command in. This allows us also to use the same
API for running processes in the host during install,
as we do for running them in the target system.

One reason for this change is wanting to run (user-specified)
commands and independently from the global dontChroot setting,
run those commands in the live system or the target.

This changes the ABI of the DLL, since targetEnvCommand()
is no longer exported. Plugins will need to be recompiled.

 - refactor targetEnvCommand() into more general runCommand().
 - While here, allow host system commands to run even if
   there is no global storage.
 - provide convenience accessors for ProcessResult members
 - Move explanation of process errors out of ProcessJob
   - Move from ProcessJob to ProcessResult, so it can be
     reused outside of ProcessJob (e.g. from ShellProcessJob).
   - Add some convenience functions, too.
2018-01-12 10:32:42 -05:00

147 lines
3.9 KiB
C++

/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
*
* Calamares 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 3 of the License, or
* (at your option) any later version.
*
* Calamares 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 Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ProcessJob.h"
#include "utils/CalamaresUtilsSystem.h"
#include "utils/Logger.h"
#include <QDir>
#include <QProcess>
namespace Calamares {
ProcessJob::ProcessJob( const QString& command,
const QString& workingPath,
bool runInChroot,
int secondsTimeout,
QObject* parent )
: Job( parent )
, m_command( command )
, m_workingPath( workingPath )
, m_runInChroot( runInChroot )
, m_timeoutSec( secondsTimeout )
{}
ProcessJob::~ProcessJob()
{}
QString
ProcessJob::prettyName() const
{
//TODO: show something more meaningful
return tr( "Run command %1 %2" )
.arg( m_command )
.arg( m_runInChroot ? "in chroot." : " ." );
}
QString
ProcessJob::prettyStatusMessage() const
{
return tr( "Running command %1 %2" )
.arg( m_command )
.arg( m_runInChroot ? "in chroot." : " ." );
}
JobResult
ProcessJob::exec()
{
int ec = 0;
QString output;
if ( m_runInChroot )
ec = CalamaresUtils::System::instance()->
targetEnvOutput( m_command,
output,
m_workingPath,
QString(),
m_timeoutSec );
else
ec = callOutput( m_command,
output,
m_workingPath,
QString(),
m_timeoutSec );
return CalamaresUtils::ProcessResult::explainProcess( this, ec, m_command, output, m_timeoutSec );
}
int
ProcessJob::callOutput( const QString& command,
QString& output,
const QString& workingPath,
const QString& stdInput,
int timeoutSec )
{
output.clear();
QProcess process;
process.setProgram( "/bin/sh" );
process.setArguments( { "-c", command } );
process.setProcessChannelMode( QProcess::MergedChannels );
if ( !workingPath.isEmpty() )
{
if ( QDir( workingPath ).exists() )
process.setWorkingDirectory( QDir( workingPath ).absolutePath() );
else
{
cLog() << "Invalid working directory:" << workingPath;
return -3;
}
}
cLog() << "Running" << command;
process.start();
if ( !process.waitForStarted() )
{
cLog() << "Process failed to start" << process.error();
return -2;
}
if ( !stdInput.isEmpty() )
{
process.write( stdInput.toLocal8Bit() );
process.closeWriteChannel();
}
if ( !process.waitForFinished( timeoutSec ? ( timeoutSec * 1000 ) : -1 ) )
{
cLog() << "Timed out. output so far:";
cLog() << process.readAllStandardOutput();
return -4;
}
output.append( QString::fromLocal8Bit( process.readAllStandardOutput() ).trimmed() );
if ( process.exitStatus() == QProcess::CrashExit )
{
cLog() << "Process crashed";
return -1;
}
cLog() << "Finished. Exit code:" << process.exitCode();
return process.exitCode();
}
} // namespace Calamares