forked from qt-creator/qt-creator
Utils: Return a bit more data from DeviceShell::runInShell
Pass on stderr data and exit code to the caller, it's typically in a better condition to handle errors. Use it to notify the user about non-available 'find' arguments and fix the fallback to ls-based operation. Change-Id: I535535de2ffa09cad1dd6e9b07eb69f807dbae2f Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io> Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -174,31 +174,11 @@ DeviceShell::~DeviceShell()
|
|||||||
* \param stdInData Data to send to the stdin of the command
|
* \param stdInData Data to send to the stdin of the command
|
||||||
* \return true if the command finished with EXIT_SUCCESS(0)
|
* \return true if the command finished with EXIT_SUCCESS(0)
|
||||||
*
|
*
|
||||||
* Runs the cmd inside the internal shell process and return whether it exited with EXIT_SUCCESS
|
* Runs the cmd inside the internal shell process and return stdout, stderr and exit code
|
||||||
*
|
*
|
||||||
* Will automatically defer to the internal thread
|
* Will automatically defer to the internal thread
|
||||||
*/
|
*/
|
||||||
bool DeviceShell::runInShell(const CommandLine &cmd, const QByteArray &stdInData)
|
RunResult DeviceShell::runInShell(const CommandLine &cmd, const QByteArray &stdInData)
|
||||||
{
|
|
||||||
QTC_ASSERT(m_shellProcess, return false);
|
|
||||||
Q_ASSERT(QThread::currentThread() != &m_thread);
|
|
||||||
|
|
||||||
const RunResult result = run(cmd, stdInData);
|
|
||||||
return result.exitCode == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief DeviceShell::outputForRunInShell
|
|
||||||
* \param cmd The command to run
|
|
||||||
* \param stdInData Data to send to the stdin of the command
|
|
||||||
* \return The stdout of the command
|
|
||||||
*
|
|
||||||
* Runs a command inside the running shell and returns the stdout that was generated by it.
|
|
||||||
*
|
|
||||||
* Will automatically defer to the internal thread
|
|
||||||
*/
|
|
||||||
DeviceShell::RunResult DeviceShell::outputForRunInShell(const CommandLine &cmd,
|
|
||||||
const QByteArray &stdInData)
|
|
||||||
{
|
{
|
||||||
QTC_ASSERT(m_shellProcess, return {});
|
QTC_ASSERT(m_shellProcess, return {});
|
||||||
Q_ASSERT(QThread::currentThread() != &m_thread);
|
Q_ASSERT(QThread::currentThread() != &m_thread);
|
||||||
@@ -210,7 +190,7 @@ DeviceShell::State DeviceShell::state() const { return m_shellScriptState; }
|
|||||||
|
|
||||||
QStringList DeviceShell::missingFeatures() const { return m_missingFeatures; }
|
QStringList DeviceShell::missingFeatures() const { return m_missingFeatures; }
|
||||||
|
|
||||||
DeviceShell::RunResult DeviceShell::run(const CommandLine &cmd, const QByteArray &stdInData)
|
RunResult DeviceShell::run(const CommandLine &cmd, const QByteArray &stdInData)
|
||||||
{
|
{
|
||||||
if (m_shellScriptState == State::NoScript) {
|
if (m_shellScriptState == State::NoScript) {
|
||||||
// Fallback ...
|
// Fallback ...
|
||||||
@@ -539,16 +519,16 @@ void DeviceShell::onReadyRead()
|
|||||||
QTC_ASSERT(itCmd != m_commandOutput.end(), continue);
|
QTC_ASSERT(itCmd != m_commandOutput.end(), continue);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Utils::DeviceShell::ParseType::StdOut:
|
case ParseType::StdOut:
|
||||||
itCmd->stdOut.append(data);
|
itCmd->stdOut.append(data);
|
||||||
break;
|
break;
|
||||||
case Utils::DeviceShell::ParseType::StdErr:
|
case ParseType::StdErr:
|
||||||
itCmd->stdErr.append(data);
|
itCmd->stdErr.append(data);
|
||||||
break;
|
break;
|
||||||
case Utils::DeviceShell::ParseType::ExitCode: {
|
case ParseType::ExitCode: {
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
int exitCode;
|
int exitCode;
|
||||||
exitCode = QString::fromUtf8(data.begin(), data.size()).toInt(&ok);
|
exitCode = data.toInt(&ok);
|
||||||
QTC_ASSERT(ok, exitCode = -1);
|
QTC_ASSERT(ok, exitCode = -1);
|
||||||
itCmd->exitCode = exitCode;
|
itCmd->exitCode = exitCode;
|
||||||
itCmd->waiter->wakeOne();
|
itCmd->waiter->wakeOne();
|
||||||
|
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#include "utils_global.h"
|
#include "utils_global.h"
|
||||||
|
|
||||||
|
#include "fileutils.h"
|
||||||
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
@@ -28,13 +30,6 @@ class QTCREATOR_UTILS_EXPORT DeviceShell : public QObject
|
|||||||
public:
|
public:
|
||||||
enum class State { FailedToStart = -1, Unknown = 0, Succeeded = 1, NoScript = 2 };
|
enum class State { FailedToStart = -1, Unknown = 0, Succeeded = 1, NoScript = 2 };
|
||||||
|
|
||||||
struct RunResult
|
|
||||||
{
|
|
||||||
int exitCode = 0;
|
|
||||||
QByteArray stdOut;
|
|
||||||
QByteArray stdErr;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ParseType {
|
enum class ParseType {
|
||||||
StdOut,
|
StdOut,
|
||||||
StdErr,
|
StdErr,
|
||||||
@@ -46,8 +41,7 @@ public:
|
|||||||
|
|
||||||
bool start();
|
bool start();
|
||||||
|
|
||||||
bool runInShell(const CommandLine &cmd, const QByteArray &stdInData = {});
|
RunResult runInShell(const CommandLine &cmd, const QByteArray &stdInData = {});
|
||||||
RunResult outputForRunInShell(const CommandLine &cmd, const QByteArray &stdInData = {});
|
|
||||||
|
|
||||||
State state() const;
|
State state() const;
|
||||||
|
|
||||||
|
@@ -592,8 +592,6 @@ void FileUtils::iterateLsOutput(const FilePath &base,
|
|||||||
const FileFilter &filter,
|
const FileFilter &filter,
|
||||||
const std::function<bool (const FilePath &)> &callBack)
|
const std::function<bool (const FilePath &)> &callBack)
|
||||||
{
|
{
|
||||||
QTC_CHECK(filter.iteratorFlags != QDirIterator::NoIteratorFlags); // FIXME: Not supported yet below.
|
|
||||||
|
|
||||||
const QList<QRegularExpression> nameRegexps =
|
const QList<QRegularExpression> nameRegexps =
|
||||||
transform(filter.nameFilters, [](const QString &filter) {
|
transform(filter.nameFilters, [](const QString &filter) {
|
||||||
QRegularExpression re;
|
QRegularExpression re;
|
||||||
@@ -625,25 +623,27 @@ void FileUtils::iterateLsOutput(const FilePath &base,
|
|||||||
// returns whether 'find' could be used.
|
// returns whether 'find' could be used.
|
||||||
static bool iterateWithFind(const FilePath &filePath,
|
static bool iterateWithFind(const FilePath &filePath,
|
||||||
const FileFilter &filter,
|
const FileFilter &filter,
|
||||||
const std::function<QByteArray(const CommandLine &)> &runInShell,
|
const std::function<RunResult(const CommandLine &)> &runInShell,
|
||||||
const std::function<bool(const Utils::FilePath &)> &callBack)
|
const std::function<bool(const FilePath &)> &callBack)
|
||||||
{
|
{
|
||||||
QTC_CHECK(filePath.isAbsolutePath());
|
QTC_CHECK(filePath.isAbsolutePath());
|
||||||
QStringList arguments{filePath.path()};
|
QStringList arguments{filePath.path()};
|
||||||
arguments << filter.asFindArguments();
|
arguments << filter.asFindArguments();
|
||||||
|
|
||||||
const QByteArray output = runInShell({"find", arguments});
|
const RunResult result = runInShell({"find", arguments});
|
||||||
const QString out = QString::fromUtf8(output.data(), output.size());
|
if (!result.stdErr.isEmpty()) {
|
||||||
if (!output.isEmpty() && !out.startsWith(filePath.path())) // missing find, unknown option
|
// missing find, unknown option e.g. "find: unknown predicate `-L'\n"
|
||||||
|
// qDebug() << "find error: " << result.stdErr;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString out = QString::fromUtf8(result.stdOut);
|
||||||
const QStringList entries = out.split("\n", Qt::SkipEmptyParts);
|
const QStringList entries = out.split("\n", Qt::SkipEmptyParts);
|
||||||
for (const QString &entry : entries) {
|
for (const QString &entry : entries) {
|
||||||
if (!entry.startsWith("find: ")) {
|
const FilePath fp = FilePath::fromString(entry);
|
||||||
const FilePath fp = FilePath::fromString(entry);
|
// Call back returning 'false' indicates a request to abort iteration.
|
||||||
if (!callBack(fp.onDevice(filePath)))
|
if (!callBack(fp.onDevice(filePath)))
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -651,7 +651,7 @@ static bool iterateWithFind(const FilePath &filePath,
|
|||||||
void FileUtils::iterateUnixDirectory(const FilePath &filePath,
|
void FileUtils::iterateUnixDirectory(const FilePath &filePath,
|
||||||
const FileFilter &filter,
|
const FileFilter &filter,
|
||||||
bool *useFind,
|
bool *useFind,
|
||||||
const std::function<QByteArray(const CommandLine &)> &runInShell,
|
const std::function<RunResult (const CommandLine &)> &runInShell,
|
||||||
const std::function<bool(const FilePath &)> &callBack)
|
const std::function<bool(const FilePath &)> &callBack)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(callBack, return);
|
QTC_ASSERT(callBack, return);
|
||||||
@@ -665,8 +665,9 @@ void FileUtils::iterateUnixDirectory(const FilePath &filePath,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if we do not have find - use ls as fallback
|
// if we do not have find - use ls as fallback
|
||||||
const QByteArray output = runInShell({"ls", {"-1", "-b", "--", filePath.path()}});
|
// FIXME: Recursion into subdirectories not implemented!
|
||||||
const QStringList entries = QString::fromUtf8(output).split('\n', Qt::SkipEmptyParts);
|
const RunResult result = runInShell({"ls", {"-1", "-b", "--", filePath.path()}});
|
||||||
|
const QStringList entries = QString::fromUtf8(result.stdOut).split('\n', Qt::SkipEmptyParts);
|
||||||
FileUtils::iterateLsOutput(filePath, entries, filter, callBack);
|
FileUtils::iterateLsOutput(filePath, entries, filter, callBack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,6 +33,13 @@ namespace Utils {
|
|||||||
|
|
||||||
class CommandLine;
|
class CommandLine;
|
||||||
|
|
||||||
|
struct QTCREATOR_UTILS_EXPORT RunResult
|
||||||
|
{
|
||||||
|
int exitCode = 0;
|
||||||
|
QByteArray stdOut;
|
||||||
|
QByteArray stdErr;
|
||||||
|
};
|
||||||
|
|
||||||
class QTCREATOR_UTILS_EXPORT FileUtils
|
class QTCREATOR_UTILS_EXPORT FileUtils
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -89,7 +96,7 @@ public:
|
|||||||
const FilePath &base,
|
const FilePath &base,
|
||||||
const FileFilter &filter,
|
const FileFilter &filter,
|
||||||
bool *useFind,
|
bool *useFind,
|
||||||
const std::function<QByteArray(const CommandLine &)> &runInShell,
|
const std::function<RunResult(const CommandLine &)> &runInShell,
|
||||||
const std::function<bool(const FilePath &)> &callBack);
|
const std::function<bool(const FilePath &)> &callBack);
|
||||||
|
|
||||||
static qint64 bytesAvailableFromDFOutput(const QByteArray &dfOutput);
|
static qint64 bytesAvailableFromDFOutput(const QByteArray &dfOutput);
|
||||||
|
@@ -125,8 +125,10 @@ public:
|
|||||||
|
|
||||||
~DockerDevicePrivate() { stopCurrentContainer(); }
|
~DockerDevicePrivate() { stopCurrentContainer(); }
|
||||||
|
|
||||||
bool runInShell(const CommandLine &cmd, const QByteArray &stdInData = {});
|
RunResult runInShell(const CommandLine &cmd, const QByteArray &stdInData = {});
|
||||||
QByteArray outputForRunInShell(const CommandLine &cmd);
|
bool runInShellSuccess(const CommandLine &cmd, const QByteArray &stdInData = {}) {
|
||||||
|
return runInShell(cmd, stdInData).exitCode == 0;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<QByteArray> fileContents(const FilePath &filePath, qint64 limit, qint64 offset);
|
std::optional<QByteArray> fileContents(const FilePath &filePath, qint64 limit, qint64 offset);
|
||||||
|
|
||||||
@@ -727,76 +729,76 @@ bool DockerDevice::isExecutableFile(const FilePath &filePath) const
|
|||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"test", {"-x", path}});
|
return d->runInShellSuccess({"test", {"-x", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::isReadableFile(const FilePath &filePath) const
|
bool DockerDevice::isReadableFile(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"test", {"-r", path, "-a", "-f", path}});
|
return d->runInShellSuccess({"test", {"-r", path, "-a", "-f", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::isWritableFile(const Utils::FilePath &filePath) const
|
bool DockerDevice::isWritableFile(const Utils::FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"test", {"-w", path, "-a", "-f", path}});
|
return d->runInShellSuccess({"test", {"-w", path, "-a", "-f", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::isReadableDirectory(const FilePath &filePath) const
|
bool DockerDevice::isReadableDirectory(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"test", {"-r", path, "-a", "-d", path}});
|
return d->runInShellSuccess({"test", {"-r", path, "-a", "-d", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::isWritableDirectory(const FilePath &filePath) const
|
bool DockerDevice::isWritableDirectory(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"test", {"-w", path, "-a", "-d", path}});
|
return d->runInShellSuccess({"test", {"-w", path, "-a", "-d", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::isFile(const FilePath &filePath) const
|
bool DockerDevice::isFile(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"test", {"-f", path}});
|
return d->runInShellSuccess({"test", {"-f", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::isDirectory(const FilePath &filePath) const
|
bool DockerDevice::isDirectory(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"test", {"-d", path}});
|
return d->runInShellSuccess({"test", {"-d", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::createDirectory(const FilePath &filePath) const
|
bool DockerDevice::createDirectory(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"mkdir", {"-p", path}});
|
return d->runInShellSuccess({"mkdir", {"-p", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::exists(const FilePath &filePath) const
|
bool DockerDevice::exists(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"test", {"-e", path}});
|
return d->runInShellSuccess({"test", {"-e", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::ensureExistingFile(const FilePath &filePath) const
|
bool DockerDevice::ensureExistingFile(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"touch", {path}});
|
return d->runInShellSuccess({"touch", {path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::removeFile(const FilePath &filePath) const
|
bool DockerDevice::removeFile(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
return d->runInShell({"rm", {filePath.path()}});
|
return d->runInShellSuccess({"rm", {filePath.path()}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::removeRecursively(const FilePath &filePath) const
|
bool DockerDevice::removeRecursively(const FilePath &filePath) const
|
||||||
@@ -811,28 +813,28 @@ bool DockerDevice::removeRecursively(const FilePath &filePath) const
|
|||||||
const int levelsNeeded = path.startsWith("/home/") ? 4 : 3;
|
const int levelsNeeded = path.startsWith("/home/") ? 4 : 3;
|
||||||
QTC_ASSERT(path.count('/') >= levelsNeeded, return false);
|
QTC_ASSERT(path.count('/') >= levelsNeeded, return false);
|
||||||
|
|
||||||
return d->runInShell({"rm", {"-rf", "--", path}});
|
return d->runInShellSuccess({"rm", {"-rf", "--", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::copyFile(const FilePath &filePath, const FilePath &target) const
|
bool DockerDevice::copyFile(const FilePath &filePath, const FilePath &target) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
QTC_ASSERT(handlesFile(target), return false);
|
QTC_ASSERT(handlesFile(target), return false);
|
||||||
return d->runInShell({"cp", {filePath.path(), target.path()}});
|
return d->runInShellSuccess({"cp", {filePath.path(), target.path()}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::renameFile(const FilePath &filePath, const FilePath &target) const
|
bool DockerDevice::renameFile(const FilePath &filePath, const FilePath &target) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
QTC_ASSERT(handlesFile(target), return false);
|
QTC_ASSERT(handlesFile(target), return false);
|
||||||
return d->runInShell({"mv", {filePath.path(), target.path()}});
|
return d->runInShellSuccess({"mv", {filePath.path(), target.path()}});
|
||||||
}
|
}
|
||||||
|
|
||||||
QDateTime DockerDevice::lastModified(const FilePath &filePath) const
|
QDateTime DockerDevice::lastModified(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
QTC_ASSERT(handlesFile(filePath), return {});
|
||||||
const QByteArray output = d->outputForRunInShell({"stat", {"-L", "-c", "%Y", filePath.path()}});
|
const RunResult result = d->runInShell({"stat", {"-L", "-c", "%Y", filePath.path()}});
|
||||||
qint64 secs = output.toLongLong();
|
qint64 secs = result.stdOut.toLongLong();
|
||||||
const QDateTime dt = QDateTime::fromSecsSinceEpoch(secs, Qt::UTC);
|
const QDateTime dt = QDateTime::fromSecsSinceEpoch(secs, Qt::UTC);
|
||||||
return dt;
|
return dt;
|
||||||
}
|
}
|
||||||
@@ -840,24 +842,24 @@ QDateTime DockerDevice::lastModified(const FilePath &filePath) const
|
|||||||
FilePath DockerDevice::symLinkTarget(const FilePath &filePath) const
|
FilePath DockerDevice::symLinkTarget(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
QTC_ASSERT(handlesFile(filePath), return {});
|
||||||
const QByteArray output = d->outputForRunInShell({"readlink", {"-n", "-e", filePath.path()}});
|
const RunResult result = d->runInShell({"readlink", {"-n", "-e", filePath.path()}});
|
||||||
const QString out = QString::fromUtf8(output.data(), output.size());
|
const QString out = QString::fromUtf8(result.stdOut);
|
||||||
return out.isEmpty() ? FilePath() : filePath.withNewPath(out);
|
return out.isEmpty() ? FilePath() : filePath.withNewPath(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 DockerDevice::fileSize(const FilePath &filePath) const
|
qint64 DockerDevice::fileSize(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return -1);
|
QTC_ASSERT(handlesFile(filePath), return -1);
|
||||||
const QByteArray output = d->outputForRunInShell({"stat", {"-L", "-c", "%s", filePath.path()}});
|
const RunResult result = d->runInShell({"stat", {"-L", "-c", "%s", filePath.path()}});
|
||||||
return output.toLongLong();
|
return result.stdOut.toLongLong();
|
||||||
}
|
}
|
||||||
|
|
||||||
QFileDevice::Permissions DockerDevice::permissions(const FilePath &filePath) const
|
QFileDevice::Permissions DockerDevice::permissions(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
QTC_ASSERT(handlesFile(filePath), return {});
|
||||||
|
|
||||||
const QByteArray output = d->outputForRunInShell({"stat", {"-L", "-c", "%a", filePath.path()}});
|
const RunResult result = d->runInShell({"stat", {"-L", "-c", "%a", filePath.path()}});
|
||||||
const uint bits = output.toUInt(nullptr, 8);
|
const uint bits = result.stdOut.toUInt(nullptr, 8);
|
||||||
QFileDevice::Permissions perm = {};
|
QFileDevice::Permissions perm = {};
|
||||||
#define BIT(n, p) if (bits & (1<<n)) perm |= QFileDevice::p
|
#define BIT(n, p) if (bits & (1<<n)) perm |= QFileDevice::p
|
||||||
BIT(0, ExeOther);
|
BIT(0, ExeOther);
|
||||||
@@ -896,7 +898,7 @@ void DockerDevice::iterateDirectory(const FilePath &filePath,
|
|||||||
const FileFilter &filter) const
|
const FileFilter &filter) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return);
|
QTC_ASSERT(handlesFile(filePath), return);
|
||||||
auto runInShell = [this](const CommandLine &cmd) { return d->outputForRunInShell(cmd); };
|
auto runInShell = [this](const CommandLine &cmd) { return d->runInShell(cmd); };
|
||||||
FileUtils::iterateUnixDirectory(filePath, filter, &d->m_useFind, runInShell, callBack);
|
FileUtils::iterateUnixDirectory(filePath, filter, &d->m_useFind, runInShell, callBack);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -911,7 +913,7 @@ std::optional<QByteArray> DockerDevice::fileContents(const FilePath &filePath,
|
|||||||
bool DockerDevice::writeFileContents(const FilePath &filePath, const QByteArray &data) const
|
bool DockerDevice::writeFileContents(const FilePath &filePath, const QByteArray &data) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
QTC_ASSERT(handlesFile(filePath), return {});
|
||||||
return d->runInShell({"dd", {"of=" + filePath.path()}}, data);
|
return d->runInShellSuccess({"dd", {"of=" + filePath.path()}}, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
Environment DockerDevice::systemEnvironment() const
|
Environment DockerDevice::systemEnvironment() const
|
||||||
@@ -926,8 +928,8 @@ void DockerDevice::aboutToBeRemoved() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<QByteArray> DockerDevicePrivate::fileContents(const FilePath &filePath,
|
std::optional<QByteArray> DockerDevicePrivate::fileContents(const FilePath &filePath,
|
||||||
qint64 limit,
|
qint64 limit,
|
||||||
qint64 offset)
|
qint64 offset)
|
||||||
{
|
{
|
||||||
updateContainerAccess();
|
updateContainerAccess();
|
||||||
|
|
||||||
@@ -939,7 +941,7 @@ std::optional<QByteArray> DockerDevicePrivate::fileContents(const FilePath &file
|
|||||||
QString("seek=%1").arg(offset / gcd)};
|
QString("seek=%1").arg(offset / gcd)};
|
||||||
}
|
}
|
||||||
|
|
||||||
const ContainerShell::RunResult r = m_shell->outputForRunInShell({"dd", args});
|
const RunResult r = m_shell->runInShell({"dd", args});
|
||||||
|
|
||||||
if (r.exitCode != 0)
|
if (r.exitCode != 0)
|
||||||
return {};
|
return {};
|
||||||
@@ -952,8 +954,8 @@ void DockerDevicePrivate::fetchSystemEnviroment()
|
|||||||
updateContainerAccess();
|
updateContainerAccess();
|
||||||
|
|
||||||
if (m_shell && m_shell->state() == DeviceShell::State::Succeeded) {
|
if (m_shell && m_shell->state() == DeviceShell::State::Succeeded) {
|
||||||
const QByteArray output = outputForRunInShell({"env", {}});
|
const RunResult result = runInShell({"env", {}});
|
||||||
const QString out = QString::fromUtf8(output.data(), output.size());
|
const QString out = QString::fromUtf8(result.stdOut);
|
||||||
m_cachedEnviroment = Environment(out.split('\n', Qt::SkipEmptyParts), q->osType());
|
m_cachedEnviroment = Environment(out.split('\n', Qt::SkipEmptyParts), q->osType());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -972,20 +974,13 @@ void DockerDevicePrivate::fetchSystemEnviroment()
|
|||||||
qCWarning(dockerDeviceLog) << "Cannot read container environment:", qPrintable(remoteError);
|
qCWarning(dockerDeviceLog) << "Cannot read container environment:", qPrintable(remoteError);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevicePrivate::runInShell(const CommandLine &cmd, const QByteArray &stdInData)
|
RunResult DockerDevicePrivate::runInShell(const CommandLine &cmd, const QByteArray &stdInData)
|
||||||
{
|
{
|
||||||
updateContainerAccess();
|
updateContainerAccess();
|
||||||
QTC_ASSERT(m_shell, return false);
|
QTC_ASSERT(m_shell, return {});
|
||||||
return m_shell->runInShell(cmd, stdInData);
|
return m_shell->runInShell(cmd, stdInData);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray DockerDevicePrivate::outputForRunInShell(const CommandLine &cmd)
|
|
||||||
{
|
|
||||||
updateContainerAccess();
|
|
||||||
QTC_ASSERT(m_shell.get(), return {});
|
|
||||||
return m_shell->outputForRunInShell(cmd).stdOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Factory
|
// Factory
|
||||||
|
|
||||||
class DockerImageItem final : public TreeItem, public DockerDeviceData
|
class DockerImageItem final : public TreeItem, public DockerDeviceData
|
||||||
|
@@ -357,8 +357,11 @@ public:
|
|||||||
~LinuxDevicePrivate();
|
~LinuxDevicePrivate();
|
||||||
|
|
||||||
bool setupShell();
|
bool setupShell();
|
||||||
bool runInShell(const CommandLine &cmd, const QByteArray &data = {});
|
RunResult runInShell(const CommandLine &cmd, const QByteArray &stdInData = {});
|
||||||
std::optional<QByteArray> outputForRunInShell(const CommandLine &cmd);
|
bool runInShellSuccess(const CommandLine &cmd, const QByteArray &stdInData = {}) {
|
||||||
|
return runInShell(cmd, stdInData).exitCode == 0;
|
||||||
|
}
|
||||||
|
|
||||||
void attachToSharedConnection(SshConnectionHandle *connectionHandle,
|
void attachToSharedConnection(SshConnectionHandle *connectionHandle,
|
||||||
const SshParameters &sshParameters);
|
const SshParameters &sshParameters);
|
||||||
|
|
||||||
@@ -462,7 +465,7 @@ qint64 SshProcessInterface::processId() const
|
|||||||
|
|
||||||
bool SshProcessInterface::runInShell(const CommandLine &command, const QByteArray &data)
|
bool SshProcessInterface::runInShell(const CommandLine &command, const QByteArray &data)
|
||||||
{
|
{
|
||||||
return d->m_devicePrivate->runInShell(command, data);
|
return d->m_devicePrivate->runInShellSuccess(command, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SshProcessInterface::start()
|
void SshProcessInterface::start()
|
||||||
@@ -807,20 +810,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Call me with shell mutex locked
|
// Call me with shell mutex locked
|
||||||
bool runInShell(const CommandLine &cmd, const QByteArray &data = {})
|
RunResult runInShell(const CommandLine &cmd, const QByteArray &data = {})
|
||||||
{
|
|
||||||
QTC_ASSERT(m_shell, return false);
|
|
||||||
return m_shell->runInShell(cmd, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call me with shell mutex locked
|
|
||||||
std::optional<QByteArray> outputForRunInShell(const CommandLine &cmd)
|
|
||||||
{
|
{
|
||||||
QTC_ASSERT(m_shell, return {});
|
QTC_ASSERT(m_shell, return {});
|
||||||
const DeviceShell::RunResult result = m_shell->outputForRunInShell(cmd);
|
return m_shell->runInShell(cmd, data);
|
||||||
if (result.exitCode == 0)
|
|
||||||
return result.stdOut;
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSshParameters(const SshParameters &sshParameters)
|
void setSshParameters(const SshParameters &sshParameters)
|
||||||
@@ -1104,22 +1097,13 @@ bool LinuxDevicePrivate::setupShell()
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxDevicePrivate::runInShell(const CommandLine &cmd, const QByteArray &data)
|
RunResult LinuxDevicePrivate::runInShell(const CommandLine &cmd, const QByteArray &data)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&m_shellMutex);
|
QMutexLocker locker(&m_shellMutex);
|
||||||
DEBUG(cmd.toUserOutput());
|
DEBUG(cmd.toUserOutput());
|
||||||
QTC_ASSERT(setupShell(), return false);
|
|
||||||
|
|
||||||
return m_handler->runInShell(cmd, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<QByteArray> LinuxDevicePrivate::outputForRunInShell(const CommandLine &cmd)
|
|
||||||
{
|
|
||||||
QMutexLocker locker(&m_shellMutex);
|
|
||||||
DEBUG(cmd);
|
|
||||||
QTC_ASSERT(setupShell(), return {});
|
QTC_ASSERT(setupShell(), return {});
|
||||||
|
|
||||||
return m_handler->outputForRunInShell(cmd);
|
return m_handler->runInShell(cmd, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinuxDevicePrivate::attachToSharedConnection(SshConnectionHandle *connectionHandle,
|
void LinuxDevicePrivate::attachToSharedConnection(SshConnectionHandle *connectionHandle,
|
||||||
@@ -1141,56 +1125,56 @@ bool LinuxDevice::isExecutableFile(const FilePath &filePath) const
|
|||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"test", {"-x", path}});
|
return d->runInShellSuccess({"test", {"-x", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxDevice::isReadableFile(const FilePath &filePath) const
|
bool LinuxDevice::isReadableFile(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"test", {"-r", path, "-a", "-f", path}});
|
return d->runInShellSuccess({"test", {"-r", path, "-a", "-f", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxDevice::isWritableFile(const FilePath &filePath) const
|
bool LinuxDevice::isWritableFile(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"test", {"-w", path, "-a", "-f", path}});
|
return d->runInShellSuccess({"test", {"-w", path, "-a", "-f", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxDevice::isReadableDirectory(const FilePath &filePath) const
|
bool LinuxDevice::isReadableDirectory(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"test", {"-r", path, "-a", "-d", path}});
|
return d->runInShellSuccess({"test", {"-r", path, "-a", "-d", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxDevice::isWritableDirectory(const FilePath &filePath) const
|
bool LinuxDevice::isWritableDirectory(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"test", {"-w", path, "-a", "-d", path}});
|
return d->runInShellSuccess({"test", {"-w", path, "-a", "-d", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxDevice::isFile(const FilePath &filePath) const
|
bool LinuxDevice::isFile(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"test", {"-f", path}});
|
return d->runInShellSuccess({"test", {"-f", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxDevice::isDirectory(const FilePath &filePath) const
|
bool LinuxDevice::isDirectory(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"test", {"-d", path}});
|
return d->runInShellSuccess({"test", {"-d", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxDevice::createDirectory(const FilePath &filePath) const
|
bool LinuxDevice::createDirectory(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"mkdir", {"-p", path}});
|
return d->runInShellSuccess({"mkdir", {"-p", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxDevice::exists(const FilePath &filePath) const
|
bool LinuxDevice::exists(const FilePath &filePath) const
|
||||||
@@ -1198,20 +1182,20 @@ bool LinuxDevice::exists(const FilePath &filePath) const
|
|||||||
DEBUG("filepath " << filePath.path());
|
DEBUG("filepath " << filePath.path());
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"test", {"-e", path}});
|
return d->runInShellSuccess({"test", {"-e", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxDevice::ensureExistingFile(const FilePath &filePath) const
|
bool LinuxDevice::ensureExistingFile(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInShell({"touch", {path}});
|
return d->runInShellSuccess({"touch", {path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxDevice::removeFile(const FilePath &filePath) const
|
bool LinuxDevice::removeFile(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
return d->runInShell({"rm", {filePath.path()}});
|
return d->runInShellSuccess({"rm", {filePath.path()}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxDevice::removeRecursively(const FilePath &filePath) const
|
bool LinuxDevice::removeRecursively(const FilePath &filePath) const
|
||||||
@@ -1226,29 +1210,28 @@ bool LinuxDevice::removeRecursively(const FilePath &filePath) const
|
|||||||
const int levelsNeeded = path.startsWith("/home/") ? 3 : 2;
|
const int levelsNeeded = path.startsWith("/home/") ? 3 : 2;
|
||||||
QTC_ASSERT(path.count('/') >= levelsNeeded, return false);
|
QTC_ASSERT(path.count('/') >= levelsNeeded, return false);
|
||||||
|
|
||||||
return d->runInShell({"rm", {"-rf", "--", path}});
|
return d->runInShellSuccess({"rm", {"-rf", "--", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxDevice::copyFile(const FilePath &filePath, const FilePath &target) const
|
bool LinuxDevice::copyFile(const FilePath &filePath, const FilePath &target) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
QTC_ASSERT(handlesFile(target), return false);
|
QTC_ASSERT(handlesFile(target), return false);
|
||||||
return d->runInShell({"cp", {filePath.path(), target.path()}});
|
return d->runInShellSuccess({"cp", {filePath.path(), target.path()}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxDevice::renameFile(const FilePath &filePath, const FilePath &target) const
|
bool LinuxDevice::renameFile(const FilePath &filePath, const FilePath &target) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
QTC_ASSERT(handlesFile(target), return false);
|
QTC_ASSERT(handlesFile(target), return false);
|
||||||
return d->runInShell({"mv", {filePath.path(), target.path()}});
|
return d->runInShellSuccess({"mv", {filePath.path(), target.path()}});
|
||||||
}
|
}
|
||||||
|
|
||||||
QDateTime LinuxDevice::lastModified(const FilePath &filePath) const
|
QDateTime LinuxDevice::lastModified(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
QTC_ASSERT(handlesFile(filePath), return {});
|
||||||
const QByteArray output = d->outputForRunInShell({"stat", {"-L", "-c", "%Y", filePath.path()}})
|
const RunResult result = d->runInShell({"stat", {"-L", "-c", "%Y", filePath.path()}});
|
||||||
.value_or(QByteArray());
|
const qint64 secs = result.stdOut.toLongLong();
|
||||||
const qint64 secs = output.toLongLong();
|
|
||||||
const QDateTime dt = QDateTime::fromSecsSinceEpoch(secs, Qt::UTC);
|
const QDateTime dt = QDateTime::fromSecsSinceEpoch(secs, Qt::UTC);
|
||||||
return dt;
|
return dt;
|
||||||
}
|
}
|
||||||
@@ -1256,18 +1239,16 @@ QDateTime LinuxDevice::lastModified(const FilePath &filePath) const
|
|||||||
FilePath LinuxDevice::symLinkTarget(const FilePath &filePath) const
|
FilePath LinuxDevice::symLinkTarget(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
QTC_ASSERT(handlesFile(filePath), return {});
|
||||||
const QByteArray output = d->outputForRunInShell({"readlink", {"-n", "-e", filePath.path()}})
|
const RunResult result = d->runInShell({"readlink", {"-n", "-e", filePath.path()}});
|
||||||
.value_or(QByteArray());
|
return result.stdOut.isEmpty() ? FilePath()
|
||||||
const QString out = QString::fromUtf8(output.data(), output.size());
|
: filePath.withNewPath(QString::fromUtf8(result.stdOut));
|
||||||
return output.isEmpty() ? FilePath() : filePath.withNewPath(out);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 LinuxDevice::fileSize(const FilePath &filePath) const
|
qint64 LinuxDevice::fileSize(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return -1);
|
QTC_ASSERT(handlesFile(filePath), return -1);
|
||||||
const QByteArray output = d->outputForRunInShell({"stat", {"-L", "-c", "%s", filePath.path()}})
|
const RunResult result = d->runInShell({"stat", {"-L", "-c", "%s", filePath.path()}});
|
||||||
.value_or(QByteArray());
|
return result.stdOut.toLongLong();
|
||||||
return output.toLongLong();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 LinuxDevice::bytesAvailable(const FilePath &filePath) const
|
qint64 LinuxDevice::bytesAvailable(const FilePath &filePath) const
|
||||||
@@ -1275,17 +1256,15 @@ qint64 LinuxDevice::bytesAvailable(const FilePath &filePath) const
|
|||||||
QTC_ASSERT(handlesFile(filePath), return -1);
|
QTC_ASSERT(handlesFile(filePath), return -1);
|
||||||
CommandLine cmd("df", {"-k"});
|
CommandLine cmd("df", {"-k"});
|
||||||
cmd.addArg(filePath.path());
|
cmd.addArg(filePath.path());
|
||||||
const QByteArray output = d->outputForRunInShell(cmd).value_or(QByteArray());
|
const RunResult result = d->runInShell(cmd);
|
||||||
|
return FileUtils::bytesAvailableFromDFOutput(result.stdOut);
|
||||||
return FileUtils::bytesAvailableFromDFOutput(output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QFileDevice::Permissions LinuxDevice::permissions(const FilePath &filePath) const
|
QFileDevice::Permissions LinuxDevice::permissions(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
QTC_ASSERT(handlesFile(filePath), return {});
|
||||||
const QByteArray output = d->outputForRunInShell({"stat", {"-L", "-c", "%a", filePath.path()}})
|
const RunResult result = d->runInShell({"stat", {"-L", "-c", "%a", filePath.path()}});
|
||||||
.value_or(QByteArray());
|
const uint bits = result.stdOut.toUInt(nullptr, 8);
|
||||||
const uint bits = output.toUInt(nullptr, 8);
|
|
||||||
QFileDevice::Permissions perm = {};
|
QFileDevice::Permissions perm = {};
|
||||||
#define BIT(n, p) if (bits & (1<<n)) perm |= QFileDevice::p
|
#define BIT(n, p) if (bits & (1<<n)) perm |= QFileDevice::p
|
||||||
BIT(0, ExeOther);
|
BIT(0, ExeOther);
|
||||||
@@ -1305,7 +1284,7 @@ bool LinuxDevice::setPermissions(const FilePath &filePath, QFileDevice::Permissi
|
|||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
QTC_ASSERT(handlesFile(filePath), return false);
|
||||||
const int flags = int(permissions);
|
const int flags = int(permissions);
|
||||||
return d->runInShell({"chmod", {QString::number(flags, 16), filePath.path()}});
|
return d->runInShellSuccess({"chmod", {QString::number(flags, 16), filePath.path()}});
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinuxDevice::iterateDirectory(const FilePath &filePath,
|
void LinuxDevice::iterateDirectory(const FilePath &filePath,
|
||||||
@@ -1313,9 +1292,7 @@ void LinuxDevice::iterateDirectory(const FilePath &filePath,
|
|||||||
const FileFilter &filter) const
|
const FileFilter &filter) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return);
|
QTC_ASSERT(handlesFile(filePath), return);
|
||||||
auto runInShell = [this](const CommandLine &cmd) {
|
auto runInShell = [this](const CommandLine &cmd) { return d->runInShell(cmd); };
|
||||||
return d->outputForRunInShell(cmd).value_or(QByteArray());
|
|
||||||
};
|
|
||||||
FileUtils::iterateUnixDirectory(filePath, filter, &d->m_useFind, runInShell, callBack);
|
FileUtils::iterateUnixDirectory(filePath, filter, &d->m_useFind, runInShell, callBack);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1331,19 +1308,20 @@ std::optional<QByteArray> LinuxDevice::fileContents(const FilePath &filePath,
|
|||||||
}
|
}
|
||||||
CommandLine cmd(FilePath::fromString("dd"), args, CommandLine::Raw);
|
CommandLine cmd(FilePath::fromString("dd"), args, CommandLine::Raw);
|
||||||
|
|
||||||
const std::optional<QByteArray> output = d->outputForRunInShell(cmd);
|
const RunResult result = d->runInShell(cmd);
|
||||||
if (output) {
|
if (result.exitCode != 0) {
|
||||||
DEBUG(*output << QByteArray::fromHex(*output));
|
|
||||||
} else {
|
|
||||||
DEBUG("fileContents failed");
|
DEBUG("fileContents failed");
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
return output;
|
|
||||||
|
DEBUG(result.stdOut << QByteArray::fromHex(result.stdOut));
|
||||||
|
return result.stdOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxDevice::writeFileContents(const FilePath &filePath, const QByteArray &data) const
|
bool LinuxDevice::writeFileContents(const FilePath &filePath, const QByteArray &data) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
QTC_ASSERT(handlesFile(filePath), return {});
|
||||||
return d->runInShell({"dd", {"of=" + filePath.path()}}, data);
|
return d->runInShellSuccess({"dd", {"of=" + filePath.path()}}, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static FilePaths dirsToCreate(const FilesToTransfer &files)
|
static FilePaths dirsToCreate(const FilesToTransfer &files)
|
||||||
|
@@ -162,7 +162,7 @@ private slots:
|
|||||||
|
|
||||||
QRandomGenerator generator;
|
QRandomGenerator generator;
|
||||||
|
|
||||||
const DeviceShell::RunResult result = shell.outputForRunInShell({"echo", {testData}});
|
const RunResult result = shell.runInShell({"echo", {testData}});
|
||||||
QCOMPARE(result.exitCode, 0);
|
QCOMPARE(result.exitCode, 0);
|
||||||
const QString expected = testData + "\n";
|
const QString expected = testData + "\n";
|
||||||
const QString resultAsUtf8 = QString::fromUtf8(result.stdOut);
|
const QString resultAsUtf8 = QString::fromUtf8(result.stdOut);
|
||||||
@@ -210,7 +210,7 @@ private slots:
|
|||||||
|
|
||||||
QRandomGenerator generator;
|
QRandomGenerator generator;
|
||||||
|
|
||||||
const DeviceShell::RunResult result = shell.outputForRunInShell({"cat", {}}, testData.toUtf8());
|
const RunResult result = shell.runInShell({"cat", {}}, testData.toUtf8());
|
||||||
QCOMPARE(result.exitCode, 0);
|
QCOMPARE(result.exitCode, 0);
|
||||||
const QString resultAsUtf8 = QString::fromUtf8(result.stdOut);
|
const QString resultAsUtf8 = QString::fromUtf8(result.stdOut);
|
||||||
QCOMPARE(resultAsUtf8.size(), testData.size());
|
QCOMPARE(resultAsUtf8.size(), testData.size());
|
||||||
@@ -236,8 +236,7 @@ private slots:
|
|||||||
TestShell shell(cmdLine);
|
TestShell shell(cmdLine);
|
||||||
QCOMPARE(shell.state(), DeviceShell::State::Succeeded);
|
QCOMPARE(shell.state(), DeviceShell::State::Succeeded);
|
||||||
|
|
||||||
const DeviceShell::RunResult result = shell.outputForRunInShell({"cat", {}},
|
const RunResult result = shell.runInShell({"cat", {}}, m_asciiTestData);
|
||||||
m_asciiTestData);
|
|
||||||
QCOMPARE(result.stdOut, m_asciiTestData);
|
QCOMPARE(result.stdOut, m_asciiTestData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,12 +259,11 @@ private slots:
|
|||||||
TestShell shell(cmdLine);
|
TestShell shell(cmdLine);
|
||||||
QCOMPARE(shell.state(), DeviceShell::State::Succeeded);
|
QCOMPARE(shell.state(), DeviceShell::State::Succeeded);
|
||||||
|
|
||||||
const DeviceShell::RunResult result = shell.outputForRunInShell({"cat", {}},
|
const RunResult result = shell.runInShell({"cat", {}}, m_asciiTestData);
|
||||||
m_asciiTestData);
|
|
||||||
QCOMPARE(result.stdOut, m_asciiTestData);
|
QCOMPARE(result.stdOut, m_asciiTestData);
|
||||||
QVERIFY(result.stdErr.isEmpty());
|
QVERIFY(result.stdErr.isEmpty());
|
||||||
|
|
||||||
const DeviceShell::RunResult result2 = shell.outputForRunInShell(
|
const RunResult result2 = shell.runInShell(
|
||||||
{"cat", {"/tmp/i-do-not-exist.none"}});
|
{"cat", {"/tmp/i-do-not-exist.none"}});
|
||||||
QVERIFY(!result2.stdErr.isEmpty());
|
QVERIFY(!result2.stdErr.isEmpty());
|
||||||
QVERIFY(result2.exitCode != 0);
|
QVERIFY(result2.exitCode != 0);
|
||||||
@@ -290,7 +288,7 @@ private slots:
|
|||||||
TestShell shell(cmdLine);
|
TestShell shell(cmdLine);
|
||||||
QCOMPARE(shell.state(), DeviceShell::State::Succeeded);
|
QCOMPARE(shell.state(), DeviceShell::State::Succeeded);
|
||||||
|
|
||||||
const DeviceShell::RunResult result = shell.outputForRunInShell({}, {});
|
const RunResult result = shell.runInShell({}, {});
|
||||||
|
|
||||||
QVERIFY(result.exitCode == 255);
|
QVERIFY(result.exitCode == 255);
|
||||||
}
|
}
|
||||||
@@ -322,7 +320,7 @@ private slots:
|
|||||||
while (true) {
|
while (true) {
|
||||||
QElapsedTimer t;
|
QElapsedTimer t;
|
||||||
t.start();
|
t.start();
|
||||||
DeviceShell::RunResult result = shell.outputForRunInShell({"find", {"/usr", "-maxdepth", QString::number(maxDepth)}});
|
RunResult result = shell.runInShell({"find", {"/usr", "-maxdepth", QString::number(maxDepth)}});
|
||||||
numMs = t.elapsed();
|
numMs = t.elapsed();
|
||||||
qDebug() << "adjusted maxDepth" << maxDepth << "took" << numMs << "ms";
|
qDebug() << "adjusted maxDepth" << maxDepth << "took" << numMs << "ms";
|
||||||
if (numMs < 100 || maxDepth == 1) {
|
if (numMs < 100 || maxDepth == 1) {
|
||||||
@@ -334,7 +332,7 @@ private slots:
|
|||||||
QList<QByteArray> results = Utils::mapped<QList>(runs, [&shell, maxDepth](const int i) -> QByteArray{
|
QList<QByteArray> results = Utils::mapped<QList>(runs, [&shell, maxDepth](const int i) -> QByteArray{
|
||||||
QElapsedTimer t;
|
QElapsedTimer t;
|
||||||
t.start();
|
t.start();
|
||||||
DeviceShell::RunResult result = shell.outputForRunInShell({"find", {"/usr", "-maxdepth", QString::number(maxDepth)}});
|
RunResult result = shell.runInShell({"find", {"/usr", "-maxdepth", QString::number(maxDepth)}});
|
||||||
qDebug() << i << "took" << t.elapsed() << "ms";
|
qDebug() << i << "took" << t.elapsed() << "ms";
|
||||||
return result.stdOut;
|
return result.stdOut;
|
||||||
});
|
});
|
||||||
@@ -357,8 +355,8 @@ private slots:
|
|||||||
TestShell shell(cmdLine, true);
|
TestShell shell(cmdLine, true);
|
||||||
QCOMPARE(shell.state(), DeviceShell::State::NoScript);
|
QCOMPARE(shell.state(), DeviceShell::State::NoScript);
|
||||||
|
|
||||||
const bool result = shell.runInShell({"echo", {"Hello"}});
|
const RunResult result = shell.runInShell({"echo", {"Hello"}});
|
||||||
QCOMPARE(result, true);
|
QCOMPARE(result.exitCode, 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -100,7 +100,7 @@ class tst_DeviceShell : public QObject
|
|||||||
|
|
||||||
const QList<QByteArray> result
|
const QList<QByteArray> result
|
||||||
= mapped<QList>(testArray, [&shell](QByteArray data) -> QByteArray {
|
= mapped<QList>(testArray, [&shell](QByteArray data) -> QByteArray {
|
||||||
return shell.outputForRunInShell({"cat", {}}, data).stdOut;
|
return shell.runInShell({"cat", {}}, data).stdOut;
|
||||||
}, MapReduceOption::Ordered, QThreadPool::globalInstance());
|
}, MapReduceOption::Ordered, QThreadPool::globalInstance());
|
||||||
|
|
||||||
QCOMPARE(result, testArray);
|
QCOMPARE(result, testArray);
|
||||||
@@ -164,7 +164,7 @@ private slots:
|
|||||||
TestShell shell;
|
TestShell shell;
|
||||||
QCOMPARE(shell.state(), DeviceShell::State::Succeeded);
|
QCOMPARE(shell.state(), DeviceShell::State::Succeeded);
|
||||||
|
|
||||||
const DeviceShell::RunResult r = shell.outputForRunInShell({"cat", {}}, utf8string.toUtf8());
|
const RunResult r = shell.runInShell({"cat", {}}, utf8string.toUtf8());
|
||||||
const QString output = QString::fromUtf8(r.stdOut);
|
const QString output = QString::fromUtf8(r.stdOut);
|
||||||
QCOMPARE(output, utf8string);
|
QCOMPARE(output, utf8string);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user