diff --git a/Cargo.lock b/Cargo.lock index 2d0037de..425077b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2000,6 +2000,25 @@ dependencies = [ "serde", ] +[[package]] +name = "is-docker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" +dependencies = [ + "once_cell", +] + +[[package]] +name = "is-wsl" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +dependencies = [ + "is-docker", + "once_cell", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -2493,6 +2512,17 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +[[package]] +name = "open" +version = "5.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43bb73a7fa3799b198970490a51174027ba0d4ec504b03cd08caf513d40024bc" +dependencies = [ + "is-wsl", + "libc", + "pathdiff", +] + [[package]] name = "openssl" version = "0.10.73" @@ -2618,6 +2648,12 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + [[package]] name = "percent-encoding" version = "2.3.2" @@ -2794,6 +2830,7 @@ dependencies = [ "notify-rust", "num-traits", "once_cell", + "open", "os-release", "pango", "pkg-config", diff --git a/changelogs/24.04 b/changelogs/24.04 new file mode 100644 index 00000000..faa201da --- /dev/null +++ b/changelogs/24.04 @@ -0,0 +1,9 @@ +Pop!_OS 24.04 includes the COSMIC desktop environment. COSMIC offers better performance, productivity, and in-depth personalization to empower a wide variety of use cases. Learn more. + +When you upgrade: +* The GNOME desktop will be replaced by the new COSMIC desktop. +* New system applications will be installed, including: COSMIC Files, COSMIC Settings, COSMIC Store, COSMIC Terminal, and COSMIC Text Editor. +* Applications pinned to the dock will need to be pinned again. +* PPAs will be removed for increased upgrade reliability. +* Applications installed from PPAs or local DEB files will need to be reinstalled. +* COSMIC offers all new user settings and customizations. diff --git a/daemon/src/changelogs.rs b/daemon/src/changelogs.rs index b3e3c5ba..2092e1e6 100644 --- a/daemon/src/changelogs.rs +++ b/daemon/src/changelogs.rs @@ -1,6 +1,7 @@ use std::cmp::Ordering; pub const CHANGELOGS: &[(&str, &str)] = &[ + ("24.04", include_str!("../../changelogs/24.04")), ("22.04", include_str!("../../changelogs/22.04")), ("21.10", include_str!("../../changelogs/21.10")), ("21.04", include_str!("../../changelogs/21.04")), diff --git a/daemon/src/release/check.rs b/daemon/src/release/check.rs index 4d4867cc..bd7076d2 100644 --- a/daemon/src/release/check.rs +++ b/daemon/src/release/check.rs @@ -101,7 +101,7 @@ const HIRSUTE: &str = "21.04"; const IMPISH: &str = "21.10"; const JAMMY: &str = "22.04"; const NOBLE: &str = "24.04"; -const UNKNOWN: &str = "26.04"; +const RESOLUTE: &str = "26.04"; pub fn release_str(major: u8, minor: u8) -> &'static str { match (major, minor) { @@ -112,7 +112,7 @@ pub fn release_str(major: u8, minor: u8) -> &'static str { (21, 10) => IMPISH, (22, 4) => JAMMY, (24, 4) => NOBLE, - (26, 4) => UNKNOWN, + (26, 4) => RESOLUTE, _ => panic!("this version of pop-upgrade is not supported on this release"), } } @@ -133,11 +133,11 @@ async fn next_ Status, Status: Future }; // Only permits an upgrade if the development flag is passed - let development_enabled = |is_lts: bool, current: &'static str, next: &'static str| async move { - let build = - if development { release_check(next.into()).await } else { BuildStatus::Blacklisted }; - ReleaseStatus { current, next, build, is_lts } - }; + // let development_enabled = |is_lts: bool, current: &'static str, next: &'static str| async move { + // let build = + // if development { release_check(next.into()).await } else { BuildStatus::Blacklisted }; + // ReleaseStatus { current, next, build, is_lts } + // }; match (current.major, current.minor) { (18, 4) => available(true, BIONIC, FOCAL).await, @@ -145,8 +145,8 @@ async fn next_ Status, Status: Future (20, 10) => available(false, GROOVY, HIRSUTE).await, (21, 4) => available(false, HIRSUTE, IMPISH).await, (21, 10) => available(false, IMPISH, JAMMY).await, - (22, 4) => development_enabled(true, JAMMY, NOBLE).await, - (24, 4) => blocked(true, NOBLE, UNKNOWN).await, + (22, 4) => available(true, JAMMY, NOBLE).await, + (24, 4) => blocked(true, NOBLE, RESOLUTE).await, _ => panic!("this version of pop-upgrade is not supported on this release"), } } diff --git a/daemon/src/ubuntu_version/codename.rs b/daemon/src/ubuntu_version/codename.rs index 30daec75..3f3ae261 100644 --- a/daemon/src/ubuntu_version/codename.rs +++ b/daemon/src/ubuntu_version/codename.rs @@ -22,6 +22,7 @@ pub enum Codename { Impish, Jammy, Noble, + Resolute, } impl Codename { @@ -49,6 +50,7 @@ impl Codename { Codename::Impish => (2021, 10, 14), Codename::Jammy => (2022, 4, 21), Codename::Noble => (2024, 4, 13), + Codename::Resolute => (2026, 4, 23), } } @@ -66,6 +68,7 @@ impl Codename { Codename::Impish => 1_634_191_200, Codename::Jammy => 1_650_492_000, Codename::Noble => 1_712_959_200, + Codename::Resolute => 1_776_895_200 } } } @@ -89,6 +92,7 @@ impl FromStr for Codename { "impish" => Codename::Impish, "jammy" => Codename::Jammy, "noble" => Codename::Noble, + "resolute" => Codename::Resolute, _ => return Err(CodenameParseError::NotFound), }; @@ -109,6 +113,7 @@ impl From for &'static str { Codename::Impish => "impish", Codename::Jammy => "jammy", Codename::Noble => "noble", + Codename::Resolute => "resolute", } } } diff --git a/daemon/src/ubuntu_version/mod.rs b/daemon/src/ubuntu_version/mod.rs index 872a78c8..4bca2a5b 100644 --- a/daemon/src/ubuntu_version/mod.rs +++ b/daemon/src/ubuntu_version/mod.rs @@ -37,6 +37,7 @@ impl From for Version { Codename::Impish => (21, 10), Codename::Jammy => (22, 4), Codename::Noble => (24, 4), + Codename::Resolute => (26, 4), }; Version { major, minor, patch: 0 } diff --git a/gtk/Cargo.toml b/gtk/Cargo.toml index 14390b09..d28f8462 100644 --- a/gtk/Cargo.toml +++ b/gtk/Cargo.toml @@ -41,6 +41,7 @@ upower_dbus = "=0.1.0" uzers = "0.12.1" yansi = "1.0.1" gtk-sys = "0.15.3" +open = "5.3.3" [build-dependencies] pkg-config = "0.3.32" diff --git a/gtk/src/events/mod.rs b/gtk/src/events/mod.rs index f26f50b7..dbb58064 100644 --- a/gtk/src/events/mod.rs +++ b/gtk/src/events/mod.rs @@ -101,14 +101,14 @@ pub enum Event { } pub struct EventWidgets { - pub button_sg: gtk::SizeGroup, - pub container: gtk::Box, - pub dismisser: gtk::ListBoxRow, - pub stack: gtk::Stack, + pub button_sg: gtk::SizeGroup, + pub container: gtk::Box, + pub dismisser: gtk::ListBoxRow, + pub stack: gtk::Stack, pub loading_label: gtk::Label, pub recovery: UpgradeSection, - pub upgrade: UpgradeSection, + pub upgrade: UpgradeSection, } impl EventWidgets { @@ -154,6 +154,7 @@ pub async fn on_event(widgets: &mut EventWidgets, state: &mut State, event: UiEv InitiatedEvent::Download(version) => { widgets.upgrade.options[0] .label(&fl!("download-os", version = (&*version))) + .sublabel(None) .reset_progress() .show_progress(); @@ -185,7 +186,22 @@ pub async fn on_event(widgets: &mut EventWidgets, state: &mut State, event: UiEv UiEvent::Upgrade(event) => match event { OsUpgradeEvent::Cancelled => cancelled_upgrade(state, widgets), - OsUpgradeEvent::Dialog => release_upgrade_dialog(state, widgets), + OsUpgradeEvent::Dialog => { + let dialog = UpgradeDialog::new(&state.upgrading_from, &state.upgrading_to, false); + + let answer = dialog.run(); + dialog.close(); + if gtk::ResponseType::Accept == answer { + let _ = state.sender.send(BackgroundEvent::Finalize); + } else { + // Send upgrading event to prevent closing + (state.callback_event.borrow())(Event::Upgrading); + widgets.upgrade.options[0] + .button_class(>k::STYLE_CLASS_SUGGESTED_ACTION) + .label(&fl!("upgrade-canceling")); + let _ = state.sender.send(BackgroundEvent::Reset); + } + } OsUpgradeEvent::Dismissed(dismissed) => { info!("{} release", if dismissed { "dismissed" } else { "un-dismissed" }); @@ -207,7 +223,7 @@ pub async fn on_event(widgets: &mut EventWidgets, state: &mut State, event: UiEv OsUpgradeEvent::Notification => (state.callback_ready.borrow())(), - OsUpgradeEvent::Upgrade => upgrade_clicked(state, widgets), + OsUpgradeEvent::Upgrade => release_upgrade_dialog(state, widgets), }, UiEvent::Updating => { @@ -317,19 +333,23 @@ fn connect_refresh(state: &State, widgets: &EventWidgets) { fn connect_upgrade(state: &mut State, widgets: &EventWidgets, is_lts: bool, reboot_ready: bool) { let notice = match EolDate::fetch() { Ok(eol) => { - let (y, m, d) = eol.ymd; - match eol.status() { - EolStatus::Exceeded => Some(fl!( - "eol-exceeded", - current = fomat!((eol.version)), - next = fomat!((eol.version.next_release())) - )), - EolStatus::Imminent => Some(fl!( - "eol-imminent", - current = fomat!((eol.version)), - date = fomat!((Utc.ymd(y as i32, m, d).format("%B %-d, %Y"))) - )), - EolStatus::Ok => None, + if eol.version.major == 24 && eol.version.minor == 4 { + let (y, m, d) = eol.ymd; + match eol.status() { + EolStatus::Exceeded => Some(fl!( + "eol-exceeded", + current = fomat!((eol.version)), + next = fomat!((eol.version.next_release())) + )), + EolStatus::Imminent => Some(fl!( + "eol-imminent", + current = fomat!((eol.version)), + date = fomat!((Utc.ymd(y as i32, m, d).format("%B %-d, %Y"))) + )), + EolStatus::Ok => None, + } + } else { + Some(fl!("upgrade-cosmic")) } } Err(why) => { @@ -381,11 +401,11 @@ fn download_action(sender: sync::Weak>) -> (String, Box bool { /// When the user selects to commence an upgrade, a dialog is shown to confirm. fn release_upgrade_dialog(state: &mut State, widgets: &EventWidgets) { - let dialog = UpgradeDialog::new(&state.upgrading_from, &state.upgrading_to); - - let answer = dialog.run(); - dialog.close(); - if gtk::ResponseType::Accept == answer { - let _ = state.sender.send(BackgroundEvent::Finalize); - } else { - // Send upgrading event to prevent closing + if let Some(info) = state.upgrade_version.clone() { (state.callback_event.borrow())(Event::Upgrading); - widgets.upgrade.options[0].label(&fl!("upgrade-canceling")); - let _ = state.sender.send(BackgroundEvent::Reset); + + widgets.upgrade.options[0].label(&fl!("upgrade-preparing")).show_progress(); + + widgets.recovery.options[RECOVERY_PARTITION].sensitive(false); + widgets.recovery.options[REFRESH_OS].sensitive(false); + + if let Some(dismisser) = state.dismisser.take() { + unsafe { + dismisser.destroy(); + } + } + + let dialog = UpgradeDialog::new(&state.upgrading_from, &state.upgrading_to, true); + + let answer = dialog.run(); + dialog.close(); + if gtk::ResponseType::Accept == answer { + let _ = state.sender.send(BackgroundEvent::DownloadUpgrade(info)); + } else { + // Send upgrading event to prevent closing + (state.callback_event.borrow())(Event::Upgrading); + widgets.upgrade.options[0].label(&fl!("upgrade-canceling")); + let _ = state.sender.send(BackgroundEvent::Reset); + } } } @@ -587,32 +625,7 @@ fn upgrade_action(sender: sync::Weak>) -> (String, Box Self { - let title = gtk::Label::builder() - .label(&fomat!( - (fl!("upgrade-available", version = version)) " " - if battery::active() { - (fl!("battery-notice")) " " - } - (fl!("new-features-include")) - )) - .use_markup(true) - .xalign(0.0) - .build(); - let changelog_list = gtk::Box::new(gtk::Orientation::Vertical, 24); - - let scroller = cascade! { - gtk::ScrolledWindow::new(None::<>k::Adjustment>, None::<>k::Adjustment>); - ..set_hexpand(true); - ..set_vexpand(true); - ..add(&changelog_list); - }; - - let mut iter = changelogs::since(since); - - match iter.next() { - Some((_version, changelog)) => { - add_changelog(&changelog_list, changelog); - for (version, changelog) in iter { - changelog_list.add(>k::Separator::new(gtk::Orientation::Horizontal)); - add_version(&changelog_list, version); - add_changelog(&changelog_list, changelog); - } - } - None => { - add_changelog(&changelog_list, &fl!("error-no-changelog-found")); - } - } - + pub fn new(since: &str, version: &str, start: bool) -> Self { let dialog = DialogTemplate::new( "distributor-logo", - &fl!("button-upgrade"), - &fl!("button-perform-upgrade"), + &fl!("upgrade-to", version = version), + &if start { fl!("button-upgrade") } else { fl!("button-perform-upgrade") }, >k::STYLE_CLASS_DESTRUCTIVE_ACTION, |content| { - content.add(&title); - content.add(&scroller); + if start { + let changelog_list = gtk::Box::new(gtk::Orientation::Vertical, 24); + let scroller = cascade! { + gtk::ScrolledWindow::new(None::<>k::Adjustment>, None::<>k::Adjustment>); + ..set_hexpand(true); + ..set_vexpand(true); + ..add(&changelog_list); + }; + + let mut iter = changelogs::since(since); + + match iter.next() { + Some((_version, changelog)) => { + add_changelog(&changelog_list, changelog); + for (version, changelog) in iter { + changelog_list + .add(>k::Separator::new(gtk::Orientation::Horizontal)); + add_version(&changelog_list, version); + add_changelog(&changelog_list, changelog); + } + } + None => { + add_changelog(&changelog_list, &fl!("error-no-changelog-found")); + } + } + + content.add(&scroller); + } else { + let message = gtk::Label::builder() + .label(&fomat!( + if battery::active() { + (fl!("battery-notice")) " \n\n" + } + (fl!("upgrade-finalize", version = version)) + )) + .use_markup(true) + .xalign(0.0) + .build(); + + content.add(&message); + } }, ); - dialog.set_size_request(800, 600); + dialog.set_size_request(560, if start { 334 } else { 147 }); Self { dialog } } @@ -70,6 +73,7 @@ impl UpgradeDialog { fn add_changelog(changelogs: >k::Box, changelog: &str) { let changelog_label = gtk::Label::builder() .label(changelog) + .use_markup(true) .wrap(true) .xalign(0.0) .max_width_chars(40) @@ -77,6 +81,11 @@ fn add_changelog(changelogs: >k::Box, changelog: &str) { .margin_end(CHANGELOG_PADDING) .build(); + changelog_label.connect_activate_link(|_label, uri| { + let _ = open::that_detached(uri); + gtk::Inhibit(true) + }); + changelogs.add(&changelog_label); } diff --git a/i18n/en/pop_upgrade_gtk.ftl b/i18n/en/pop_upgrade_gtk.ftl index e72df1d4..3effdf8e 100644 --- a/i18n/en/pop_upgrade_gtk.ftl +++ b/i18n/en/pop_upgrade_gtk.ftl @@ -4,19 +4,18 @@ battery-notice = Plug into power before you begin. button-cancel = Cancel button-dismiss = Dismiss -button-download = Download -button-perform-refresh = Reboot & Refresh -button-perform-upgrade = Reboot & Upgrade +button-perform-refresh = Restart & Refresh +button-perform-upgrade = Restart & Install button-refresh = Refresh button-update = Update -button-upgrade = Upgrade +button-upgrade = Start Upgrade checking-for-updates = Checking for updates ... dialog-refresh-title = Refresh OS Install dialog-refresh-description = When you refresh the OS: - + {"*"} All user accounts and files in the /home directory will be kept {"*"} Users and user groups will be retained {"*"} All system applications installed by the user will be removed @@ -26,7 +25,7 @@ dialog-refresh-description = - The system language - The system keyboard layout - Network configurations managed by NetworkManager - + Please be sure to save all of your work before clicking to reboot. daemon-checking = Checking for updates to daemon @@ -79,14 +78,17 @@ recovery-sync = Syncing recovery image to disk recovery-update-found = Recovery partition update is available recovery-verify = Verifying the fetched recovery image -refresh-description = Reinstall while keeping user accounts and files +refresh-description = Reinstall while retaining user accounts and files. refresh-header = Refresh OS release-current = You are running the most current {-os} version -upgrade-available = {-os} {$version} is available! +upgrade-available = {-os} {$version} is available +upgrade-cosmic = Includes the COSMIC desktop environment. upgrade-canceling = Canceling upgrade upgrade-downloading = {-os} is currently downloading +upgrade-finalize = The system will be upgraded to {-os} { $version }. upgrade-from-to = Upgrade from {$current} to {$next} is available upgrade-preparing = Preparing Upgrade upgrade-ready = {-os} is ready to upgrade to {$version} +upgrade-to = Upgrade to {-os} { $version }