forked from qt-creator/qt-creator
Rename QHashSeedType to QHashValueType and use it also for return values. Use qHashMulti directly instead of continuing using temporary QPairs. Avoids ugly namespace tricks to find the new pair overloads, and is actually clearer. Classes used in signals cannot be forward-declared. ... Change-Id: I22450a0c642437a43f876e8e89cc8788fff3db61 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
664 lines
26 KiB
C++
664 lines
26 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
** Contact: https://www.qt.io/licensing/
|
|
**
|
|
** This file is part of Qt Creator.
|
|
**
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
** General Public License version 3 as published by the Free Software
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
** included in the packaging of this file. Please review the following
|
|
** information to ensure the GNU General Public License requirements will
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include "iosconfigurations.h"
|
|
#include "iosconstants.h"
|
|
#include "iosdevice.h"
|
|
#include "iossimulator.h"
|
|
#include "simulatorcontrol.h"
|
|
#include "iosprobe.h"
|
|
|
|
#include <coreplugin/icore.h>
|
|
#include <utils/algorithm.h>
|
|
#include <utils/synchronousprocess.h>
|
|
#include <utils/qtcassert.h>
|
|
#include <utils/synchronousprocess.h>
|
|
#include <projectexplorer/kitmanager.h>
|
|
#include <projectexplorer/kitinformation.h>
|
|
#include <projectexplorer/devicesupport/devicemanager.h>
|
|
#include <projectexplorer/toolchainmanager.h>
|
|
#include <projectexplorer/toolchain.h>
|
|
#include <projectexplorer/gcctoolchain.h>
|
|
#include <projectexplorer/projectexplorerconstants.h>
|
|
#include <debugger/debuggeritemmanager.h>
|
|
#include <debugger/debuggeritem.h>
|
|
#include <debugger/debuggerkitinformation.h>
|
|
#include <qtsupport/baseqtversion.h>
|
|
#include <qtsupport/qtkitinformation.h>
|
|
#include <qtsupport/qtversionmanager.h>
|
|
#include <qtsupport/qtversionfactory.h>
|
|
|
|
#include <QDir>
|
|
#include <QDomDocument>
|
|
#include <QFileInfo>
|
|
#include <QFileSystemWatcher>
|
|
#include <QHash>
|
|
#include <QList>
|
|
#include <QLoggingCategory>
|
|
#include <QProcess>
|
|
#include <QSettings>
|
|
#include <QStringList>
|
|
#include <QStandardPaths>
|
|
#include <QTimer>
|
|
|
|
#include <memory>
|
|
|
|
using namespace ProjectExplorer;
|
|
using namespace QtSupport;
|
|
using namespace Utils;
|
|
using namespace Debugger;
|
|
|
|
namespace {
|
|
static Q_LOGGING_CATEGORY(kitSetupLog, "qtc.ios.kitSetup", QtWarningMsg)
|
|
static Q_LOGGING_CATEGORY(iosCommonLog, "qtc.ios.common", QtWarningMsg)
|
|
}
|
|
|
|
using ToolChainPair = std::pair<ClangToolChain *, ClangToolChain *>;
|
|
namespace Ios {
|
|
namespace Internal {
|
|
|
|
const char SettingsGroup[] = "IosConfigurations";
|
|
const char ignoreAllDevicesKey[] = "IgnoreAllDevices";
|
|
const char screenshotDirPathKey[] = "ScreeshotDirPath";
|
|
|
|
const char provisioningTeamsTag[] = "IDEProvisioningTeams";
|
|
const char freeTeamTag[] = "isFreeProvisioningTeam";
|
|
const char emailTag[] = "eMail";
|
|
const char teamNameTag[] = "teamName";
|
|
const char teamIdTag[] = "teamID";
|
|
|
|
const char udidTag[] = "UUID";
|
|
const char profileNameTag[] = "Name";
|
|
const char appIdTag[] = "AppIDName";
|
|
const char expirationDateTag[] = "ExpirationDate";
|
|
const char profileTeamIdTag[] = "TeamIdentifier";
|
|
|
|
static const QString xcodePlistPath = QDir::homePath() + "/Library/Preferences/com.apple.dt.Xcode.plist";
|
|
static const QString provisioningProfileDirPath = QDir::homePath() + "/Library/MobileDevice/Provisioning Profiles";
|
|
|
|
static Utils::Id deviceId(const QString &sdkName)
|
|
{
|
|
if (sdkName.startsWith("iphoneos", Qt::CaseInsensitive))
|
|
return Constants::IOS_DEVICE_TYPE;
|
|
else if (sdkName.startsWith("iphonesimulator", Qt::CaseInsensitive))
|
|
return Constants::IOS_SIMULATOR_TYPE;
|
|
return {};
|
|
}
|
|
|
|
static bool isSimulatorDeviceId(const Utils::Id &id)
|
|
{
|
|
return id == Constants::IOS_SIMULATOR_TYPE;
|
|
}
|
|
|
|
static QList<ClangToolChain *> clangToolChains(const QList<ToolChain *> &toolChains)
|
|
{
|
|
QList<ClangToolChain *> clangToolChains;
|
|
foreach (ToolChain *toolChain, toolChains)
|
|
if (toolChain->typeId() == ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID)
|
|
clangToolChains.append(static_cast<ClangToolChain *>(toolChain));
|
|
return clangToolChains;
|
|
}
|
|
|
|
static QList<ClangToolChain *> autoDetectedIosToolChains()
|
|
{
|
|
const QList<ClangToolChain *> toolChains = clangToolChains(ToolChainManager::toolChains());
|
|
return Utils::filtered(toolChains, [](ClangToolChain *toolChain) {
|
|
return toolChain->isAutoDetected()
|
|
&& (toolChain->displayName().startsWith("iphone")
|
|
|| toolChain->displayName().startsWith("Apple Clang")); // TODO tool chains should be marked directly
|
|
});
|
|
}
|
|
|
|
static ToolChainPair findToolChainForPlatform(const XcodePlatform &platform,
|
|
const XcodePlatform::ToolchainTarget &target,
|
|
const QList<ClangToolChain *> &toolChains)
|
|
{
|
|
ToolChainPair platformToolChains;
|
|
auto toolchainMatch = [](ClangToolChain *toolChain, const Utils::FilePath &compilerPath, const QStringList &flags) {
|
|
return compilerPath == toolChain->compilerCommand()
|
|
&& flags == toolChain->platformCodeGenFlags()
|
|
&& flags == toolChain->platformLinkerFlags();
|
|
};
|
|
platformToolChains.first = Utils::findOrDefault(toolChains, std::bind(toolchainMatch, std::placeholders::_1,
|
|
platform.cCompilerPath,
|
|
target.backendFlags));
|
|
platformToolChains.second = Utils::findOrDefault(toolChains, std::bind(toolchainMatch, std::placeholders::_1,
|
|
platform.cxxCompilerPath,
|
|
target.backendFlags));
|
|
return platformToolChains;
|
|
}
|
|
|
|
static QHash<XcodePlatform::ToolchainTarget, ToolChainPair> findToolChains(const QList<XcodePlatform> &platforms)
|
|
{
|
|
QHash<XcodePlatform::ToolchainTarget, ToolChainPair> platformToolChainHash;
|
|
const QList<ClangToolChain *> toolChains = autoDetectedIosToolChains();
|
|
for (const XcodePlatform &platform : platforms) {
|
|
for (const XcodePlatform::ToolchainTarget &target : platform.targets) {
|
|
ToolChainPair platformToolchains = findToolChainForPlatform(platform, target,
|
|
toolChains);
|
|
if (platformToolchains.first || platformToolchains.second)
|
|
platformToolChainHash.insert(target, platformToolchains);
|
|
}
|
|
}
|
|
return platformToolChainHash;
|
|
}
|
|
|
|
static QSet<Kit *> existingAutoDetectedIosKits()
|
|
{
|
|
return Utils::toSet(Utils::filtered(KitManager::kits(), [](Kit *kit) -> bool {
|
|
Utils::Id deviceKind = DeviceTypeKitAspect::deviceTypeId(kit);
|
|
return kit->isAutoDetected() && (deviceKind == Constants::IOS_DEVICE_TYPE
|
|
|| deviceKind == Constants::IOS_SIMULATOR_TYPE);
|
|
}));
|
|
}
|
|
|
|
static void printKits(const QSet<Kit *> &kits)
|
|
{
|
|
foreach (const Kit *kit, kits)
|
|
qCDebug(kitSetupLog) << " -" << kit->displayName();
|
|
}
|
|
|
|
static void setupKit(Kit *kit, Utils::Id pDeviceType, const ToolChainPair& toolChains,
|
|
const QVariant &debuggerId, const Utils::FilePath &sdkPath, BaseQtVersion *qtVersion)
|
|
{
|
|
DeviceTypeKitAspect::setDeviceTypeId(kit, pDeviceType);
|
|
if (toolChains.first)
|
|
ToolChainKitAspect::setToolChain(kit, toolChains.first);
|
|
else
|
|
ToolChainKitAspect::clearToolChain(kit, ProjectExplorer::Constants::C_LANGUAGE_ID);
|
|
if (toolChains.second)
|
|
ToolChainKitAspect::setToolChain(kit, toolChains.second);
|
|
else
|
|
ToolChainKitAspect::clearToolChain(kit, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
|
|
|
|
QtKitAspect::setQtVersion(kit, qtVersion);
|
|
// only replace debugger with the default one if we find an unusable one here
|
|
// (since the user could have changed it)
|
|
if ((!DebuggerKitAspect::debugger(kit)
|
|
|| !DebuggerKitAspect::debugger(kit)->isValid()
|
|
|| DebuggerKitAspect::debugger(kit)->engineType() != LldbEngineType)
|
|
&& debuggerId.isValid())
|
|
DebuggerKitAspect::setDebugger(kit, debuggerId);
|
|
|
|
kit->setMutable(DeviceKitAspect::id(), true);
|
|
kit->setSticky(QtKitAspect::id(), true);
|
|
kit->setSticky(ToolChainKitAspect::id(), true);
|
|
kit->setSticky(DeviceTypeKitAspect::id(), true);
|
|
kit->setSticky(SysRootKitAspect::id(), true);
|
|
kit->setSticky(DebuggerKitAspect::id(), false);
|
|
|
|
SysRootKitAspect::setSysRoot(kit, sdkPath);
|
|
}
|
|
|
|
static QVersionNumber findXcodeVersion(const Utils::FilePath &developerPath)
|
|
{
|
|
const FilePath xcodeInfo = developerPath.parentDir().pathAppended("Info.plist");
|
|
if (xcodeInfo.exists()) {
|
|
QSettings settings(xcodeInfo.toString(), QSettings::NativeFormat);
|
|
return QVersionNumber::fromString(settings.value("CFBundleShortVersionString").toString());
|
|
} else {
|
|
qCDebug(iosCommonLog) << "Error finding Xcode version." << xcodeInfo.toUserOutput() <<
|
|
"does not exist.";
|
|
}
|
|
return QVersionNumber();
|
|
}
|
|
|
|
static QByteArray decodeProvisioningProfile(const QString &path)
|
|
{
|
|
QTC_ASSERT(!path.isEmpty(), return QByteArray());
|
|
|
|
Utils::SynchronousProcess p;
|
|
p.setTimeoutS(3);
|
|
// path is assumed to be valid file path to .mobileprovision
|
|
const QStringList args = {"smime", "-inform", "der", "-verify", "-in", path};
|
|
Utils::SynchronousProcessResponse res = p.runBlocking({"openssl", args});
|
|
if (res.result != Utils::SynchronousProcessResponse::Finished)
|
|
qCDebug(iosCommonLog) << "Reading signed provisioning file failed" << path;
|
|
return res.stdOut().toLatin1();
|
|
}
|
|
|
|
void IosConfigurations::updateAutomaticKitList()
|
|
{
|
|
const QList<XcodePlatform> platforms = XcodeProbe::detectPlatforms().values();
|
|
if (!platforms.isEmpty())
|
|
setDeveloperPath(platforms.first().developerPath);
|
|
qCDebug(kitSetupLog) << "Developer path:" << developerPath();
|
|
|
|
// target -> tool chain
|
|
const auto targetToolChainHash = findToolChains(platforms);
|
|
|
|
const auto qtVersions = Utils::toSet(QtVersionManager::versions([](const BaseQtVersion *v) {
|
|
return v->isValid() && v->type() == Constants::IOSQT;
|
|
}));
|
|
|
|
const DebuggerItem *possibleDebugger = DebuggerItemManager::findByEngineType(LldbEngineType);
|
|
const QVariant debuggerId = (possibleDebugger ? possibleDebugger->id() : QVariant());
|
|
|
|
QSet<Kit *> existingKits = existingAutoDetectedIosKits();
|
|
qCDebug(kitSetupLog) << "Existing auto-detected iOS kits:";
|
|
printKits(existingKits);
|
|
QSet<Kit *> resultingKits;
|
|
for (const XcodePlatform &platform : platforms) {
|
|
for (const auto &sdk : platform.sdks) {
|
|
const auto targets = Utils::filtered(platform.targets,
|
|
[&sdk](const XcodePlatform::ToolchainTarget &target) {
|
|
return sdk.architectures.first() == target.architecture;
|
|
});
|
|
if (targets.empty())
|
|
continue;
|
|
|
|
const auto target = targets.front();
|
|
|
|
const ToolChainPair &platformToolchains = targetToolChainHash.value(target);
|
|
if (!platformToolchains.first && !platformToolchains.second) {
|
|
qCDebug(kitSetupLog) << " - No tool chain found";
|
|
continue;
|
|
}
|
|
Utils::Id pDeviceType = deviceId(sdk.directoryName);
|
|
if (!pDeviceType.isValid()) {
|
|
qCDebug(kitSetupLog) << "Unsupported/Invalid device type" << sdk.directoryName;
|
|
continue;
|
|
}
|
|
|
|
for (BaseQtVersion *qtVersion : qtVersions) {
|
|
qCDebug(kitSetupLog) << " - Qt version:" << qtVersion->displayName();
|
|
Kit *kit = Utils::findOrDefault(existingKits, [&pDeviceType, &platformToolchains, &qtVersion](const Kit *kit) {
|
|
// we do not compare the sdk (thus automatically upgrading it in place if a
|
|
// new Xcode is used). Change?
|
|
return DeviceTypeKitAspect::deviceTypeId(kit) == pDeviceType
|
|
&& ToolChainKitAspect::cxxToolChain(kit) == platformToolchains.second
|
|
&& ToolChainKitAspect::cToolChain(kit) == platformToolchains.first
|
|
&& QtKitAspect::qtVersion(kit) == qtVersion;
|
|
});
|
|
QTC_ASSERT(!resultingKits.contains(kit), continue);
|
|
if (kit) {
|
|
qCDebug(kitSetupLog) << " - Kit matches:" << kit->displayName();
|
|
kit->blockNotification();
|
|
setupKit(kit, pDeviceType, platformToolchains, debuggerId, sdk.path, qtVersion);
|
|
kit->unblockNotification();
|
|
} else {
|
|
qCDebug(kitSetupLog) << " - Setting up new kit";
|
|
const auto init = [&](Kit *k) {
|
|
k->setAutoDetected(true);
|
|
const QString baseDisplayName = isSimulatorDeviceId(pDeviceType)
|
|
? tr("%1 Simulator").arg(qtVersion->unexpandedDisplayName())
|
|
: qtVersion->unexpandedDisplayName();
|
|
k->setUnexpandedDisplayName(baseDisplayName);
|
|
setupKit(k, pDeviceType, platformToolchains, debuggerId, sdk.path, qtVersion);
|
|
};
|
|
kit = KitManager::registerKit(init);
|
|
}
|
|
resultingKits.insert(kit);
|
|
}
|
|
}
|
|
}
|
|
// remove unused kits
|
|
existingKits.subtract(resultingKits);
|
|
qCDebug(kitSetupLog) << "Removing unused kits:";
|
|
printKits(existingKits);
|
|
foreach (Kit *kit, existingKits)
|
|
KitManager::deregisterKit(kit);
|
|
}
|
|
|
|
static IosConfigurations *m_instance = nullptr;
|
|
|
|
IosConfigurations *IosConfigurations::instance()
|
|
{
|
|
return m_instance;
|
|
}
|
|
|
|
void IosConfigurations::initialize()
|
|
{
|
|
QTC_CHECK(m_instance == nullptr);
|
|
m_instance = new IosConfigurations(nullptr);
|
|
}
|
|
|
|
void IosConfigurations::kitsRestored()
|
|
{
|
|
disconnect(KitManager::instance(), &KitManager::kitsLoaded,
|
|
this, &IosConfigurations::kitsRestored);
|
|
IosConfigurations::updateAutomaticKitList();
|
|
connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged,
|
|
IosConfigurations::instance(), &IosConfigurations::updateAutomaticKitList);
|
|
}
|
|
|
|
bool IosConfigurations::ignoreAllDevices()
|
|
{
|
|
return m_instance->m_ignoreAllDevices;
|
|
}
|
|
|
|
void IosConfigurations::setIgnoreAllDevices(bool ignoreDevices)
|
|
{
|
|
if (ignoreDevices != m_instance->m_ignoreAllDevices) {
|
|
m_instance->m_ignoreAllDevices = ignoreDevices;
|
|
m_instance->save();
|
|
}
|
|
}
|
|
|
|
void IosConfigurations::setScreenshotDir(const FilePath &path)
|
|
{
|
|
if (m_instance->m_screenshotDir != path) {
|
|
m_instance->m_screenshotDir = path;
|
|
m_instance->save();
|
|
}
|
|
}
|
|
|
|
FilePath IosConfigurations::screenshotDir()
|
|
{
|
|
return m_instance->m_screenshotDir;
|
|
}
|
|
|
|
FilePath IosConfigurations::developerPath()
|
|
{
|
|
return m_instance->m_developerPath;
|
|
}
|
|
|
|
QVersionNumber IosConfigurations::xcodeVersion()
|
|
{
|
|
return m_instance->m_xcodeVersion;
|
|
}
|
|
|
|
void IosConfigurations::save()
|
|
{
|
|
QSettings *settings = Core::ICore::settings();
|
|
settings->beginGroup(SettingsGroup);
|
|
settings->setValue(ignoreAllDevicesKey, m_ignoreAllDevices);
|
|
settings->setValue(screenshotDirPathKey, m_screenshotDir.toString());
|
|
settings->endGroup();
|
|
}
|
|
|
|
IosConfigurations::IosConfigurations(QObject *parent)
|
|
: QObject(parent)
|
|
{
|
|
load();
|
|
connect(KitManager::instance(), &KitManager::kitsLoaded,
|
|
this, &IosConfigurations::kitsRestored);
|
|
}
|
|
|
|
void IosConfigurations::load()
|
|
{
|
|
QSettings *settings = Core::ICore::settings();
|
|
settings->beginGroup(SettingsGroup);
|
|
m_ignoreAllDevices = settings->value(ignoreAllDevicesKey, false).toBool();
|
|
m_screenshotDir = FilePath::fromString(settings->value(screenshotDirPathKey).toString());
|
|
if (!m_screenshotDir.exists()) {
|
|
QString defaultDir =
|
|
QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).constFirst();
|
|
m_screenshotDir = FilePath::fromString(defaultDir);
|
|
}
|
|
|
|
settings->endGroup();
|
|
}
|
|
|
|
void IosConfigurations::updateSimulators()
|
|
{
|
|
// currently we have just one simulator
|
|
DeviceManager *devManager = DeviceManager::instance();
|
|
Utils::Id devId = Constants::IOS_SIMULATOR_DEVICE_ID;
|
|
IDevice::ConstPtr dev = devManager->find(devId);
|
|
if (dev.isNull()) {
|
|
dev = IDevice::ConstPtr(new IosSimulator(devId));
|
|
devManager->addDevice(dev);
|
|
}
|
|
SimulatorControl::updateAvailableSimulators();
|
|
}
|
|
|
|
void IosConfigurations::setDeveloperPath(const FilePath &devPath)
|
|
{
|
|
static bool hasDevPath = false;
|
|
if (devPath != m_instance->m_developerPath) {
|
|
m_instance->m_developerPath = devPath;
|
|
m_instance->save();
|
|
if (!hasDevPath && !devPath.isEmpty()) {
|
|
hasDevPath = true;
|
|
QTimer::singleShot(1000, IosDeviceManager::instance(),
|
|
&IosDeviceManager::monitorAvailableDevices);
|
|
m_instance->updateSimulators();
|
|
|
|
// Find xcode version.
|
|
m_instance->m_xcodeVersion = findXcodeVersion(m_instance->m_developerPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
void IosConfigurations::initializeProvisioningData()
|
|
{
|
|
// Initialize provisioning data only on demand. i.e. when first call to a provisioing data API
|
|
// is made.
|
|
if (m_provisioningDataWatcher)
|
|
return;
|
|
|
|
// Instantiate m_provisioningDataWatcher to mark initialized before calling loadProvisioningData.
|
|
m_provisioningDataWatcher = new QFileSystemWatcher(this);
|
|
|
|
m_instance->loadProvisioningData(false);
|
|
|
|
// Watch the provisioing profiles folder and xcode plist for changes and
|
|
// update the content accordingly.
|
|
m_provisioningDataWatcher->addPath(xcodePlistPath);
|
|
m_provisioningDataWatcher->addPath(provisioningProfileDirPath);
|
|
connect(m_provisioningDataWatcher, &QFileSystemWatcher::directoryChanged,
|
|
std::bind(&IosConfigurations::loadProvisioningData, this, true));
|
|
connect(m_provisioningDataWatcher, &QFileSystemWatcher::fileChanged,
|
|
std::bind(&IosConfigurations::loadProvisioningData, this, true));
|
|
}
|
|
|
|
void IosConfigurations::loadProvisioningData(bool notify)
|
|
{
|
|
m_developerTeams.clear();
|
|
m_provisioningProfiles.clear();
|
|
|
|
// Populate Team id's
|
|
const QSettings xcodeSettings(xcodePlistPath, QSettings::NativeFormat);
|
|
const QVariantMap teamMap = xcodeSettings.value(provisioningTeamsTag).toMap();
|
|
QList<QVariantMap> teams;
|
|
for (auto accountiterator = teamMap.cbegin(), end = teamMap.cend();
|
|
accountiterator != end; ++accountiterator) {
|
|
QVariantMap teamInfo = accountiterator.value().toMap();
|
|
int provisioningTeamIsFree = teamInfo.value(freeTeamTag).toBool() ? 1 : 0;
|
|
teamInfo[freeTeamTag] = provisioningTeamIsFree;
|
|
teamInfo[emailTag] = accountiterator.key();
|
|
teams.append(teamInfo);
|
|
}
|
|
|
|
// Sort team id's to move the free provisioning teams at last of the list.
|
|
Utils::sort(teams, [](const QVariantMap &teamInfo1, const QVariantMap &teamInfo2) {
|
|
return teamInfo1.value(freeTeamTag).toInt() < teamInfo2.value(freeTeamTag).toInt();
|
|
});
|
|
|
|
foreach (auto teamInfo, teams) {
|
|
auto team = std::make_shared<DevelopmentTeam>();
|
|
team->m_name = teamInfo.value(teamNameTag).toString();
|
|
team->m_email = teamInfo.value(emailTag).toString();
|
|
team->m_identifier = teamInfo.value(teamIdTag).toString();
|
|
team->m_freeTeam = teamInfo.value(freeTeamTag).toInt() == 1;
|
|
m_developerTeams.append(team);
|
|
}
|
|
|
|
const QDir provisioningProflesDir(provisioningProfileDirPath);
|
|
const QStringList filters = {"*.mobileprovision"};
|
|
foreach (QFileInfo fileInfo, provisioningProflesDir.entryInfoList(filters, QDir::NoDotAndDotDot | QDir::Files)) {
|
|
QDomDocument provisioningDoc;
|
|
auto profile = std::make_shared<ProvisioningProfile>();
|
|
QString teamID;
|
|
if (provisioningDoc.setContent(decodeProvisioningProfile(fileInfo.absoluteFilePath()))) {
|
|
QDomNodeList nodes = provisioningDoc.elementsByTagName("key");
|
|
for (int i = 0;i<nodes.count(); ++i) {
|
|
QDomElement e = nodes.at(i).toElement();
|
|
|
|
if (e.text().compare(udidTag) == 0)
|
|
profile->m_identifier = e.nextSiblingElement().text();
|
|
|
|
if (e.text().compare(profileNameTag) == 0)
|
|
profile->m_name = e.nextSiblingElement().text();
|
|
|
|
if (e.text().compare(appIdTag) == 0)
|
|
profile->m_appID = e.nextSiblingElement().text();
|
|
|
|
if (e.text().compare(expirationDateTag) == 0)
|
|
profile->m_expirationDate = QDateTime::fromString(e.nextSiblingElement().text(),
|
|
Qt::ISODate).toUTC();
|
|
|
|
if (e.text().compare(profileTeamIdTag) == 0) {
|
|
teamID = e.nextSibling().firstChildElement().text();
|
|
auto team = developmentTeam(teamID);
|
|
if (team) {
|
|
profile->m_team = team;
|
|
team->m_profiles.append(profile);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
qCDebug(iosCommonLog) << "Error reading provisoing profile" << fileInfo.absoluteFilePath();
|
|
}
|
|
|
|
if (profile->m_team)
|
|
m_provisioningProfiles.append(profile);
|
|
else
|
|
qCDebug(iosCommonLog) << "Skipping profile. No corresponding team found" << profile;
|
|
}
|
|
|
|
if (notify)
|
|
emit provisioningDataChanged();
|
|
}
|
|
|
|
const DevelopmentTeams &IosConfigurations::developmentTeams()
|
|
{
|
|
QTC_CHECK(m_instance);
|
|
m_instance->initializeProvisioningData();
|
|
return m_instance->m_developerTeams;
|
|
}
|
|
|
|
DevelopmentTeamPtr IosConfigurations::developmentTeam(const QString &teamID)
|
|
{
|
|
QTC_CHECK(m_instance);
|
|
m_instance->initializeProvisioningData();
|
|
return findOrDefault(m_instance->m_developerTeams,
|
|
Utils::equal(&DevelopmentTeam::identifier, teamID));
|
|
}
|
|
|
|
const ProvisioningProfiles &IosConfigurations::provisioningProfiles()
|
|
{
|
|
QTC_CHECK(m_instance);
|
|
m_instance->initializeProvisioningData();
|
|
return m_instance->m_provisioningProfiles;
|
|
}
|
|
|
|
ProvisioningProfilePtr IosConfigurations::provisioningProfile(const QString &profileID)
|
|
{
|
|
QTC_CHECK(m_instance);
|
|
m_instance->initializeProvisioningData();
|
|
return Utils::findOrDefault(m_instance->m_provisioningProfiles,
|
|
Utils::equal(&ProvisioningProfile::identifier, profileID));
|
|
}
|
|
|
|
IosToolChainFactory::IosToolChainFactory()
|
|
{
|
|
setSupportedLanguages({ProjectExplorer::Constants::C_LANGUAGE_ID,
|
|
ProjectExplorer::Constants::CXX_LANGUAGE_ID});
|
|
}
|
|
|
|
QList<ToolChain *> IosToolChainFactory::autoDetect(const QList<ToolChain *> &existingToolChains)
|
|
{
|
|
QList<ClangToolChain *> existingClangToolChains = clangToolChains(existingToolChains);
|
|
const QList<XcodePlatform> platforms = XcodeProbe::detectPlatforms().values();
|
|
QList<ToolChain *> toolChains;
|
|
toolChains.reserve(platforms.size());
|
|
for (const XcodePlatform &platform : platforms) {
|
|
for (const XcodePlatform::ToolchainTarget &target : platform.targets) {
|
|
ToolChainPair platformToolchains = findToolChainForPlatform(platform, target,
|
|
existingClangToolChains);
|
|
auto createOrAdd = [&](ClangToolChain *toolChain, Utils::Id l) {
|
|
if (!toolChain) {
|
|
toolChain = new ClangToolChain;
|
|
toolChain->setDetection(ToolChain::AutoDetection);
|
|
toolChain->setLanguage(l);
|
|
toolChain->setDisplayName(target.name);
|
|
toolChain->setPlatformCodeGenFlags(target.backendFlags);
|
|
toolChain->setPlatformLinkerFlags(target.backendFlags);
|
|
toolChain->resetToolChain(l == ProjectExplorer::Constants::CXX_LANGUAGE_ID ?
|
|
platform.cxxCompilerPath : platform.cCompilerPath);
|
|
existingClangToolChains.append(toolChain);
|
|
}
|
|
toolChains.append(toolChain);
|
|
};
|
|
|
|
createOrAdd(platformToolchains.first, ProjectExplorer::Constants::C_LANGUAGE_ID);
|
|
createOrAdd(platformToolchains.second, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
|
|
}
|
|
}
|
|
return toolChains;
|
|
}
|
|
|
|
QString DevelopmentTeam::identifier() const
|
|
{
|
|
return m_identifier;
|
|
}
|
|
|
|
QString DevelopmentTeam::displayName() const
|
|
{
|
|
return QString("%1 - %2").arg(m_email).arg(m_name);
|
|
}
|
|
|
|
QString DevelopmentTeam::details() const
|
|
{
|
|
return tr("%1 - Free Provisioning Team : %2")
|
|
.arg(m_identifier).arg(m_freeTeam ? tr("Yes") : tr("No"));
|
|
}
|
|
|
|
QDebug &operator<<(QDebug &stream, DevelopmentTeamPtr team)
|
|
{
|
|
QTC_ASSERT(team, return stream);
|
|
stream << team->displayName() << team->identifier() << team->isFreeProfile();
|
|
foreach (auto profile, team->m_profiles)
|
|
stream << "Profile:" << profile;
|
|
return stream;
|
|
}
|
|
|
|
QString ProvisioningProfile::identifier() const
|
|
{
|
|
return m_identifier;
|
|
}
|
|
|
|
QString ProvisioningProfile::displayName() const
|
|
{
|
|
return m_name;
|
|
}
|
|
|
|
QString ProvisioningProfile::details() const
|
|
{
|
|
return tr("Team: %1\nApp ID: %2\nExpiration date: %3").arg(m_team->identifier()).arg(m_appID)
|
|
.arg(QLocale::system().toString(m_expirationDate.toLocalTime(), QLocale::ShortFormat));
|
|
}
|
|
|
|
QDebug &operator<<(QDebug &stream, std::shared_ptr<ProvisioningProfile> profile)
|
|
{
|
|
QTC_ASSERT(profile, return stream);
|
|
return stream << profile->displayName() << profile->identifier() << profile->details();
|
|
}
|
|
|
|
} // namespace Internal
|
|
} // namespace Ios
|