Commit ee6ecef5 authored by Oliver Wolff's avatar Oliver Wolff
Browse files

Use mapping file for app deployment on Windows Phone



Change-Id: I4c61e1b19c89277829148d31f8ff2b971375d93e
Reviewed-by: default avatarAndrew Knight <andrew.knight@digia.com>
Reviewed-by: default avatarJoerg Bornemann <joerg.bornemann@digia.com>
parent ee4f2557
......@@ -35,8 +35,14 @@
#include <projectexplorer/target.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/buildtargetinfo.h>
#include <projectexplorer/deployablefile.h>
#include <projectexplorer/deploymentdata.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <qtsupport/qtkitinformation.h>
#include <utils/qtcprocess.h>
#include <QRegularExpression>
using namespace ProjectExplorer;
using Utils::QtcProcess;
......@@ -45,6 +51,7 @@ namespace Internal {
WinRtPackageDeploymentStep::WinRtPackageDeploymentStep(BuildStepList *bsl)
: AbstractProcessStep(bsl, Constants::WINRT_BUILD_STEP_DEPLOY)
, m_createMappingFile(false)
{
setDisplayName(tr("Run windeployqt"));
m_args = defaultWinDeployQtArguments();
......@@ -56,11 +63,46 @@ bool WinRtPackageDeploymentStep::init()
const QString targetPath
= target()->applicationTargets().targetForProject(proFile).toString()
+ QLatin1String(".exe");
QString targetDir = targetPath.left(targetPath.lastIndexOf(QLatin1Char('/')) + 1);
// ### Actually, targetForProject is supposed to return the file path including the file
// extension. Whenever this will eventually work, we have to remove the .exe suffix here.
const QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(target()->kit());
if (!qt)
return false;
m_isWinPhone = (qt->type() == QLatin1String(Constants::WINRT_WINPHONEQT));
QString args = QtcProcess::quoteArg(QDir::toNativeSeparators(targetPath));
args += QLatin1Char(' ') + m_args;
if (m_isWinPhone) {
m_manifestFileName = QLatin1String("WMAppManifest");
m_createMappingFile = true;
} else {
m_manifestFileName = QLatin1String("AppxManifest");
}
if (m_createMappingFile) {
args += QLatin1String(" -list mapping");
m_mappingFileContent = QLatin1String("[Files]\n\"") + QDir::toNativeSeparators(targetDir)
+ m_manifestFileName + QLatin1String(".xml\" \"") + m_manifestFileName + QLatin1String(".xml\"\n");
QDir assetDirectory(targetDir + QLatin1String("assets"));
if (assetDirectory.exists()) {
QStringList iconsToDeploy;
const QString fullManifestPath = targetDir + m_manifestFileName + QLatin1String(".xml");
if (!parseIconsAndExecutableFromManifest(fullManifestPath, &iconsToDeploy,
&m_executablePathInManifest)) {
raiseError(tr("Cannot parse manifest file %1.").arg(fullManifestPath));
return false;
}
foreach (QString icon, iconsToDeploy) {
m_mappingFileContent += QLatin1Char('"')
+ QDir::toNativeSeparators(targetDir + icon) + QLatin1String("\" \"")
+ QDir::toNativeSeparators(icon) + QLatin1String("\"\n");
}
}
}
ProcessParameters *params = processParameters();
params->setCommand(QLatin1String("windeployqt.exe"));
......@@ -70,6 +112,67 @@ bool WinRtPackageDeploymentStep::init()
return AbstractProcessStep::init();
}
bool WinRtPackageDeploymentStep::processSucceeded(int exitCode, QProcess::ExitStatus status)
{
if (m_createMappingFile) {
Utils::FileName proFile = Utils::FileName::fromString(project()->projectFilePath());
QString targetPath
= target()->applicationTargets().targetForProject(proFile).toString();
QString targetDir = targetPath.left(targetPath.lastIndexOf(QLatin1Char('/')) + 1);
QString targetInstallationPath;
// The list holds the local file paths and the "remote" file paths
QList<QPair<QString, QString> > installableFilesList;
foreach (DeployableFile file, target()->deploymentData().allFiles()) {
QString remoteFilePath = file.remoteFilePath();
QString localFilePath = file.localFilePath().toString();
if (localFilePath == targetPath) {
if (!targetPath.endsWith(QLatin1String(".exe"))) {
remoteFilePath += QLatin1String(".exe");
localFilePath += QLatin1String(".exe");
}
targetInstallationPath = remoteFilePath;
}
installableFilesList.append(QPair<QString, QString>(localFilePath, remoteFilePath));
}
// if there are no INSTALLS set we just deploy the files from windeployqt, the manifest
// and the icons referenced in there and the actual build target
if (targetInstallationPath.isEmpty()) {
targetPath += QLatin1String(".exe");
m_mappingFileContent
+= QLatin1Char('"') + QDir::toNativeSeparators(targetPath) + QLatin1String("\" \"")
+ QDir::toNativeSeparators(m_executablePathInManifest) + QLatin1String("\"\n");
} else {
targetInstallationPath = targetInstallationPath.left(targetInstallationPath.lastIndexOf(QLatin1Char('/')) + 1);
for (int i = 0; i < installableFilesList.length(); ++i) {
QPair<QString, QString> pair = installableFilesList.at(i);
// For the mapping file we need the remote paths relative to the application's executable
const QString relativeRemotePath = QDir(targetInstallationPath).relativeFilePath(pair.second);
m_mappingFileContent += QLatin1Char('"') + QDir::toNativeSeparators(pair.first)
+ QLatin1String("\" \"") + QDir::toNativeSeparators(relativeRemotePath)
+ QLatin1String("\"\n");
}
}
const QString mappingFilePath = targetDir + m_manifestFileName + QLatin1String(".map");
QFile mappingFile(mappingFilePath);
if (!mappingFile.open(QFile::WriteOnly | QFile::Text)) {
raiseError(tr("Cannot open mapping file %1 for writing.").arg(mappingFilePath));
return false;
}
mappingFile.write(m_mappingFileContent.toUtf8());
}
return AbstractProcessStep::processSucceeded(exitCode, status);
}
void WinRtPackageDeploymentStep::stdOutput(const QString &line)
{
if (m_createMappingFile)
m_mappingFileContent += line;
AbstractProcessStep::stdOutput(line);
}
BuildStepConfigWidget *WinRtPackageDeploymentStep::createConfigWidget()
{
return new WinRtPackageDeploymentStepWidget(this);
......@@ -93,6 +196,13 @@ QString WinRtPackageDeploymentStep::defaultWinDeployQtArguments() const
return args;
}
void WinRtPackageDeploymentStep::raiseError(const QString &errorMessage)
{
emit addOutput(errorMessage, BuildStep::ErrorMessageOutput);
emit addTask(ProjectExplorer::Task(ProjectExplorer::Task::Error, errorMessage, Utils::FileName(), -1,
ProjectExplorer::Constants::TASK_CATEGORY_DEPLOYMENT));
}
bool WinRtPackageDeploymentStep::fromMap(const QVariantMap &map)
{
if (!AbstractProcessStep::fromMap(map))
......@@ -110,5 +220,31 @@ QVariantMap WinRtPackageDeploymentStep::toMap() const
return map;
}
bool WinRtPackageDeploymentStep::parseIconsAndExecutableFromManifest(QString manifestFileName, QStringList *icons, QString *executable)
{
if (!icons->isEmpty())
icons->clear();
QFile manifestFile(manifestFileName);
if (!manifestFile.open(QFile::ReadOnly))
return false;
const QString contents = QString::fromUtf8(manifestFile.readAll());
QRegularExpression iconPattern(QStringLiteral("[\\\\/a-zA-Z0-9_\\-\\!]*\\.(png|jpg|jpeg)"));
QRegularExpressionMatchIterator iterator = iconPattern.globalMatch(contents);
while (iterator.hasNext()) {
QRegularExpressionMatch match = iterator.next();
const QString icon = match.captured(0);
icons->append(icon);
}
QRegularExpression executablePattern(QStringLiteral("ImagePath=\"([a-zA-Z0-9_-]*\\.exe)\""));
QRegularExpressionMatch match = executablePattern.match(contents);
if (!match.hasMatch())
return false;
*executable = match.captured(1);
return true;
}
} // namespace Internal
} // namespace WinRt
......@@ -41,17 +41,28 @@ class WinRtPackageDeploymentStep : public ProjectExplorer::AbstractProcessStep
public:
explicit WinRtPackageDeploymentStep(ProjectExplorer::BuildStepList *bsl);
bool init();
bool processSucceeded(int exitCode, QProcess::ExitStatus status);
void stdOutput(const QString &line);
ProjectExplorer::BuildStepConfigWidget *createConfigWidget();
void setWinDeployQtArguments(const QString &args);
QString winDeployQtArguments() const;
QString defaultWinDeployQtArguments() const;
void raiseError(const QString &errorMessage);
bool fromMap(const QVariantMap &map);
QVariantMap toMap() const;
private:
bool parseIconsAndExecutableFromManifest(QString manifestFileName, QStringList *items, QString *executable);
QString m_args;
QString m_executablePathInManifest;
QString m_mappingFileContent;
QString m_manifestFileName;
bool m_isWinPhone;
bool m_createMappingFile;
};
} // namespace Internal
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment