2
* Copyright 2013 Canonical Ltd.
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU Lesser General Public License as published by
6
* the Free Software Foundation; version 2.1.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU Lesser General Public License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
* Author: Juhapekka Piiroinen <juhapekka.piiroinen@canonical.com>
19
#include "ubuntupackagingwidget.h"
20
#include "ubuntusecuritypolicypickerdialog.h"
21
#include "ui_ubuntupackagingwidget.h"
22
#include "ubuntuconstants.h"
23
#include "ubuntumenu.h"
24
#include "ubuntuclicktool.h"
25
#include "ubuntucmakemakestep.h"
26
#include "ubuntuvalidationresultmodel.h"
27
#include "ubuntudevice.h"
28
#include "ubuntupackagestep.h"
29
#include "ubuntushared.h"
30
#include "ubuntucmakecache.h"
31
#include "ubuntuprojecthelper.h"
33
#include <projectexplorer/projectexplorer.h>
34
#include <projectexplorer/project.h>
35
#include <projectexplorer/session.h>
36
#include <projectexplorer/iprojectmanager.h>
37
#include <projectexplorer/buildconfiguration.h>
38
#include <projectexplorer/kitinformation.h>
39
#include <projectexplorer/target.h>
40
#include <projectexplorer/buildmanager.h>
41
#include <projectexplorer/kit.h>
42
#include <projectexplorer/buildsteplist.h>
43
#include <projectexplorer/toolchain.h>
44
#include <coreplugin/actionmanager/actionmanager.h>
45
#include <coreplugin/actionmanager/actioncontainer.h>
46
#include <cmakeprojectmanager/cmakeprojectconstants.h>
47
#include <ssh/sshconnection.h>
48
#include <qmlprojectmanager/qmlprojectconstants.h>
49
#include <qmakeprojectmanager/qmakeprojectmanagerconstants.h>
51
#include <QFileDialog>
52
#include <QJsonDocument>
53
#include <QJsonParseError>
54
#include <QListWidgetItem>
57
#include <QMessageBox>
58
#include <QScriptEngine>
59
#include <QRegularExpression>
61
using namespace Ubuntu;
62
using namespace Ubuntu::Internal;
68
UbuntuPackagingWidget::UbuntuPackagingWidget(QWidget *parent) :
70
ui(new Ui::UbuntuPackagingWidget),
71
m_postPackageTask(Verify)
74
ui->groupBoxValidate->hide();
76
m_inputParser = new ClickRunChecksParser(this);
77
m_validationModel = new UbuntuValidationResultModel(this);
79
connect(m_inputParser,&ClickRunChecksParser::parsedNewTopLevelItem
80
,m_validationModel,&UbuntuValidationResultModel::appendItem);
82
ui->treeViewValidate->setModel(m_validationModel);
84
connect(&m_ubuntuProcess,SIGNAL(started(QString)),this,SLOT(onStarted(QString)));
85
connect(&m_ubuntuProcess,SIGNAL(message(QString)),this,SLOT(onMessage(QString)));
86
connect(&m_ubuntuProcess,SIGNAL(finished(QString,int)),this,SLOT(onFinished(QString, int)));
87
connect(&m_ubuntuProcess,SIGNAL(error(QString)),this,SLOT(onError(QString)));
89
connect(ui->treeViewValidate->selectionModel(),SIGNAL(currentChanged(QModelIndex,QModelIndex)),this,SLOT(onValidationItemSelected(QModelIndex)));
90
connect(m_validationModel,SIGNAL(rowsInserted(QModelIndex,int,int)),this,SLOT(onNewValidationData()));
92
connect(UbuntuMenu::instance(),SIGNAL(requestBuildAndInstallProject()),this,SLOT(buildAndInstallPackageRequested()));
93
connect(UbuntuMenu::instance(),SIGNAL(requestBuildAndVerifyProject()),this,SLOT(buildAndVerifyPackageRequested()));
94
connect(UbuntuMenu::instance(),SIGNAL(requestBuildProject()),this,SLOT(buildPackageRequested()));
96
connect(ui->pushButtonCreateAndInstall,SIGNAL(clicked()),this,SLOT(buildAndInstallPackageRequested()));
97
connect(ProjectExplorer::ProjectExplorerPlugin::instance(),SIGNAL(updateRunActions()),this,SLOT(targetChanged()));
99
m_reviewToolsInstalled = false;
100
checkClickReviewerTool();
103
UbuntuPackagingWidget::~UbuntuPackagingWidget()
106
clearPackageBuildList();
109
void UbuntuPackagingWidget::onFinishedAction(const QProcess *proc, QString cmd)
114
disconnect(m_UbuntuMenu_connection);
116
if (!m_reviewToolsInstalled)
119
ProjectExplorer::Project* startupProject = ProjectExplorer::SessionManager::startupProject();
121
//first try to use the version in the deploy directory. It is always in the root of the click package
122
QString manifestPath;
124
if(startupProject->activeTarget() && startupProject->activeTarget()->activeBuildConfiguration()) {
125
manifestPath = startupProject->activeTarget()->activeBuildConfiguration()->buildDirectory()
126
.appendPath(QLatin1String(Constants::UBUNTU_DEPLOY_DESTDIR))
127
.appendPath(QStringLiteral("manifest.json"))
131
if(!QFile::exists(manifestPath)) {
132
//fall back to the project directory
133
manifestPath = UbuntuProjectHelper::getManifestPath(startupProject->activeTarget(),
134
Utils::FileName::fromString(startupProject->projectDirectory())
135
.appendPath(QStringLiteral("manifest.json")).toString());
138
UbuntuClickManifest manifest;
139
if(!manifest.load(manifestPath))
142
QString sClickPackageName;
143
QString sClickPackagePath;
144
sClickPackageName = QString::fromLatin1("%0_%1_all.click").arg(manifest.name()).arg(manifest.version());
145
sClickPackagePath = startupProject->projectDirectory();
147
QRegularExpression re(QLatin1String("\\/\\w+$")); // search for the project name in the path
148
QRegularExpressionMatch match = re.match(sClickPackagePath);
149
if (match.hasMatch()) {
150
QString matched = match.captured(0);
151
sClickPackagePath.chop(matched.length()-1); //leave the slash
154
sClickPackagePath.append(sClickPackageName);
155
m_ubuntuProcess.stop();
157
if (sClickPackagePath.isEmpty())
160
if (m_reviewToolsInstalled) {
162
if(debug) qDebug()<<"Going to verify: "<<sClickPackagePath;
164
m_ubuntuProcess.append(QStringList() << QString::fromLatin1(Constants::CLICK_REVIEWERSTOOLS_LOCATION).arg(sClickPackagePath));
165
m_ubuntuProcess.start(QString(QLatin1String(Constants::UBUNTUPACKAGINGWIDGET_CLICK_REVIEWER_TOOLS_AGAINST_PACKAGE)).arg(sClickPackagePath));
170
void UbuntuPackagingWidget::onNewValidationData()
172
if(!ui->treeViewValidate->selectionModel()->hasSelection()) {
173
QModelIndex index = m_validationModel->findFirstErrorItem();
175
ui->treeViewValidate->setCurrentIndex(index);
179
void UbuntuPackagingWidget::onValidationItemSelected(const QModelIndex &index)
181
if(index.isValid()) {
182
QUrl link = m_validationModel->data(index,UbuntuValidationResultModel::LinkRole).toUrl();
184
ui->labelErrorLink->setText(
185
QString::fromLatin1(Constants::UBUNTUPACKAGINGWIDGET_CLICK_REVIEWER_TOOLS_LINK_DISPLAYTEXT)
186
.arg(link.toString(QUrl::FullyEncoded)));
188
ui->labelErrorLink->setText(QLatin1String(""));
190
ui->labelErrorType->setText(m_validationModel->data(index,UbuntuValidationResultModel::TypeRole).toString());
191
ui->plainTextEditDescription->setPlainText(m_validationModel->data(index,UbuntuValidationResultModel::DescriptionRole).toString());
195
void UbuntuPackagingWidget::onMessage(QString msg)
197
printToOutputPane(msg);
199
m_inputParser->addRecievedData(msg);
202
void UbuntuPackagingWidget::onFinished(QString cmd, int code) {
203
m_inputParser->endRecieveData();
205
m_inputParser->emitTextItem(QLatin1String("Command finished successfully"),cmd,ClickRunChecksParser::NoIcon);
207
m_inputParser->emitTextItem(QLatin1String("Command failed"),cmd,ClickRunChecksParser::Error);
208
if (cmd == QString::fromLatin1(Constants::UBUNTUWIDGETS_ONFINISHED_SCRIPT_LOCAL_PACKAGE_INSTALLED).arg(Ubuntu::Constants::UBUNTU_SCRIPTPATH)) {
209
resetValidationResult();
210
QStringList lines = m_reply.trimmed().split(QLatin1String(Constants::LINEFEED));
211
foreach(QString line, lines) {
212
line = line.trimmed();
213
if (line.isEmpty()) {
216
if (line.startsWith(QLatin1String(Constants::UBUNTUDEVICESWIDGET_ONFINISHED_LOCAL_NO_EMULATOR_INSTALLED))) {
217
// There is no click reviewer tool installed
218
m_reviewToolsInstalled = false;
219
ui->groupBoxValidate->hide();
220
emit reviewToolsInstalledChanged(m_reviewToolsInstalled);
222
QStringList lineData = line.split(QLatin1String(Constants::SPACE));
223
QString sReviewerToolPackageStatus = lineData.takeFirst();
224
//QString sReviewerToolPackageName = lineData.takeFirst();
225
//QString sReviewerToolPackageVersion = lineData.takeFirst();
226
if (sReviewerToolPackageStatus.startsWith(QLatin1String(Constants::INSTALLED))) {
227
// There is click reviewer tool installed
228
ui->groupBoxValidate->show();
229
m_reviewToolsInstalled = true;
230
emit reviewToolsInstalledChanged(m_reviewToolsInstalled);
238
void UbuntuPackagingWidget::onError(QString msg) {
242
m_inputParser->emitTextItem(QLatin1String("Error"),msg,ClickRunChecksParser::Error);
245
void UbuntuPackagingWidget::onStarted(QString cmd) {
246
resetValidationResult();
247
m_inputParser->emitTextItem(QLatin1String("Start Command"),cmd,ClickRunChecksParser::NoIcon);
250
bool UbuntuPackagingWidget::reviewToolsInstalled()
252
return m_reviewToolsInstalled;
255
void UbuntuPackagingWidget::on_pushButtonReviewersTools_clicked() {
256
ProjectExplorer::Project* startupProject = ProjectExplorer::SessionManager::startupProject();
257
m_ubuntuProcess.stop();
259
QString directory = QDir::homePath();
260
if(startupProject) directory = startupProject->projectDirectory();
262
QString clickPackage = QFileDialog::getOpenFileName(this,QString(QLatin1String(Constants::UBUNTU_CLICK_PACKAGE_SELECTOR_TEXT)),QString(QLatin1String("%0/..")).arg(directory),QLatin1String(Constants::UBUNTU_CLICK_PACKAGE_MASK));
263
if (clickPackage.isEmpty()) return;
264
m_inputParser->beginRecieveData();
265
m_ubuntuProcess.append(QStringList() << QString::fromLatin1(Constants::CLICK_REVIEWERSTOOLS_LOCATION).arg(clickPackage));
266
m_ubuntuProcess.start(QString(QLatin1String(Constants::UBUNTUPACKAGINGWIDGET_CLICK_REVIEWER_TOOLS_AGAINST_PACKAGE)).arg(clickPackage));
269
void UbuntuPackagingWidget::on_pushButtonClickPackage_clicked() {
270
ProjectExplorer::Project* project = ProjectExplorer::SessionManager::startupProject();
274
QString mimeType = project->projectManager()->mimeType();
275
if(mimeType == QLatin1String(CMakeProjectManager::Constants::CMAKEMIMETYPE)
276
|| mimeType == QLatin1String(Ubuntu::Constants::UBUNTUPROJECT_MIMETYPE)
277
|| mimeType == QLatin1String(QmlProjectManager::Constants::QMLPROJECT_MIMETYPE)
278
|| mimeType == QLatin1String(QmakeProjectManager::Constants::PROFILE_MIMETYPE)) {
279
if(m_reviewToolsInstalled)
280
m_postPackageTask = Verify;
282
m_postPackageTask = None;
285
m_UbuntuMenu_connection = QObject::connect(UbuntuMenu::instance(),SIGNAL(finished_action(const QProcess*,QString)),this,SLOT(onFinishedAction(const QProcess*,QString)));
287
if(!m_UbuntuMenu_connection)
288
qWarning()<<"Could not connect signals";
290
QAction* action = UbuntuMenu::menuAction(Core::Id(Constants::UBUNTUPACKAGINGWIDGET_BUILDPACKAGE_ID));
297
void UbuntuPackagingWidget::checkClickReviewerTool() {
298
m_ubuntuProcess.stop();
299
QString sReviewerPackageName = QLatin1String(Ubuntu::Constants::REVIEWER_PACKAGE_NAME);
300
m_ubuntuProcess.append(QStringList() << QString::fromLatin1(Constants::UBUNTUWIDGETS_LOCAL_PACKAGE_INSTALLED_SCRIPT).arg(Ubuntu::Constants::UBUNTU_SCRIPTPATH).arg(sReviewerPackageName) << QApplication::applicationDirPath());
301
m_ubuntuProcess.start(QString::fromLatin1(Constants::UBUNTUPACKAGINGWIDGET_LOCAL_REVIEWER_INSTALLED));
304
void UbuntuPackagingWidget::buildFinished(const bool success)
306
disconnect(m_buildManagerConnection);
308
UbuntuPackageStep *pckStep = qobject_cast<UbuntuPackageStep*>(m_packageBuildSteps->steps().last());
309
if (pckStep && !pckStep->packagePath().isEmpty()) {
310
m_ubuntuProcess.stop();
312
QString sClickPackagePath = pckStep->packagePath();
313
if (sClickPackagePath.isEmpty()) {
314
clearPackageBuildList();
318
switch (m_postPackageTask) {
322
if(debug) qDebug()<<"Going to verify: "<<sClickPackagePath;
324
m_inputParser->beginRecieveData();
325
m_ubuntuProcess.append(QStringList() << QString::fromLatin1(Constants::CLICK_REVIEWERSTOOLS_LOCATION).arg(sClickPackagePath));
326
m_ubuntuProcess.start(QString(QLatin1String(Constants::UBUNTUPACKAGINGWIDGET_CLICK_REVIEWER_TOOLS_AGAINST_PACKAGE)).arg(sClickPackagePath));
330
ProjectExplorer::IDevice::ConstPtr dev = ProjectExplorer::DeviceKitInformation::device(pckStep->target()->kit());
332
break; //fall through to clear buildsteps
333
if (!dev->type().toString().startsWith(QLatin1String(Constants::UBUNTU_DEVICE_TYPE_ID)))
334
break; //fall through to clear buildsteps
336
UbuntuDevice::ConstPtr ubuntuDev = qSharedPointerCast<const UbuntuDevice>(dev);
337
QSsh::SshConnectionParameters connParams = ubuntuDev->sshParameters();
339
m_ubuntuProcess.append(QStringList()
340
<< QString::fromLatin1(Constants::UBUNTUPACKAGINGWIDGET_CLICK_DEPLOY_SCRIPT)
341
.arg(Constants::UBUNTU_SCRIPTPATH)
342
.arg(ubuntuDev->serialNumber())
343
.arg(sClickPackagePath)
344
.arg(QStringLiteral("%1@%2").arg(connParams.userName).arg(connParams.host))
345
.arg(connParams.port)
346
.arg(QStringLiteral("/home/%1/dev_tmp").arg(connParams.userName))
347
.arg(connParams.userName));
348
m_ubuntuProcess.start(QLatin1String(Constants::UBUNTUPACKAGINGWIDGET_CLICK_DEPLOY_MESSAGE));
354
clearPackageBuildList();
357
void UbuntuPackagingWidget::buildAndInstallPackageRequested()
359
m_postPackageTask = Install;
363
void UbuntuPackagingWidget::buildAndVerifyPackageRequested()
365
m_postPackageTask = Verify;
369
void UbuntuPackagingWidget::buildPackageRequested()
371
m_postPackageTask = None;
375
void UbuntuPackagingWidget::targetChanged()
377
ProjectExplorer::Project *p = ProjectExplorer::SessionManager::startupProject();
378
bool buildButtonsEnabled = p &&
380
p->activeTarget()->kit() &&
381
ProjectExplorer::ToolChainKitInformation::toolChain(p->activeTarget()->kit()) &&
382
ProjectExplorer::ToolChainKitInformation::toolChain(p->activeTarget()->kit())->type() == QLatin1String(Constants::UBUNTU_CLICK_TOOLCHAIN_ID);
384
ui->pushButtonClickPackage->setEnabled(buildButtonsEnabled);
385
ui->pushButtonCreateAndInstall->setEnabled(buildButtonsEnabled);
390
* \brief UbuntuPackagingWidget::buildClickPackage
391
* Starts the build of a cmake project. Make sure to set
392
* m_postPackageTask correctly before calling this function
394
void UbuntuPackagingWidget::buildClickPackage()
396
ProjectExplorer::Project* project = ProjectExplorer::SessionManager::startupProject();
400
QString mimeType = project->projectManager()->mimeType();
401
bool isCMake = mimeType == QLatin1String(CMakeProjectManager::Constants::CMAKEMIMETYPE);
402
bool isHtml = mimeType == QLatin1String(Ubuntu::Constants::UBUNTUPROJECT_MIMETYPE);
403
bool isQml = mimeType == QLatin1String(QmlProjectManager::Constants::QMLPROJECT_MIMETYPE);
404
bool isQmake = mimeType == QLatin1String(QmakeProjectManager::Constants::PROFILE_MIMETYPE);
406
if(isCMake || isHtml || isQml || isQmake) {
407
ProjectExplorer::Target* target = project->activeTarget();
411
ProjectExplorer::Kit* k = target->kit();
415
if(!ProjectExplorer::DeviceTypeKitInformation::deviceTypeId(k).toString().startsWith(QLatin1String(Ubuntu::Constants::UBUNTU_DEVICE_TYPE_ID))) {
416
QMessageBox::warning(this,tr("Wrong kit type"),tr("It is not supported to create click packages for a non UbuntuSDK target"));
420
if(ProjectExplorer::BuildManager::isBuilding()) {
421
QMessageBox::information(this,tr("Build running"),tr("There is currently a build running, please wait for it to be finished"));
425
ProjectExplorer::BuildConfiguration* bc = target->activeBuildConfiguration();
427
QMessageBox::information(this,tr("Error"),tr("Please add a valid buildconfiguration to your project"));
431
if(!bc->isEnabled()) {
432
QString disabledReason = bc->disabledReason();
433
QMessageBox::information(this,tr("Disabled"),tr("The currently selected Buildconfiguration is disabled. %1").arg(disabledReason));
437
clearPackageBuildList();
439
m_packageBuildSteps = QSharedPointer<ProjectExplorer::BuildStepList> (new ProjectExplorer::BuildStepList(bc,ProjectExplorer::Constants::BUILDSTEPS_BUILD));
440
if (isCMake || isQmake) {
441
//add the normal buildsteps
442
m_packageBuildSteps->cloneSteps(bc->stepList(Core::Id(ProjectExplorer::Constants::BUILDSTEPS_BUILD)));
445
//append the click packaging step
446
UbuntuPackageStep* package = new UbuntuPackageStep(m_packageBuildSteps.data());
447
package->setPackageMode(UbuntuPackageStep::DisableDebugScript);
448
m_packageBuildSteps->appendStep(package);
450
m_buildManagerConnection = connect(ProjectExplorer::BuildManager::instance(),SIGNAL(buildQueueFinished(bool)),this,SLOT(buildFinished(bool)));
452
ProjectExplorer::BuildManager::buildList(m_packageBuildSteps.data(),tr("Build Project"));
457
* \brief UbuntuPackagingWidget::clearAdditionalBuildSteps
458
* Clears the last used additional buildsteps
459
* \note This will cancel a current build if its building the ProjectConfiguration
460
* the BuildSteps belong to!
462
void UbuntuPackagingWidget::clearPackageBuildList()
464
if (!m_packageBuildSteps)
467
if(ProjectExplorer::BuildManager::isBuilding( static_cast<ProjectExplorer::ProjectConfiguration *>(m_packageBuildSteps->parent())))
468
ProjectExplorer::BuildManager::cancel();
470
m_packageBuildSteps->deleteLater();
471
m_packageBuildSteps.clear();
474
void UbuntuPackagingWidget::resetValidationResult()
476
m_validationModel->clear();
477
ui->plainTextEditDescription->clear();
478
ui->labelErrorType->clear();