diff --git a/src/admin/delete_version.rs b/src/admin/delete_version.rs index 1e004cc569e..16665d4f930 100644 --- a/src/admin/delete_version.rs +++ b/src/admin/delete_version.rs @@ -5,7 +5,8 @@ use crate::tasks::spawn_blocking; use crate::worker::jobs; use crate::{admin::dialoguer, db, schema::versions}; use anyhow::Context; -use diesel::prelude::*; +use diesel::{Connection, ExpressionMethods, QueryDsl}; +use diesel_async::async_connection_wrapper::AsyncConnectionWrapper; #[derive(clap::Parser, Debug)] #[command( @@ -27,18 +28,25 @@ pub struct Opts { } pub async fn run(opts: Opts) -> anyhow::Result<()> { - spawn_blocking(move || { - let crate_name = &opts.crate_name; + let mut conn = db::oneoff_async_connection() + .await + .context("Failed to establish database connection")?; - let conn = &mut db::oneoff_connection().context("Failed to establish database connection")?; + let store = Storage::from_environment(); - let store = Storage::from_environment(); + let crate_id: i32 = { + use diesel_async::RunQueryDsl; - let crate_id: i32 = crates::table + crates::table .select(crates::id) - .filter(crates::name.eq(crate_name)) - .first(conn) - .context("Failed to look up crate id from the database")?; + .filter(crates::name.eq(&opts.crate_name)) + .first(&mut conn) + .await + .context("Failed to look up crate id from the database") + }?; + + { + let crate_name = &opts.crate_name; println!("Deleting the following versions of the `{crate_name}` crate:"); println!(); @@ -47,9 +55,20 @@ pub async fn run(opts: Opts) -> anyhow::Result<()> { } println!(); - if !opts.yes && !dialoguer::confirm("Do you want to permanently delete these versions?")? { + if !opts.yes + && !dialoguer::async_confirm("Do you want to permanently delete these versions?") + .await? + { return Ok(()); } + } + + let opts = spawn_blocking::<_, _, anyhow::Error>(move || { + use diesel::RunQueryDsl; + + let conn: &mut AsyncConnectionWrapper<_> = &mut conn.into(); + + let crate_name = &opts.crate_name; conn.transaction(|conn| { info!(%crate_name, %crate_id, versions = ?opts.versions, "Deleting versions from the database"); @@ -87,27 +106,26 @@ pub async fn run(opts: Opts) -> anyhow::Result<()> { warn!(%crate_name, ?error, "Failed to enqueue index sync jobs"); } - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .context("Failed to initialize tokio runtime")?; + Ok(opts) + }).await?; - for version in &opts.versions { - debug!(%crate_name, %version, "Deleting crate file from S3"); - if let Err(error) = rt.block_on(store.delete_crate_file(crate_name, version)) { - warn!(%crate_name, %version, ?error, "Failed to delete crate file from S3"); - } + let crate_name = &opts.crate_name; - debug!(%crate_name, %version, "Deleting readme file from S3"); - match rt.block_on(store.delete_readme(crate_name, version)) { - Err(object_store::Error::NotFound { .. }) => {} - Err(error) => { - warn!(%crate_name, %version, ?error, "Failed to delete readme file from S3") - } - Ok(_) => {} + for version in &opts.versions { + debug!(%crate_name, %version, "Deleting crate file from S3"); + if let Err(error) = store.delete_crate_file(crate_name, version).await { + warn!(%crate_name, %version, ?error, "Failed to delete crate file from S3"); + } + + debug!(%crate_name, %version, "Deleting readme file from S3"); + match store.delete_readme(crate_name, version).await { + Err(object_store::Error::NotFound { .. }) => {} + Err(error) => { + warn!(%crate_name, %version, ?error, "Failed to delete readme file from S3") } + Ok(_) => {} } + } - Ok(()) - }).await + Ok(()) } diff --git a/src/admin/dialoguer.rs b/src/admin/dialoguer.rs index 9701e6fb3ca..941fe5492bf 100644 --- a/src/admin/dialoguer.rs +++ b/src/admin/dialoguer.rs @@ -1,6 +1,12 @@ +use crate::tasks::spawn_blocking; use ::dialoguer::{theme::Theme, Confirm}; -pub fn confirm(msg: &str) -> dialoguer::Result { +pub async fn async_confirm(msg: impl Into) -> anyhow::Result { + let msg = msg.into(); + spawn_blocking(move || confirm(msg).map_err(anyhow::Error::from)).await +} + +pub fn confirm(msg: impl Into) -> dialoguer::Result { Confirm::with_theme(&CustomTheme) .with_prompt(msg) .default(false)