forked from qt-creator/qt-creator
iOS: Extend the information cached for simulator
Change-Id: Ia2bc421b2af7d1e82d48bbd9d7914f177fef30d0 Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
@@ -42,6 +42,7 @@
|
|||||||
#include <qtsupport/qtoutputformatter.h>
|
#include <qtsupport/qtoutputformatter.h>
|
||||||
#include <qtsupport/qtkitinformation.h>
|
#include <qtsupport/qtkitinformation.h>
|
||||||
|
|
||||||
|
#include <utils/algorithm.h>
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
@@ -67,6 +68,14 @@ namespace Internal {
|
|||||||
|
|
||||||
static const QLatin1String deviceTypeKey("Ios.device_type");
|
static const QLatin1String deviceTypeKey("Ios.device_type");
|
||||||
|
|
||||||
|
static IosDeviceType toIosDeviceType(const SimulatorInfo &device)
|
||||||
|
{
|
||||||
|
IosDeviceType iosDeviceType(IosDeviceType::SimulatedDevice,
|
||||||
|
device.identifier,
|
||||||
|
QString("%1, %2").arg(device.name).arg(device.runtimeName));
|
||||||
|
return iosDeviceType;
|
||||||
|
}
|
||||||
|
|
||||||
class IosRunConfigurationWidget : public RunConfigWidget
|
class IosRunConfigurationWidget : public RunConfigWidget
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -350,22 +359,24 @@ QString IosRunConfiguration::disabledReason() const
|
|||||||
|
|
||||||
IosDeviceType IosRunConfiguration::deviceType() const
|
IosDeviceType IosRunConfiguration::deviceType() const
|
||||||
{
|
{
|
||||||
QList<IosDeviceType> availableSimulators;
|
if (m_deviceType.type == IosDeviceType::SimulatedDevice) {
|
||||||
if (m_deviceType.type == IosDeviceType::SimulatedDevice)
|
QList<SimulatorInfo> availableSimulators = SimulatorControl::availableSimulators();
|
||||||
availableSimulators = SimulatorControl::availableSimulators();
|
if (availableSimulators.isEmpty())
|
||||||
if (!availableSimulators.isEmpty()) {
|
return m_deviceType;
|
||||||
QList<IosDeviceType> elegibleDevices;
|
if (Utils::contains(availableSimulators,
|
||||||
QString devname = m_deviceType.identifier.split(QLatin1Char(',')).value(0);
|
Utils::equal(&SimulatorInfo::identifier, m_deviceType.identifier))) {
|
||||||
foreach (const IosDeviceType &dType, availableSimulators) {
|
|
||||||
if (dType == m_deviceType)
|
|
||||||
return m_deviceType;
|
return m_deviceType;
|
||||||
if (!devname.isEmpty() && dType.identifier.startsWith(devname)
|
|
||||||
&& dType.identifier.split(QLatin1Char(',')).value(0) == devname)
|
|
||||||
elegibleDevices << dType;
|
|
||||||
}
|
}
|
||||||
if (!elegibleDevices.isEmpty())
|
const QStringList parts = m_deviceType.displayName.split(QLatin1Char(','));
|
||||||
return elegibleDevices.last();
|
if (parts.count() < 2)
|
||||||
return availableSimulators.last();
|
return toIosDeviceType(availableSimulators.last());
|
||||||
|
|
||||||
|
QList<SimulatorInfo> eligibleDevices;
|
||||||
|
eligibleDevices = Utils::filtered(availableSimulators, [parts](const SimulatorInfo &info) {
|
||||||
|
return info.name == parts.at(0) && info.runtimeName == parts.at(1);
|
||||||
|
});
|
||||||
|
return toIosDeviceType(eligibleDevices.isEmpty() ? availableSimulators.last()
|
||||||
|
: eligibleDevices.last());
|
||||||
}
|
}
|
||||||
return m_deviceType;
|
return m_deviceType;
|
||||||
}
|
}
|
||||||
@@ -413,7 +424,7 @@ void IosRunConfigurationWidget::setDeviceTypeIndex(int devIndex)
|
|||||||
{
|
{
|
||||||
QVariant selectedDev = m_deviceTypeModel.data(m_deviceTypeModel.index(devIndex, 0), Qt::UserRole + 1);
|
QVariant selectedDev = m_deviceTypeModel.data(m_deviceTypeModel.index(devIndex, 0), Qt::UserRole + 1);
|
||||||
if (selectedDev.isValid())
|
if (selectedDev.isValid())
|
||||||
m_runConfiguration->setDeviceType(selectedDev.value<IosDeviceType>());
|
m_runConfiguration->setDeviceType(toIosDeviceType(selectedDev.value<SimulatorInfo>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -423,25 +434,27 @@ void IosRunConfigurationWidget::updateValues()
|
|||||||
m_deviceTypeLabel->setVisible(showDeviceSelector);
|
m_deviceTypeLabel->setVisible(showDeviceSelector);
|
||||||
m_deviceTypeComboBox->setVisible(showDeviceSelector);
|
m_deviceTypeComboBox->setVisible(showDeviceSelector);
|
||||||
if (showDeviceSelector && m_deviceTypeModel.rowCount() == 0) {
|
if (showDeviceSelector && m_deviceTypeModel.rowCount() == 0) {
|
||||||
foreach (const IosDeviceType &dType, SimulatorControl::availableSimulators()) {
|
foreach (const SimulatorInfo &device, SimulatorControl::availableSimulators()) {
|
||||||
QStandardItem *item = new QStandardItem(dType.displayName);
|
QStandardItem *item = new QStandardItem(QString("%1, %2").arg(device.name)
|
||||||
|
.arg(device.runtimeName));
|
||||||
QVariant v;
|
QVariant v;
|
||||||
v.setValue(dType);
|
v.setValue(device);
|
||||||
item->setData(v);
|
item->setData(v);
|
||||||
m_deviceTypeModel.appendRow(item);
|
m_deviceTypeModel.appendRow(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IosDeviceType currentDType = m_runConfiguration->deviceType();
|
IosDeviceType currentDType = m_runConfiguration->deviceType();
|
||||||
|
QVariant currentData = m_deviceTypeComboBox->currentData();
|
||||||
if (currentDType.type == IosDeviceType::SimulatedDevice && !currentDType.identifier.isEmpty()
|
if (currentDType.type == IosDeviceType::SimulatedDevice && !currentDType.identifier.isEmpty()
|
||||||
&& (!m_deviceTypeComboBox->currentData().isValid()
|
&& (!currentData.isValid()
|
||||||
|| currentDType != m_deviceTypeComboBox->currentData().value<IosDeviceType>()))
|
|| currentDType != toIosDeviceType(currentData.value<SimulatorInfo>())))
|
||||||
{
|
{
|
||||||
bool didSet = false;
|
bool didSet = false;
|
||||||
for (int i = 0; m_deviceTypeModel.hasIndex(i, 0); ++i) {
|
for (int i = 0; m_deviceTypeModel.hasIndex(i, 0); ++i) {
|
||||||
QVariant vData = m_deviceTypeModel.data(m_deviceTypeModel.index(i, 0), Qt::UserRole + 1);
|
QVariant vData = m_deviceTypeModel.data(m_deviceTypeModel.index(i, 0), Qt::UserRole + 1);
|
||||||
IosDeviceType dType = vData.value<IosDeviceType>();
|
SimulatorInfo dType = vData.value<SimulatorInfo>();
|
||||||
if (dType == currentDType) {
|
if (dType.identifier == currentDType.identifier) {
|
||||||
m_deviceTypeComboBox->setCurrentIndex(i);
|
m_deviceTypeComboBox->setCurrentIndex(i);
|
||||||
didSet = true;
|
didSet = true;
|
||||||
break;
|
break;
|
||||||
|
@@ -24,9 +24,9 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "simulatorcontrol.h"
|
#include "simulatorcontrol.h"
|
||||||
#include "iossimulator.h"
|
|
||||||
#include "iosconfigurations.h"
|
#include "iosconfigurations.h"
|
||||||
|
|
||||||
|
#include "utils/algorithm.h"
|
||||||
#include "utils/runextensions.h"
|
#include "utils/runextensions.h"
|
||||||
#include "utils/qtcassert.h"
|
#include "utils/qtcassert.h"
|
||||||
#include "utils/synchronousprocess.h"
|
#include "utils/synchronousprocess.h"
|
||||||
@@ -83,20 +83,10 @@ static bool runSimCtlCommand(QStringList args, QByteArray *output)
|
|||||||
|
|
||||||
class SimulatorControlPrivate {
|
class SimulatorControlPrivate {
|
||||||
private:
|
private:
|
||||||
struct SimDeviceInfo {
|
|
||||||
bool isBooted() const { return state.compare(QStringLiteral("Booted")) == 0; }
|
|
||||||
bool isAvailable() const { return !availability.contains(QStringLiteral("unavailable")); }
|
|
||||||
QString name;
|
|
||||||
QString udid;
|
|
||||||
QString availability;
|
|
||||||
QString state;
|
|
||||||
QString sdk;
|
|
||||||
};
|
|
||||||
|
|
||||||
SimulatorControlPrivate();
|
SimulatorControlPrivate();
|
||||||
~SimulatorControlPrivate();
|
~SimulatorControlPrivate();
|
||||||
|
|
||||||
static SimDeviceInfo deviceInfo(const QString &simUdid);
|
static SimulatorInfo deviceInfo(const QString &simUdid);
|
||||||
static QString bundleIdentifier(const Utils::FileName &bundlePath);
|
static QString bundleIdentifier(const Utils::FileName &bundlePath);
|
||||||
static QString bundleExecutable(const Utils::FileName &bundlePath);
|
static QString bundleExecutable(const Utils::FileName &bundlePath);
|
||||||
|
|
||||||
@@ -108,7 +98,7 @@ private:
|
|||||||
const QStringList &extraArgs, const QString &stdoutPath,
|
const QStringList &extraArgs, const QString &stdoutPath,
|
||||||
const QString &stderrPath);
|
const QString &stderrPath);
|
||||||
|
|
||||||
static QList<IosDeviceType> availableDevices;
|
static QList<SimulatorInfo> availableDevices;
|
||||||
friend class SimulatorControl;
|
friend class SimulatorControl;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -123,44 +113,51 @@ SimulatorControl::~SimulatorControl()
|
|||||||
delete d;
|
delete d;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Ios::Internal::IosDeviceType> SimulatorControl::availableSimulators()
|
QList<SimulatorInfo> SimulatorControl::availableSimulators()
|
||||||
{
|
{
|
||||||
return SimulatorControlPrivate::availableDevices;
|
return SimulatorControlPrivate::availableDevices;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QList<IosDeviceType> getAvailableSimulators()
|
static QList<SimulatorInfo> getAllSimulatorDevices()
|
||||||
{
|
{
|
||||||
QList<IosDeviceType> availableDevices;
|
QList<SimulatorInfo> simulatorDevices;
|
||||||
QByteArray output;
|
QByteArray output;
|
||||||
runSimCtlCommand({QLatin1String("list"), QLatin1String("-j"), QLatin1String("devices")}, &output);
|
runSimCtlCommand({QLatin1String("list"), QLatin1String("-j"), QLatin1String("devices")}, &output);
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(output);
|
QJsonDocument doc = QJsonDocument::fromJson(output);
|
||||||
if (!doc.isNull()) {
|
if (!doc.isNull()) {
|
||||||
const QJsonObject buildInfo = doc.object().value("devices").toObject();
|
const QJsonObject runtimeObject = doc.object().value(QStringLiteral("devices")).toObject();
|
||||||
foreach (const QString &buildVersion, buildInfo.keys()) {
|
foreach (const QString &runtime, runtimeObject.keys()) {
|
||||||
QJsonArray devices = buildInfo.value(buildVersion).toArray();
|
const QJsonArray devices = runtimeObject.value(runtime).toArray();
|
||||||
foreach (const QJsonValue device, devices) {
|
foreach (const QJsonValue deviceValue, devices) {
|
||||||
QJsonObject deviceInfo = device.toObject();
|
QJsonObject deviceObject = deviceValue.toObject();
|
||||||
QString deviceName = QString("%1, %2")
|
SimulatorInfo device;
|
||||||
.arg(deviceInfo.value("name").toString("Unknown"))
|
device.identifier = deviceObject.value(QStringLiteral("udid")).toString();
|
||||||
.arg(buildVersion);
|
device.name = deviceObject.value(QStringLiteral("name")).toString();
|
||||||
QString deviceUdid = deviceInfo.value("udid").toString("Unknown");
|
device.runtimeName = runtime;
|
||||||
if (!deviceInfo.value("availability").toString().contains("unavailable")) {
|
const QString availableStr = deviceObject.value(QStringLiteral("availability")).toString();
|
||||||
IosDeviceType iOSDevice(IosDeviceType::SimulatedDevice, deviceUdid, deviceName);
|
device.available = !availableStr.contains("unavailable");
|
||||||
availableDevices.append(iOSDevice);
|
device.state = deviceObject.value(QStringLiteral("state")).toString();
|
||||||
|
simulatorDevices.append(device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
stable_sort(simulatorDevices.begin(), simulatorDevices.end());
|
||||||
stable_sort(availableDevices.begin(), availableDevices.end());
|
|
||||||
} else {
|
} else {
|
||||||
qCDebug(simulatorLog) << "Error parsing json output from simctl. Output:" << output;
|
qCDebug(simulatorLog) << "Error parsing json output from simctl. Output:" << output;
|
||||||
}
|
}
|
||||||
|
return simulatorDevices;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QList<SimulatorInfo> getAvailableSimulators()
|
||||||
|
{
|
||||||
|
auto filterSim = [](const SimulatorInfo &device) { return device.available;};
|
||||||
|
QList<SimulatorInfo> availableDevices = Utils::filtered(getAllSimulatorDevices(), filterSim);
|
||||||
return availableDevices;
|
return availableDevices;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatorControl::updateAvailableSimulators()
|
void SimulatorControl::updateAvailableSimulators()
|
||||||
{
|
{
|
||||||
QFuture< QList<IosDeviceType> > future = Utils::runAsync(getAvailableSimulators);
|
QFuture< QList<SimulatorInfo> > future = Utils::runAsync(getAvailableSimulators);
|
||||||
Utils::onResultReady(future, [](const QList<IosDeviceType> &devices) {
|
Utils::onResultReady(future, [](const QList<SimulatorInfo> &devices) {
|
||||||
SimulatorControlPrivate::availableDevices = devices;
|
SimulatorControlPrivate::availableDevices = devices;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -202,7 +199,7 @@ SimulatorControl::launchApp(const QString &simUdid, const QString &bundleIdentif
|
|||||||
waitForDebugger, extraArgs, stdoutPath, stderrPath);
|
waitForDebugger, extraArgs, stdoutPath, stderrPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<IosDeviceType> SimulatorControlPrivate::availableDevices;
|
QList<SimulatorInfo> SimulatorControlPrivate::availableDevices;
|
||||||
|
|
||||||
SimulatorControlPrivate::SimulatorControlPrivate()
|
SimulatorControlPrivate::SimulatorControlPrivate()
|
||||||
{
|
{
|
||||||
@@ -213,41 +210,16 @@ SimulatorControlPrivate::~SimulatorControlPrivate()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SimulatorControlPrivate::SimDeviceInfo SimulatorControlPrivate::deviceInfo(const QString &simUdid)
|
SimulatorInfo SimulatorControlPrivate::deviceInfo(const QString &simUdid)
|
||||||
{
|
{
|
||||||
SimDeviceInfo info;
|
auto matchDevice = [simUdid](const SimulatorInfo &device) {
|
||||||
bool found = false;
|
return device.identifier == simUdid;
|
||||||
if (!simUdid.isEmpty()) {
|
};
|
||||||
QByteArray output;
|
SimulatorInfo device = Utils::findOrDefault(getAllSimulatorDevices(), matchDevice);
|
||||||
runSimCtlCommand({QLatin1String("list"), QLatin1String("-j"), QLatin1String("devices")}, &output);
|
if (device.identifier.isEmpty())
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(output);
|
|
||||||
if (!doc.isNull()) {
|
|
||||||
const QJsonObject buildInfo = doc.object().value(QStringLiteral("devices")).toObject();
|
|
||||||
foreach (const QString &buildVersion, buildInfo.keys()) {
|
|
||||||
QJsonArray devices = buildInfo.value(buildVersion).toArray();
|
|
||||||
foreach (const QJsonValue device, devices) {
|
|
||||||
QJsonObject deviceInfo = device.toObject();
|
|
||||||
QString deviceUdid = deviceInfo.value(QStringLiteral("udid")).toString();
|
|
||||||
if (deviceUdid.compare(simUdid) == 0) {
|
|
||||||
found = true;
|
|
||||||
info.name = deviceInfo.value(QStringLiteral("name")).toString();
|
|
||||||
info.udid = deviceUdid;
|
|
||||||
info.state = deviceInfo.value(QStringLiteral("state")).toString();
|
|
||||||
info.sdk = buildVersion;
|
|
||||||
info.availability = deviceInfo.value(QStringLiteral("availability")).toString();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (found)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qCDebug(simulatorLog) << "Cannot find device info. Error parsing json output from simctl. Output:" << output;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qCDebug(simulatorLog) << "Cannot find device info. Invalid UDID.";
|
qCDebug(simulatorLog) << "Cannot find device info. Invalid UDID.";
|
||||||
}
|
|
||||||
return info;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SimulatorControlPrivate::bundleIdentifier(const Utils::FileName &bundlePath)
|
QString SimulatorControlPrivate::bundleIdentifier(const Utils::FileName &bundlePath)
|
||||||
@@ -293,7 +265,7 @@ void SimulatorControlPrivate::startSimulator(QFutureInterface<SimulatorControl::
|
|||||||
const QString &simUdid)
|
const QString &simUdid)
|
||||||
{
|
{
|
||||||
SimulatorControl::ResponseData response(simUdid);
|
SimulatorControl::ResponseData response(simUdid);
|
||||||
if (deviceInfo(simUdid).isAvailable()) {
|
if (deviceInfo(simUdid).available) {
|
||||||
// Simulator is available.
|
// Simulator is available.
|
||||||
const QString cmd = IosConfigurations::developerPath()
|
const QString cmd = IosConfigurations::developerPath()
|
||||||
.appendPath(QStringLiteral("/Applications/Simulator.app/Contents/MacOS/Simulator"))
|
.appendPath(QStringLiteral("/Applications/Simulator.app/Contents/MacOS/Simulator"))
|
||||||
@@ -307,7 +279,7 @@ void SimulatorControlPrivate::startSimulator(QFutureInterface<SimulatorControl::
|
|||||||
// So the simulator is started and we'll wait for it to reach to a state
|
// So the simulator is started and we'll wait for it to reach to a state
|
||||||
// where we can interact with it.
|
// where we can interact with it.
|
||||||
auto start = chrono::high_resolution_clock::now();
|
auto start = chrono::high_resolution_clock::now();
|
||||||
SimulatorControlPrivate::SimDeviceInfo info;
|
SimulatorInfo info;
|
||||||
do {
|
do {
|
||||||
info = deviceInfo(simUdid);
|
info = deviceInfo(simUdid);
|
||||||
if (fi.isCanceled())
|
if (fi.isCanceled())
|
||||||
|
@@ -37,9 +37,22 @@ QT_END_NAMESPACE
|
|||||||
namespace Ios {
|
namespace Ios {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class IosDeviceType;
|
|
||||||
class SimulatorControlPrivate;
|
class SimulatorControlPrivate;
|
||||||
|
|
||||||
|
class SimulatorInfo {
|
||||||
|
public:
|
||||||
|
bool isBooted() const { return state.compare(QStringLiteral("Booted")) == 0; }
|
||||||
|
bool available;
|
||||||
|
QString state;
|
||||||
|
QString runtimeName;
|
||||||
|
QString name;
|
||||||
|
QString identifier;
|
||||||
|
bool operator <(const SimulatorInfo &o) const
|
||||||
|
{
|
||||||
|
return name < o.name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class SimulatorControl : public QObject
|
class SimulatorControl : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -59,7 +72,7 @@ public:
|
|||||||
~SimulatorControl();
|
~SimulatorControl();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static QList<IosDeviceType> availableSimulators();
|
static QList<SimulatorInfo> availableSimulators();
|
||||||
static void updateAvailableSimulators();
|
static void updateAvailableSimulators();
|
||||||
static bool isSimulatorRunning(const QString &simUdid);
|
static bool isSimulatorRunning(const QString &simUdid);
|
||||||
static QString bundleIdentifier(const Utils::FileName &bundlePath);
|
static QString bundleIdentifier(const Utils::FileName &bundlePath);
|
||||||
@@ -78,3 +91,5 @@ private:
|
|||||||
};
|
};
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Ios
|
} // namespace Ios
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(Ios::Internal::SimulatorInfo)
|
||||||
|
Reference in New Issue
Block a user