Commit 2b7582e4 authored by Tomi Leppänen's avatar Tomi Leppänen

Merge branch 'jb47559' into 'master'

Allow enabling developer mode from local package.

See merge request !126
parents ceaca903 72708b96
......@@ -4,7 +4,7 @@ Version: 0.5.27
Release: 1
Group: System/Libraries
License: BSD
URL: https://git.merproject.org/mer-core/nemo-qml-plugin-systemsettings
URL: https://git.sailfishos.org/mer-core/nemo-qml-plugin-systemsettings
Source0: %{name}-%{version}.tar.bz2
Requires(post): /sbin/ldconfig
Requires(postun): /sbin/ldconfig
......
/*
* Copyright (C) 2013-2018 Jolla Ltd.
* Copyright (c) 2013 – 2019 Jolla Ltd.
* Copyright (c) 2019 Open Mobile Platform LLC.
* Contact: Thomas Perl <thomas.perl@jollamobile.com>
* Contact: Raine Makelainen <raine.makelainen@jolla.com>
*
......@@ -55,6 +56,7 @@
/* A file that is provided by the developer mode package */
#define DEVELOPER_MODE_PROVIDED_FILE "/usr/bin/devel-su"
#define DEVELOPER_MODE_PACKAGE "jolla-developer-mode"
#define DEVELOPER_MODE_PACKAGE_PRELOAD_DIR "/var/lib/jolla-developer-mode/preloaded/"
/* D-Bus service */
#define USB_MODED_SERVICE "com.meego.usb_moded"
......@@ -84,6 +86,17 @@ static QMap<QString,QString> enumerate_network_interfaces()
return result;
}
static QString get_cached_package(const QString &version)
{
QDir dir(DEVELOPER_MODE_PACKAGE_PRELOAD_DIR);
QStringList filters;
filters << QStringLiteral("%1-%2.*.rpm").arg(DEVELOPER_MODE_PACKAGE).arg(version);
auto preloaded = dir.entryList(filters, QDir::Files, QDir::Name);
if (preloaded.empty())
return QString();
return dir.absoluteFilePath(preloaded.last());
}
DeveloperModeSettings::DeveloperModeSettings(QObject *parent)
: QObject(parent)
, m_usbModeDaemon(USB_MODED_SERVICE, USB_MODED_PATH, USB_MODED_INTERFACE, QDBusConnection::systemBus())
......@@ -97,6 +110,8 @@ DeveloperModeSettings::DeveloperModeSettings(QObject *parent)
, m_transactionRole(PackageKit::Transaction::RoleUnknown)
, m_transactionStatus(PackageKit::Transaction::StatusUnknown)
, m_refreshedForInstall(false)
, m_localInstallFailed(false)
, m_localDeveloperModePackagePath(get_cached_package(QStringLiteral("*"))) // Initialized to possibly incompatible package
{
int uid = getdef_num("UID_MIN", -1);
struct passwd *pwd;
......@@ -106,6 +121,23 @@ DeveloperModeSettings::DeveloperModeSettings(QObject *parent)
qCWarning(lcDeveloperModeLog) << "Failed to return username using getpwuid()";
}
// Resolve and update local package path
if (!m_localDeveloperModePackagePath.isEmpty()) {
PackageKit::Transaction *resolvePackage = PackageKit::Daemon::resolve(DEVELOPER_MODE_PACKAGE"-preload", PackageKit::Transaction::FilterInstalled);
connect(resolvePackage, &PackageKit::Transaction::errorCode, this, &DeveloperModeSettings::reportTransactionErrorCode);
connect(resolvePackage, &PackageKit::Transaction::package,
this, [this](PackageKit::Transaction::Info info, const QString &packageID, const QString &summary) {
Q_UNUSED(summary)
Q_ASSERT(info == PackageKit::Transaction::InfoInstalled);
const QString version = PackageKit::Transaction::packageVersion(packageID);
m_localDeveloperModePackagePath = get_cached_package(version);
if (m_localDeveloperModePackagePath.isEmpty()) {
emit repositoryAccessRequiredChanged();
}
qCDebug(lcDeveloperModeLog) << "Preload package version: " << version << ", local package path: " << m_localDeveloperModePackagePath;
});
}
refresh();
// TODO: Watch WLAN / USB IP addresses for changes
......@@ -146,6 +178,12 @@ int DeveloperModeSettings::workProgress() const
return m_workProgress;
}
bool DeveloperModeSettings::repositoryAccessRequired() const
{
// Aka local-install-of-developer-mode-package-is-not-possible
return m_localInstallFailed || m_localDeveloperModePackagePath.isEmpty();
}
void DeveloperModeSettings::setDeveloperMode(bool enabled)
{
if (m_developerModeEnabled != enabled) {
......@@ -233,8 +271,49 @@ void DeveloperModeSettings::refreshPackageCacheAndInstall()
void DeveloperModeSettings::resolveAndExecute(Command command)
{
setWorkStatus(Preparing);
m_workProgress = 0;
m_developerModePackageId.clear(); // might differ between installed/available
if (command == InstallCommand && !m_localInstallFailed && !m_localDeveloperModePackagePath.isEmpty()) {
// Resolve which version of developer mode package is expected
PackageKit::Transaction *resolvePackage = PackageKit::Daemon::resolve(DEVELOPER_MODE_PACKAGE"-preload", PackageKit::Transaction::FilterInstalled);
connect(resolvePackage, &PackageKit::Transaction::errorCode, this, &DeveloperModeSettings::reportTransactionErrorCode);
connect(resolvePackage, &PackageKit::Transaction::package,
this, [this](PackageKit::Transaction::Info info, const QString &packageID, const QString &summary) {
Q_UNUSED(summary)
Q_ASSERT(info == PackageKit::Transaction::InfoInstalled);
const QString version = PackageKit::Transaction::packageVersion(packageID);
m_localDeveloperModePackagePath = get_cached_package(version);
emit repositoryAccessRequiredChanged();
qCDebug(lcDeveloperModeLog) << "Preload package version: " << version << ", local package path: " << m_localDeveloperModePackagePath;
});
connect(resolvePackage, &PackageKit::Transaction::finished,
this, [this](PackageKit::Transaction::Exit status, uint runtime) {
Q_UNUSED(runtime)
if (status != PackageKit::Transaction::ExitSuccess || m_localDeveloperModePackagePath.isEmpty()) {
qCDebug(lcDeveloperModeLog) << "Preloaded package not found, must use remote package";
// No cached package => install from repos
resolveAndExecute(InstallCommand);
} else {
PackageKit::Transaction *tx = PackageKit::Daemon::installFiles(QStringList() << m_localDeveloperModePackagePath);
connectCommandSignals(tx);
connect(tx, &PackageKit::Transaction::finished,
this, [this](PackageKit::Transaction::Exit status, uint runtime) {
if (status == PackageKit::Transaction::ExitSuccess) {
qCDebug(lcDeveloperModeLog) << "Developer mode installation from local package transaction done:" << status << runtime;
resetState();
} else if (status == PackageKit::Transaction::ExitFailed) {
qCWarning(lcDeveloperModeLog) << "Developer mode installation from local package failed, trying from repos";
m_localInstallFailed = true;
emit repositoryAccessRequiredChanged();
resolveAndExecute(InstallCommand); // TODO: If repo access is not available this can not bail out
} // else ExitUnknown (ignored)
});
}
});
} else {
PackageKit::Transaction::Filters filters;
if (command == RemoveCommand) {
filters = PackageKit::Transaction::FilterInstalled;
......@@ -299,6 +378,7 @@ void DeveloperModeSettings::resolveAndExecute(Command command)
});
}
});
}
}
void DeveloperModeSettings::connectCommandSignals(PackageKit::Transaction *transaction)
......@@ -319,19 +399,16 @@ void DeveloperModeSettings::connectCommandSignals(PackageKit::Transaction *trans
void DeveloperModeSettings::updateState(int percentage, PackageKit::Transaction::Status status, PackageKit::Transaction::Role role)
{
// Do not update progress when finished.
if (status == PackageKit::Transaction::StatusFinished) {
return;
}
// Expected changes from PackageKit when installing packages:
// 1. Change to 'install packages' role
// 1. Change to 'install packages' role or 'install files' if installing from local package file
// 2. Status changes:
// setup -> refresh cache -> query -> resolve deps -> install (refer to as 'Preparing' status)
// -> download ('DownloadingPackages' status)
// -> install ('InstallingPackages' status)
// -> finished
//
// If installing from local package fails, it starts over!
//
// Expected changes from PackageKit when removing packages:
// 1. Change to 'remove packages' role
// 2. Status changes:
......@@ -347,10 +424,17 @@ void DeveloperModeSettings::updateState(int percentage, PackageKit::Transaction:
m_transactionRole = role;
m_transactionStatus = status;
// Do not update progress when finished or role is unknown.
if (m_transactionStatus == PackageKit::Transaction::StatusFinished
|| m_transactionRole == PackageKit::Transaction::RoleUnknown) {
return;
}
if (percentage >= 0 && percentage <= 100) {
int rangeStart = 0;
int rangeEnd = 0;
if (m_transactionRole == PackageKit::Transaction::RoleInstallPackages) {
if (m_transactionRole == PackageKit::Transaction::RoleInstallPackages
|| m_transactionRole == PackageKit::Transaction::RoleInstallFiles) {
switch (m_transactionStatus) {
case PackageKit::Transaction::StatusRefreshCache: // 0-10 %
rangeStart = 0;
......@@ -362,7 +446,10 @@ void DeveloperModeSettings::updateState(int percentage, PackageKit::Transaction:
rangeEnd = 20;
break;
case PackageKit::Transaction::StatusDownload: // 20-60 %
// Skip downloading when installing from local file
if (m_transactionRole != PackageKit::Transaction::RoleInstallFiles) {
workStatus = DownloadingPackages;
}
rangeStart = 20;
rangeEnd = 60;
break;
......
/*
* Copyright (C) 2013 Jolla Ltd.
* Copyright (c) 2013 – 2019 Jolla Ltd.
* Copyright (c) 2019 Open Mobile Platform LLC.
* Contact: Thomas Perl <thomas.perl@jollamobile.com>
*
* You may use this file under the terms of the BSD license as follows:
......@@ -55,6 +56,7 @@ class SYSTEMSETTINGS_EXPORT DeveloperModeSettings : public QObject
Q_PROPERTY(bool developerModeEnabled READ developerModeEnabled NOTIFY developerModeEnabledChanged)
Q_PROPERTY(enum DeveloperModeSettings::Status workStatus READ workStatus NOTIFY workStatusChanged)
Q_PROPERTY(int workProgress READ workProgress NOTIFY workProgressChanged)
Q_PROPERTY(bool repositoryAccessRequired READ repositoryAccessRequired NOTIFY repositoryAccessRequiredChanged)
public:
explicit DeveloperModeSettings(QObject *parent = NULL);
......@@ -74,6 +76,7 @@ public:
bool developerModeEnabled() const;
enum DeveloperModeSettings::Status workStatus() const;
int workProgress() const;
bool repositoryAccessRequired() const;
Q_INVOKABLE void setDeveloperMode(bool enabled);
Q_INVOKABLE void setUsbIpAddress(const QString &usbIpAddress);
......@@ -85,6 +88,7 @@ signals:
void developerModeEnabledChanged();
void workStatusChanged();
void workProgressChanged();
void repositoryAccessRequiredChanged();
private slots:
void reportTransactionErrorCode(PackageKit::Transaction::Error code, const QString &details);
......@@ -117,6 +121,8 @@ private:
PackageKit::Transaction::Role m_transactionRole;
PackageKit::Transaction::Status m_transactionStatus;
bool m_refreshedForInstall;
bool m_localInstallFailed;
QString m_localDeveloperModePackagePath;
};
Q_DECLARE_METATYPE(DeveloperModeSettings::Status)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment