diff --git a/Cargo.lock b/Cargo.lock index bac742953a..e93a1caddf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1170,30 +1170,15 @@ dependencies = [ "which 4.4.2", ] -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec 0.6.3", -] - [[package]] name = "bit-set" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ - "bit-vec 0.8.0", + "bit-vec", ] -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - [[package]] name = "bit-vec" version = "0.8.0" @@ -1465,7 +1450,7 @@ dependencies = [ "bytes 1.9.0", "cargo-component-core", "cargo-config2", - "cargo_metadata 0.19.1", + "cargo_metadata", "clap", "futures", "heck 0.5.0", @@ -1545,20 +1530,6 @@ dependencies = [ "serde", ] -[[package]] -name = "cargo_metadata" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror 1.0.69", -] - [[package]] name = "cargo_metadata" version = "0.19.1" @@ -1865,7 +1836,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68578f196d2a33ff61b27fae256c3164f65e36382648e30666dde05b8cc9dfdf" dependencies = [ "async-trait", - "convert_case 0.6.0", + "convert_case", "json5", "nom", "pathdiff", @@ -1961,12 +1932,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "convert_case" version = "0.6.0" @@ -2620,19 +2585,6 @@ dependencies = [ "syn 2.0.96", ] -[[package]] -name = "derive_more" -version = "0.99.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" -dependencies = [ - "convert_case 0.4.0", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.96", -] - [[package]] name = "derive_more" version = "1.0.0" @@ -3172,11 +3124,11 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fancy-regex" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2" +checksum = "6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298" dependencies = [ - "bit-set 0.5.3", + "bit-set", "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -3799,7 +3751,7 @@ dependencies = [ "async-trait", "bincode", "bytes 1.9.0", - "cargo_metadata 0.19.1", + "cargo_metadata", "futures-core", "golem-wasm-ast", "golem-wasm-rpc", @@ -3830,7 +3782,7 @@ dependencies = [ "clap_complete", "cli-table", "colored", - "derive_more 1.0.0", + "derive_more", "dirs 5.0.1", "env_logger 0.11.6", "futures-util", @@ -3925,7 +3877,7 @@ dependencies = [ "combine", "console-subscriber", "dashmap", - "derive_more 1.0.0", + "derive_more", "figment", "fred", "git-version", @@ -4082,20 +4034,22 @@ dependencies = [ [[package]] name = "golem-examples" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c0bcbbedbbecc9c66f2349150cbeb1b9e9704958611af624fbf11ea7202c4d9" +checksum = "f0ae4fa06a19377a53f113c47c70724416fd9cf6b9f655749250ded3f81de616" dependencies = [ "Inflector", - "cargo_metadata 0.18.1", + "cargo_metadata", "clap", "colored", "copy_dir", - "derive_more 0.99.18", + "derive_more", "dir-diff", "fancy-regex", "golem-wit", "include_dir", + "itertools 0.14.0", + "nanoid", "once_cell", "regex", "serde", @@ -4111,7 +4065,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b33e98f6cc141902ffcc13d027d0bb9a4d3310e51ff182f67236384e8dfeb3ac" dependencies = [ "clap", - "convert_case 0.6.0", + "convert_case", "fmt", "indexmap 2.7.0", "indoc", @@ -4311,7 +4265,7 @@ dependencies = [ "async-trait", "bigdecimal", "bincode", - "cargo_metadata 0.19.1", + "cargo_metadata", "git-version", "golem-wasm-ast", "poem-openapi", @@ -4433,7 +4387,7 @@ dependencies = [ "cap-fs-ext", "cap-std", "cap-time-ext", - "cargo_metadata 0.19.1", + "cargo_metadata", "chrono", "console-subscriber", "dashmap", @@ -4513,7 +4467,7 @@ dependencies = [ "bincode", "bytes 1.9.0", "console-subscriber", - "derive_more 1.0.0", + "derive_more", "figment", "futures", "futures-util", @@ -4568,7 +4522,7 @@ dependencies = [ "chrono", "conditional-trait-gen", "criterion", - "derive_more 1.0.0", + "derive_more", "fastrand", "figment", "fred", @@ -5573,6 +5527,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.14" @@ -6216,6 +6179,15 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" +[[package]] +name = "nanoid" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8" +dependencies = [ + "rand", +] + [[package]] name = "nanorand" version = "0.7.0" @@ -7349,7 +7321,7 @@ dependencies = [ "base64 0.22.1", "bytes 1.9.0", "chrono", - "derive_more 1.0.0", + "derive_more", "futures-util", "humantime", "indexmap 2.7.0", @@ -7681,8 +7653,8 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" dependencies = [ - "bit-set 0.8.0", - "bit-vec 0.8.0", + "bit-set", + "bit-vec", "bitflags 2.7.0", "lazy_static 1.5.0", "num-traits", diff --git a/golem-cli/Cargo.toml b/golem-cli/Cargo.toml index 81b143e9ea..cc2c7fbd84 100644 --- a/golem-cli/Cargo.toml +++ b/golem-cli/Cargo.toml @@ -45,7 +45,7 @@ derive_more = { workspace = true } dirs = "5.0.1" futures-util = { workspace = true } glob = "0.3.1" -golem-examples = "1.1.0" +golem-examples = "1.1.1" h2 = "0.4.7" http = { workspace = true } humansize = { workspace = true } diff --git a/golem-cli/src/command.rs b/golem-cli/src/command.rs index 746c1acefd..9023371f78 100644 --- a/golem-cli/src/command.rs +++ b/golem-cli/src/command.rs @@ -32,6 +32,8 @@ use api_deployment::ApiDeploymentSubcommand; use clap::{self, Command, Subcommand}; use component::ComponentSubCommand; use golem_common::uri::oss::uri::ComponentUri; +use golem_examples::cli::NameOrLanguage; +use golem_examples::model::{ComponentName, GuestLanguage, GuestLanguageTier, PackageName}; use golem_wasm_rpc_stubgen::App; use plugin::PluginSubcommand; use profile::{ProfileSubCommand, UniversalProfileAdd}; @@ -104,9 +106,43 @@ pub enum StaticSharedCommand { #[command(flatten)] command: diagnose::cli::Command, }, - /// Create a new Golem component from built-in examples - #[command(flatten)] - Examples(golem_examples::cli::Command), + + /// Create a new Golem standalone component example project from built-in examples + #[command()] + New { + #[command(flatten)] + name_or_language: NameOrLanguage, + + /// The package name of the generated component (in namespace:name format) + #[arg(short, long)] + package_name: Option, + + /// The new component's name + component_name: ComponentName, + }, + + /// Add a new Golem component to a project using Golem Application Manifest + #[command()] + NewAppComponent { + /// The component name (and package name) of the generated component (in namespace:name format) + component_name: PackageName, + + /// Component language + #[arg(short, long, alias = "lang")] + language: GuestLanguage, + }, + + /// Lists the built-in examples available for creating new components + #[command()] + ListExamples { + /// The minimum language tier to include in the list + #[arg(short, long)] + min_tier: Option, + + /// Filter examples by a given guest language + #[arg(short, long, alias = "lang")] + language: Option, + }, } impl CliCommand for StaticSharedCommand { @@ -116,19 +152,22 @@ impl CliCommand for StaticSharedCommand { diagnose(command); Ok(GolemResult::Empty) } - StaticSharedCommand::Examples(golem_examples::cli::Command::ListExamples { - min_tier, - language, - }) => examples::process_list_examples(min_tier, language), - StaticSharedCommand::Examples(golem_examples::cli::Command::New { + StaticSharedCommand::ListExamples { min_tier, language } => { + examples::list_standalone_examples(min_tier, language) + } + StaticSharedCommand::New { name_or_language, package_name, component_name, - }) => examples::process_new( + } => examples::new( name_or_language.example_name(), component_name, package_name, ), + StaticSharedCommand::NewAppComponent { + component_name, + language, + } => examples::new_app_component(component_name, language), } } } diff --git a/golem-cli/src/diagnose.rs b/golem-cli/src/diagnose.rs index a4a194d742..5d61f9f63f 100644 --- a/golem-cli/src/diagnose.rs +++ b/golem-cli/src/diagnose.rs @@ -716,7 +716,7 @@ impl DetectedTool { pub fn diagnose(command: cli::Command) { let selected_language = match &command.language { - Some(language) => SelectedLanguage::from_flag(language.clone()), + Some(language) => SelectedLanguage::from_flag(*language), None => SelectedLanguage::from_env(), }; diff --git a/golem-cli/src/examples.rs b/golem-cli/src/examples.rs index 39aa9ecb7a..94a27af434 100644 --- a/golem-cli/src/examples.rs +++ b/golem-cli/src/examples.rs @@ -14,24 +14,25 @@ use std::env; +use crate::model::{ExampleDescription, GolemError, GolemResult}; use golem_examples::model::{ - ComponentName, ExampleName, ExampleParameters, GuestLanguage, GuestLanguageTier, PackageName, + ComponentName, ComposableAppGroupName, ExampleName, ExampleParameters, GuestLanguage, + GuestLanguageTier, PackageName, TargetExistsResolveMode, }; use golem_examples::*; +use itertools::Itertools; -use crate::model::{ExampleDescription, GolemError, GolemResult}; - -pub fn process_new( +pub fn new( example_name: ExampleName, component_name: ComponentName, package_name: Option, ) -> Result { - let examples = GolemExamples::list_all_examples(); + let examples = all_standalone_examples(); let example = examples.iter().find(|example| example.name == example_name); match example { Some(example) => { let cwd = env::current_dir().expect("Failed to get current working directory"); - match GolemExamples::instantiate( + match instantiate_example( example, &ExampleParameters { component_name, @@ -39,6 +40,7 @@ pub fn process_new( .unwrap_or(PackageName::from_string("golem:component").unwrap()), target_path: cwd, }, + TargetExistsResolveMode::Fail, ) { Ok(instructions) => Ok(GolemResult::Str(instructions.to_string())), Err(err) => GolemResult::err(format!("Failed to instantiate component: {err}")), @@ -50,11 +52,11 @@ pub fn process_new( } } -pub fn process_list_examples( +pub fn list_standalone_examples( min_tier: Option, language: Option, ) -> Result { - let examples = GolemExamples::list_all_examples() + let examples = all_standalone_examples() .iter() .filter(|example| match &language { Some(language) => example.language == *language, @@ -69,3 +71,43 @@ pub fn process_list_examples( Ok(GolemResult::Ok(Box::new(examples))) } + +pub fn new_app_component( + component_name: PackageName, + language: GuestLanguage, +) -> Result { + let all_examples = all_composable_app_examples(); + + let Some(language_examples) = all_examples.get(&language) else { + return Err(GolemError(format!( + "No template found for {}, currently supported languages: {}", + language, + all_examples.keys().join(", ") + ))); + }; + + let default_examples = language_examples + .get(&ComposableAppGroupName::default()) + .expect("No default template found for the selected language"); + + assert_eq!( + default_examples.components.len(), + 1, + "Expected exactly one default component template" + ); + + let default_component_example = &default_examples.components[0]; + + match add_component_by_example( + default_examples.common.as_ref(), + default_component_example, + &env::current_dir().expect("Failed to get current working directory"), + &component_name, + ) { + Ok(_) => Ok(GolemResult::Str(format!( + "Added new app component {}", + component_name.to_string_with_colon() + ))), + Err(err) => Err(GolemError(format!("Failed to add component: {err}"))), + } +} diff --git a/golem-cli/src/model.rs b/golem-cli/src/model.rs index 460cf24733..445ad053d4 100644 --- a/golem-cli/src/model.rs +++ b/golem-cli/src/model.rs @@ -596,7 +596,7 @@ impl ExampleDescription { pub fn from_example(example: &Example) -> Self { Self { name: example.name.clone(), - language: example.language.clone(), + language: example.language, description: example.description.clone(), tier: example.language.tier(), } diff --git a/golem-cli/src/model/text.rs b/golem-cli/src/model/text.rs index 38fba00540..2ac5c17ba3 100644 --- a/golem-cli/src/model/text.rs +++ b/golem-cli/src/model/text.rs @@ -695,7 +695,7 @@ pub mod example { fn from(value: &ExampleDescription) -> Self { Self { name: value.name.clone(), - language: value.language.clone(), + language: value.language, tier: value.tier.clone(), description: textwrap::wrap(&value.description, 30).join("\n"), } diff --git a/test-components/auction-example/auction-registry/golem.yaml b/test-components/auction-example/auction-registry/golem.yaml index c7a3ca0b61..b7cda62f1b 100644 --- a/test-components/auction-example/auction-registry/golem.yaml +++ b/test-components/auction-example/auction-registry/golem.yaml @@ -1,7 +1,7 @@ # Schema for IDEA: -# $schema: https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json # Schema for vscode-yaml -# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json components: auction-registry: diff --git a/test-components/auction-example/auction/golem.yaml b/test-components/auction-example/auction/golem.yaml index 6852fdd359..dd5ba8c541 100644 --- a/test-components/auction-example/auction/golem.yaml +++ b/test-components/auction-example/auction/golem.yaml @@ -1,7 +1,7 @@ # Schema for IDEA: -# $schema: https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json # Schema for vscode-yaml -# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json components: auction: diff --git a/test-components/auction-example/golem.yaml b/test-components/auction-example/golem.yaml index fc14644feb..5f051e3e6a 100644 --- a/test-components/auction-example/golem.yaml +++ b/test-components/auction-example/golem.yaml @@ -1,7 +1,7 @@ # Schema for IDEA: -# $schema: https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json # Schema for vscode-yaml -# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json tempDir: target/golem-temp templates: diff --git a/test-components/rpc/caller/golem.yaml b/test-components/rpc/caller/golem.yaml index 256d497f08..70bf7a944f 100644 --- a/test-components/rpc/caller/golem.yaml +++ b/test-components/rpc/caller/golem.yaml @@ -1,7 +1,7 @@ # Schema for IDEA: -# $schema: https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json # Schema for vscode-yaml -# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json components: caller: diff --git a/test-components/rpc/counters/golem.yaml b/test-components/rpc/counters/golem.yaml index 0ca0ef07eb..b3e6819c09 100644 --- a/test-components/rpc/counters/golem.yaml +++ b/test-components/rpc/counters/golem.yaml @@ -1,7 +1,7 @@ # Schema for IDEA: -# $schema: https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json # Schema for vscode-yaml -# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json components: counters: diff --git a/test-components/rpc/ephemeral/golem.yaml b/test-components/rpc/ephemeral/golem.yaml index 5484ccedf1..499373bd50 100644 --- a/test-components/rpc/ephemeral/golem.yaml +++ b/test-components/rpc/ephemeral/golem.yaml @@ -1,7 +1,7 @@ # Schema for IDEA: -# $schema: https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json # Schema for vscode-yaml -# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json components: ephemeral: diff --git a/test-components/rpc/golem.yaml b/test-components/rpc/golem.yaml index fc14644feb..5f051e3e6a 100644 --- a/test-components/rpc/golem.yaml +++ b/test-components/rpc/golem.yaml @@ -1,7 +1,7 @@ # Schema for IDEA: -# $schema: https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json # Schema for vscode-yaml -# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json tempDir: target/golem-temp templates: diff --git a/test-components/rust-service/rpc/child-component/golem.yaml b/test-components/rust-service/rpc/child-component/golem.yaml index dad604c8c0..04b3b06b2a 100644 --- a/test-components/rust-service/rpc/child-component/golem.yaml +++ b/test-components/rust-service/rpc/child-component/golem.yaml @@ -1,7 +1,7 @@ # Schema for IDEA: -# $schema: https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json # Schema for vscode-yaml -# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json components: child-component: diff --git a/test-components/rust-service/rpc/golem.yaml b/test-components/rust-service/rpc/golem.yaml index c579ae6dda..1019c8be30 100644 --- a/test-components/rust-service/rpc/golem.yaml +++ b/test-components/rust-service/rpc/golem.yaml @@ -1,7 +1,7 @@ # Schema for IDEA: -# $schema: https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json # Schema for vscode-yaml -# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json tempDir: target/golem-temp templates: diff --git a/test-components/rust-service/rpc/parent-component/golem.yaml b/test-components/rust-service/rpc/parent-component/golem.yaml index 86e960b83e..7d507d0c9e 100644 --- a/test-components/rust-service/rpc/parent-component/golem.yaml +++ b/test-components/rust-service/rpc/parent-component/golem.yaml @@ -1,7 +1,7 @@ # Schema for IDEA: -# $schema: https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json # Schema for vscode-yaml -# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json components: parent-component: diff --git a/test-components/ts-rpc/caller/golem.yaml b/test-components/ts-rpc/caller/golem.yaml index 375321e37d..e7ebfaacfc 100644 --- a/test-components/ts-rpc/caller/golem.yaml +++ b/test-components/ts-rpc/caller/golem.yaml @@ -1,7 +1,7 @@ # Schema for IDEA: -# $schema: https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json # Schema for vscode-yaml -# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json components: caller: diff --git a/test-components/ts-rpc/counter/golem.yaml b/test-components/ts-rpc/counter/golem.yaml index 5603d26bcb..bdd48e8e7b 100644 --- a/test-components/ts-rpc/counter/golem.yaml +++ b/test-components/ts-rpc/counter/golem.yaml @@ -1,7 +1,7 @@ # Schema for IDEA: -# $schema: https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json # Schema for vscode-yaml -# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json components: counter: diff --git a/test-components/ts-rpc/golem.yaml b/test-components/ts-rpc/golem.yaml index 0155947ee9..7d1960795e 100644 --- a/test-components/ts-rpc/golem.yaml +++ b/test-components/ts-rpc/golem.yaml @@ -1,7 +1,7 @@ # Schema for IDEA: -# $schema: https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json # Schema for vscode-yaml -# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.0/golem.schema.json +# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json tempDir: dist/golem-temp witDeps: diff --git a/wasm-rpc-stubgen/src/commands/app.rs b/wasm-rpc-stubgen/src/commands/app.rs index 6122735f7a..e2ea8185b2 100644 --- a/wasm-rpc-stubgen/src/commands/app.rs +++ b/wasm-rpc-stubgen/src/commands/app.rs @@ -20,6 +20,7 @@ use crate::wit_generate::{ use crate::wit_resolve::{ResolvedWitApplication, WitDepsResolver}; use crate::{commands, naming, WasmRpcOverride}; use anyhow::{anyhow, bail, Context, Error}; +use colored::control::SHOULD_COLORIZE; use colored::Colorize; use glob::{glob_with, MatchOptions}; use golem_wasm_rpc::WASM_RPC_VERSION; @@ -559,36 +560,128 @@ pub fn clean(config: Config) -> anyhow: Ok(()) } -// TODO: collect_custom_commands is not selected_component_names aware yet -pub fn collect_custom_commands( +pub fn print_dynamic_help( config: Config, -) -> anyhow::Result>> { - set_log_output(config.log_output); +) -> anyhow::Result<()> { + static LABEL_SOURCE: &str = "Source"; + static LABEL_SELECTED: &str = "Selected"; + static LABEL_TEMPLATE: &str = "Template"; + static LABEL_PROFILES: &str = "Profiles"; + static LABEL_DEPENDENCIES: &str = "Dependencies"; + + let label_padding = { + [ + &LABEL_SOURCE, + &LABEL_SELECTED, + &LABEL_TEMPLATE, + &LABEL_PROFILES, + &LABEL_DEPENDENCIES, + ] + .map(|label| label.len()) + .into_iter() + .max() + .unwrap_or(0) + + 1 + }; - let (app, _selected_component_names) = to_anyhow( - config.log_output, - "Failed to load application manifest(s), see problems above", - load_app(&config), - )?; + let print_field = |label: &'static str, value: String| { + println!(" {:>::new(); - for profile in &all_profiles { - for command in app.all_custom_commands(profile.as_ref()) { - if !commands.contains_key(command.as_str()) { - commands.insert(command.clone(), BTreeSet::new()); + match profile { + None => { + println!("{}", "Custom commands:".log_color_help_group()) + } + Some(profile) => { + println!( + "{}{}{}", + "Custom commands for ".log_color_help_group(), + profile.as_str().log_color_help_group(), + " profile:".log_color_help_group() + ) } - profile.iter().for_each(|profile| { - commands - .get_mut(command.as_str()) - .unwrap() - .insert(profile.clone()); - }); } + for command in commands { + println!(" {}", command.bold()) + } + println!() } - Ok(commands) + Ok(()) } pub fn custom_command( diff --git a/wasm-rpc-stubgen/src/lib.rs b/wasm-rpc-stubgen/src/lib.rs index 075d75a16f..2fe51bdf5c 100644 --- a/wasm-rpc-stubgen/src/lib.rs +++ b/wasm-rpc-stubgen/src/lib.rs @@ -33,8 +33,6 @@ use crate::stub::{StubConfig, StubDefinition}; use crate::wit_generate::UpdateCargoToml; use anyhow::Context; use clap::Subcommand; -use colored::Colorize; -use itertools::Itertools; use std::collections::HashSet; use std::marker::PhantomData; use std::path::PathBuf; @@ -194,7 +192,7 @@ pub struct App { #[derive(Subcommand, Debug)] pub enum AppSubCommand { - /// Runs component build steps + /// Run component build steps Build(AppBuildArgs), /// Clean outputs Clean, @@ -290,7 +288,7 @@ pub async fn run_app_command( None => { clap_command.print_help()?; println!(); - print_app_custom_commands_help(config); + print_dynamic_help(config); exit(2); } } @@ -336,34 +334,10 @@ fn app_manifest_sources_to_resolve_mode( } } -fn print_app_custom_commands_help( - mut config: commands::app::Config, -) { +fn print_dynamic_help(mut config: commands::app::Config) { config.log_output = Output::None; - match commands::app::collect_custom_commands(config) { - Ok(commands) => { - if !commands.is_empty() { - println!("{}", "Custom commands:".bold().underline()); - for (command, profiles) in commands { - if profiles.is_empty() { - println!(" {}", command); - } else { - println!( - " {} ({})", - command, - profiles.iter().map(|s| s.to_string()).join(", ") - ); - } - } - println!(); - } - } - Err(err) => { - println!( - "{}\n{:?}", - "Cannot show custom commands:".log_color_warn(), - err - ); - } + + if let Some(err) = commands::app::print_dynamic_help(config).err() { + println!("{}\n{}", "Cannot show dynamic help:".log_color_warn(), err); } } diff --git a/wasm-rpc-stubgen/src/log.rs b/wasm-rpc-stubgen/src/log.rs index b9f361758c..37b244b617 100644 --- a/wasm-rpc-stubgen/src/log.rs +++ b/wasm-rpc-stubgen/src/log.rs @@ -253,6 +253,10 @@ pub trait LogColorize { self.as_str().bold() } + fn log_color_help_group(&self) -> ColoredString { + self.as_str().bold().underline() + } + fn log_color_error_highlight(&self) -> ColoredString { self.as_str().bold().red().underline() } diff --git a/wasm-rpc-stubgen/src/model/app.rs b/wasm-rpc-stubgen/src/model/app.rs index a380eda3ec..bb9ea0e8e1 100644 --- a/wasm-rpc-stubgen/src/model/app.rs +++ b/wasm-rpc-stubgen/src/model/app.rs @@ -6,7 +6,7 @@ use crate::validation::{ValidatedResult, ValidationBuilder}; use crate::{fs, naming}; use serde::{Deserialize, Serialize}; use std::cmp::Ordering; -use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; +use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::fmt::Formatter; use std::fmt::{Debug, Display}; use std::hash::Hash; @@ -232,6 +232,10 @@ impl Application { self.components.keys() } + pub fn has_any_component(&self) -> bool { + !self.components.is_empty() + } + pub fn contains_component(&self, component_name: &ComponentName) -> bool { self.components.contains_key(component_name) } @@ -282,6 +286,36 @@ impl Application { custom_commands } + pub fn all_custom_commands_for_all_profiles( + &self, + ) -> BTreeMap, BTreeSet> { + let mut custom_commands = BTreeMap::, BTreeSet>::new(); + + custom_commands + .entry(None) + .or_default() + .extend(self.custom_commands.keys().cloned()); + + for profile in self.all_option_profiles() { + let profile_commands: &mut BTreeSet = { + if custom_commands.contains_key(&profile) { + custom_commands.get_mut(&profile).unwrap() + } else { + custom_commands.entry(profile.clone()).or_default() + } + }; + + profile_commands.extend(self.component_names().flat_map(|component_name| { + self.component_properties(component_name, profile.as_ref()) + .custom_commands + .keys() + .cloned() + })); + } + + custom_commands + } + pub fn temp_dir(&self) -> PathBuf { match self.temp_dir.as_ref() { Some(temp_dir) => temp_dir.source.as_path().join(&temp_dir.value), @@ -316,9 +350,9 @@ impl Application { .unwrap_or(&self.no_dependencies) } - fn component_profiles(&self, component_name: &ComponentName) -> HashSet { + pub fn component_profiles(&self, component_name: &ComponentName) -> BTreeSet { match &self.component(component_name).properties { - ResolvedComponentProperties::Properties { .. } => HashSet::new(), + ResolvedComponentProperties::Properties { .. } => BTreeSet::new(), ResolvedComponentProperties::Profiles { profiles, .. } => { profiles.keys().cloned().collect() }