<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** 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 Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "winrtpackagedeploymentstep.h"

#include "winrtconstants.h"
#include "winrtpackagedeploymentstepwidget.h"
#include "winrtrunconfiguration.h"

#include <projectexplorer/project.h>
#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/qtcassert.h>
#include <utils/qtcprocess.h>

#include <QRegularExpression>

using namespace ProjectExplorer;
using Utils::QtcProcess;

namespace WinRt {
namespace Internal {

WinRtPackageDeploymentStep::WinRtPackageDeploymentStep(BuildStepList *bsl)
    : AbstractProcessStep(bsl, Constants::WINRT_BUILD_STEP_DEPLOY)
    , m_createMappingFile(false)
{
    setDisplayName(tr("Run windeployqt"));
    m_args = defaultWinDeployQtArguments();
}

bool WinRtPackageDeploymentStep::init()
{
    WinRtRunConfiguration *rc = qobject_cast<WinRtRunConfiguration *>(
                target()->activeRunConfiguration());
    QTC_ASSERT(rc, return false);

    const Utils::FileName activeProjectFilePath = Utils::FileName::fromString(rc->proFilePath());
    Utils::FileName appTargetFilePath;
    foreach (const BuildTargetInfo &buildTarget, target()->applicationTargets().list) {
        if (buildTarget.projectFilePath == activeProjectFilePath) {
            appTargetFilePath = buildTarget.targetFilePath;
            break;
        }
    }

    m_targetFilePath = appTargetFilePath.toString();
    if (m_targetFilePath.isEmpty()) {
        // ### raise error in 3.3
        // raiseError(tr("No executable to deploy found in %1.").arg(rc->proFilePath()));
        return false;
    }

    // ### Ideally, the file paths in applicationTargets() should already have the .exe suffix.
    // Whenever this will eventually work, we can drop appending the .exe suffix here.
    if (!m_targetFilePath.endsWith(QLatin1String(".exe"), Qt::CaseInsensitive))
        m_targetFilePath.append(QLatin1String(".exe"));

    m_targetDirPath = appTargetFilePath.parentDir().toString();
    if (!m_targetDirPath.endsWith(QLatin1Char('/')))
        m_targetDirPath += QLatin1Char('/');

    const QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(target()->kit());
    if (!qt)
        return false;

    QString args = QtcProcess::quoteArg(QDir::toNativeSeparators(m_targetFilePath));
    args += QLatin1Char(' ') + m_args;

    m_manifestFileName = QStringLiteral("AppxManifest");

    if (qt->type() == QLatin1String(Constants::WINRT_WINPHONEQT)) {
        m_createMappingFile = true;
        if (qt->mkspec().toString().contains(QLatin1String("msvc2012")))
            m_manifestFileName = QStringLiteral("WMAppManifest");
    }

    if (m_createMappingFile) {
        args += QLatin1String(" -list mapping");
        m_mappingFileContent = QLatin1String("[Files]\n");
        if (qt->mkspec().toString().contains(QLatin1String("msvc2012"))) {
            m_mappingFileContent += QLatin1Char('"') + QDir::toNativeSeparators(m_targetDirPath) + m_manifestFileName
                    + QLatin1String(".xml\" \"") + m_manifestFileName + QLatin1String(".xml\"\n");
        }

        QDir assetDirectory(m_targetDirPath + QLatin1String("assets"));
        if (assetDirectory.exists()) {
            QStringList iconsToDeploy;
            const QString fullManifestPath = m_targetDirPath + 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(m_targetDirPath + icon) + QLatin1String("\" \"")
                        + QDir::toNativeSeparators(icon) + QLatin1String("\"\n");
            }
        }
    }

    ProcessParameters *params = processParameters();
    params->setCommand(QLatin1String("windeployqt.exe"));
    params->setArguments(args);
    params->setEnvironment(target()->activeBuildConfiguration()->environment());

