diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2021-02-26 10:56:52 +0100 |
---|---|---|
committer | Matthias Beyer <matthias.beyer@atos.net> | 2021-03-01 08:25:46 +0100 |
commit | ea54f4309db4a16bc7d19da7c51c614b3e34ccdf (patch) | |
tree | 25bedbbce9e78d4925b98e11ad777fde50d7c518 | |
parent | 6ebc1f4c8d36b6a19205a294553010ee7f3e7f74 (diff) |
Implement "release rm" subcommand
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/cli.rs | 137 | ||||
-rw-r--r-- | src/commands/release.rs | 71 |
3 files changed, 167 insertions, 42 deletions
@@ -22,6 +22,7 @@ colored = "2" config = "0.10" csv = "1.1" daggy = { version = "0.7", features = [ "serde" ] } +dialoguer = "0.7" diesel = { version = "1.4", features = ["postgres", "chrono", "uuid", "serde_json"] } env_logger = "0.8" filters = "0.4.0" @@ -662,51 +662,106 @@ pub fn cli<'a>() -> App<'a> { ) .subcommand(App::new("release") - .about("Release artifacts") - .arg(Arg::new("submit_uuid") - .required(true) - .multiple(false) - .index(1) - .value_name("SUBMIT") - .about("The submit uuid from which to release a package") - ) - .arg(Arg::new("release_store_name") - .required(true) - .multiple(false) - .long("to") - .value_name("RELEASE_STORE_NAME") - .about("Release store name to release to") + .subcommand(App::new("rm") + .about("Remove release artifacts") .long_about(indoc::indoc!(r#" - Butido can release to different release stores, based on this CLI flag. - The release stores that are available must be listed in the configuration. + Removes a released artifact from the release store and deletes the according database entry. + + This command asks interactively whether you want to delete data. + This can't be turned off. "#)) + .arg(Arg::new("release_store_name") + .required(true) + .multiple(false) + .long("from") + .value_name("RELEASE_STORE_NAME") + .about("Release store name to remove release from") + ) + + .arg(Arg::new("package_name") + .required(false) + .multiple(false) + .index(1) + .value_name("PKG") + .about("The name of the package") + .conflicts_with("artifact_path") + .requires("package_version") + ) + + .arg(Arg::new("package_version") + .required(false) + .multiple(false) + .index(2) + .value_name("VERSION") + .about("The exact version of the package (string match)") + .conflicts_with("artifact_path") + .requires("package_name") + ) + + .arg(Arg::new("artifact_path") + .required(false) + .multiple(false) + .long("path") + .value_name("PATH") + .about("Path to a released artifact") + .conflicts_with_all(&["package_name", "package_version"]) + ) + + .group(ArgGroup::new("artifact_or_package") + .args(&["package_name", "package_version", "artifact_path"]) + .multiple(true) + .required(true) + ) ) - .arg(Arg::new("package_name") - .required(false) - .multiple(false) - .index(2) - .value_name("PKG") - .about("The name of the package") - .conflicts_with("all-packages") - ) - .arg(Arg::new("all-packages") - .required(false) - .multiple(false) - .long("all") - .about("Release all packages") - .conflicts_with("package_name") - ) - .group(ArgGroup::new("package") - .args(&["package_name", "all-packages"]) - .required(true) // one of these is required - ) - .arg(Arg::new("package_version") - .required(false) - .multiple(false) - .index(3) - .value_name("VERSION") - .about("The exact version of the package (string match)") + + .subcommand(App::new("new") + .about("Release artifacts") + .arg(Arg::new("submit_uuid") + .required(true) + .multiple(false) + .index(1) + .value_name("SUBMIT") + .about("The submit uuid from which to release a package") + ) + .arg(Arg::new("release_store_name") + .required(true) + .multiple(false) + .long("to") + .value_name("RELEASE_STORE_NAME") + .about("Release store name to release to") + .long_about(indoc::indoc!(r#" + Butido can release to different release stores, based on this CLI flag. + The release stores that are available must be listed in the configuration. + "#)) + ) + .arg(Arg::new("package_name") + .required(false) + .multiple(false) + .index(2) + .value_name("PKG") + .about("The name of the package") + .conflicts_with("all-packages") + ) + .arg(Arg::new("all-packages") + .required(false) + .multiple(false) + .long("all") + .about("Release all packages") + .conflicts_with("package_name") + ) + .group(ArgGroup::new("package") + .args(&["package_name", "all-packages"]) + .required(true) // one of these is required + ) + .arg(Arg::new("package_version") + .required(false) + .multiple(false) + .index(3) + .value_name("VERSION") + .about("The exact version of the package (string match)") + ) ) + ) .subcommand(App::new("lint") diff --git a/src/commands/release.rs b/src/commands/release.rs index 51ecd89..a3d53f0 100644 --- a/src/commands/release.rs +++ b/src/commands/release.rs @@ -8,6 +8,7 @@ // SPDX-License-Identifier: EPL-2.0 // +use std::io::Write; use std::path::PathBuf; use anyhow::anyhow; @@ -15,7 +16,7 @@ use anyhow::Error; use anyhow::Result; use clap::ArgMatches; use diesel::prelude::*; -use log::{debug, trace}; +use log::{debug, info, trace}; use tokio_stream::StreamExt; use crate::config::Configuration; @@ -28,6 +29,20 @@ pub async fn release( config: &Configuration, matches: &ArgMatches, ) -> Result<()> { + match matches.subcommand() { + Some(("new", matches)) => new_release(db_connection_config, config, matches).await, + Some(("rm", matches)) => rm_release(db_connection_config, config, matches).await, + Some((other, _matches)) => Err(anyhow!("Unknown subcommand: {}", other)), + None => Err(anyhow!("Missing subcommand")), + } +} + + +async fn new_release( + db_connection_config: DbConnectionConfig, + config: &Configuration, + matches: &ArgMatches, +) -> Result<()> { let release_store_name = matches.value_of("release_store_name").unwrap(); // safe by clap if !(config.releases_directory().exists() && config.releases_directory().is_dir()) { return Err(anyhow!( @@ -155,3 +170,57 @@ pub async fn release( Ok(()) }) } + +pub async fn rm_release( + db_connection_config: DbConnectionConfig, + config: &Configuration, + matches: &ArgMatches, +) -> Result<()> { + let release_store_name = matches.value_of("release_store_name").unwrap(); // safe by clap + if !(config.releases_directory().exists() && config.releases_directory().is_dir()) { + return Err(anyhow!( + "Release directory does not exist or does not point to directory: {}", + config.releases_directory().display() + )); + } + + let pname = matches.value_of("package_name").map(String::from).unwrap(); // TODO: FIXME + let pvers = matches.value_of("package_version").map(String::from).unwrap(); // TODO: FIXME + debug!("Remove Release called for: {:?} {:?}", pname, pvers); + + let conn = crate::db::establish_connection(db_connection_config)?; + + let (release, artifact) = crate::schema::jobs::table + .inner_join(crate::schema::packages::table) + .inner_join(crate::schema::artifacts::table) + .inner_join(crate::schema::releases::table + .on(crate::schema::releases::artifact_id.eq(crate::schema::artifacts::id))) + .inner_join(crate::schema::release_stores::table + .on(crate::schema::release_stores::id.eq(crate::schema::releases::release_store_id))) + .filter(crate::schema::packages::dsl::name.eq(&pname) + .and(crate::schema::packages::dsl::version.eq(&pvers))) + .filter(crate::schema::release_stores::dsl::store_name.eq(&release_store_name)) + .order(crate::schema::releases::dsl::release_date.desc()) + .select((crate::schema::releases::all_columns, crate::schema::artifacts::all_columns)) + .first::<(crate::db::models::Release, crate::db::models::Artifact)>(&conn)?; + + let artifact_path = config.releases_directory().join(release_store_name).join(&artifact.path); + if !artifact_path.is_file() { + return Err(anyhow!("Not a file: {}", artifact_path.display())) + } + + writeln!(std::io::stderr(), "Going to delete: {}", artifact_path.display())?; + writeln!(std::io::stderr(), "Going to remove from database: Release with ID {} from {}", release.id, release.release_date)?; + if !dialoguer::Confirm::new().with_prompt("Continue?").interact()? { + return Ok(()) + } + + tokio::fs::remove_file(&artifact_path).await?; + info!("File removed"); + + diesel::delete(&release).execute(&conn)?; + info!("Release deleted from database"); + + Ok(()) +} + |