Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Install PackageKit based Operating System Updates as Offline Updates #1943

Merged
merged 28 commits into from
Dec 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e2f6683
Install Operating System Updates (deb based) as offline updates
meisenzahl Oct 31, 2022
488dfee
Make only_download the default for Pk.Task
meisenzahl Oct 31, 2022
27cf041
Check if updates were already prepared
meisenzahl Oct 31, 2022
72acc6d
Add improved error handling
meisenzahl Oct 31, 2022
9d7bf22
Satisfy linter
meisenzahl Oct 31, 2022
06d8af7
Merge branch 'master' into packagekit-offline-updates
meisenzahl Nov 4, 2022
10c5898
Merge branch 'master' into packagekit-offline-updates
meisenzahl Nov 30, 2022
e9eec18
Merge branch 'master' into packagekit-offline-updates
danirabbit Dec 9, 2022
c574bf9
Change label from "Update" to "Download" for operating system updates
meisenzahl Dec 12, 2022
3e6f33c
Add function to get downloaded updates
meisenzahl Dec 18, 2022
7a2ed9e
Rename functions
meisenzahl Dec 19, 2022
a9af2b7
Update
meisenzahl Dec 19, 2022
3378af9
Satisfy linter
meisenzahl Dec 19, 2022
c26082d
Filter not prepared updates
meisenzahl Dec 19, 2022
cab6b5e
PackageKit: Group all packages to Operating System Updates
meisenzahl Dec 19, 2022
3b0eacb
Remove additional restart widget
meisenzahl Dec 19, 2022
0d606cf
Satisfy linter
meisenzahl Dec 19, 2022
a3d1818
Readd error handling
meisenzahl Dec 19, 2022
f33b032
Merge branch 'master' into packagekit-offline-updates
meisenzahl Dec 21, 2022
10954a9
PackageKitBackend: Add comment with reason why prepared updates are r…
meisenzahl Dec 21, 2022
2bcba47
Merge branch 'master' into packagekit-offline-updates
meisenzahl Dec 22, 2022
94e2327
Remove unused code
meisenzahl Dec 22, 2022
57ec270
PackageKitBackend: Remove unnecessary whitespace
meisenzahl Dec 22, 2022
e8038d5
Revert "Remove unused code"
meisenzahl Dec 22, 2022
e6b0856
Merge branch 'master' into packagekit-offline-updates
meisenzahl Dec 22, 2022
6d4065d
PackageKitBackend: Don't refresh cache if updates are prepared
meisenzahl Dec 23, 2022
d225814
Merge branch 'master' into packagekit-offline-updates
meisenzahl Dec 24, 2022
b342abb
Merge branch 'master' into packagekit-offline-updates
danirabbit Dec 27, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/Core/BackendAggregator.vala
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,22 @@ public class AppCenterCore.BackendAggregator : Backend, Object {
set { }
}

public async Gee.Collection<PackageDetails> get_prepared_applications (Cancellable? cancellable = null) {
var apps = new Gee.TreeSet<PackageDetails> ();
foreach (var backend in backends) {
if (cancellable.is_cancelled ()) {
break;
}

var prepared = yield backend.get_prepared_applications (cancellable);
if (prepared != null) {
apps.add_all (prepared);
}
}

return apps;
}

