s60publisherovi.cpp 18.7 KB
Newer Older
1
2
3
4
5
6
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
hjk's avatar
hjk committed
7
** Contact: Nokia Corporation (info@qt.nokia.com)
8
9
10
11
**
**
** GNU Lesser General Public License Usage
**
hjk's avatar
hjk committed
12
13
14
15
16
17
** 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.
18
19
**
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
21
22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23
24
25
26
27
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
28
** If you have questions regarding the use of this file, please contact
Tobias Hunger's avatar
Tobias Hunger committed
29
** Nokia at info@qt.nokia.com.
30
31
32
33
34
35
36
37
**
**************************************************************************/
#include "s60publisherovi.h"

#include "qt4symbiantarget.h"
#include "s60certificateinfo.h"
#include "s60manager.h"

38
39
40
41
42
43
44
#include "qt4buildconfiguration.h"
#include "qmakestep.h"
#include "makestep.h"
#include "qt4project.h"

#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/buildstep.h>
45
46
#include <qtsupport/qtversionmanager.h>
#include <qtsupport/profilereader.h>
47

48
#include <utils/qtcassert.h>
49
#include <utils/fileutils.h>
50
#include <proparser/prowriter.h>
51

52
#include <QtCore/QProcess>
53
54
55
56
57
58

