Skip to content

Commit

Permalink
feat: check multiple receipt paths
Browse files Browse the repository at this point in the history
We now check multiple receipt paths, including XDG_CONFIG_HOME.
We load a receipt from the first path which contains a receipt file,
ensuring we're able to manage the absence of a receipt in that path
if that environment variable is set.
  • Loading branch information
mistydemeo committed Dec 18, 2024
1 parent 7381318 commit 81ffaaf
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 17 deletions.
10 changes: 10 additions & 0 deletions axoupdater/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@ pub enum AxoupdateError {
app_name: String,
},

/// Not a generic receipt load failure, but the receipt itself doesn't exist.
#[error("Unable to load receipt for app {app_name}")]
#[diagnostic(help(
"This may indicate that this installation of {app_name} was installed via a method that's not eligible for upgrades."
))]
NoReceipt {
/// This app's name
app_name: String,
},

/// Indicates that this app's name couldn't be determined when trying
/// to autodetect it.
#[error("Unable to determine the name of the app to update")]
Expand Down
50 changes: 35 additions & 15 deletions axoupdater/src/receipt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,49 +116,69 @@ impl AxoUpdater {
}
}

pub(crate) fn get_config_path(app_name: &str) -> AxoupdateResult<Utf8PathBuf> {
/// Returns a Vec of possible receipt locations, beginning with
/// `XDG_CONFIG_HOME` (if set).
pub(crate) fn get_config_paths(app_name: &str) -> AxoupdateResult<Vec<Utf8PathBuf>> {
let mut potential_homes = vec![];

if env::var("AXOUPDATER_CONFIG_WORKING_DIR").is_ok() {
Ok(Utf8PathBuf::try_from(current_dir()?)?)
Ok(vec![Utf8PathBuf::try_from(current_dir()?)?])
} else if let Ok(path) = env::var("AXOUPDATER_CONFIG_PATH") {
Ok(Utf8PathBuf::from(path))
Ok(vec![Utf8PathBuf::from(path)])
} else {
let xdg_home = env::var("XDG_CONFIG_HOME")
.ok()
.map(PathBuf::from)
.map(Utf8PathBuf::from)
.map(|h| h.join(app_name));
let xdg_home_exists = xdg_home.as_ref().map(|h| h.exists()).unwrap_or(false);

if let Some(home) = &xdg_home {
if home.exists() {
potential_homes.push(home.to_owned());
}
}
let home = if cfg!(windows) {
env::var("LOCALAPPDATA")
.map(PathBuf::from)
.map(|h| h.join(app_name))
.ok()
} else if xdg_home_exists {
xdg_home
} else {
homedir::my_home()?.map(|path| path.join(".config").join(app_name))
};
let Some(home) = home else {
if let Some(home) = home {
potential_homes.push(Utf8PathBuf::try_from(home)?);
}

if potential_homes.is_empty() {
return Err(AxoupdateError::NoHome {});
};
}

Ok(Utf8PathBuf::try_from(home)?)
Ok(potential_homes)
}
}

/// Iterates through the list of possible receipt locations from
/// `get_config_paths` and returns the first that contains a valid receipt.
pub(crate) fn get_receipt_path(app_name: &str) -> AxoupdateResult<Option<Utf8PathBuf>> {
for receipt_prefix in get_config_paths(app_name)? {
let install_receipt_path = receipt_prefix.join(format!("{app_name}-receipt.json"));
if install_receipt_path.exists() {
return Ok(Some(install_receipt_path));
}
}

Ok(None)
}

fn load_receipt_from_path(install_receipt_path: &Utf8PathBuf) -> AxoupdateResult<InstallReceipt> {
Ok(SourceFile::load_local(install_receipt_path)?.deserialize_json()?)
}

fn load_receipt_for(app_name: &str) -> AxoupdateResult<InstallReceipt> {
let Ok(receipt_prefix) = get_config_path(app_name) else {
return Err(AxoupdateError::ConfigFetchFailed {
let Some(install_receipt_path) = get_receipt_path(app_name)? else {
return Err(AxoupdateError::NoReceipt {
app_name: app_name.to_owned(),
});
};

let install_receipt_path = receipt_prefix.join(format!("{app_name}-receipt.json"));

load_receipt_from_path(&install_receipt_path).map_err(|_| AxoupdateError::ReceiptLoadFailed {
app_name: app_name.to_owned(),
})
Expand Down
7 changes: 5 additions & 2 deletions axoupdater/src/test/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{
process::{Command, Stdio},
};

use crate::{receipt::get_config_path, ReleaseSourceType};
use crate::{receipt::get_receipt_path, ReleaseSourceType};

static RECEIPT_TEMPLATE: &str = r#"{"binaries":[BINARIES],"install_prefix":"INSTALL_PREFIX","provider":{"source":"cargo-dist","version":"0.10.0-prerelease.1"},"source":{"app_name":"APP_NAME","name":"PACKAGE","owner":"OWNER","release_type":"RELEASE_TYPE"},"version":"VERSION"}"#;

Expand Down Expand Up @@ -104,7 +104,10 @@ pub fn perform_runtest(runtest_args: &RuntestArgs) -> PathBuf {
let app_home = &home.join(".cargo").join("bin");
let app_path = &app_home.join(basename);

let config_path = get_config_path(app_name).unwrap().into_std_path_buf();
let config_path = get_receipt_path(app_name)
.unwrap()
.unwrap()
.into_std_path_buf();

// Ensure we delete any previous copy that may exist
// at this path before we copy in our version.
Expand Down

0 comments on commit 81ffaaf

Please sign in to comment.