Explode out even more variants of default download URLs (#329)

This commit is contained in:
Félix Saparelli 2022-09-02 16:00:46 +12:00 committed by GitHub
parent b330a18d40
commit 0cb4c993b3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 98 additions and 90 deletions

View file

@ -55,80 +55,61 @@ The default value for `pkg-url` will depend on the repository of the package.
It is setup to work with github releases, gitlab releases, bitbucket downloads It is setup to work with github releases, gitlab releases, bitbucket downloads
and source forge downloads. and source forge downloads.
#### Github If your package already uses any of these URLs, you shouldn't need to set anything.
For github, the `pkg-url` is set to The URLs are derived from a set of filenames and a set of paths, which are
"multiplied together": every filename appended to every path. The filenames
are:
```rust - `{ name }-{ target }-{ version }.{ archive-format }`
[ - `{ name }-{ target }-v{ version }.{ archive-format }`
"{ repo }/releases/download/v{ version }/{ name }-{ target }-v{ version }.{ archive-format }", - `{ name }-{ version }-{ target }.{ archive-format }`
"{ repo }/releases/download/v{ version }/{ name }-v{ version }-{ target }.{ archive-format }", - `{ name }-v{ version }-{ target }.{ archive-format }`
"{ repo }/releases/download/v{ version }/{ name }-{ version }-{ target }.{ archive-format }", - `{ name }-{ version }-{ target }.{ archive-format }`
"{ repo }/releases/download/v{ version }/{ name }-{ target }.{ archive-format }", - `{ name }-v{ version }-{ target }.{ archive-format }`
] - `{ name }-{ target }.{ archive-format }` ("versionless")
```
The first 3 versions does not overwrite different targets or versions when manually downloaded. The paths are:
All `pkg-url` templates download binaries located at `{ repo }/releases/download/v{ version }/`, which #### for GitHub
is compatible with github tags / releases.
If your package already uses this approach, you shouldn't need to set anything. - `{ repo }/releases/download/{ version }/`
- `{ repo }/releases/download/v{ version }/`
#### GitLab #### for GitLab
For gitlab, the `pkg-url` is set to - `{ repo }/-/releases/{ version }/downloads/binaries/`
- `{ repo }/-/releases/v{ version }/downloads/binaries/`
```rust Note that this uses the [Permanent links to release assets][gitlab-permalinks]
[ feature of GitLab EE: it requires you to create an asset as a link with a
"{ repo }/-/releases/v{ version }/downloads/binaries/{ name }-{ target }-v{ version }.{ archive-format }", `filepath`, which, as of writing, can only be set using GitLab's API.
"{ repo }/-/releases/v{ version }/downloads/binaries/{ name }-v{ version }-{ target }.{ archive-format }",
"{ repo }/-/releases/v{ version }/downloads/binaries/{ name }-{ version }-{ target }.{ archive-format }",
"{ repo }/-/releases/v{ version }/downloads/binaries/{ name }-{ target }.{ archive-format }",
]
```
This will attempt to find the release assets with `filepath` set to [gitlab-permalinks]: https://docs.gitlab.com/ee/user/project/releases/index.html#permanent-links-to-latest-release-assets
`binaries/{ name }-{ target }.{ archive-format }`
Note that this uses the [Permanent links to release assets](https://gitlab.kitware.com/help/user/project/releases/index#permanent-links-to-latest-release-assets) feature of gitlab, it requires you to #### for BitBucket
create an asset as a link with a `filepath`, which can be set only using gitlab api as of the writing.
#### BitBucket - `{ repo }/downloads/`
For bitbucket, the `pkg-url` is set to Binaries must be uploaded into the project's "Downloads" page on BitBucket.
```rust Also note that as there are no per-release downloads, the "versionless"
[ filename is not considered here.
"{ repo }/downloads/{ name }-{ target }-v{ version }.{ archive-format }",
"{ repo }/downloads/{ name }-v{ version }-{ target }.{ archive-format }",
"{ repo }/downloads/{ name }-{ version }-{ target }.{ archive-format }",
]
```
To setup the package for binstall, upload the binary into bitbucket downloads page of your project, #### for SourceForge
with its name set to be `{ name }-{ target }-v{ version }.{ archive-format }`.
#### SourceForge - `{ repo }/files/binaries/{ version }`
- `{ repo }/files/binaries/v{ version }`
For source forge, the `pkg-url` is set to The URLs also have `/download` appended as per SourceForge's schema.
```rust Binary must be uploaded to the "File" page of your project, under the directory
[ `binaries/v{ version }`.
"{ repo }/files/binaries/v{ version }/{ name }-{ target }-v{ version }.{ archive-format }/download",
"{ repo }/files/binaries/v{ version }/{ name }-v{ version }-{ target }.{ archive-format }/download",
"{ repo }/files/binaries/v{ version }/{ name }-{ version }-{ target }.{ archive-format }/download",
"{ repo }/files/binaries/v{ version }/{ name }-{ target }.{ archive-format }/download",
]
```
To setup the package for binstall, upload the binary to the file page of your project,
under the directory `binaries/v{ version }` with the filename `{ name }-{ target }.{ archive-format }`.
#### Others #### Others
For all other situations, `binstall` does not provide a default `pkg-url` and you need to manually For all other situations, `binstall` does not provide a default `pkg-url` and
specify it. you need to manually specify it.
### QuickInstall ### QuickInstall

View file

@ -1,4 +1,4 @@
use std::{borrow::Cow, path::Path, sync::Arc}; use std::{path::Path, sync::Arc};
use compact_str::{CompactString, ToCompactString}; use compact_str::{CompactString, ToCompactString};
use futures_util::stream::{FuturesUnordered, StreamExt}; use futures_util::stream::{FuturesUnordered, StreamExt};
@ -23,7 +23,7 @@ use crate::{
use super::Data; use super::Data;
mod hosting; mod hosting;
use hosting::GitHostingServices; use hosting::RepositoryHost;
pub struct GhCrateMeta { pub struct GhCrateMeta {
client: Client, client: Client,
@ -86,13 +86,13 @@ impl super::Fetcher for GhCrateMeta {
None None
}; };
let pkg_urls = if let Some(pkg_url) = self.data.meta.pkg_url.as_deref() { let pkg_urls = if let Some(pkg_url) = self.data.meta.pkg_url.clone() {
Cow::Owned(vec![pkg_url]) vec![pkg_url]
} else if let Some(repo) = repo.as_ref() { } else if let Some(repo) = repo.as_ref() {
if let Some(pkg_urls) = if let Some(pkg_urls) =
GitHostingServices::guess_git_hosting_services(repo)?.get_default_pkg_url_template() RepositoryHost::guess_git_hosting_services(repo)?.get_default_pkg_url_template()
{ {
Cow::Borrowed(pkg_urls) pkg_urls
} else { } else {
warn!( warn!(
concat!( concat!(

View file

@ -3,16 +3,17 @@ use url::Url;
use crate::errors::BinstallError; use crate::errors::BinstallError;
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum GitHostingServices { pub enum RepositoryHost {
GitHub, GitHub,
GitLab, GitLab,
BitBucket, BitBucket,
SourceForge, SourceForge,
Unknown, Unknown,
} }
impl GitHostingServices {
impl RepositoryHost {
pub fn guess_git_hosting_services(repo: &Url) -> Result<Self, BinstallError> { pub fn guess_git_hosting_services(repo: &Url) -> Result<Self, BinstallError> {
use GitHostingServices::*; use RepositoryHost::*;
match repo.domain() { match repo.domain() {
Some(domain) if domain.starts_with("github") => Ok(GitHub), Some(domain) if domain.starts_with("github") => Ok(GitHub),
@ -23,34 +24,60 @@ impl GitHostingServices {
} }
} }
pub fn get_default_pkg_url_template(self) -> Option<&'static [&'static str]> { pub fn get_default_pkg_url_template(self) -> Option<Vec<String>> {
use GitHostingServices::*; use RepositoryHost::*;
let full_filenames = &[
"{ name }-{ target }-v{ version }.{ archive-format }",
"{ name }-{ target }-{ version }.{ archive-format }",
"{ name }-{ version }-{ target }.{ archive-format }",
"{ name }-v{ version }-{ target }.{ archive-format }",
"{ name }-{ version }-{ target }.{ archive-format }",
"{ name }-v{ version }-{ target }.{ archive-format }",
];
let noversion_filenames = &["{ name }-{ target }.{ archive-format }"];
match self { match self {
GitHub => Some(&[ GitHub => Some(apply_filenames_to_paths(
"{ repo }/releases/download/v{ version }/{ name }-{ target }-v{ version }.{ archive-format }", &[
"{ repo }/releases/download/v{ version }/{ name }-v{ version }-{ target }.{ archive-format }", "{ repo }/releases/download/{ version }",
"{ repo }/releases/download/v{ version }/{ name }-{ version }-{ target }.{ archive-format }", "{ repo }/releases/download/v{ version }",
"{ repo }/releases/download/v{ version }/{ name }-{ target }.{ archive-format }", ],
]), &[full_filenames, noversion_filenames],
GitLab => Some(&[ )),
"{ repo }/-/releases/v{ version }/downloads/binaries/{ name }-{ target }-v{ version }.{ archive-format }", GitLab => Some(apply_filenames_to_paths(
"{ repo }/-/releases/v{ version }/downloads/binaries/{ name }-v{ version }-{ target }.{ archive-format }", &[
"{ repo }/-/releases/v{ version }/downloads/binaries/{ name }-{ version }-{ target }.{ archive-format }", "{ repo }/-/releases/{ version }/downloads/binaries",
"{ repo }/-/releases/v{ version }/downloads/binaries/{ name }-{ target }.{ archive-format }", "{ repo }/-/releases/v{ version }/downloads/binaries",
]), ],
BitBucket => Some(&[ &[full_filenames, noversion_filenames],
"{ repo }/downloads/{ name }-{ target }-v{ version }.{ archive-format }", )),
"{ repo }/downloads/{ name }-v{ version }-{ target }.{ archive-format }", BitBucket => Some(apply_filenames_to_paths(
"{ repo }/downloads/{ name }-{ version }-{ target }.{ archive-format }", &["{ repo }/downloads"],
]), &[full_filenames],
SourceForge => Some(&[ )),
"{ repo }/files/binaries/v{ version }/{ name }-{ target }-v{ version }.{ archive-format }/download", SourceForge => Some(
"{ repo }/files/binaries/v{ version }/{ name }-v{ version }-{ target }.{ archive-format }/download", apply_filenames_to_paths(
"{ repo }/files/binaries/v{ version }/{ name }-{ version }-{ target }.{ archive-format }/download", &[
"{ repo }/files/binaries/v{ version }/{ name }-{ target }.{ archive-format }/download", "{ repo }/files/binaries/{ version }",
]), "{ repo }/files/binaries/v{ version }",
],
&[full_filenames, noversion_filenames],
)
.into_iter()
.map(|url| format!("{url}/download"))
.collect(),
),
Unknown => None, Unknown => None,
} }
} }
} }
fn apply_filenames_to_paths(paths: &[&str], filenames: &[&[&str]]) -> Vec<String> {
filenames
.iter()
.flat_map(|fs| fs.iter())
.flat_map(|filename| paths.iter().map(move |path| format!("{path}/{filename}")))
.collect()
}

View file

@ -25,7 +25,7 @@ where
block_in_place(move || { block_in_place(move || {
fs::create_dir_all(path.parent().unwrap())?; fs::create_dir_all(path.parent().unwrap())?;
let mut file = fs::File::create(&path)?; let mut file = fs::File::create(path)?;
// remove it unless the operation isn't aborted and no write // remove it unless the operation isn't aborted and no write
// fails. // fails.