namespace Qt4ProjectManager {
namespace Internal {

S60PublisherOvi::S60PublisherOvi(QObject *parent) :
    QObject(parent),
59
60
    m_reader(0),
    m_finishedAndSuccessful(false)
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
{
    // build m_rejectedVendorNames
    m_rejectedVendorNames.append(Constants::REJECTED_VENDOR_NAMES_NOKIA);
    m_rejectedVendorNames.append(Constants::REJECTED_VENDOR_NAMES_VENDOR);
    m_rejectedVendorNames.append(Constants::REJECTED_VENDOR_NAMES_VENDOR_EN);
    m_rejectedVendorNames.append(Constants::REJECTED_VENDOR_NAMES_EMPTY);

    // build m_capabilitiesForCertifiedSigned
    m_capabilitiesForCertifiedSigned.append(Constants::CERTIFIED_SIGNED_CAPABILITY_COMM_DD);
    m_capabilitiesForCertifiedSigned.append(Constants::CERTIFIED_SIGNED_CAPABILITY_DISK_ADMIN);
    m_capabilitiesForCertifiedSigned.append(Constants::CERTIFIED_SIGNED_CAPABILITY_MULTIMEDIA_DD);
    m_capabilitiesForCertifiedSigned.append(Constants::CERTIFIED_SIGNED_CAPABILITY_NETWORK_CONTROL);

    // build m_capabilitesForManufacturerApproved
    m_capabilitesForManufacturerApproved.append(Constants::MANUFACTURER_APPROVED_CAPABILITY_ALL_FILES);
    m_capabilitesForManufacturerApproved.append(Constants::MANUFACTURER_APPROVED_CAPABILITY_DRM);
    m_capabilitesForManufacturerApproved.append(Constants::MANUFACTURER_APPROVED_CAPABILITY_TCB);

    // set up colours for progress reports
    m_errorColor = Qt::red;
    m_commandColor = Qt::blue;
    m_okColor = Qt::darkGreen;
    m_normalColor = Qt::black;
}

S60PublisherOvi::~S60PublisherOvi()
{
    cleanUp();
}

void S60PublisherOvi::setBuildConfiguration(Qt4BuildConfiguration *qt4bc)
{
    // set build configuration
    m_qt4bc = qt4bc;
}

97
98
99
100
101
void S60PublisherOvi::setDisplayName(const QString &displayName)
{
    m_displayName = displayName;
}

102
103
104
105
106
void S60PublisherOvi::setVendorName(const QString &vendorName)
{
    m_vendorName = vendorName;
}

107
void S60PublisherOvi::setLocalVendorNames(const QString &localVendorNames)
108
{
109
110
111
112
113
114
    QStringList vendorNames = localVendorNames.split(',');
    QStringList resultingList;
    foreach (QString vendorName, vendorNames) {
        resultingList.append("\\\"" +vendorName.trimmed()+"\\\"");
    }
    m_localVendorNames = resultingList.join(", ");
115
116
117
118
119
120
121
122
123
124
125
126
127
}

void S60PublisherOvi::setAppUid(const QString &appuid)
{
    m_appUid = appuid;
}

void S60PublisherOvi::cleanUp()
{
    if (m_qt4project && m_reader) {
        m_qt4project->destroyProFileReader(m_reader);
        m_reader = 0;
    }
128
    m_publishSteps.clear();
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
}

void S60PublisherOvi::completeCreation()
{
    // set active target
    m_activeTargetOfProject = qobject_cast<Qt4SymbianTarget *>(m_qt4bc->target());
    QTC_ASSERT(m_activeTargetOfProject, return);

    //set up project
    m_qt4project = m_activeTargetOfProject->qt4Project();

    // set up pro file reader
    m_reader = m_qt4project->createProFileReader(m_qt4project->rootProjectNode(), m_qt4bc);
    //m_reader->setCumulative(false); // todo need to reenable that, after fixing parsing for symbian scopes

    ProFile *profile = m_reader->parsedProFile(m_qt4project->rootProjectNode()->path());
    m_reader->accept(profile, ProFileEvaluator::LoadProOnly);
    profile->deref();

148
    // set up process for creating the resulting SIS files
149
150
151
152
153
154
155
    ProjectExplorer::AbstractProcessStep * makeStep = m_qt4bc->makeStep();
    makeStep->init();
    const ProjectExplorer::ProcessParameters * const makepp = makeStep->processParameters();

    ProjectExplorer::AbstractProcessStep *qmakeStep = m_qt4bc->qmakeStep();
    qmakeStep->init();
    const ProjectExplorer::ProcessParameters * const qmakepp = qmakeStep->processParameters();
156

157
158
159
160
161
    m_publishSteps.clear();
    m_publishSteps.append(new S60CommandPublishStep(*m_qt4bc,
                                                    makepp->effectiveCommand() + ' ' + QLatin1String("clean -w"),
                                                    tr("Clean"),
                                                    false));
162

163
164
    m_publishSteps.append(new S60CommandPublishStep(*m_qt4bc,
                                                    qmakepp->effectiveCommand() + ' ' + qmakepp->arguments(),
Pawel Polanski's avatar
Pawel Polanski committed
165
                                                    tr("qmake")));
166

167
168
169
    m_publishSteps.append(new S60CommandPublishStep(*m_qt4bc,
                                                    makepp->effectiveCommand() + ' ' + makepp->arguments(),
                                                    tr("Build")));
170
171
172
173
174
175
176
177
    if (isDynamicLibrary(*m_qt4project)) {
        const QString freezeArg = QLatin1String("freeze-") + makepp->arguments();
        m_publishSteps.append(new S60CommandPublishStep(*m_qt4bc,
                                                        makepp->effectiveCommand() + ' ' + freezeArg,
                                                        tr("Freeze")));

        m_publishSteps.append(new S60CommandPublishStep(*m_qt4bc,
                                                        makepp->effectiveCommand() + ' ' + QLatin1String("clean -w"),
Pawel Polanski's avatar
Pawel Polanski committed
178
                                                        tr("Secondary clean"),
179
180
181
182
                                                        false));

        m_publishSteps.append(new S60CommandPublishStep(*m_qt4bc,
                                                        qmakepp->effectiveCommand() + ' ' + qmakepp->arguments(),
Pawel Polanski's avatar
Pawel Polanski committed
183
                                                        tr("Secondary qmake")));
184
185
186

        m_publishSteps.append(new S60CommandPublishStep(*m_qt4bc,
                                                        makepp->effectiveCommand() + ' ' + makepp->arguments(),
Pawel Polanski's avatar
Pawel Polanski committed
187
                                                        tr("Secondary build")));
188
    }
189
190
191

    QString signArg = QLatin1String("unsigned_installer_sis");
    if (m_qt4bc->qtVersion()->qtVersion() == QtSupport::QtVersionNumber(4,6,3) )
Pawel Polanski's avatar
Pawel Polanski committed
192
        signArg = QLatin1String("installer_sis");
193
194
    m_publishSteps.append(new S60CommandPublishStep(*m_qt4bc,
                                                    makepp->effectiveCommand() + ' ' + signArg,
195
                                                    tr("Making SIS file")));
196
197

    // set up access to vendor names
Pawel Polanski's avatar
Pawel Polanski committed
198
    QStringList deploymentLevelVars = m_reader->values(QLatin1String("DEPLOYMENT"));
199
200
201
    QStringList vendorInfoVars;
    QStringList valueLevelVars;

Friedemann Kleint's avatar
Friedemann Kleint committed
202
    foreach (const QString &deploymentLevelVar, deploymentLevelVars) {
Pawel Polanski's avatar
Pawel Polanski committed
203
        vendorInfoVars = m_reader->values(deploymentLevelVar+QLatin1String(".pkg_prerules"));
Friedemann Kleint's avatar
Friedemann Kleint committed
204
        foreach (const QString &vendorInfoVar, vendorInfoVars) {
205
            valueLevelVars = m_reader->values(vendorInfoVar);
Friedemann Kleint's avatar
Friedemann Kleint committed
206
            foreach (const QString &valueLevelVar, valueLevelVars) {
Pawel Polanski's avatar
Pawel Polanski committed
207
                if (valueLevelVar.startsWith(QLatin1String("%{\""))) {
208
209
210
211
212
213
                    m_vendorInfoVariable = vendorInfoVar;
                    break;
                }
            }
        }
    }
214
215
}

216
217
218
219
220
221
222
223
224
225
226
bool S60PublisherOvi::isDynamicLibrary(const Qt4Project &project) const
{
    Qt4ProFileNode *proFile = project.rootProjectNode();
    if (proFile->projectType() == LibraryTemplate) {
        const QStringList &config(proFile->variableValue(ConfigVar));
        if (!config.contains(QLatin1String("static")) && !config.contains(QLatin1String("staticlib")))
            return true;
    }
    return false;
}

227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
QString S60PublisherOvi::nameFromTarget() const
{
    QString target = m_reader->value(QLatin1String("TARGET"));
    if (target.isEmpty())
        target = QFileInfo(m_qt4project->rootProjectNode()->path()).baseName();
    return target;
}

QString S60PublisherOvi::displayName() const
{
    const QStringList displayNameList = m_reader->values(QLatin1String("DEPLOYMENT.display_name"));

    if (displayNameList.isEmpty())
        return nameFromTarget();

    return displayNameList.join(QLatin1String(" "));
}

245
QString S60PublisherOvi::globalVendorName() const
246
{
247
    QStringList vendorinfos = m_reader->values(m_vendorInfoVariable);
248
249

    foreach (QString vendorinfo, vendorinfos) {
250
        if (vendorinfo.startsWith(':')) {
Friedemann Kleint's avatar
Friedemann Kleint committed
251
            return vendorinfo.remove(':').remove('"').trimmed();
252
253
        }
    }
Primrose Mbanefo's avatar
Primrose Mbanefo committed
254
    return QString();
255
256
}

257
QString S60PublisherOvi::localisedVendorNames() const
258
{
259
    QStringList vendorinfos = m_reader->values(m_vendorInfoVariable);
260
261
262
263
    QString result;

    QStringList localisedVendorNames;
    foreach (QString vendorinfo, vendorinfos) {
264
        if (vendorinfo.startsWith('%')) {
Pawel Polanski's avatar
Pawel Polanski committed
265
            localisedVendorNames = vendorinfo.remove(QLatin1String("%{")).remove('}').split(',');
266
267
            foreach (QString localisedVendorName, localisedVendorNames) {
                if (!result.isEmpty())
Pawel Polanski's avatar
Pawel Polanski committed
268
                    result.append(QLatin1String(", "));
269
270
271
272
273
                result.append(localisedVendorName.remove("\"").trimmed());
            }
            return result;
        }
    }
Primrose Mbanefo's avatar
Primrose Mbanefo committed
274
    return QString();
275
276
}

277
bool S60PublisherOvi::isVendorNameValid(const QString &vendorName) const
278
{
279
280
281
282
283
    // vendorName cannot containg "Nokia"
    if (vendorName.trimmed().contains(Constants::REJECTED_VENDOR_NAMES_NOKIA, Qt::CaseInsensitive))
        return false;

    // vendorName cannot be any of the rejected vendor names
284
285
286
    foreach (const QString &rejectedVendorName, m_rejectedVendorNames)
        if (vendorName.trimmed().compare(rejectedVendorName, Qt::CaseInsensitive) == 0)
            return false;
287

288
289
290
    return true;
}

291
QString S60PublisherOvi::qtVersion() const
292
{
dt's avatar
dt committed
293
294
    if (!m_qt4bc->qtVersion())
        return QString();
295
296
297
    return m_qt4bc->qtVersion()->displayName();
}

298
QString S60PublisherOvi::uid3() const
299
{
Pawel Polanski's avatar
Pawel Polanski committed
300
    return m_reader->value(QLatin1String("TARGET.UID3"));
301
302
}

303
bool S60PublisherOvi::isUID3Valid(const QString &uid3) const
304
305
306
307
308
309
310
{
    bool ok;
    ulong hex = uid3.trimmed().toULong(&ok, 0);

    return ok && (hex >= AssignedRestrictedStart && hex <= AssignedRestrictedEnd);
}

311
bool S60PublisherOvi::isTestUID3(const QString &uid3) const
312
313
314
{
    bool ok;
    ulong hex = uid3.trimmed().toULong(&ok, 0);
Pawel Polanski's avatar
Pawel Polanski committed
315
    return ok && (hex >= TestStart && hex <= TestEnd);
316
317
}

318
bool S60PublisherOvi::isKnownSymbianSignedUID3(const QString &uid3) const
319
320
321
322
323
324
{
    bool ok;
    ulong hex = uid3.trimmed().toULong(&ok, 0);
    return ok && (hex >= SymbianSignedUnprotectedStart && hex <= SymbianSignedUnprotectedEnd);
}

325
QString S60PublisherOvi::capabilities() const
326
{
Pawel Polanski's avatar
Pawel Polanski committed
327
    return m_reader->values(QLatin1String("TARGET.CAPABILITY")).join(", ");
328
329
}

330
bool S60PublisherOvi::isCapabilityOneOf(const QString &capability, CapabilityLevel level) const
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
{
    QStringList capabilitiesInLevel;
    if (level == CertifiedSigned)
        capabilitiesInLevel = m_capabilitiesForCertifiedSigned;
    else if (level == ManufacturerApproved)
        capabilitiesInLevel = m_capabilitesForManufacturerApproved;

    return capabilitiesInLevel.contains(capability.trimmed());
}

void S60PublisherOvi::updateProFile(const QString &var, const QString &values)
{
    QStringList lines;
    ProFile *profile = m_reader->parsedProFile(m_qt4project->rootProjectNode()->path());

346
347
348
    Utils::FileReader reader;
    if (!reader.fetch(m_qt4project->rootProjectNode()->path(), QIODevice::Text)) {
        emit progressReport(reader.errorString(), m_errorColor);
349
350
        return;
    }
351
    lines = QString::fromLocal8Bit(reader.data()).split(QLatin1Char('\n'));
352

353
    ProWriter::putVarValues(profile, &lines, QStringList() << values, var,
354
                            ProWriter::ReplaceValues | ProWriter::OneLine | ProWriter::AppendOperator,
Pawel Polanski's avatar
Pawel Polanski committed
355
                            QLatin1String("symbian"));
356

357
    Utils::FileSaver saver(m_qt4project->rootProjectNode()->path(), QIODevice::Text);
Pawel Polanski's avatar
Pawel Polanski committed
358
    saver.write(lines.join(QLatin1String("\n")).toLocal8Bit());
359
360
    if (!saver.finalize())
        emit progressReport(saver.errorString(), m_errorColor);
361
362
363
364
}

void S60PublisherOvi::updateProFile()
{
365
    if (m_vendorInfoVariable.isEmpty()) {
366
367
368
        m_vendorInfoVariable = QLatin1String("vendorinfo");
        updateProFile(QLatin1String("my_deployment.pkg_prerules"), m_vendorInfoVariable);
        updateProFile(QLatin1String("DEPLOYMENT"), QLatin1String("my_deployment"));
369
370
    }

371
372
373
    if (!m_displayName.isEmpty() && m_displayName != nameFromTarget())
        updateProFile(QLatin1String("DEPLOYMENT.display_name"), m_displayName);

Pawel Polanski's avatar
Pawel Polanski committed
374
375
376
377
378
379
    updateProFile(m_vendorInfoVariable, QLatin1String("\"%{")
                  + m_localVendorNames
                  + QLatin1String("}\" \":\\\"")
                  + m_vendorName
                  + QLatin1String("\\\"\"") );
    updateProFile(QLatin1String("TARGET.UID3"), m_appUid);
380
381
382
383
384
}

void S60PublisherOvi::buildSis()
{
    updateProFile();
385
    if (!runStep()) {
386
        emit progressReport(tr("Done.\n"), m_commandColor);
387
388
        emit finished();
    }
389
390
}

391
bool S60PublisherOvi::runStep()
392
{
393
    QTC_ASSERT(m_publishSteps.count(), return false);
394

395
396
397
398
399
400
    S60PublishStep *step = m_publishSteps.at(0);
    emit progressReport(step->displayDescription() + '\n', m_commandColor);
    connect(step, SIGNAL(finished(bool)), this, SLOT(publishStepFinished(bool)));
    connect(step, SIGNAL(output(QString,bool)), this, SLOT(printMessage(QString,bool)));
    step->start();
    return true;
401
402
}

403
bool S60PublisherOvi::nextStep()
404
{
405
406
407
    QTC_ASSERT(m_publishSteps.count(), return false);
    m_publishSteps.removeAt(0);
    return m_publishSteps.count();
408
409
}

410
void S60PublisherOvi::printMessage(QString message, bool error)
411
{
412
    emit progressReport(message + '\n', error ? m_errorColor : m_okColor);
413
414
}

415
void S60PublisherOvi::publishStepFinished(bool success)
416
{
417
    if (!success && m_publishSteps.at(0)->mandatory()) {
418
        emit progressReport(tr("SIS file not created due to previous errors.\n") , m_errorColor);
419
420
421
        emit finished();
        return;
    }
422

423
424
425
426
427
    if (nextStep())
        runStep();
    else {
        QString sisFile;
        if (sisExists(sisFile)) {
428
            emit progressReport(tr("Created %1.\n").arg(QDir::toNativeSeparators(sisFile)), m_normalColor);
429
430
431
            m_finishedAndSuccessful = true;
            emit succeeded();
        }
432
        emit progressReport(tr("Done.\n"), m_commandColor);
433
434
        emit finished();
    }
435
436
}

437
bool S60PublisherOvi::sisExists(QString &sisFile)
438
{
439
    QString fileNamePostFix = QLatin1String("_installer_unsigned.sis");
440
    if (m_qt4bc->qtVersion()->qtVersion() == QtSupport::QtVersionNumber(4,6,3) )
Pawel Polanski's avatar
Pawel Polanski committed
441
        fileNamePostFix = QLatin1String("_installer.sis");
442

443
    sisFile = m_qt4bc->buildDirectory() + QLatin1Char('/') + m_qt4project->displayName() + fileNamePostFix;
444

445
446
    QFileInfo fi(sisFile);
    return fi.exists();
447
448
}

449
QString S60PublisherOvi::createdSisFileContainingFolder()
450
{
Pawel Polanski's avatar
Pawel Polanski committed
451
    QString fileNamePostFix = QLatin1String("_installer_unsigned.sis");
452
    if (m_qt4bc->qtVersion()->qtVersion() == QtSupport::QtVersionNumber(4,6,3) )
Pawel Polanski's avatar
Pawel Polanski committed
453
        fileNamePostFix = QLatin1String("_installer.sis");
454

Pawel Polanski's avatar
Pawel Polanski committed
455
    QString resultFile = m_qt4bc->buildDirectory() + '/' + m_qt4project->displayName() + fileNamePostFix;
456
457
458
459
460
    QFileInfo fi(resultFile);

    return fi.exists() ? QDir::toNativeSeparators(m_qt4bc->buildDirectory()) : QString();
}

461
QString S60PublisherOvi::createdSisFilePath()
462
{
Pawel Polanski's avatar
Pawel Polanski committed
463
    QString fileNamePostFix = QLatin1String("_installer_unsigned.sis");
464
    if (m_qt4bc->qtVersion()->qtVersion() == QtSupport::QtVersionNumber(4,6,3) )
Pawel Polanski's avatar
Pawel Polanski committed
465
        fileNamePostFix = QLatin1String("_installer.sis");
466

Pawel Polanski's avatar
Pawel Polanski committed
467
    QString resultFile = m_qt4bc->buildDirectory() + '/' + m_qt4project->displayName() + fileNamePostFix;
468
469
    QFileInfo fi(resultFile);

470
    return fi.exists() ? QDir::toNativeSeparators(m_qt4bc->buildDirectory()+ '/' + m_qt4project->displayName() + fileNamePostFix) : QString();
471
472
473
474
475
476
477
}

bool S60PublisherOvi::hasSucceeded()
{
    return m_finishedAndSuccessful;
}

478
479
480
481
482
483
// ======== S60PublishStep

S60PublishStep::S60PublishStep(bool mandatory, QObject *parent)
    : QObject(parent),
      m_succeeded(false),
      m_mandatory(mandatory)
484
{
485
}
486

487
488
489
490
bool S60PublishStep::succeeded() const
{
    return m_succeeded;
}
491

492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
bool S60PublishStep::mandatory() const
{
    return m_mandatory;
}

void S60PublishStep::setSucceeded(bool succeeded)
{
    m_succeeded = succeeded;
}

// ======== S60CommandPublishStep

S60CommandPublishStep::S60CommandPublishStep(const Qt4ProjectManager::Qt4BuildConfiguration &bc,
                                             const QString &command,
                                             const QString &name,
                                             bool mandatory,
                                             QObject *parent)
    : S60PublishStep(mandatory, parent),
      m_proc(new QProcess(this)),
      m_command(command),
      m_name(name)
{
    m_proc->setEnvironment(bc.environment().toStringList());
    m_proc->setWorkingDirectory(bc.buildDirectory());

    connect(m_proc, SIGNAL(finished(int)), SLOT(processFinished(int)));
}

void S60CommandPublishStep::processFinished(int exitCode)
{
    QByteArray outputText = m_proc->readAllStandardOutput();
    if (!outputText.isEmpty())
        emit output(outputText, false);

    outputText = m_proc->readAllStandardError();
    if (!outputText.isEmpty())
        emit output(outputText, true);

    setSucceeded(exitCode == QProcess::NormalExit);
    emit finished(succeeded());
}

void S60CommandPublishStep::start()
{
    emit output(m_command, false);
    m_proc->start(m_command);
}

QString S60CommandPublishStep::displayDescription() const
{
    //: %1 is a name of the Publish Step i.e. Clean Step
    return tr("Running %1").arg(m_name);
544
545
546
547
}

} // namespace Internal
} // namespace Qt4ProjectManager