From 1bcdb33fb1d2eb8756b8d08cdd6167a8f19e053d Mon Sep 17 00:00:00 2001
From: ck <qt-info@nokia.com>
Date: Tue, 3 Aug 2010 16:27:34 +0200
Subject: [PATCH] Maemo: Create packaging templates in project directory.

Reviewed-by: kh1
---
 .../qt-maemo/maemomanager.cpp                 |   2 +
 .../qt-maemo/maemopackagecreationstep.cpp     | 273 ++++++++++--------
 .../qt-maemo/maemopackagecreationstep.h       |  17 +-
 .../qt-maemo/maemopackagecreationwidget.cpp   |  34 ++-
 .../qt-maemo/maemopackagecreationwidget.h     |   1 +
 .../qt-maemo/maemotemplatesmanager.cpp        | 248 ++++++++++++++++
 .../qt-maemo/maemotemplatesmanager.h          |  72 +++++
 .../qt4projectmanager/qt-maemo/qt-maemo.pri   |   6 +-
 8 files changed, 524 insertions(+), 129 deletions(-)
 create mode 100644 src/plugins/qt4projectmanager/qt-maemo/maemotemplatesmanager.cpp
 create mode 100644 src/plugins/qt4projectmanager/qt-maemo/maemotemplatesmanager.h

diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemomanager.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemomanager.cpp
index b47b096a0d3..8d0a941c0f2 100644
--- a/src/plugins/qt4projectmanager/qt-maemo/maemomanager.cpp
+++ b/src/plugins/qt4projectmanager/qt-maemo/maemomanager.cpp
@@ -36,6 +36,7 @@
 #include "maemoqemumanager.h"
 #include "maemorunfactories.h"
 #include "maemosettingspage.h"
+#include "maemotemplatesmanager.h"
 #include "maemotoolchain.h"
 
 #include <extensionsystem/pluginmanager.h>
@@ -66,6 +67,7 @@ MaemoManager::MaemoManager()
     m_instance = this;
     MaemoQemuManager::instance(this);
     MaemoDeviceConfigurations::instance(this);
+    MaemoTemplatesManager::instance(this);
 
     PluginManager *pluginManager = PluginManager::instance();
     pluginManager->addObject(m_runControlFactory);
diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationstep.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationstep.cpp
index 6769d6de2f1..54aa6fa1fe5 100644
--- a/src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationstep.cpp
+++ b/src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationstep.cpp
@@ -47,6 +47,7 @@
 #include "maemoglobal.h"
 #include "maemopackagecreationwidget.h"
 #include "maemoprofilewrapper.h"
+#include "maemotemplatesmanager.h"
 #include "maemotoolchain.h"
 
 #include <projectexplorer/buildsteplist.h>
@@ -62,8 +63,6 @@
 
 namespace {
     const QLatin1String PackagingEnabledKey("Packaging Enabled");
-    const QLatin1String DefaultVersionNumber("0.0.1");
-    const QLatin1String VersionNumberKey("Version Number");
 }
 
 using namespace ProjectExplorer::Constants;
