diff --git a/Cargo.toml b/Cargo.toml index 69e0e52..eeb3599 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" [dependencies] glob = "0.3.0" -rpm = { version = "0.12.1", default-features = false } +rpm = { version = "0.13.1", default-features = false } toml = "0.7" cargo_toml = "0.15" clap = { version = "4.3", features = ["derive"] } diff --git a/README.md b/README.md index 0eb3c58..7b5443b 100644 --- a/README.md +++ b/README.md @@ -57,9 +57,29 @@ from [the `Cargo.toml` file](https://doc.rust-lang.org/cargo/reference/manifest. * release: optional string of release. * epoch: optional number of epoch. * pre_install_script: optional string or file path of pre_install_script. + * pre_install_script_flags: optional integer value to set scriptlet flags. + * pre_install_script_prog: optional string array to set scriptlet interpreter/arguments. * pre_uninstall_script: optional string or file path of pre_uninstall_script. + * pre_uninstall_script_flags: optional integer value to set scriptlet flags. + * pre_uninstall_script_prog: optional string array to set scriptlet interpreter/arguments. +* pre_trans_script: optional string or file path of pre_trans_script. + * pre_trans_script_flags: optional integer value to set scriptlet flags. + * pre_trans_script_prog: optional string array to set scriptlet interpreter/arguments. +* pre_untrans_script: optional string or file path of pre_untrans_script. + * pre_untrans_script_flags: optional integer value to set scriptlet flags. + * pre_untrans_script_prog: optional string array to set scriptlet interpreter/arguments. * post_install_script: optional string or file path of post_install_script. + * post_install_script_flags: optional integer value to set scriptlet flags. + * post_install_script_prog: optional string array to set scriptlet interpreter/arguments. * post_uninstall_script: optional string or file path of post_uninstall_script. + * post_uninstall_script_flags: optional integer value to set scriptlet flags. + * post_uninstall_script_prog: optional string array to set scriptlet interpreter/arguments. +* post_trans_script: optional string or file path of post_trans_script. + * post_trans_script_flags: optional integer value to set scriptlet flags. + * post_trans_script_prog: optional string array to set scriptlet interpreter/arguments. +* post_untrans_script: optional string or file path of post_untrans_script. + * post_untrans_script_flags: optional integer value to set scriptlet flags. + * post_untrans_script_prog: optional string array to set scriptlet interpreter/arguments. * requires: optional list of Requires * auto-req: optional string `"no"` to disable the automatic dependency process * require-sh: optional boolean `false` to omit `/bin/sh` from Requirements @@ -199,3 +219,26 @@ The default payload compress type of the generated RPM file is zstd. You can specify the payload compress type with `--payload-compress TYPE`: none, gzip, or zstd. For the legacy system (e.g. centos7), specify legacy compress type explicitly e.g. `--payload-compress none`. + + +### Scriptlet Flags and Prog Settings + +Scriptlet settings can be configured via `*_script_flags` and `*_script_prog` settings. + +**Scriptlet Flags** + +| Flag | Setting Value | Description | Example Usage | +| ---- | ------------- | ----------- | ------- | +| `RPMSCRIPT_FLAG_EXPAND` | 1 | Enables macro expansion | `pre_install_script_flags = 0b001` | +| `RPMSCRIPT_FLAG_QFORMAT` | 2 | Enables header query format expansion | `pre_install_script_flags = 0b010` | +| `RPMSCRIPT_FLAG_CRITICAL` | 4 | Enables critical severity for scriplet success or failure | `pre_install_script_flags = 0b100` | + +**Example** + +```toml +pre_install_script = """ +echo preinstall +""" +pre_install_script_flags = 0b011 # Enables EXPAND and QFORMAT flags +pre_install_script_prog = ["/bin/blah/bash", "-c"] # Sets the interpreter/argument settings for the scriptlet +``` diff --git a/src/config/metadata.rs b/src/config/metadata.rs index 8387c8d..5f0a379 100644 --- a/src/config/metadata.rs +++ b/src/config/metadata.rs @@ -1,6 +1,7 @@ use crate::error::{ConfigError, FileAnnotatedError}; use crate::{Error, ExtraMetadataSource}; use cargo_toml::Manifest; +use rpm::Scriptlet; use std::fs; use std::path::PathBuf; use toml::value::Table; @@ -305,6 +306,30 @@ impl<'a> CompoundMetadataConfig<'a> { } Ok(None) } + + /// Returns a configured scriptlet, + /// + pub(super) fn get_scriptlet( + &self, + name: &str, + content: impl Into, + ) -> Result, ConfigError> { + let flags_key = format!("{name}_flags"); + let prog_key = format!("{name}_prog"); + + let mut scriptlet = Scriptlet::new(content); + + if let Some(flags) = self.get_i64(flags_key.as_str())? { + scriptlet = scriptlet.flags(rpm::ScriptletFlags::from_bits_retain(flags as u32)); + } + + if let Some(prog) = self.get_array(prog_key.as_str())? { + let prog = prog.iter().filter_map(|p| p.as_str()); + scriptlet = scriptlet.prog(prog.collect()); + } + + Ok(Some(scriptlet)) + } } impl<'a> TomlValueHelper<'a> for CompoundMetadataConfig<'a> { @@ -425,4 +450,36 @@ mod test { assert_eq!(metadata.get_i64("c").unwrap(), Some(4)); assert_eq!(metadata.get_i64("not-exist").unwrap(), None); } + + #[test] + fn test_get_scriptlet_config() { + let metadata = toml! { + test_script_flags = 0b011 + test_script_prog = ["/bin/blah/bash", "-c"] + }; + + let metadata_config = MetadataConfig { + metadata: &metadata, + branch_path: None, + }; + + let metadata = CompoundMetadataConfig { + config: &[metadata_config], + }; + + let scriptlet = metadata + .get_scriptlet("test_script", "echo hello world") + .expect("should be able to parse") + .expect("should be valid scriptlet"); + + assert_eq!( + scriptlet.flags, + Some(rpm::ScriptletFlags::EXPAND | rpm::ScriptletFlags::QFORMAT) + ); + assert_eq!( + scriptlet.program, + Some(vec!["/bin/blah/bash".to_string(), "-c".to_string()]) + ); + assert_eq!(scriptlet.script.as_str(), "echo hello world"); + } } diff --git a/src/config/mod.rs b/src/config/mod.rs index fdf17e7..1ad8d15 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -186,32 +186,91 @@ impl Config { } if let Some(pre_install_script) = metadata.get_str("pre_install_script")? { - builder = builder.pre_install_script(&load_script_if_path( - pre_install_script, - parent, - cfg.build_target, - )?); + let scriptlet = metadata.get_scriptlet( + "pre_install_script", + load_script_if_path(pre_install_script, parent, cfg.build_target)?, + )?; + + if let Some(scriptlet) = scriptlet { + builder = builder.pre_install_script(scriptlet); + } } + if let Some(pre_uninstall_script) = metadata.get_str("pre_uninstall_script")? { - builder = builder.pre_uninstall_script(&load_script_if_path( - pre_uninstall_script, - parent, - cfg.build_target, - )?); + let scriptlet = metadata.get_scriptlet( + "pre_uninstall_script", + load_script_if_path(pre_uninstall_script, parent, cfg.build_target)?, + )?; + + if let Some(scriptlet) = scriptlet { + builder = builder.pre_uninstall_script(scriptlet); + } } + if let Some(post_install_script) = metadata.get_str("post_install_script")? { - builder = builder.post_install_script(&load_script_if_path( - post_install_script, - parent, - cfg.build_target, - )?); + let scriptlet = metadata.get_scriptlet( + "post_install_script", + load_script_if_path(post_install_script, parent, cfg.build_target)?, + )?; + + if let Some(scriptlet) = scriptlet { + builder = builder.post_install_script(scriptlet); + } } + if let Some(post_uninstall_script) = metadata.get_str("post_uninstall_script")? { - builder = builder.post_uninstall_script(&load_script_if_path( - post_uninstall_script, - parent, - cfg.build_target, - )?); + let scriptlet = metadata.get_scriptlet( + "post_uninstall_script", + load_script_if_path(post_uninstall_script, parent, cfg.build_target)?, + )?; + + if let Some(scriptlet) = scriptlet { + builder = builder.post_uninstall_script(scriptlet); + } + } + + if let Some(pre_trans_script) = metadata.get_str("pre_trans_script")? { + let scriptlet = metadata.get_scriptlet( + "pre_trans_script", + load_script_if_path(pre_trans_script, parent, cfg.build_target)?, + )?; + + if let Some(scriptlet) = scriptlet { + builder = builder.pre_trans_script(scriptlet); + } + } + + if let Some(post_trans_script) = metadata.get_str("post_trans_script")? { + let scriptlet = metadata.get_scriptlet( + "post_trans_script", + load_script_if_path(post_trans_script, parent, cfg.build_target)?, + )?; + + if let Some(scriptlet) = scriptlet { + builder = builder.post_trans_script(scriptlet); + } + } + + if let Some(pre_untrans_script) = metadata.get_str("pre_untrans_script")? { + let scriptlet = metadata.get_scriptlet( + "pre_untrans_script", + load_script_if_path(pre_untrans_script, parent, cfg.build_target)?, + )?; + + if let Some(scriptlet) = scriptlet { + builder = builder.pre_untrans_script(scriptlet); + } + } + + if let Some(post_untrans_script) = metadata.get_str("post_untrans_script")? { + let scriptlet = metadata.get_scriptlet( + "post_untrans_script", + load_script_if_path(post_untrans_script, parent, cfg.build_target)?, + )?; + + if let Some(scriptlet) = scriptlet { + builder = builder.post_untrans_script(scriptlet); + } } if let Some(url) = match (