Skip to content
Snippets Groups Projects
maemotemplatesmanager.cpp 9.2 KiB
Newer Older
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/

#include "maemotemplatesmanager.h"

#include "maemopackagecreationstep.h"
#include "maemotoolchain.h"

#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
#include <qt4projectmanager/qt4projectmanagerconstants.h>
#include <qt4projectmanager/qt4target.h>

#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QList>
#include <QtCore/QProcess>
#include <QtGui/QMessageBox>

using namespace ProjectExplorer;

namespace Qt4ProjectManager {
namespace Internal {

const QLatin1String MaemoTemplatesManager::PackagingDirName("packaging");

MaemoTemplatesManager *MaemoTemplatesManager::m_instance = 0;

MaemoTemplatesManager *MaemoTemplatesManager::instance(QObject *parent)
{
    Q_ASSERT(!m_instance != !parent);
    if (!m_instance)
        m_instance = new MaemoTemplatesManager(parent);
    return m_instance;
}

MaemoTemplatesManager::MaemoTemplatesManager(QObject *parent) :
    QObject(parent), m_activeProject(0)
{
    SessionManager * const session
        = ProjectExplorerPlugin::instance()->session();
    connect(session, SIGNAL(startupProjectChanged(ProjectExplorer::Project*)),
        this, SLOT(handleActiveProjectChanged(ProjectExplorer::Project*)));
    handleActiveProjectChanged(session->startupProject());
}

void MaemoTemplatesManager::handleActiveProjectChanged(ProjectExplorer::Project *project)
{
    if (m_activeProject)
        disconnect(m_activeProject, 0, this, 0);
    m_activeProject= project;
    if (m_activeProject) {
        connect(m_activeProject, SIGNAL(addedTarget(ProjectExplorer::Target*)),
            this, SLOT(createTemplatesIfNecessary(ProjectExplorer::Target*)));
        connect(m_activeProject,
            SIGNAL(activeTargetChanged(ProjectExplorer::Target*)), this,
            SLOT(createTemplatesIfNecessary(ProjectExplorer::Target*)));
        const QList<Target *> &targets = m_activeProject->targets();
        foreach (Target * const target, targets)
            createTemplatesIfNecessary(target);
    }
}

void MaemoTemplatesManager::createTemplatesIfNecessary(ProjectExplorer::Target *target)
{
    Q_ASSERT_X(m_activeProject, Q_FUNC_INFO,
        "Impossible: Received signal from unknown project");

    if (!target
        || target->id() != QLatin1String(Constants::MAEMO_DEVICE_TARGET_ID))
        return;

    QDir projectDir(m_activeProject->projectDirectory());
    if (projectDir.exists(PackagingDirName))
        return;
    const QString packagingTemplatesDir
        = projectDir.path() + QLatin1Char('/') + PackagingDirName;
    if (!projectDir.mkdir(PackagingDirName)) {
        raiseError(tr("Could not create directory '%1'.")
            .arg(QDir::toNativeSeparators(packagingTemplatesDir)));
        return;
    }

    QProcess dh_makeProc;
    QString error;
    const Qt4Target * const qt4Target = qobject_cast<Qt4Target *>(target);
    Q_ASSERT_X(qt4Target, Q_FUNC_INFO, "Target ID does not match actual type.");
    const MaemoToolChain * const tc
        = dynamic_cast<MaemoToolChain *>(qt4Target->activeBuildConfiguration()->toolChain());
    Q_ASSERT_X(tc, Q_FUNC_INFO, "Maemo target has no maemo toolchain.");
    if (!MaemoPackageCreationStep::preparePackagingProcess(&dh_makeProc, tc,
        packagingTemplatesDir, &error)) {
        raiseError(error);
        return;
    }

    const QString command = QLatin1String("dh_make -s -n -p ")
        + m_activeProject->displayName() + QLatin1Char('_')
        + MaemoPackageCreationStep::DefaultVersionNumber;
    dh_makeProc.start(MaemoPackageCreationStep::packagingCommand(tc, command));
    if (!dh_makeProc.waitForStarted()) {
        raiseError(tr("Unable to create debian templates: dh_make failed (%1)")
            .arg(dh_makeProc.errorString()));
        return;
    }
    dh_makeProc.write("\n"); // Needs user input.
    dh_makeProc.waitForFinished(-1);
    if (dh_makeProc.error() != QProcess::UnknownError
        || dh_makeProc.exitCode() != 0) {
        raiseError(tr("Unable to create debian templates: dh_make failed (%1)")
            .arg(dh_makeProc.errorString()));
        return;
    }

    QDir debianDir(packagingTemplatesDir + QLatin1String("/debian"));
    const QStringList &files
        = debianDir.entryList(QStringList() << QLatin1String("*.??"),
              QDir::Files);
    foreach (const QString &fileName, files)
        debianDir.remove(fileName);

    const QString rulesFilePath
        = packagingTemplatesDir + QLatin1String("/debian/rules");
    QFile rulesFile(rulesFilePath);
    if (!rulesFile.open(QIODevice::ReadWrite)) {
        raiseError(tr("Packaging Error: Cannot open file '%1'.")
                   .arg(QDir::toNativeSeparators(rulesFilePath)));
        return;
    }

    QByteArray rulesContents = rulesFile.readAll();
    rulesContents.replace("DESTDIR", "INSTALL_ROOT");
    rulesContents.replace("dh_shlibdeps", "# dh_shlibdeps");

    // Would be the right solution, but does not work (on Windows),
    // because dpkg-genchanges doesn't know about it (and can't be told).
    // rulesContents.replace("dh_builddeb", "dh_builddeb --destdir=.");

    rulesFile.resize(0);
    rulesFile.write(rulesContents);
    if (rulesFile.error() != QFile::NoError) {
        raiseError(tr("Packaging Error: Cannot write file '%1'.")
                   .arg(QDir::toNativeSeparators(rulesFilePath)));
        return;
    }
}

QString MaemoTemplatesManager::version(const Project *project,
    QString *error) const
{
    const QString changeLogFilePath
        = project->projectDirectory() + QLatin1Char('/') + PackagingDirName
            + QLatin1String("/debian/changelog");
    const QString nativePath = QDir::toNativeSeparators(changeLogFilePath);
    QFile changeLog(changeLogFilePath);
    if (!changeLog.exists()) {
        *error = tr("File '%1' does not exist").arg(nativePath);
        return QString();
    }
    if (!changeLog.open(QIODevice::ReadOnly)) {
        *error = tr("Cannot open Debian changelog file '%1': %2")
            .arg(nativePath, changeLog.errorString());
        return QString();
    }
    const QByteArray &firstLine = changeLog.readLine();
    const int openParenPos = firstLine.indexOf('(');
    if (openParenPos == -1) {
        *error = tr("Debian changelog file '%1' has unexpected format.")
            .arg(nativePath);
        return QString();
    }
    const int closeParenPos = firstLine.indexOf(')', openParenPos);
    if (closeParenPos == -1) {
        *error = tr("Debian changelog file '%1' has unexpected format.")
            .arg(nativePath);
        return QString();
    }
    return QString::fromUtf8(firstLine.mid(openParenPos + 1,
        closeParenPos - openParenPos - 1).data());
}

bool MaemoTemplatesManager::setVersion(const Project *project,
    const QString &version, QString *error) const
{
    const QString debianDir = project->projectDirectory() + QLatin1Char('/')
        + PackagingDirName + QLatin1String("/debian/");
    const QString changeLogFilePath = debianDir + QLatin1String("changelog");
    const QString nativePath = QDir::toNativeSeparators(changeLogFilePath);
    QFile changeLog(changeLogFilePath);
    if (!changeLog.exists()) {
        *error = tr("File '%1' does not exist").arg(nativePath);
        return false;
    }
    if (!changeLog.open(QIODevice::ReadWrite)) {
        *error = tr("Cannot open Debian changelog file '%1': %2")
            .arg(nativePath , changeLog.errorString());
        return false;
    }

    QString content = QString::fromUtf8(changeLog.readAll());
    content.replace(QRegExp(QLatin1String("\\([a-zA-Z0-9_\\.]+\\)")),
        QLatin1Char('(') % version % QLatin1Char(')'));
    changeLog.resize(0);
    changeLog.write(content.toUtf8());
    changeLog.close();
    if (changeLog.error() != QFile::NoError) {
        *error = tr("Error writing Debian changelog file '%1': %2")
            .arg(nativePath , changeLog.errorString());
        return false;
    }
    return true;
}

void MaemoTemplatesManager::raiseError(const QString &reason)
{
    QMessageBox::critical(0, tr("Error creating Maemo templates"), reason);
}

} // namespace Internal
} // namespace Qt4ProjectManager