@@ -74,10 +73,11 @@ using ProjectExplorer::Task;
 namespace Qt4ProjectManager {
 namespace Internal {
 
+const QLatin1String MaemoPackageCreationStep::DefaultVersionNumber("0.0.1");
+
 MaemoPackageCreationStep::MaemoPackageCreationStep(BuildStepList *bsl)
     : ProjectExplorer::BuildStep(bsl, CreatePackageId),
-      m_packagingEnabled(true),
-      m_versionString(DefaultVersionNumber)
+      m_packagingEnabled(true)
 {
     ctor();
 }
@@ -85,8 +85,7 @@ MaemoPackageCreationStep::MaemoPackageCreationStep(BuildStepList *bsl)
 MaemoPackageCreationStep::MaemoPackageCreationStep(BuildStepList *bsl,
     MaemoPackageCreationStep *other)
     : BuildStep(bsl, other),
-      m_packagingEnabled(other->m_packagingEnabled),
-      m_versionString(other->m_versionString)
+      m_packagingEnabled(other->m_packagingEnabled)
 {
     ctor();
 }
@@ -110,14 +109,12 @@ QVariantMap MaemoPackageCreationStep::toMap() const
 {
     QVariantMap map(ProjectExplorer::BuildStep::toMap());
     map.insert(PackagingEnabledKey, m_packagingEnabled);
-    map.insert(VersionNumberKey, m_versionString);
     return map;
 }
 
 bool MaemoPackageCreationStep::fromMap(const QVariantMap &map)
 {
     m_packagingEnabled = map.value(PackagingEnabledKey, true).toBool();
-    m_versionString = map.value(VersionNumberKey, DefaultVersionNumber).toString();
     return ProjectExplorer::BuildStep::fromMap(map);
 }
 
@@ -137,99 +134,47 @@ bool MaemoPackageCreationStep::createPackage()
         return true;
 
     emit addOutput(tr("Creating package file ..."), BuildStep::MessageOutput);
-    QFile configFile(targetRoot() % QLatin1String("/config.sh"));
-    if (!configFile.open(QIODevice::ReadOnly)) {
-        raiseError(tr("Cannot open MADDE config file '%1'.")
-                   .arg(nativePath(configFile)));
+    m_buildProc.reset(new QProcess);
+    QString error;
+    if (!preparePackagingProcess(m_buildProc.data(), maemoToolChain(),
+        buildDirectory(), &error)) {
+        raiseError(error);
         return false;
     }
 
-    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
-    const QString &path = QDir::toNativeSeparators(maddeRoot() + QLatin1Char('/'));
-
-    const QLatin1String key("PATH");
-    QString colon = QLatin1String(":");
-#ifdef Q_OS_WIN
-    colon = QLatin1String(";");
-    env.insert(key, path % QLatin1String("bin") % colon % env.value(key));
-#endif
-
-    env.insert(key, targetRoot() % "/bin" % colon % env.value(key));
-    env.insert(key, path % QLatin1String("madbin") % colon % env.value(key));
-
-    QString perlLib = QDir::fromNativeSeparators(path % QLatin1String("madlib/perl5"));
-#ifdef Q_OS_WIN
-    perlLib = perlLib.remove(QLatin1Char(':'));
-    perlLib = perlLib.prepend(QLatin1Char('/'));
-#endif
-    env.insert(QLatin1String("PERL5LIB"), perlLib);
-
-    const QString buildDir = buildDirectory();
-    env.insert(QLatin1String("PWD"), buildDir);
-
-    const QRegExp envPattern(QLatin1String("([^=]+)=[\"']?([^;\"']+)[\"']? ;.*"));
-    QByteArray line;
-    do {
-        line = configFile.readLine(200);
-        if (envPattern.exactMatch(line))
-            env.insert(envPattern.cap(1), envPattern.cap(2));
-    } while (!line.isEmpty());
-    
-
-    m_buildProc.reset(new QProcess);
     connect(m_buildProc.data(), SIGNAL(readyReadStandardOutput()), this,
         SLOT(handleBuildOutput()));
     connect(m_buildProc.data(), SIGNAL(readyReadStandardError()), this,
         SLOT(handleBuildOutput()));
-    m_buildProc->setProcessEnvironment(env);
-    m_buildProc->setWorkingDirectory(buildDir);
-    m_buildProc->start("cd " + buildDir);
-    m_buildProc->waitForFinished();
-
-    // cache those two since we can change the version number during packaging
-    // and might fail later to modify, copy, remove etc. the generated package
-    const QString version = versionString();
-    const QString pkgFilePath = packageFilePath();
-
-    if (!QFileInfo(buildDir + QLatin1String("/debian")).exists()) {
-        const QString command = QLatin1String("dh_make -s -n -p ")
-            % projectName() % QLatin1Char('_') % versionString();
-        if (!runCommand(command))
-            return false;
 
-        QFile rulesFile(buildDir + QLatin1String("/debian/rules"));
-        if (!rulesFile.open(QIODevice::ReadWrite)) {
-            raiseError(tr("Packaging Error: Cannot open file '%1'.")
-                       .arg(nativePath(rulesFile)));
-            return false;
-        }
-
-        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(nativePath(rulesFile)));
-            return false;
-        }
+    const QString debianDirPath = buildDirectory() + QLatin1String("/debian");
+    if (!removeDirectory(debianDirPath)) {
+        raiseError(tr("Packaging failed."),
+            tr("Could not remove directory '%1'.").arg(debianDirPath));
+        return false;
     }
-
-    {
-        QFile::remove(buildDir + QLatin1String("/debian/files"));
-        QFile changeLog(buildDir + QLatin1String("/debian/changelog"));
-        if (changeLog.open(QIODevice::ReadWrite)) {
-            QString content = QString::fromUtf8(changeLog.readAll());
-            content.replace(QRegExp("\\([a-zA-Z0-9_\\.]+\\)"),
-                QLatin1Char('(') % version % QLatin1Char(')'));
-            changeLog.resize(0);
-            changeLog.write(content.toUtf8());
+    QDir buildDir(buildDirectory());
+    if (!buildDir.mkdir("debian")) {
+        raiseError(tr("Could not create debian directory '%1'.")
+                   .arg(debianDirPath));
+        return false;
+    }
+    const QString templatesDirPath
+        = buildConfiguration()->target()->project()->projectDirectory()
+            + QLatin1Char('/') + MaemoTemplatesManager::PackagingDirName
+            + QLatin1String("/debian");
+    QDir templatesDir(templatesDirPath);
+    const QStringList &files = templatesDir.entryList(QDir::Files);
+    foreach (const QString &fileName, files) {
+        const QString srcFile
+                = templatesDirPath + QLatin1Char('/') + fileName;
+        const QString destFile
+                = debianDirPath + QLatin1Char('/') + fileName;
+        if (!QFile::copy(srcFile, destFile)) {
+            raiseError(tr("Could not copy file '%1' to '%2'")
+                       .arg(QDir::toNativeSeparators(srcFile),
+                            QDir::toNativeSeparators(destFile)));
+            return false;
         }
     }
 
@@ -237,24 +182,30 @@ bool MaemoPackageCreationStep::createPackage()
         return false;
 
     // Workaround for non-working dh_builddeb --destdir=.
-    if (!QDir(buildDir).isRoot()) {
-        const QString packageFileName = QFileInfo(pkgFilePath).fileName();
-        const QString changesFileName = QFileInfo(packageFileName)
+    if (!QDir(buildDirectory()).isRoot()) {
+        const ProjectExplorer::Project * const project
+            = buildConfiguration()->target()->project();
+        QString error;
+        const QString pkgFileName = packageFileName(project,
+            MaemoTemplatesManager::instance()->version(project, &error));
+        if (!error.isEmpty())
+            raiseError(tr("Packaging failed."), error);
+        const QString changesFileName = QFileInfo(pkgFileName)
             .completeBaseName() + QLatin1String(".changes");
-        const QString packageSourceDir = buildDir + QLatin1String("/../");
+        const QString packageSourceDir = buildDirectory() + QLatin1String("/../");
         const QString packageSourceFilePath
-            = packageSourceDir + packageFileName;
+            = packageSourceDir + pkgFileName;
         const QString changesSourceFilePath
             = packageSourceDir + changesFileName;
         const QString changesTargetFilePath
-            = buildDir + QLatin1Char('/') + changesFileName;
-        QFile::remove(pkgFilePath);
+            = buildDirectory() + QLatin1Char('/') + changesFileName;
+        QFile::remove(packageFilePath());
         QFile::remove(changesTargetFilePath);
-        if (!QFile::rename(packageSourceFilePath, pkgFilePath)
+        if (!QFile::rename(packageSourceFilePath, packageFilePath())
             || !QFile::rename(changesSourceFilePath, changesTargetFilePath)) {
             raiseError(tr("Packaging failed."),
                 tr("Could not move package files from %1 to %2.")
-                .arg(packageSourceDir, buildDir));
+                .arg(packageSourceDir, buildDirectory()));
             return false;
         }
     }
@@ -264,21 +215,38 @@ bool MaemoPackageCreationStep::createPackage()
     return true;
 }
 
+bool MaemoPackageCreationStep::removeDirectory(const QString &dirPath)
+{
+    QDir dir(dirPath);
+    if (!dir.exists())
+        return true;
+
+    const QStringList &files = dir.entryList(QDir::Files);
+    foreach (const QString &fileName, files) {
+        if (!dir.remove(fileName))
+            return false;
+    }
+
+    const QStringList &subDirs
+        = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
+    foreach (const QString &subDirName, subDirs) {
+        if (!removeDirectory(dirPath + QLatin1Char('/') + subDirName))
+            return false;
+    }
+
+    return dir.rmdir(dirPath);
+}
+
 bool MaemoPackageCreationStep::runCommand(const QString &command)
 {
     emit addOutput(tr("Package Creation: Running command '%1'.").arg(command), BuildStep::MessageOutput);
-    QString perl;
-#ifdef Q_OS_WIN
-    perl = maddeRoot() + QLatin1String("/bin/perl.exe ");
-#endif
-    m_buildProc->start(perl + maddeRoot() % QLatin1String("/madbin/") % command);
+    m_buildProc->start(packagingCommand(maemoToolChain(), command));
     if (!m_buildProc->waitForStarted()) {
         raiseError(tr("Packaging failed."),
             tr("Packaging error: Could not start command '%1'. Reason: %2")
             .arg(command).arg(m_buildProc->errorString()));
         return false;
     }
-    m_buildProc->write("\n"); // For dh_make
     m_buildProc->waitForFinished(-1);
     if (m_buildProc->error() != QProcess::UnknownError || m_buildProc->exitCode() != 0) {
         QString mainMessage = tr("Packaging Error: Command '%1' failed.")
@@ -364,22 +332,32 @@ bool MaemoPackageCreationStep::packagingNeeded() const
 
 QString MaemoPackageCreationStep::packageFilePath() const
 {
-    return buildDirectory() % '/' % projectName()
-        % QLatin1Char('_') % versionString() % QLatin1String("_armel.deb");
+    QString error;
+    const QString &version = versionString(&error);
+    if (version.isEmpty())
+        return QString();
+    return buildDirectory() % '/'
+        % packageFileName(buildConfiguration()->target()->project(), version);
 }
 
-QString MaemoPackageCreationStep::versionString() const
+QString MaemoPackageCreationStep::versionString(QString *error) const
 {
-    return m_versionString;
+    return MaemoTemplatesManager::instance()
+        ->version(buildConfiguration()->target()->project(), error);
+
 }
 
-void MaemoPackageCreationStep::setVersionString(const QString &version)
+bool MaemoPackageCreationStep::setVersionString(const QString &version,
+    QString *error)
 {
-    m_versionString = version;
-    emit packageFilePathChanged();
+    const bool success = MaemoTemplatesManager::instance()
+        ->setVersion(buildConfiguration()->target()->project(), version, error);
+    if (success)
+        emit packageFilePathChanged();
+    return success;
 }
 
-QString MaemoPackageCreationStep::nativePath(const QFile &file) const
+QString MaemoPackageCreationStep::nativePath(const QFile &file)
 {
     return QDir::toNativeSeparators(QFileInfo(file).filePath());
 }
@@ -392,6 +370,71 @@ void MaemoPackageCreationStep::raiseError(const QString &shortMsg,
                       TASK_CATEGORY_BUILDSYSTEM));
 }
 
+bool MaemoPackageCreationStep::preparePackagingProcess(QProcess *proc,
+    const MaemoToolChain *tc, const QString &workingDir, QString *error)
+{
+    QFile configFile(tc->targetRoot() % QLatin1String("/config.sh"));
+    if (!configFile.open(QIODevice::ReadOnly)) {
+        *error = tr("Cannot open MADDE config file '%1'.")
+            .arg(nativePath(configFile));
+        return false;
+    }
+
+    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+    const QString &path
+        = QDir::toNativeSeparators(tc->maddeRoot() + QLatin1Char('/'));
+
+    const QLatin1String key("PATH");
+    QString colon = QLatin1String(":");
+#ifdef Q_OS_WIN
+    colon = QLatin1String(";");
+    env.insert(key, path % QLatin1String("bin") % colon % env.value(key));
+#endif
+
+    env.insert(key, tc->targetRoot() % "/bin" % colon % env.value(key));
+    env.insert(key, path % QLatin1String("madbin") % colon % env.value(key));
+
+    QString perlLib
+        = QDir::fromNativeSeparators(path % QLatin1String("madlib/perl5"));
+#ifdef Q_OS_WIN
+    perlLib = perlLib.remove(QLatin1Char(':'));
+    perlLib = perlLib.prepend(QLatin1Char('/'));
+#endif
+    env.insert(QLatin1String("PERL5LIB"), perlLib);
+    env.insert(QLatin1String("PWD"), workingDir);
+
+    const QRegExp envPattern(QLatin1String("([^=]+)=[\"']?([^;\"']+)[\"']? ;.*"));
+    QByteArray line;
+    do {
+        line = configFile.readLine(200);
+        if (envPattern.exactMatch(line))
+            env.insert(envPattern.cap(1), envPattern.cap(2));
+    } while (!line.isEmpty());
+
+    proc->setProcessEnvironment(env);
+    proc->setWorkingDirectory(workingDir);
+    proc->start("cd " + workingDir);
+    proc->waitForFinished();
+    return true;
+}
+
+QString MaemoPackageCreationStep::packagingCommand(const MaemoToolChain *tc,
+    const QString &commandName)
+{
+    QString perl;
+#ifdef Q_OS_WIN
+    perl = tc->maddeRoot() + QLatin1String("/bin/perl.exe ");
+#endif
+    return perl + tc->maddeRoot() % QLatin1String("/madbin/") % commandName;
+}
+
+QString MaemoPackageCreationStep::packageFileName(const ProjectExplorer::Project *project,
+    const QString &version)
+{
+    return project->displayName() % QLatin1Char('_') % version
+        % QLatin1String("_armel.deb");
+}
+
 const QLatin1String MaemoPackageCreationStep::CreatePackageId("Qt4ProjectManager.MaemoPackageCreationStep");
 
 } // namespace Internal
diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationstep.h b/src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationstep.h
index a569136a0f3..86b3f2e4eeb 100644
--- a/src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationstep.h
+++ b/src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationstep.h
@@ -72,8 +72,17 @@ public:
     bool isPackagingEnabled() const { return m_packagingEnabled; }
     void setPackagingEnabled(bool enabled) { m_packagingEnabled = enabled; }
 
-    QString versionString() const;
-    void setVersionString(const QString &version);
+    QString versionString(QString *error) const;
+    bool setVersionString(const QString &version, QString *error);
+
+    static bool preparePackagingProcess(QProcess *proc, const MaemoToolChain *tc,
+        const QString &workingDir, QString *error);
+    static QString packagingCommand(const MaemoToolChain *tc,
+        const QString &commandName);
+    static QString packageFileName(const ProjectExplorer::Project *project,
+        const QString &version);
+
+    static const QLatin1String DefaultVersionNumber;
 
 signals:
     void packageFilePathChanged();
@@ -94,10 +103,11 @@ private:
     virtual bool fromMap(const QVariantMap &map);
 
     bool createPackage();
+    bool removeDirectory(const QString &dirPath);
     bool runCommand(const QString &command);
     QString maddeRoot() const;
     QString targetRoot() const;
-    QString nativePath(const QFile &file) const;
+    static QString nativePath(const QFile &file);
     bool packagingNeeded() const;
     void raiseError(const QString &shortMsg,
                     const QString &detailedMsg = QString());
@@ -110,7 +120,6 @@ private:
     static const QLatin1String CreatePackageId;
 
     bool m_packagingEnabled;
-    QString m_versionString;
     QScopedPointer<QProcess> m_buildProc;
 };
 
diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationwidget.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationwidget.cpp
index 834e20c4f1b..81dc6e77b76 100644
--- a/src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationwidget.cpp
+++ b/src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationwidget.cpp
@@ -49,6 +49,9 @@
 #include <projectexplorer/target.h>
 #include <qt4projectmanager/qt4buildconfiguration.h>
 
+#include <QtCore/QTimer>
+#include <QtGui/QMessageBox>
+
 namespace Qt4ProjectManager {
 namespace Internal {
 
@@ -60,18 +63,29 @@ MaemoPackageCreationWidget::MaemoPackageCreationWidget(MaemoPackageCreationStep
     m_ui->setupUi(this);
     m_ui->skipCheckBox->setChecked(!m_step->isPackagingEnabled());
     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
-    const QStringList list = m_step->versionString().split(QLatin1Char('.'),
+    QTimer::singleShot(0, this, SLOT(initVersion()));
+}
+
+void MaemoPackageCreationWidget::init()
+{
+}
+
+void MaemoPackageCreationWidget::initVersion()
+{
+    QString error;
+    QString versionString = m_step->versionString(&error);
+    if (versionString.isEmpty()) {
+        QMessageBox::critical(this, tr("No version available."), error);
+        versionString = MaemoPackageCreationStep::DefaultVersionNumber;
+    }
+    const QStringList list = versionString.split(QLatin1Char('.'),
         QString::SkipEmptyParts);
     m_ui->major->setValue(list.value(0, QLatin1String("0")).toInt());
     m_ui->minor->setValue(list.value(1, QLatin1String("0")).toInt());
     m_ui->patch->setValue(list.value(2, QLatin1String("0")).toInt());
-    versionInfoChanged();
     connect(m_step, SIGNAL(packageFilePathChanged()), this,
         SIGNAL(updateSummary()));
-}
-
-void MaemoPackageCreationWidget::init()
-{
+    versionInfoChanged();
 }
 
 QString MaemoPackageCreationWidget::summaryText() const
@@ -94,8 +108,12 @@ void MaemoPackageCreationWidget::handleSkipButtonToggled(bool checked)
 
 void MaemoPackageCreationWidget::versionInfoChanged()
 {
-    m_step->setVersionString(m_ui->major->text() + QLatin1Char('.')
-        + m_ui->minor->text() + QLatin1Char('.') + m_ui->patch->text());
+    QString error;
+    const bool success = m_step->setVersionString(m_ui->major->text()
+        + QLatin1Char('.') + m_ui->minor->text() + QLatin1Char('.')
+        + m_ui->patch->text(), &error);
+    if (!success)
+        QMessageBox::critical(this, tr("Could not set version number"), error);
 }
 
 } // namespace Internal
diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationwidget.h b/src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationwidget.h
index 6f01bdeaa76..f73ac9a0eb3 100644
--- a/src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationwidget.h
+++ b/src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationwidget.h
@@ -66,6 +66,7 @@ public:
 private slots:
     void handleSkipButtonToggled(bool checked);
     void versionInfoChanged();
+    void initVersion();
 
 private:
     MaemoPackageCreationStep * const m_step;
diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemotemplatesmanager.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemotemplatesmanager.cpp
new file mode 100644
index 00000000000..b7d9d9da153
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt-maemo/maemotemplatesmanager.cpp
@@ -0,0 +1,248 @@
+/**************************************************************************
+**
+** 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
diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemotemplatesmanager.h b/src/plugins/qt4projectmanager/qt-maemo/maemotemplatesmanager.h
new file mode 100644
index 00000000000..15af028cd29
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt-maemo/maemotemplatesmanager.h
@@ -0,0 +1,72 @@
+/**************************************************************************
+**
+** 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.
+**
+**************************************************************************/
+
+#ifndef MAEMOTEMPLATESCREATOR_H
+#define MAEMOTEMPLATESCREATOR_H
+
+#include <QtCore/QObject>
+
+namespace ProjectExplorer {
+class Project;
+class Target;
+}
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class MaemoTemplatesManager : public QObject
+{
+    Q_OBJECT
+
+public:
+    static MaemoTemplatesManager *instance(QObject *parent = 0);
+
+    QString version(const ProjectExplorer::Project *project,
+        QString *error) const;
+    bool setVersion(const ProjectExplorer::Project *project,
+        const QString &version, QString *error) const;
+
+    static const QLatin1String PackagingDirName;
+
+private slots:
+    void handleActiveProjectChanged(ProjectExplorer::Project *project);
+    void createTemplatesIfNecessary(ProjectExplorer::Target *target);
+
+private:
+    explicit MaemoTemplatesManager(QObject *parent);
+    void raiseError(const QString &reason);
+
+    static MaemoTemplatesManager *m_instance;
+    ProjectExplorer::Project *m_activeProject;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // MAEMOTEMPLATESCREATOR_H
diff --git a/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri b/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri
index 22542222fae..53b7fc4c835 100644
--- a/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri
+++ b/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri
@@ -28,7 +28,8 @@ HEADERS += \
     $$PWD/maemodebugsupport.h \
     $$PWD/maemodeviceconfiglistmodel.h \
     $$PWD/maemoremotemountsmodel.h \
-    $$PWD/maemodeviceenvreader.h
+    $$PWD/maemodeviceenvreader.h \
+    $$PWD/maemotemplatesmanager.h
 
 SOURCES += \
     $$PWD/maemoconfigtestdialog.cpp \
@@ -58,7 +59,8 @@ SOURCES += \
     $$PWD/maemodebugsupport.cpp \
     $$PWD/maemodeviceconfiglistmodel.cpp \
     $$PWD/maemoremotemountsmodel.cpp \
-    $$PWD/maemodeviceenvreader.cpp
+    $$PWD/maemodeviceenvreader.cpp \
+    $$PWD/maemotemplatesmanager.cpp
 
 FORMS += \
     $$PWD/maemoconfigtestdialog.ui \
-- 
GitLab