Skip to content

Commit

Permalink
Add identifier for releases with multiple compatible assets
Browse files Browse the repository at this point in the history
This change is relevant when you have multiple binaries as part of a
single release. In this case, the target is not enough to determine
which asset to choose. Thus this change allows an identifier to be
passed along from the builders, to select the correct one in such cases.

This adds argument `identifier: Option<&str>` to `Release::asset_for`,
which allows the caller to specify a string that must be part of the
asset name in addition to the target.

Additionally it adds a method to `ReleaseUpdate` which allows the
identifier to be specified in the `UpdateBuilder` structs.

One possible change, could be to make the `identifier` a closure, or
like the `Pattern` like the struct search functions in `std`, instead of
relying on only substrings.
  • Loading branch information
oeb25 committed Feb 11, 2023
1 parent 69306ee commit a98f052
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 7 deletions.
16 changes: 16 additions & 0 deletions src/backends/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ pub struct UpdateBuilder {
repo_owner: Option<String>,
repo_name: Option<String>,
target: Option<String>,
identifier: Option<String>,
bin_name: Option<String>,
bin_install_path: Option<PathBuf>,
bin_path_in_archive: Option<PathBuf>,
Expand Down Expand Up @@ -295,6 +296,14 @@ impl UpdateBuilder {
self
}

/// Set the identifiable token for the asset in case of multiple compatible assets
///
/// If unspecified, the first asset matching the target will be chosen
pub fn identifier(&mut self, identifier: &str) -> &mut Self {
self.identifier = Some(identifier.to_owned());
self
}

/// Set the exe's name. Also sets `bin_path_in_archive` if it hasn't already been set.
///
/// This method will append the platform specific executable file suffix
Expand Down Expand Up @@ -415,6 +424,7 @@ impl UpdateBuilder {
.as_ref()
.map(|t| t.to_owned())
.unwrap_or_else(|| get_target().to_owned()),
identifier: self.identifier.clone(),
bin_name: if let Some(ref name) = self.bin_name {
name.to_owned()
} else {
Expand Down Expand Up @@ -449,6 +459,7 @@ pub struct Update {
repo_owner: String,
repo_name: String,
target: String,
identifier: Option<String>,
current_version: String,
target_version: Option<String>,
bin_name: String,
Expand Down Expand Up @@ -535,6 +546,10 @@ impl ReleaseUpdate for Update {
self.target_version.clone()
}

fn identifier(&self) -> Option<String> {
self.identifier.clone()
}

fn bin_name(&self) -> String {
self.bin_name.clone()
}
Expand Down Expand Up @@ -578,6 +593,7 @@ impl Default for UpdateBuilder {
repo_owner: None,
repo_name: None,
target: None,
identifier: None,
bin_name: None,
bin_install_path: None,
bin_path_in_archive: None,
Expand Down
27 changes: 20 additions & 7 deletions src/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,19 @@ impl Release {
}

/// Return the first `ReleaseAsset` for the current release who's name
/// contains the specified `target`
pub fn asset_for(&self, target: &str) -> Option<ReleaseAsset> {
/// contains the specified `target` and possibly `identifier`
pub fn asset_for(&self, target: &str, identifier: Option<&str>) -> Option<ReleaseAsset> {
self.assets
.iter()
.filter(|asset| asset.name.contains(target))
.find(|asset| {
asset.name.contains(target)
&& if let Some(i) = identifier {
asset.name.contains(i)
} else {
true
}
})
.cloned()
.next()
}
}

Expand All @@ -85,6 +91,11 @@ pub trait ReleaseUpdate {
/// Target version optionally specified for the update
fn target_version(&self) -> Option<String>;

/// Optional identifier of determining the asset among multiple matches
fn identifier(&self) -> Option<String> {
None
}

/// Name of the binary being updated
fn bin_name(&self) -> String;

Expand Down Expand Up @@ -190,9 +201,11 @@ pub trait ReleaseUpdate {
}
};

let target_asset = release.asset_for(&target).ok_or_else(|| {
format_err!(Error::Release, "No asset found for target: `{}`", target)
})?;
let target_asset = release
.asset_for(&target, self.identifier().as_deref())
.ok_or_else(|| {
format_err!(Error::Release, "No asset found for target: `{}`", target)
})?;

let prompt_confirmation = !self.no_confirm();
if self.show_output() || prompt_confirmation {
Expand Down

0 comments on commit a98f052

Please sign in to comment.