feat: git::Repository cancellation support (#1288)

feat: `git::Repository` support cancellation.

To make sure users can cancel git operation via signal, e.g. when the
git operation fail or users no longer want to install.

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
Jiahao XU 2023-08-13 00:18:02 +10:00 committed by GitHub
parent ef99dd795f
commit fbed317df5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 113 additions and 16 deletions

View file

@ -16,7 +16,7 @@ use crate::{
errors::BinstallError,
helpers::{
cargo_toml::Manifest,
git::{GitUrl, Repository},
git::{GitCancellationToken, GitUrl, Repository},
remote::Client,
},
manifests::cargo_toml_binstall::Meta,
@ -30,10 +30,14 @@ struct GitIndex {
}
impl GitIndex {
fn new(url: GitUrl) -> Result<Self, BinstallError> {
fn new(url: GitUrl, cancellation_token: GitCancellationToken) -> Result<Self, BinstallError> {
let tempdir = TempDir::new()?;
let repo = Repository::shallow_clone_bare(url.clone(), tempdir.as_ref())?;
let repo = Repository::shallow_clone_bare(
url.clone(),
tempdir.as_ref(),
Some(cancellation_token),
)?;
let config: RegistryConfig = {
let config = repo
@ -108,6 +112,10 @@ impl GitRegistry {
let version_req = version_req.clone();
let this = self.clone();
let cancellation_token = GitCancellationToken::default();
// Cancel git operation if the future is cancelled (dropped).
let cancel_on_drop = cancellation_token.clone().cancel_on_drop();
let (matched_version, dl_url) = spawn_blocking(move || {
let GitIndex {
_tempdir: _,
@ -116,7 +124,7 @@ impl GitRegistry {
} = this
.0
.git_index
.get_or_try_init(|| GitIndex::new(this.0.url.clone()))?;
.get_or_try_init(|| GitIndex::new(this.0.url.clone(), cancellation_token))?;
let matched_version =
Self::find_crate_matched_ver(repo, &crate_name, &crate_prefix, &version_req)?;
@ -132,6 +140,9 @@ impl GitRegistry {
})
.await??;
// Git operation done, disarm it
cancel_on_drop.disarm();
parse_manifest(client, name, dl_url, matched_version).await
}
}

View file

@ -373,16 +373,26 @@ impl PackageInfo {
}
#[cfg(feature = "git")]
Some(Git(git_url)) => {
use helpers::git::{GitCancellationToken, Repository as GitRepository};
let git_url = git_url.clone();
let name = name.clone();
let cancellation_token = GitCancellationToken::default();
// Cancel git operation if the future is cancelled (dropped).
let cancel_on_drop = cancellation_token.clone().cancel_on_drop();
spawn_blocking(move || {
let ret = spawn_blocking(move || {
let dir = TempDir::new()?;
helpers::git::Repository::shallow_clone(git_url, dir.as_ref())?;
GitRepository::shallow_clone(git_url, dir.as_ref(), Some(cancellation_token))?;
load_manifest_from_workspace(dir.as_ref(), &name).map_err(BinstallError::from)
})
.await??
.await??;
// Git operation done, disarm it
cancel_on_drop.disarm();
ret
}
None => {
Box::pin(