Skip to content

Commit

Permalink
Explode out even more variants of default download URLs (rust-lang#329)
Browse files Browse the repository at this point in the history
  • Loading branch information
passcod authored Sep 2, 2022
1 parent b330a18 commit 0cb4c99
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 90 deletions.
89 changes: 35 additions & 54 deletions SUPPORT.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
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
[
"{ 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/v{ version }/{ name }-{ version }-{ target }.{ archive-format }",
"{ repo }/releases/download/v{ version }/{ name }-{ target }.{ archive-format }",
]
```
- `{ name }-{ target }-{ version }.{ archive-format }`
- `{ name }-{ target }-v{ 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 }`
- `{ 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
is compatible with github tags / releases.
#### for GitHub

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
[
"{ repo }/-/releases/v{ version }/downloads/binaries/{ name }-{ target }-v{ version }.{ archive-format }",
"{ 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 }",
]
```
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
`filepath`, which, as of writing, can only be set using GitLab's API.

This will attempt to find the release assets with `filepath` set to
`binaries/{ name }-{ target }.{ archive-format }`
[gitlab-permalinks]: https://docs.gitlab.com/ee/user/project/releases/index.html#permanent-links-to-latest-release-assets

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
create an asset as a link with a `filepath`, which can be set only using gitlab api as of the writing.
#### for BitBucket

#### BitBucket
- `{ repo }/downloads/`

For bitbucket, the `pkg-url` is set to
Binaries must be uploaded into the project's "Downloads" page on BitBucket.

```rust
[
"{ repo }/downloads/{ name }-{ target }-v{ version }.{ archive-format }",
"{ repo }/downloads/{ name }-v{ version }-{ target }.{ archive-format }",
"{ repo }/downloads/{ name }-{ version }-{ target }.{ archive-format }",
]
```
Also note that as there are no per-release downloads, the "versionless"
filename is not considered here.

To setup the package for binstall, upload the binary into bitbucket downloads page of your project,
with its name set to be `{ name }-{ target }-v{ version }.{ archive-format }`.
#### for SourceForge

#### SourceForge
- `{ repo }/files/binaries/{ version }`
- `{ repo }/files/binaries/v{ version }`

For source forge, the `pkg-url` is set to

```rust
[
"{ 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",
]
```
The URLs also have `/download` appended as per SourceForge's schema.

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 }`.
Binary must be uploaded to the "File" page of your project, under the directory
`binaries/v{ version }`.

#### Others

For all other situations, `binstall` does not provide a default `pkg-url` and you need to manually
specify it.
For all other situations, `binstall` does not provide a default `pkg-url` and
you need to manually specify it.

### QuickInstall

Expand Down
12 changes: 6 additions & 6 deletions crates/lib/src/fetchers/gh_crate_meta.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{borrow::Cow, path::Path, sync::Arc};
use std::{path::Path, sync::Arc};

use compact_str::{CompactString, ToCompactString};
use futures_util::stream::{FuturesUnordered, StreamExt};
Expand All @@ -23,7 +23,7 @@ use crate::{
use super::Data;

mod hosting;
use hosting::GitHostingServices;
use hosting::RepositoryHost;

pub struct GhCrateMeta {
client: Client,
Expand Down Expand Up @@ -86,13 +86,13 @@ impl super::Fetcher for GhCrateMeta {
None
};

let pkg_urls = if let Some(pkg_url) = self.data.meta.pkg_url.as_deref() {
Cow::Owned(vec![pkg_url])
let pkg_urls = if let Some(pkg_url) = self.data.meta.pkg_url.clone() {
vec![pkg_url]
} else if let Some(repo) = repo.as_ref() {
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 {
warn!(
concat!(
Expand Down
85 changes: 56 additions & 29 deletions crates/lib/src/fetchers/gh_crate_meta/hosting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ use url::Url;
use crate::errors::BinstallError;

#[derive(Copy, Clone, Debug)]
pub enum GitHostingServices {
pub enum RepositoryHost {
GitHub,
GitLab,
BitBucket,
SourceForge,
Unknown,
}
impl GitHostingServices {

impl RepositoryHost {
pub fn guess_git_hosting_services(repo: &Url) -> Result<Self, BinstallError> {
use GitHostingServices::*;
use RepositoryHost::*;

match repo.domain() {
Some(domain) if domain.starts_with("github") => Ok(GitHub),
Expand All @@ -23,34 +24,60 @@ impl GitHostingServices {
}
}

pub fn get_default_pkg_url_template(self) -> Option<&'static [&'static str]> {
use GitHostingServices::*;
pub fn get_default_pkg_url_template(self) -> Option<Vec<String>> {
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 {
GitHub => Some(&[
"{ 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/v{ version }/{ name }-{ version }-{ target }.{ archive-format }",
"{ repo }/releases/download/v{ version }/{ name }-{ target }.{ archive-format }",
]),
GitLab => Some(&[
"{ repo }/-/releases/v{ version }/downloads/binaries/{ name }-{ target }-v{ version }.{ archive-format }",
"{ 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 }",
]),
BitBucket => Some(&[
"{ repo }/downloads/{ name }-{ target }-v{ version }.{ archive-format }",
"{ repo }/downloads/{ name }-v{ version }-{ target }.{ archive-format }",
"{ repo }/downloads/{ name }-{ version }-{ target }.{ archive-format }",
]),
SourceForge => Some(&[
"{ 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",
]),
Unknown => None,
GitHub => Some(apply_filenames_to_paths(
&[
"{ repo }/releases/download/{ version }",
"{ repo }/releases/download/v{ version }",
],
&[full_filenames, noversion_filenames],
)),
GitLab => Some(apply_filenames_to_paths(
&[
"{ repo }/-/releases/{ version }/downloads/binaries",
"{ repo }/-/releases/v{ version }/downloads/binaries",
],
&[full_filenames, noversion_filenames],
)),
BitBucket => Some(apply_filenames_to_paths(
&["{ repo }/downloads"],
&[full_filenames],
)),
SourceForge => Some(
apply_filenames_to_paths(
&[
"{ repo }/files/binaries/{ version }",
"{ repo }/files/binaries/v{ version }",
],
&[full_filenames, noversion_filenames],
)
.into_iter()
.map(|url| format!("{url}/download"))
.collect(),
),
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()
}
2 changes: 1 addition & 1 deletion crates/lib/src/helpers/download/async_extracter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ where
block_in_place(move || {
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
// fails.
Expand Down

0 comments on commit 0cb4c99

Please sign in to comment.