forked from qt-creator/qt-creator
Docker: Let some commands run inside shell
If there is no local access for the docker container we create lots of explicit docker calls which take time to be created and executed as this always fires up another connection to the container. Currently we expect the container to have a shell and we already have it in place, so re-use the shell to execute at least a couple of commands. This heavily increases the performance of these commands. Change-Id: Ic778a250a2b3b8c5ce2a8dd6b7fa8c532bc6d4bf Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -69,6 +69,7 @@
|
|||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
#include <QRandomGenerator>
|
||||||
#include <QTextBrowser>
|
#include <QTextBrowser>
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
@@ -307,6 +308,8 @@ public:
|
|||||||
~DockerDevicePrivate() { stopCurrentContainer(); }
|
~DockerDevicePrivate() { stopCurrentContainer(); }
|
||||||
|
|
||||||
bool runInContainer(const CommandLine &cmd) const;
|
bool runInContainer(const CommandLine &cmd) const;
|
||||||
|
bool runInShell(const CommandLine &cmd) const;
|
||||||
|
QString outputForRunInShell(const CommandLine &cmd) const;
|
||||||
|
|
||||||
void tryCreateLocalFileAccess();
|
void tryCreateLocalFileAccess();
|
||||||
|
|
||||||
@@ -318,6 +321,7 @@ public:
|
|||||||
|
|
||||||
// For local file access
|
// For local file access
|
||||||
QPointer<QtcProcess> m_shell;
|
QPointer<QtcProcess> m_shell;
|
||||||
|
mutable QMutex m_shellMutex;
|
||||||
QString m_container;
|
QString m_container;
|
||||||
QString m_mergedDir;
|
QString m_mergedDir;
|
||||||
QFileSystemWatcher m_mergedDirWatcher;
|
QFileSystemWatcher m_mergedDirWatcher;
|
||||||
@@ -746,6 +750,7 @@ void DockerDevicePrivate::stopCurrentContainer()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_shell) {
|
if (m_shell) {
|
||||||
|
QMutexLocker l(&m_shellMutex);
|
||||||
m_shell->write("exit\n");
|
m_shell->write("exit\n");
|
||||||
m_shell->waitForFinished(2000);
|
m_shell->waitForFinished(2000);
|
||||||
if (m_shell->state() == QProcess::NotRunning) {
|
if (m_shell->state() == QProcess::NotRunning) {
|
||||||
@@ -1032,7 +1037,7 @@ bool DockerDevice::isExecutableFile(const FilePath &filePath) const
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInContainer({"test", {"-x", path}});
|
return d->runInShell({"test", {"-x", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::isReadableFile(const FilePath &filePath) const
|
bool DockerDevice::isReadableFile(const FilePath &filePath) const
|
||||||
@@ -1046,7 +1051,7 @@ bool DockerDevice::isReadableFile(const FilePath &filePath) const
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInContainer({"test", {"-r", path, "-a", "-f", path}});
|
return d->runInShell({"test", {"-r", path, "-a", "-f", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::isWritableFile(const Utils::FilePath &filePath) const
|
bool DockerDevice::isWritableFile(const Utils::FilePath &filePath) const
|
||||||
@@ -1060,7 +1065,7 @@ bool DockerDevice::isWritableFile(const Utils::FilePath &filePath) const
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInContainer({"test", {"-w", path, "-a", "-f", path}});
|
return d->runInShell({"test", {"-w", path, "-a", "-f", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::isReadableDirectory(const FilePath &filePath) const
|
bool DockerDevice::isReadableDirectory(const FilePath &filePath) const
|
||||||
@@ -1074,7 +1079,7 @@ bool DockerDevice::isReadableDirectory(const FilePath &filePath) const
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInContainer({"test", {"-r", path, "-a", "-d", path}});
|
return d->runInShell({"test", {"-r", path, "-a", "-d", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::isWritableDirectory(const FilePath &filePath) const
|
bool DockerDevice::isWritableDirectory(const FilePath &filePath) const
|
||||||
@@ -1088,7 +1093,7 @@ bool DockerDevice::isWritableDirectory(const FilePath &filePath) const
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInContainer({"test", {"-w", path, "-a", "-d", path}});
|
return d->runInShell({"test", {"-w", path, "-a", "-d", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::isFile(const FilePath &filePath) const
|
bool DockerDevice::isFile(const FilePath &filePath) const
|
||||||
@@ -1102,7 +1107,7 @@ bool DockerDevice::isFile(const FilePath &filePath) const
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInContainer({"test", {"-f", path}});
|
return d->runInShell({"test", {"-f", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::isDirectory(const FilePath &filePath) const
|
bool DockerDevice::isDirectory(const FilePath &filePath) const
|
||||||
@@ -1116,7 +1121,7 @@ bool DockerDevice::isDirectory(const FilePath &filePath) const
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInContainer({"test", {"-d", path}});
|
return d->runInShell({"test", {"-d", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::createDirectory(const FilePath &filePath) const
|
bool DockerDevice::createDirectory(const FilePath &filePath) const
|
||||||
@@ -1144,7 +1149,7 @@ bool DockerDevice::exists(const FilePath &filePath) const
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInContainer({"test", {"-e", path}});
|
return d->runInShell({"test", {"-e", path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::ensureExistingFile(const FilePath &filePath) const
|
bool DockerDevice::ensureExistingFile(const FilePath &filePath) const
|
||||||
@@ -1158,7 +1163,7 @@ bool DockerDevice::ensureExistingFile(const FilePath &filePath) const
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
return d->runInContainer({"touch", {path}});
|
return d->runInShell({"touch", {path}});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::removeFile(const FilePath &filePath) const
|
bool DockerDevice::removeFile(const FilePath &filePath) const
|
||||||
@@ -1271,12 +1276,8 @@ FilePaths DockerDevice::directoryEntries(const FilePath &filePath,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QtcProcess proc;
|
const QString output = d->outputForRunInShell({"ls", {"-1", "-b", "--", filePath.path()}});
|
||||||
proc.setCommand({"ls", {"-1", "-b", "--", filePath.path()}});
|
QStringList entries = output.split('\n', Qt::SkipEmptyParts);
|
||||||
runProcess(proc);
|
|
||||||
proc.waitForFinished();
|
|
||||||
|
|
||||||
QStringList entries = proc.stdOut().split('\n', Qt::SkipEmptyParts);
|
|
||||||
return FilePath::filterEntriesHelper(filePath, entries, nameFilters, filters, sort);
|
return FilePath::filterEntriesHelper(filePath, entries, nameFilters, filters, sort);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1388,6 +1389,48 @@ bool DockerDevicePrivate::runInContainer(const CommandLine &cmd) const
|
|||||||
return exitCode == 0;
|
return exitCode == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DockerDevicePrivate::runInShell(const CommandLine &cmd) const
|
||||||
|
{
|
||||||
|
if (m_accessible == NoDaemon)
|
||||||
|
return false;
|
||||||
|
QTC_ASSERT(m_shell, return false);
|
||||||
|
QMutexLocker l(&m_shellMutex);
|
||||||
|
m_shell->readAllStandardOutput(); // clean possible left-overs
|
||||||
|
m_shell->write(cmd.toUserOutput().toUtf8() + "\necho $?\n");
|
||||||
|
m_shell->waitForReadyRead();
|
||||||
|
QByteArray output = m_shell->readAllStandardOutput();
|
||||||
|
int result = output.toInt();
|
||||||
|
LOG("Run command in shell:" << cmd.toUserOutput() << "result: " << output << " ==>" << result);
|
||||||
|
return result == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate hex value
|
||||||
|
static QByteArray randomHex()
|
||||||
|
{
|
||||||
|
quint32 val = QRandomGenerator::global()->generate();
|
||||||
|
return QString::number(val, 16).toUtf8();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DockerDevicePrivate::outputForRunInShell(const CommandLine &cmd) const
|
||||||
|
{
|
||||||
|
if (m_accessible == NoDaemon)
|
||||||
|
return {};
|
||||||
|
QTC_ASSERT(m_shell, return {});
|
||||||
|
QMutexLocker l(&m_shellMutex);
|
||||||
|
m_shell->readAllStandardOutput(); // clean possible left-overs
|
||||||
|
const QByteArray markerWithNewLine("___QC_DOCKER_" + randomHex() + "_OUTPUT_MARKER___\n");
|
||||||
|
m_shell->write(cmd.toUserOutput().toUtf8() + "\necho -n \"" + markerWithNewLine + "\"\n");
|
||||||
|
QByteArray output;
|
||||||
|
while (!output.endsWith(markerWithNewLine)) {
|
||||||
|
m_shell->waitForReadyRead();
|
||||||
|
output.append(m_shell->readAllStandardOutput());
|
||||||
|
}
|
||||||
|
LOG("Run command in shell:" << cmd.toUserOutput() << "output size:" << output.size());
|
||||||
|
if (QTC_GUARD(output.endsWith(markerWithNewLine)))
|
||||||
|
output.chop(markerWithNewLine.size());
|
||||||
|
return QString::fromUtf8(output);
|
||||||
|
}
|
||||||
|
|
||||||
// Factory
|
// Factory
|
||||||
|
|
||||||
DockerDeviceFactory::DockerDeviceFactory()
|
DockerDeviceFactory::DockerDeviceFactory()
|
||||||
|
Reference in New Issue
Block a user