Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion crates/fig_desktop/src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ pub async fn run_install(ctx: Arc<Context>, ignore_immediate_update: bool) {
use tokio::time::timeout;
// Check for updates but timeout after 3 seconds to avoid making the user wait too long
// todo: don't download the index file twice
match timeout(Duration::from_secs(3), check_for_updates(true)).await {
match timeout(Duration::from_secs(3), check_for_updates(true, true)).await {
Ok(Ok(Some(_))) => {
crate::update::check_for_update(true, true).await;
},
Expand Down
30 changes: 9 additions & 21 deletions crates/fig_desktop/src/tray.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
use std::borrow::Cow;

use cfg_if::cfg_if;
use fig_install::index::get_file_type;
use fig_install::{
InstallComponents,
UpdateOptions,
};
use fig_os_shim::{
Context,
Os,
};
use fig_os_shim::Context;
use fig_remote_ipc::figterm::FigtermState;
use fig_util::consts::PRODUCT_NAME;
use fig_util::manifest::{
FileType,
Variant,
bundle_metadata,
manifest,
};
use fig_util::url::USER_MANUAL;
use muda::{
Expand Down Expand Up @@ -101,6 +97,7 @@ fn tray_update(proxy: &EventLoopProxy) {
ignore_rollout: true,
interactive: true,
relaunch_dashboard: true,
is_auto_update: false,
},
)
.await;
Expand Down Expand Up @@ -140,24 +137,15 @@ fn tray_update(proxy: &EventLoopProxy) {
/// continuing.
///
/// Returns `true` if we should continue with updating, `false` otherwise.
///
/// Currently only the Linux flow gets affected, since some bundles (eg, `AppImage`) are able to
/// update and others (packages like `deb`) cannot.
async fn should_continue_with_update(ctx: &Context, proxy: &EventLoopProxy) -> bool {
if !(ctx.platform().os() == Os::Linux && manifest().variant == Variant::Full) {
return true;
}

match fig_install::check_for_updates(true).await {
match fig_install::check_for_updates(true, false).await {
Ok(Some(pkg)) => {
let file_type = bundle_metadata(&ctx)
let file_type = get_file_type(ctx, &Variant::Full)
.await
.map_err(|err| error!(?err, "Failed to get bundle metadata"))
.ok()
.flatten()
.map(|md| md.packaged_as);
// Only AppImage is able to self-update.
if file_type == Some(FileType::AppImage) {
.map_err(|err| error!(?err, "Failed to get file type"))
.ok();
// Only AppImage and dmg is able to self-update.
if file_type == Some(FileType::AppImage) || file_type == Some(FileType::Dmg) {
let (tx, mut rx) = tokio::sync::mpsc::channel(1);
proxy
.send_event(
Expand Down
1 change: 1 addition & 0 deletions crates/fig_desktop/src/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ pub async fn check_for_update(show_webview: bool, relaunch_dashboard: bool) -> b
ignore_rollout: false,
interactive: show_webview,
relaunch_dashboard,
is_auto_update: true,
})
.await
{
Expand Down
3 changes: 2 additions & 1 deletion crates/fig_desktop_api/src/requests/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ pub async fn update_application(request: UpdateApplicationRequest) -> RequestRes
ignore_rollout: request.ignore_rollout.unwrap_or(true),
interactive: request.interactive.unwrap_or(true),
relaunch_dashboard: request.relaunch_dashboard.unwrap_or(true),
is_auto_update: false,
},
));
RequestResult::success()
}

pub async fn check_for_updates(_request: CheckForUpdatesRequest) -> RequestResult {
fig_install::check_for_updates(true)
fig_install::check_for_updates(true, false)
.await
.map(|res| {
Box::new(ServerOriginatedSubMessage::CheckForUpdatesResponse(
Expand Down
81 changes: 72 additions & 9 deletions crates/fig_install/src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,15 @@ impl Index {
/// than the currently installed version*. This is useful to check if an update exists for the
/// given target and variant without filtering on file type, e.g. in the case of Linux desktop
/// bundles.
#[allow(clippy::too_many_arguments)]
pub fn find_next_version(
&self,
target_triple: &TargetTriple,
variant: &Variant,
file_type: Option<&FileType>,
current_version: &str,
ignore_rollout: bool,
is_auto_update: bool,
threshold_override: Option<u8>,
) -> Result<Option<UpdatePackage>, Error> {
if !self.supported.iter().any(|support| {
Expand Down Expand Up @@ -137,6 +139,7 @@ impl Index {
Some(rollout) => rollout.start <= right_now,
None => true,
})
.filter(|version| !is_auto_update || !version.disable_autoupdate)
.collect::<Vec<&RemoteVersion>>();

valid_versions.sort_unstable_by(|lhs, rhs| lhs.version.cmp(&rhs.version));
Expand Down Expand Up @@ -252,20 +255,22 @@ struct Support {
file_type: Option<FileType>,
}

#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub(crate) struct RemoteVersion {
pub version: Version,
pub rollout: Option<Rollout>,
pub packages: Vec<Package>,
#[serde(default)]
pub disable_autoupdate: bool,
}

#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub(crate) struct Rollout {
start: u64,
end: u64,
}

#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Package {
#[serde(deserialize_with = "deser_enum_other")]
Expand Down Expand Up @@ -306,7 +311,7 @@ pub struct UpdatePackage {
pub cli_path: Option<String>,
}

#[derive(Deserialize, Serialize, PartialEq, Eq, EnumString, Debug, Display)]
#[derive(Deserialize, Serialize, PartialEq, Eq, EnumString, Debug, Clone, Display)]
#[serde(rename_all = "camelCase")]
#[strum(serialize_all = "camelCase")]
pub enum PackageArchitecture {
Expand Down Expand Up @@ -360,14 +365,21 @@ pub async fn check_for_updates(
variant: &Variant,
file_type: Option<&FileType>,
ignore_rollout: bool,
is_auto_update: bool,
) -> Result<Option<UpdatePackage>, Error> {
const CURRENT_VERSION: &str = env!("CARGO_PKG_VERSION");
pull(&channel)
.await?
.find_next_version(target_triple, variant, file_type, CURRENT_VERSION, ignore_rollout, None)
pull(&channel).await?.find_next_version(
target_triple,
variant,
file_type,
CURRENT_VERSION,
ignore_rollout,
is_auto_update,
None,
)
}

pub(crate) async fn get_file_type(ctx: &Context, variant: &Variant) -> Result<FileType, Error> {
pub async fn get_file_type(ctx: &Context, variant: &Variant) -> Result<FileType, Error> {
match ctx.platform().os() {
fig_os_shim::Os::Mac => Ok(FileType::Dmg),
fig_os_shim::Os::Linux => match variant {
Expand Down Expand Up @@ -429,6 +441,7 @@ mod tests {
&Variant::Full,
Some(FileType::Dmg).as_ref(),
false,
false,
)
.await
.unwrap();
Expand Down Expand Up @@ -515,7 +528,8 @@ mod tests {
"sha256": "5a6abea56bfa91bd58d49fe40322058d0efea825f7e19f7fb7db1c204ae625b6",
"size": 76836772,
}
]
],
"disable_autoupdate": true,
},
{
"version": "2.0.0",
Expand Down Expand Up @@ -560,6 +574,11 @@ mod tests {

assert_eq!(index.versions.len(), 4);

assert!(
!index.versions[1].disable_autoupdate,
"missing disable_autoupdate field should default to false"
);

// check the 1.0.0 entry matches
assert_eq!(index.versions[2], RemoteVersion {
version: Version::new(1, 0, 0),
Expand Down Expand Up @@ -588,6 +607,7 @@ mod tests {
cli_path: None,
}
],
disable_autoupdate: true,
});
}

Expand All @@ -604,6 +624,7 @@ mod tests {
Some(&FileType::TarZst),
"1.2.1",
true,
false,
None,
)
.unwrap();
Expand All @@ -619,6 +640,7 @@ mod tests {
Some(&FileType::TarZst),
"1.2.0",
true,
false,
None,
)
.unwrap()
Expand All @@ -635,6 +657,7 @@ mod tests {
Some(&FileType::TarZst),
"1.2.1",
true,
false,
None,
);
assert!(next.is_err());
Expand All @@ -649,10 +672,50 @@ mod tests {
None,
"1.0.5",
true,
false,
None,
)
.unwrap()
.expect("should have update package");
assert_eq!(next.version.to_string().as_str(), "1.2.1");
}

#[test]
fn index_autoupdate_does_not_update_into_disabled() {
let mut index = load_test_index();

let next = index
.find_next_version(
&TargetTriple::X86_64UnknownLinuxGnu,
&Variant::Full,
None,
"1.0.5",
true,
true,
None,
)
.unwrap()
.expect("should have update package");
assert_eq!(next.version.to_string().as_str(), "1.2.0");

// Push a newer update that does not have autoupdate disabled
let mut last = index.versions.last().cloned().unwrap();
last.version = Version::from_str("2.0.0").unwrap();
last.disable_autoupdate = false;
index.versions.push(last);

let next = index
.find_next_version(
&TargetTriple::X86_64UnknownLinuxGnu,
&Variant::Full,
None,
"1.0.5",
true,
true,
None,
)
.unwrap()
.expect("should have update package");
assert_eq!(next.version.to_string().as_str(), "2.0.0");
}
}
8 changes: 6 additions & 2 deletions crates/fig_install/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ pub fn get_max_channel() -> Channel {
.unwrap()
}

pub async fn check_for_updates(ignore_rollout: bool) -> Result<Option<UpdatePackage>, Error> {
pub async fn check_for_updates(ignore_rollout: bool, is_auto_update: bool) -> Result<Option<UpdatePackage>, Error> {
let manifest = manifest();
let ctx = Context::new();
let file_type = match (&manifest.variant, ctx.platform().os()) {
Expand All @@ -157,6 +157,7 @@ pub async fn check_for_updates(ignore_rollout: bool) -> Result<Option<UpdatePack
&manifest.variant,
file_type.as_ref(),
ignore_rollout,
is_auto_update,
)
.await
}
Expand All @@ -177,6 +178,8 @@ pub struct UpdateOptions {
pub interactive: bool,
/// If to relaunch into dashboard after update (false will launch in background)
pub relaunch_dashboard: bool,
/// Whether or not the update is being invoked automatically without the user's approval
pub is_auto_update: bool,
}

/// Attempt to update if there is a newer version of Fig
Expand All @@ -187,10 +190,11 @@ pub async fn update(
ignore_rollout,
interactive,
relaunch_dashboard,
is_auto_update,
}: UpdateOptions,
) -> Result<bool, Error> {
info!("Checking for updates...");
if let Some(update) = check_for_updates(ignore_rollout).await? {
if let Some(update) = check_for_updates(ignore_rollout, is_auto_update).await? {
info!("Found update: {}", update.version);
debug!("Update info: {:?}", update);

Expand Down
1 change: 1 addition & 0 deletions crates/fig_install/test_files/test-index.json
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@

{
"version": "1.2.1",
"disable_autoupdate": true,
"packages": [
{
"kind": "deb",
Expand Down
2 changes: 1 addition & 1 deletion crates/fig_util/src/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub enum ManagedBy {

/// The target triplet, describes a platform on which the project is build for. Note that this also
/// includes "fake" targets like `universal-apple-darwin` as provided by [Tauri](https://tauri.app/v1/guides/building/macos/#binary-targets)
#[derive(Deserialize, Serialize, PartialEq, Eq, EnumString, Debug, Display)]
#[derive(Deserialize, Serialize, PartialEq, Eq, EnumString, Debug, Clone, Display)]
pub enum TargetTriple {
#[serde(rename = "universal-apple-darwin")]
#[strum(serialize = "universal-apple-darwin")]
Expand Down
2 changes: 1 addition & 1 deletion crates/figterm/src/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pub fn check_for_update(context: &Context) {
}

tokio::spawn(async {
match fig_install::check_for_updates(false).await {
match fig_install::check_for_updates(false, true).await {
Ok(Some(pkg)) => {
if let Err(err) = fig_settings::state::set_value(UPDATE_AVAILABLE_KEY, pkg.version.to_string()) {
warn!(?err, "Error setting {UPDATE_AVAILABLE_KEY}: {err}");
Expand Down
4 changes: 4 additions & 0 deletions crates/q_cli/src/cli/debug/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ pub enum DebugSubcommand {
#[arg(short = 'r', long)]
enable_rollout: bool,
#[arg(short, long)]
is_auto_update: bool,
#[arg(short, long)]
override_threshold: Option<u8>,
#[arg(short, long)]
file_type: String,
Expand Down Expand Up @@ -748,6 +750,7 @@ impl DebugSubcommand {
variant,
version: current_version,
enable_rollout,
is_auto_update,
override_threshold,
file_type,
} => {
Expand All @@ -765,6 +768,7 @@ impl DebugSubcommand {
Some(&FileType::from_str(file_type)?),
current_version,
!enable_rollout,
*is_auto_update,
*override_threshold,
);

Expand Down
Loading
Loading