public async Gee.Collection<Package> get_installed_applications (Cancellable? cancellable = null) {
var apps = new Gee.TreeSet<Package> ();
foreach (var backend in backends) {
Expand Down
1 change: 1 addition & 0 deletions src/Core/BackendInterface.vala
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public interface AppCenterCore.Backend : Object {
public abstract Job.Type job_type { get; protected set; }
public abstract bool working { public get; protected set; }

public abstract async Gee.Collection<PackageDetails> get_prepared_applications (Cancellable? cancellable = null);
public abstract async Gee.Collection<Package> get_installed_applications (Cancellable? cancellable = null);
public abstract Gee.Collection<Package> get_applications_for_category (AppStream.Category category);
public abstract Gee.Collection<Package> search_applications (string query, AppStream.Category? category);
Expand Down
4 changes: 4 additions & 0 deletions src/Core/Client.vala
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ public class AppCenterCore.Client : Object {
last_cache_update = new DateTime.from_unix_utc (AppCenter.App.settings.get_int64 ("last-refresh-time"));
}

public async Gee.Collection<AppCenterCore.PackageDetails> get_prepared_applications (Cancellable? cancellable = null) {
return yield BackendAggregator.get_default ().get_prepared_applications (cancellable);
}

public async Gee.Collection<AppCenterCore.Package> get_installed_applications (Cancellable? cancellable = null) {
return yield BackendAggregator.get_default ().get_installed_applications (cancellable);
}
Expand Down
6 changes: 6 additions & 0 deletions src/Core/FlatpakBackend.vala
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,12 @@ public class AppCenterCore.FlatpakBackend : Backend, Object {
return job;
}

public async Gee.Collection<PackageDetails> get_prepared_applications (Cancellable? cancellable = null) {
var prepared_apps = new Gee.HashSet<PackageDetails> ();

return prepared_apps;
}

public async Gee.Collection<Package> get_installed_applications (Cancellable? cancellable = null) {
var installed_apps = new Gee.HashSet<Package> ();

Expand Down
7 changes: 6 additions & 1 deletion src/Core/Job.vala
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ public class AppCenterCore.Job : Object {
REMOVE_PACKAGE,
IS_PACKAGE_INSTALLED,
GET_PACKAGE_DETAILS,
GET_PACKAGE_DEPENDENCIES
GET_PACKAGE_DEPENDENCIES,
GET_PREPARED_PACKAGES
}

public Job (Type type) {
Expand All @@ -47,6 +48,10 @@ public class AppCenterCore.Job : Object {

public abstract class AppCenterCore.JobArgs { }

public class AppCenterCore.GetPreparedPackagesArgs : JobArgs {
public Cancellable? cancellable;
}

public class AppCenterCore.GetInstalledPackagesArgs : JobArgs {
public Cancellable? cancellable;
}
Expand Down
160 changes: 152 additions & 8 deletions src/Core/PackageKitBackend.vala
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ public class AppCenterCore.PackageKitBackend : Backend, Object {
job_type = job.operation;
working = true;
switch (job.operation) {
case Job.Type.GET_PREPARED_PACKAGES:
get_prepared_packages_internal (job);
break;
case Job.Type.GET_INSTALLED_PACKAGES:
get_installed_packages_internal (job);
break;
Expand Down Expand Up @@ -148,7 +151,9 @@ public class AppCenterCore.PackageKitBackend : Backend, Object {
});

loop.run ();
client = new Task ();
client = new Task () {
only_download = true
};
}

private PackageKitBackend () {
Expand Down Expand Up @@ -325,6 +330,27 @@ public class AppCenterCore.PackageKitBackend : Backend, Object {
return null;
}

public async Gee.Collection<AppCenterCore.PackageDetails> get_prepared_applications (Cancellable? cancellable = null) {
var packages = new Gee.TreeSet<AppCenterCore.PackageDetails> ();

var pk_prepared = yield get_prepared_packages ();
var package_array = pk_prepared.get_package_array ();
foreach (var pk_package in package_array) {
packages.add (new PackageDetails () {
name = pk_package.get_name (),
description = pk_package.description,
summary = pk_package.get_summary (),
version = pk_package.get_version ()
});
}

if (package_array.length > 0) {
updates_changed_callback ();
}

return packages;
}

public async Gee.Collection<AppCenterCore.Package> get_installed_applications (Cancellable? cancellable = null) {
var packages = new Gee.TreeSet<AppCenterCore.Package> ();
var installed = yield get_installed_packages (cancellable);
Expand Down Expand Up @@ -479,6 +505,62 @@ public class AppCenterCore.PackageKitBackend : Backend, Object {
return job;
}

private void get_prepared_packages_internal (Job job) {
var args = (GetPreparedPackagesArgs)job.args;
var cancellable = args.cancellable;

Pk.Results? results = null;
try {
results = client.get_updates (0, cancellable, (t, p) => { });
} catch (Error e) {
job.error = e;
job.results_ready ();
return;
}

string[] package_ids = {};
var downloaded_updates = get_downloaded_updates ();
results.get_package_array ().foreach ((pk_package) => {
if (downloaded_updates.contains (pk_package.get_id ())) {
package_ids += pk_package.get_id ();
}
});

if (package_ids.length == 0) {
job.result = Value (typeof (Object));
job.result.take_object (new Pk.Results ());
job.results_ready ();
return;
}

package_ids += null;

Pk.Results details;
try {
details = client.get_details (package_ids, cancellable, (p, t) => {});
} catch (Error e) {
job.error = e;
job.results_ready ();
return;
}

details.get_details_array ().foreach ((details) => {
results.add_details (details);
});

job.result = Value (typeof (Object));
job.result.take_object ((owned) results);
job.results_ready ();
}

public async Pk.Results get_prepared_packages (Cancellable? cancellable = null) {
var job_args = new GetPreparedPackagesArgs ();
job_args.cancellable = cancellable;

var job = yield launch_job (Job.Type.GET_PREPARED_PACKAGES, job_args);
return (Pk.Results)job.result.get_object ();
}

private void get_installed_packages_internal (Job job) {
unowned var args = (GetInstalledPackagesArgs)job.args;
unowned var cancellable = args.cancellable;
Expand Down Expand Up @@ -670,6 +752,9 @@ public class AppCenterCore.PackageKitBackend : Backend, Object {
});

exit_status = results.get_exit_code ();
if (exit_status == Pk.Exit.SUCCESS) {
Pk.offline_trigger (Pk.OfflineAction.REBOOT, cancellable);
}
} catch (Error e) {
job.error = e;
job.results_ready ();
Expand Down Expand Up @@ -756,6 +841,53 @@ public class AppCenterCore.PackageKitBackend : Backend, Object {
return job.result.get_boolean ();
}

private Gee.ArrayList<string> get_downloaded_updates () {
var downloaded_updates = new Gee.ArrayList<string> ();

// A PackageKit update query with Filters set to Pk.Filter.DOWNLOADED and Pk.Filter.NOT_INSTALLED
// returns all downloaded but not installed packages even if they are not prepared for an update.
// So instead we read the prepared updates from the configuration file which would also be read
// by the PackageKit daemon on boot.
const string PK_PREPARED_IDS_PATH = "/var/lib/PackageKit/prepared-update";

if (!FileUtils.test (PK_PREPARED_IDS_PATH, FileTest.IS_REGULAR)) {
return downloaded_updates;
}

var key_file = new KeyFile ();
try {
key_file.load_from_file (PK_PREPARED_IDS_PATH, KeyFileFlags.NONE);
var prepared_ids = key_file.get_string ("update", "prepared_ids").split (",");
downloaded_updates = new Gee.ArrayList<string>.wrap (prepared_ids);
} catch (Error e) {
warning ("Unable to read PackageKit prepared ids: %s", e.message);
}

return downloaded_updates;
}

public bool is_restart_required () {
const string PK_OFFLINE_UPDATE_ACTION_PATH = "/var/lib/PackageKit/offline-update-action";

if (!FileUtils.test (PK_OFFLINE_UPDATE_ACTION_PATH, FileTest.IS_REGULAR)) {
return false;
}

var pk_offline_update_action = File.new_for_path (PK_OFFLINE_UPDATE_ACTION_PATH);
try {
var @is = pk_offline_update_action.read ();
var dis = new DataInputStream (@is);

if ("reboot" in dis.read_line ()) {
return true;
}
} catch (Error e) {
critical ("Couldn't read PackageKit offline update action: %s", e.message);
}

return false;
}

private void get_updates_internal (Job job) {
var args = (GetUpdatesArgs)job.args;
var cancellable = args.cancellable;
Expand All @@ -782,18 +914,21 @@ public class AppCenterCore.PackageKitBackend : Backend, Object {
return;
}

if (results.get_package_array ().length == 0) {
string[] package_ids = {};
var downloaded_updates = get_downloaded_updates ();
results.get_package_array ().foreach ((pk_package) => {
if (!downloaded_updates.contains (pk_package.get_id ())) {
package_ids += pk_package.get_id ();
}
});

if (package_ids.length == 0) {
job.result = Value (typeof (Object));
job.result.take_object (results);
job.result.take_object (new Pk.Results ());
job.results_ready ();
return;
}

string[] package_ids = {};
results.get_package_array ().foreach ((pk_package) => {
package_ids += pk_package.get_id ();
});

package_ids += null;

Pk.Results details;
Expand Down Expand Up @@ -830,6 +965,15 @@ public class AppCenterCore.PackageKitBackend : Backend, Object {
unowned var args = (RefreshCacheArgs)job.args;
unowned var cancellable = args.cancellable;

// Don't refresh cache if PackageKit prepared updates.
// Otherwise PackageKit deletes all information related to prepared updates
if (get_downloaded_updates ().size > 0) {
job.result = Value (typeof (bool));
job.result.set_boolean (true);
job.results_ready ();
return;
}

Pk.Results? results = null;
try {
results = client.refresh_cache (false, cancellable, (t, p) => { });
Expand Down
6 changes: 6 additions & 0 deletions src/Core/UbuntuDriversBackend.vala
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ public class AppCenterCore.UbuntuDriversBackend : Backend, Object {
return command.get_exit_status () == 0;
}

public async Gee.Collection<PackageDetails> get_prepared_applications (Cancellable? cancellable = null) {
var prepared_packages = new Gee.HashSet<PackageDetails> ();

return prepared_packages;
}

public async Gee.Collection<Package> get_installed_applications (Cancellable? cancellable = null) {
if (cached_packages != null) {
return cached_packages;
Expand Down
53 changes: 20 additions & 33 deletions src/Core/UpdateManager.vala
Original file line number Diff line number Diff line change
Expand Up @@ -88,25 +88,16 @@ public class AppCenterCore.UpdateManager : Object {

package_array.foreach ((pk_package) => {
var pkg_name = pk_package.get_name ();
var appcenter_package = client.lookup_package_by_id (pkg_name);
if (appcenter_package != null) {
debug ("Added %s to app updates", pkg_name);
apps_with_updates.add (appcenter_package);
count++;
appcenter_package.latest_version = pk_package.get_version ();
updates_size += appcenter_package.change_information.size;
} else {
debug ("Added %s to OS updates", pkg_name);
os_count++;
unowned string pkg_summary = pk_package.get_summary ();
unowned string pkg_version = pk_package.get_version ();
os_desc += Markup.printf_escaped (
"%s\n\t%s\n\t%s\n",
pkg_name,
pkg_summary,
_("Version: %s").printf (pkg_version)
);
}
debug ("Added %s to OS updates", pkg_name);
os_count++;
unowned string pkg_summary = pk_package.get_summary ();
unowned string pkg_version = pk_package.get_version ();
os_desc += Markup.printf_escaped (
"%s\n\t%s\n\t%s\n",
pkg_name,
pkg_summary,
_("Version: %s").printf (pkg_version)
);
});

os_updates.component.set_pkgnames ({});
Expand Down Expand Up @@ -221,19 +212,13 @@ public class AppCenterCore.UpdateManager : Object {
try {
pk_package.set_id (pk_detail.get_package_id ());
var pkg_name = pk_package.get_name ();
var appcenter_package = client.lookup_package_by_id (pkg_name);
if (appcenter_package != null) {
appcenter_package.change_information.updatable_packages.@set (client, pk_package.get_id ());
appcenter_package.change_information.size += pk_detail.size;
appcenter_package.update_state ();
} else {
var pkgnames = os_updates.component.pkgnames;
pkgnames += pkg_name;
os_updates.component.pkgnames = pkgnames;

os_updates.change_information.updatable_packages.@set (client, pk_package.get_id ());
os_updates.change_information.size += pk_detail.size;
}

var pkgnames = os_updates.component.pkgnames;
pkgnames += pkg_name;
os_updates.component.pkgnames = pkgnames;

os_updates.change_information.updatable_packages.@set (client, pk_package.get_id ());
os_updates.change_information.size += pk_detail.size;
} catch (Error e) {
critical (e.message);
}
Expand All @@ -245,7 +230,9 @@ public class AppCenterCore.UpdateManager : Object {
}

public void update_restart_state () {
if (restart_file.query_exists ()) {
var should_restart = restart_file.query_exists () || PackageKitBackend.get_default ().is_restart_required ();

if (should_restart) {
if (!restart_required) {
string title = _("Restart Required");
string body = _("Please restart your system to finalize updates");
Expand Down
1 change: 1 addition & 0 deletions src/MainWindow.vala
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ public class AppCenter.MainWindow : Hdy.ApplicationWindow {
case GET_DOWNLOAD_SIZE:
overlaybar.label = _("Getting download size…");
break;
case GET_PREPARED_PACKAGES:
case GET_INSTALLED_PACKAGES:
case GET_UPDATES:
case REFRESH_CACHE:
Expand Down
Loading