diff --git a/docs/guide/configuration.md b/docs/guide/configuration.md index 6121f0f..cbe293f 100644 --- a/docs/guide/configuration.md +++ b/docs/guide/configuration.md @@ -15,6 +15,7 @@ shrink = true appcds = true crac = false compact_banner = false +one_time_banner = false # Gradle multi-project options gradle_project = "app" @@ -39,6 +40,7 @@ All fields are optional. | `gradle_project` | string | — | Gradle subproject to build (for multi-project) | | `modules` | array | — | Manual module list (bypasses jdeps detection) | | `jlink_runtime` | string | — | Path to existing jlink runtime to reuse | +| `one_time_banner` | boolean | `false` | Show the banner only on the first run | ## Precedence diff --git a/docs/reference/cli.md b/docs/reference/cli.md index a86388b..dbca1fa 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -28,7 +28,8 @@ jbundle build [OPTIONS] --input --output | `--shrink [true\|false]` | `false` | Shrink uberjar by removing non-essential files | | `--no-appcds` | — | Disable AppCDS generation | | `--crac` | — | Enable CRaC checkpoint (Linux only) | -| `--compact-banner` | — | Use a compact banner in the wrapper | +| `--compact-banner` | `false` | Use a compact banner in the wrapper | +| `--one-time-banner` | `false` | Show the banner only on the first run | | `--gradle-project ` | — | Gradle subproject to build (multi-project) | | `--all` | — | Build all application subprojects (Gradle) | | `--modules ` | — | Manual module list, comma-separated | diff --git a/src/cli.rs b/src/cli.rs index f6c3ad0..0bd8f89 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -76,6 +76,10 @@ pub enum Command { /// Use a compact banner in the wrapper #[arg(long)] compact_banner: bool, + + /// Show the banner only on the first run + #[arg(long)] + one_time_banner: bool, }, /// Analyze a JAR or project and report size breakdown diff --git a/src/config.rs b/src/config.rs index ac97628..06e5d31 100644 --- a/src/config.rs +++ b/src/config.rs @@ -174,6 +174,7 @@ pub struct BuildConfig { pub appcds: bool, pub crac: bool, pub compact_banner: bool, + pub one_time_banner: bool, /// Gradle subproject to build (for multi-project builds) pub gradle_project: Option, /// Build all application subprojects (Gradle multi-project) diff --git a/src/main.rs b/src/main.rs index 74efb82..bd2b631 100644 --- a/src/main.rs +++ b/src/main.rs @@ -66,6 +66,7 @@ async fn main() -> Result<()> { jlink_runtime, verbose: _, compact_banner, + one_time_banner, } => { let input_path = std::fs::canonicalize(&input).unwrap_or_else(|_| PathBuf::from(&input)); @@ -141,6 +142,12 @@ async fn main() -> Result<()> { .and_then(|c| c.compact_banner) .unwrap_or(false); + let one_time_banner = one_time_banner + || project_config + .as_ref() + .and_then(|c| c.one_time_banner) + .unwrap_or(false); + // Gradle subproject selection (CLI > config file) let gradle_project = gradle_project.or_else(|| { project_config @@ -186,6 +193,7 @@ async fn main() -> Result<()> { appcds, crac, compact_banner, + one_time_banner, gradle_project, build_all: all, modules_override, @@ -523,6 +531,8 @@ async fn run_build(config: BuildConfig) -> Result<()> { let compact_banner = config.compact_banner; + let one_time_banner = config.one_time_banner; + // Step: Pack binary let step = pipeline.start_step("Packing binary"); pack::create_binary(&pack::PackOptions { @@ -535,6 +545,7 @@ async fn run_build(config: BuildConfig) -> Result<()> { appcds: config.appcds, java_version, compact_banner, + one_time_banner, })?; let size = std::fs::metadata(&config.output)?.len(); Pipeline::finish_step( diff --git a/src/pack/mod.rs b/src/pack/mod.rs index fead10b..2620710 100644 --- a/src/pack/mod.rs +++ b/src/pack/mod.rs @@ -20,6 +20,7 @@ pub struct PackOptions<'a> { pub appcds: bool, pub java_version: u8, pub compact_banner: bool, + pub one_time_banner: bool, } pub fn create_binary(opts: &PackOptions) -> Result<(), PackError> { @@ -66,6 +67,7 @@ pub fn create_binary(opts: &PackOptions) -> Result<(), PackError> { appcds: opts.appcds, java_version: opts.java_version, compact_banner: opts.compact_banner, + one_time_banner: opts.one_time_banner, }); let stub_script = stub::finalize_stub(&stub_script); diff --git a/src/pack/stub.rs b/src/pack/stub.rs index 5ca8191..35d2760 100644 --- a/src/pack/stub.rs +++ b/src/pack/stub.rs @@ -12,6 +12,7 @@ pub struct StubParams<'a> { pub appcds: bool, pub java_version: u8, pub compact_banner: bool, + pub one_time_banner: bool, } pub fn generate(params: &StubParams) -> String { @@ -50,6 +51,18 @@ pub fn generate(params: &StubParams) -> String { BANNER"# }; + let banner_display = if params.one_time_banner { + format!( + r#"mkdir -p "$JBUNDLE_RUNS" +if [ ! -e "$JBUNDLE_RUNS/$APP_HASH" ]; then + touch "$JBUNDLE_RUNS/$APP_HASH" + {jbundle_banner} +fi"# + ) + } else { + jbundle_banner.to_string() + }; + // AppCDS via AutoCreateSharedArchive (JDK 19+) let cds_flags = if params.appcds && params.java_version >= 19 { r#" @@ -64,11 +77,12 @@ CDS_FLAG="-XX:+AutoCreateSharedArchive -XX:SharedArchiveFile=$CDS_FILE""# r#"#!/bin/sh set -e CACHE="${{HOME}}/.jbundle/cache" +JBUNDLE_RUNS="${{HOME}}/.jbundle/runs" RT_HASH="{runtime_hash}" RT_SIZE={runtime_size} APP_HASH="{app_hash}" APP_SIZE={app_size} CRAC_SIZE={crac_size} CRAC_HASH="{crac_hash_val}" -{jbundle_banner} +{banner_display} STUB_SIZE=__STUB_SIZE__ @@ -144,6 +158,7 @@ mod tests { appcds: true, java_version: 21, compact_banner: false, + one_time_banner: false, } } diff --git a/src/project_config.rs b/src/project_config.rs index 32b68a0..4347f1b 100644 --- a/src/project_config.rs +++ b/src/project_config.rs @@ -16,6 +16,7 @@ pub struct ProjectConfig { pub appcds: Option, pub crac: Option, pub compact_banner: Option, + pub one_time_banner: Option, /// Gradle subproject to build (for multi-project builds) pub gradle_project: Option, /// Manual module override (bypasses jdeps detection) @@ -57,6 +58,7 @@ profile = "cli" appcds = false crac = true compact_banner = false +one_time_banner = false gradle_project = "jabkit" modules = ["java.base", "java.sql"] jlink_runtime = "./build/jlink" @@ -76,6 +78,7 @@ jlink_runtime = "./build/jlink" assert_eq!(config.appcds, Some(false)); assert_eq!(config.crac, Some(true)); assert_eq!(config.compact_banner, Some(false)); + assert_eq!(config.one_time_banner, Some(false)); assert_eq!(config.gradle_project.as_deref(), Some("jabkit")); assert_eq!( config.modules,