diff --git a/rust/patchable/README.md b/rust/patchable/README.md index 76c90b1fd..80bbe59d5 100644 --- a/rust/patchable/README.md +++ b/rust/patchable/README.md @@ -48,21 +48,21 @@ The version-level config contains: ### Template -If you're adding a completely new product, you need to create the product-level config once: +If you're adding a completely new product, you need to initialize the product-level config once using patchable: -```toml -# docker-images/druid/stackable/patches/patchable.toml -upstream = "https://github.com/apache/druid.git" -mirror = "https://github.com/stackabletech/druid.git" +```sh +cargo patchable init product druid --upstream https://github.com/apache/druid.git --default-mirror https://github.com/stackabletech/druid.git ``` +This will create the product-level configuration in `docker-images/druid/stackable/patches/patchable.toml`. + If you just want to add a new version, initialize the version-level config with patchable: ```sh -cargo patchable init druid 28.0.0 --base=druid-28.0.0 --mirror +cargo patchable init version druid 28.0.0 --base druid-28.0.0 --mirror ``` -This will initialize the version-level config with the base commit hash and the default mirror URL from the product-level config. +This will initialize the version-level config in `docker-images/druid/stackable/patches/28.0.0/patchable.toml` with the base commit hash and the default mirror URL from the product-level config. You can optionally provide the `--ssh` flag to use SSH instead of HTTPS for Git operations. ## Glossary diff --git a/rust/patchable/src/main.rs b/rust/patchable/src/main.rs index 65983daf9..10b5ae988 100644 --- a/rust/patchable/src/main.rs +++ b/rust/patchable/src/main.rs @@ -180,24 +180,10 @@ enum Cmd { pv: ProductVersion, }, - /// Creates a patchable.toml for a given product version + /// Creates patchable.toml configuration files Init { - #[clap(flatten)] - pv: ProductVersion, - - /// The upstream commit-ish (such as druid-28.0.0) that the patch series applies to - /// - /// Refs (such as tags and branches) will be resolved to commit IDs. - #[clap(long)] - base: String, - - /// Mirror the product version to the default mirror repository - #[clap(long)] - mirror: bool, - - /// Use SSH for git operations - #[clap(long)] - ssh: bool, + #[clap(subcommand)] + init_type: InitCmd, }, /// Shows the patch directory for a given product version @@ -218,6 +204,41 @@ enum Cmd { ImagesDir, } +#[derive(clap::Parser)] +enum InitCmd { + /// Creates a patchable.toml for a given product + Product { + /// The product name slug (such as druid) + product: String, + /// The upstream repository URL (e.g. https://github.com/apache/druid.git) + #[clap(long)] + upstream: String, + /// The default mirror repository URL (e.g. https://github.com/stackabletech/druid.git) + #[clap(long)] + default_mirror: Option, + }, + + /// Creates a patchable.toml for a given product version + Version { + #[clap(flatten)] + pv: ProductVersion, + + /// The upstream commit-ish (such as druid-28.0.0) that the patch series applies to + /// + /// Refs (such as tags and branches) will be resolved to commit IDs. + #[clap(long)] + base: String, + + /// Mirror the product version to the default mirror repository + #[clap(long)] + mirror: bool, + + /// Use SSH for git operations + #[clap(long)] + ssh: bool, + }, +} + #[derive(Debug, Snafu)] pub enum Error { #[snafu(display("failed to configure git logging"))] @@ -475,10 +496,61 @@ fn main() -> Result<()> { } Cmd::Init { - pv, - base, - mirror, - ssh, + init_type: + InitCmd::Product { + product, + upstream, + default_mirror, + }, + } => { + let product_config_path = ProductVersionContext { + pv: ProductVersion { + product: product.clone(), + version: "".to_string(), + }, + images_repo_root, + } + .product_config_path(); + + tracing::info!( + path = ?product_config_path, + "creating product configuration directory and file" + ); + + if let Some(product_config_dir) = product_config_path.parent() { + std::fs::create_dir_all(product_config_dir).context(CreatePatchDirSnafu { + path: product_config_dir, + })?; + } + + let product_config = ProductConfig { + upstream, + default_mirror, + }; + + let config_toml = + toml::to_string_pretty(&product_config).context(SerializeConfigSnafu)?; + File::create_new(&product_config_path) + .and_then(|mut f| f.write_all(config_toml.as_bytes())) + .context(SaveConfigSnafu { + path: &product_config_path, + })?; + + tracing::info!( + config.path = ?product_config_path, + product = product, + "created configuration for product" + ); + } + + Cmd::Init { + init_type: + InitCmd::Version { + pv, + base, + mirror, + ssh, + }, } => { let ctx = ProductVersionContext { pv, @@ -510,6 +582,7 @@ fn main() -> Result<()> { let mirror_url = if mirror { let mut mirror_url = config .default_mirror + .filter(|s| !s.is_empty()) .context(InitMirrorNotConfiguredSnafu)?; if ssh { mirror_url = @@ -572,6 +645,7 @@ fn main() -> Result<()> { std::fs::create_dir_all(config_dir) .context(CreatePatchDirSnafu { path: config_dir })?; } + let config_toml = toml::to_string_pretty(&config).context(SerializeConfigSnafu)?; File::create_new(&config_path) .and_then(|mut f| f.write_all(config_toml.as_bytes()))