    return AbstractProcessStep::init();
}

bool WinRtPackageDeploymentStep::processSucceeded(int exitCode, QProcess::ExitStatus status)
{
    if (m_createMappingFile) {
        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 == m_targetFilePath) {
                if (!m_targetFilePath.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 (in case of 2012)
        // and the icons referenced in there and the actual build target
        QString baseDir;
        if (targetInstallationPath.isEmpty()) {
            if (!m_targetFilePath.endsWith(QLatin1String(".exe")))
                m_targetFilePath.append(QLatin1String(".exe"));
            m_mappingFileContent
                    += QLatin1Char('"') + QDir::toNativeSeparators(m_targetFilePath)
                    + QLatin1String("\" \"")
                    + QDir::toNativeSeparators(m_executablePathInManifest) + QLatin1String("\"\n");
            baseDir = m_targetDirPath;
        } else {
            baseDir = targetInstallationPath.left(targetInstallationPath.lastIndexOf(QLatin1Char('/')) + 1);
        }

        typedef QPair<QString, QString> QStringPair;
        foreach (const QStringPair &pair, installableFilesList) {
            // For the mapping file we need the remote paths relative to the application's executable
            QString relativeRemotePath;
            if (QDir(pair.second).isRelative())
                relativeRemotePath = pair.second;
            else
                relativeRemotePath = QDir(baseDir).relativeFilePath(pair.second);

            if (QDir(relativeRemotePath).isAbsolute() || relativeRemotePath.startsWith(QLatin1String(".."))) {
                // for 3.3?
                // raiseWarning(tr("File %1 is outside of the executable's directory. These files cannot be installed.").arg(relativeRemotePath));
                continue;
            }
            m_mappingFileContent += QLatin1Char('"') + QDir::toNativeSeparators(pair.first)
                    + QLatin1String("\" \"") + QDir::toNativeSeparators(relativeRemotePath)
                    + QLatin1String("\"\n");
        }

        const QString mappingFilePath = m_targetDirPath + 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());<commit_msg>Fixed font deployment for winphone 8.0<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** 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 Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "winrtpackagedeploymentstep.h"

#include "winrtconstants.h"
#include "winrtpackagedeploymentstepwidget.h"
#include "winrtrunconfiguration.h"

#include <projectexplorer/project.h>
#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/qtcassert.h>
#include <utils/qtcprocess.h>

#include <QRegularExpression>

using namespace ProjectExplorer;
using Utils::QtcProcess;

namespace WinRt {
namespace Internal {

WinRtPackageDeploymentStep::WinRtPackageDeploymentStep(BuildStepList *bsl)
    : AbstractProcessStep(bsl, Constants::WINRT_BUILD_STEP_DEPLOY)
    , m_createMappingFile(false)
{
    setDisplayName(tr("Run windeployqt"));
    m_args = defaultWinDeployQtArguments();
}

bool WinRtPackageDeploymentStep::init()
{
    WinRtRunConfiguration *rc = qobject_cast<WinRtRunConfiguration *>(
                target()->activeRunConfiguration());
    QTC_ASSERT(rc, return false);

    const Utils::FileName activeProjectFilePath = Utils::FileName::fromString(rc->proFilePath());
    Utils::FileName appTargetFilePath;
    foreach (const BuildTargetInfo &buildTarget, target()->applicationTargets().list) {
        if (buildTarget.projectFilePath == activeProjectFilePath) {
            appTargetFilePath = buildTarget.targetFilePath;
            break;
        }
    }

    m_targetFilePath = appTargetFilePath.toString();
    if (m_targetFilePath.isEmpty()) {
        // ### raise error in 3.3
        // raiseError(tr("No executable to deploy found in %1.").arg(rc->proFilePath()));
        return false;
    }

    // ### Ideally, the file paths in applicationTargets() should already have the .exe suffix.
    // Whenever this will eventually work, we can drop appending the .exe suffix here.
    if (!m_targetFilePath.endsWith(QLatin1String(".exe"), Qt::CaseInsensitive))
        m_targetFilePath.append(QLatin1String(".exe"));

    m_targetDirPath = appTargetFilePath.parentDir().toString();
    if (!m_targetDirPath.endsWith(QLatin1Char('/')))
        m_targetDirPath += QLatin1Char('/');

    const QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(target()->kit());
    if (!qt)
        return false;

    QString args = QtcProcess::quoteArg(QDir::toNativeSeparators(m_targetFilePath));
    args += QLatin1Char(' ') + m_args;

    m_manifestFileName = QStringLiteral("AppxManifest");

    if (qt->type() == QLatin1String(Constants::WINRT_WINPHONEQT)) {
        m_createMappingFile = true;
        if (qt->mkspec().toString().contains(QLatin1String("msvc2012")))
            m_manifestFileName = QStringLiteral("WMAppManifest");
    }

    if (m_createMappingFile) {
        args += QLatin1String(" -list mapping");
        m_mappingFileContent = QLatin1String("[Files]\n");
        if (qt->mkspec().toString().contains(QLatin1String("msvc2012"))) {
            m_mappingFileContent += QLatin1Char('"') + QDir::toNativeSeparators(m_targetDirPath) + m_manifestFileName
                    + QLatin1String(".xml\" \"") + m_manifestFileName + QLatin1String(".xml\"\n");
        }

        QDir assetDirectory(m_targetDirPath + QLatin1String("assets"));
        if (assetDirectory.exists()) {
            QStringList iconsToDeploy;
            const QString fullManifestPath = m_targetDirPath + 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(m_targetDirPath + icon) + QLatin1String("\" \"")
                        + QDir::toNativeSeparators(icon) + QLatin1String("\"\n");
            }
        }
    }

    ProcessParameters *params = processParameters();
    params->setCommand(QLatin1String("windeployqt.exe"));
    params->setArguments(args);
    params->setEnvironment(target()->activeBuildConfiguration()->environment());

    return AbstractProcessStep::init();
}

bool WinRtPackageDeploymentStep::processSucceeded(int exitCode, QProcess::ExitStatus status)
{
    if (m_createMappingFile) {
        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 == m_targetFilePath) {
                if (!m_targetFilePath.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 (in case of 2012)
        // and the icons referenced in there and the actual build target
        QString baseDir;
        if (targetInstallationPath.isEmpty()) {
            if (!m_targetFilePath.endsWith(QLatin1String(".exe")))
                m_targetFilePath.append(QLatin1String(".exe"));
            m_mappingFileContent
                    += QLatin1Char('"') + QDir::toNativeSeparators(m_targetFilePath)
                    + QLatin1String("\" \"")
                    + QDir::toNativeSeparators(m_executablePathInManifest) + QLatin1String("\"\n");
            baseDir = m_targetDirPath;
        } else {
            baseDir = targetInstallationPath.left(targetInstallationPath.lastIndexOf(QLatin1Char('/')) + 1);
        }

        typedef QPair<QString, QString> QStringPair;
        foreach (const QStringPair &pair, installableFilesList) {
            // For the mapping file we need the remote paths relative to the application's executable
            QString relativeRemotePath;
            if (QDir(pair.second).isRelative())
                relativeRemotePath = pair.second;
            else
                relativeRemotePath = QDir(baseDir).relativeFilePath(pair.second);

            if (QDir(relativeRemotePath).isAbsolute() || relativeRemotePath.startsWith(QLatin1String(".."))) {
                // special case for winphone 8.0 font deployment
                const QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(target()->kit());
                if (!qt)
                    return false;
                if (qt->mkspec().toString().contains(QLatin1String("msvc2012"))) {
                    const QString fileName = relativeRemotePath.mid(relativeRemotePath.lastIndexOf(QLatin1Char('/')) + 1);
                    if (QFile::exists(m_targetDirPath + QLatin1String("fonts/") + fileName)) {
                        relativeRemotePath = QLatin1String("fonts/") + fileName;
                    } else {
                        // for 3.3?
                        // raiseWarning(tr("File %1 is outside of the executable's directory. These files cannot be installed.").arg(relativeRemotePath));
                        continue;
                    }
                } else {
                    // for 3.3?
                    // raiseWarning(tr("File %1 is outside of the executable's directory. These files cannot be installed.").arg(relativeRemotePath));
                    continue;
                }
            }

            m_mappingFileContent += QLatin1Char('"') + QDir::toNativeSeparators(pair.first)
                    + QLatin1String("\" \"") + QDir::toNativeSeparators(relativeRemotePath)
                    + QLatin1String("\"\n");
        }

        const QString mappingFilePath = m_targetDirPath + 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());
{'fraction_non_alphanumeric': 0.12604344895525482, 'fraction_numerical': 0.007777259293824856, 'mean_word_length': 3.0427583315866693, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 65, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4619878', 'n_tokens_mistral': 5292, 'n_tokens_neox': 5012, 'n_words': 1166}