Skip to content

Commit 35037a3

Browse files
authored
Improve showcases (#159)
* bazel: fix rust_analyzer support - update targets - add config * showcases: use kyron public examples * showcases: add graceful exit - apply formatting * showcases: add cli - parse selected showcases - `all` to run all showcases
1 parent e6b41d3 commit 35037a3

6 files changed

Lines changed: 104 additions & 47 deletions

File tree

bazel_common/score_modules_target_sw.MODULE.bazel

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,14 @@ bazel_dep(name = "score_orchestrator")
5454
git_override(
5555
module_name = "score_orchestrator",
5656
remote = "https://github.com/eclipse-score/orchestrator.git",
57-
commit = "675007a2baa226fad1e2979ed732360dc111d056",
57+
commit = "600fdd8186305ffbf495e4fc788195c077de79ac",
5858
)
5959

6060
bazel_dep(name = "score_kyron")
6161
git_override(
6262
module_name = "score_kyron",
6363
remote = "https://github.com/eclipse-score/kyron.git",
64-
commit = "d4d0afc1dd733a0c8a4aba9cc2b2b3a58d38ebf6",
64+
commit = "5acfb1a593ec65cf4f64424f581c6ddd04813ee7",
6565
)
6666

6767
bazel_dep(name = "score_lifecycle_health")

known_good.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
},
6565
"score_orchestrator": {
6666
"repo": "https://github.com/eclipse-score/orchestrator.git",
67-
"hash": "675007a2baa226fad1e2979ed732360dc111d056",
67+
"hash": "600fdd8186305ffbf495e4fc788195c077de79ac",
6868
"metadata": {
6969
"code_root_path": "//src/...",
7070
"langs": [
@@ -74,7 +74,7 @@
7474
},
7575
"score_kyron": {
7676
"repo": "https://github.com/eclipse-score/kyron.git",
77-
"hash": "d4d0afc1dd733a0c8a4aba9cc2b2b3a58d38ebf6",
77+
"hash": "5acfb1a593ec65cf4f64424f581c6ddd04813ee7",
7878
"metadata": {
7979
"code_root_path": "//src/...",
8080
"langs": [

scripts/generate_rust_analyzer_support.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@
33
set -e
44

55
# Manual targets are not take into account, must be set explicitly
6-
bazel run @rules_rust//tools/rust_analyzer:gen_rust_project -- "@//feature_showcase/..." "@//feature_integration_tests/rust_test_scenarios:rust_test_scenarios"
6+
bazel run @rules_rust//tools/rust_analyzer:gen_rust_project -- \
7+
"@//showcases/..." \
8+
"@//feature_integration_tests/test_scenarios/rust/..." \
9+
--config=linux-x86_64

showcases/cli/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ rust_binary(
1717
name = "cli",
1818
srcs = ["main.rs"],
1919
deps = [
20+
"@score_crates//:clap",
2021
"@score_crates//:cliclack",
2122
"@score_crates//:serde",
2223
"@score_crates//:serde_json",

showcases/cli/main.rs

Lines changed: 94 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
use anyhow::{Context, Result};
2+
use clap::Parser;
23
use serde::Deserialize;
3-
use std::{
4-
collections::HashMap,
5-
env, fs,
6-
path::Path,
7-
};
4+
use std::{collections::HashMap, env, fs, path::Path};
85

9-
use cliclack::{clear_screen, intro, multiselect, outro, confirm};
10-
use std::time::Duration;
11-
use std::process::Command;
6+
use cliclack::{clear_screen, confirm, intro, multiselect, outro};
127
use std::process::Child;
8+
use std::process::Command;
9+
use std::time::Duration;
10+
11+
#[derive(Parser)]
12+
#[command(name = "SCORE CLI")]
13+
#[command(about = "SCORE CLI showcase entrypoint", long_about = None)]
14+
struct Args {
15+
/// Examples to run (comma-separated names, or "all" to run all examples, skips interactive selection)
16+
#[arg(long)]
17+
examples: Option<String>,
18+
}
1319

1420
#[derive(Debug, Deserialize, Clone)]
1521
struct AppConfig {
@@ -30,7 +36,7 @@ struct ScoreConfig {
3036
fn print_banner() {
3137
let color_code = "\x1b[38;5;99m";
3238
let reset_code = "\x1b[0m";
33-
39+
3440
let banner = r#"
3541
███████╗ ██████╗ ██████╗ ██████╗ ███████╗
3642
██╔════╝ ██╔════╝██╔═══██╗██╔══██╗██╔════╝
@@ -39,26 +45,25 @@ fn print_banner() {
3945
███████║ ╚██████╗╚██████╔╝██║ ██║███████╗
4046
╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝
4147
"#;
42-
48+
4349
println!("{}{}{}", color_code, banner, reset_code);
4450
}
4551

4652
fn pause_for_enter() -> Result<()> {
47-
confirm("Press Enter to select examples to run...")
53+
let result = confirm("Do you want to select examples to run?")
4854
.initial_value(true)
4955
.interact()?;
56+
if !result {
57+
outro("Falling back to the console. Goodbye!")?;
58+
std::process::exit(0);
59+
}
5060
Ok(())
5161
}
5262

5363
fn main() -> Result<()> {
54-
print_banner();
55-
intro("WELCOME TO SHOWCASE ENTRYPOINT")?;
56-
pause_for_enter()?;
64+
let args = Args::parse();
5765

58-
clear_screen()?;
59-
60-
let root_dir = env::var("SCORE_CLI_INIT_DIR")
61-
.unwrap_or_else(|_| "/showcases".to_string());
66+
let root_dir = env::var("SCORE_CLI_INIT_DIR").unwrap_or_else(|_| "/showcases".to_string());
6267

6368
let mut configs = Vec::new();
6469
visit_dir(Path::new(&root_dir), &mut configs)?;
@@ -67,50 +72,93 @@ fn main() -> Result<()> {
6772
anyhow::bail!("No *.score.json files found under {}", root_dir);
6873
}
6974

70-
// Create options for multiselect
71-
let options: Vec<(usize, String, String)> = configs
72-
.iter()
73-
.enumerate()
74-
.map(|(i, c)| (i, c.name.clone(), c.description.clone()))
75-
.collect();
75+
let selected = if let Some(examples_str) = args.examples {
76+
// Non-interactive mode: use provided examples
77+
let mut selected_indices = Vec::new();
78+
79+
if examples_str.to_lowercase() == "all" {
80+
// Select all available examples
81+
selected_indices = (0..configs.len()).collect();
82+
println!("Running all {} examples", configs.len());
83+
} else {
84+
// Match specific examples
85+
let requested_examples: Vec<&str> = examples_str.split(',').map(|s| s.trim()).collect();
86+
87+
for (i, config) in configs.iter().enumerate() {
88+
if requested_examples.contains(&config.name.as_str()) {
89+
selected_indices.push(i);
90+
}
91+
}
92+
93+
if selected_indices.is_empty() {
94+
anyhow::bail!(
95+
"No examples found matching: {}. Available examples: {}",
96+
examples_str,
97+
configs
98+
.iter()
99+
.map(|c| c.name.as_str())
100+
.collect::<Vec<_>>()
101+
.join(", ")
102+
);
103+
}
76104

77-
let selected: Vec<usize> = multiselect("Select examples to run (use space to select (multiselect supported), enter to run examples):")
78-
.items(&options)
79-
.interact()?;
105+
println!("Running examples: {}", examples_str);
106+
}
80107

81-
if selected.is_empty() {
82-
outro("No examples selected. Goodbye!")?;
83-
return Ok(());
84-
}
108+
selected_indices
109+
} else {
110+
// Interactive mode
111+
print_banner();
112+
intro("WELCOME TO SHOWCASE ENTRYPOINT")?;
113+
pause_for_enter()?;
114+
115+
clear_screen()?;
116+
117+
// Create options for multiselect
118+
let options: Vec<(usize, String, String)> = configs
119+
.iter()
120+
.enumerate()
121+
.map(|(i, c)| (i, c.name.clone(), c.description.clone()))
122+
.collect();
123+
124+
let selected: Vec<usize> = multiselect("Select examples to run (use space to select (multiselect supported), enter to run examples):")
125+
.items(&options)
126+
.interact()?;
127+
128+
if selected.is_empty() {
129+
outro("No examples selected. Goodbye!")?;
130+
return Ok(());
131+
}
132+
133+
selected
134+
};
85135

86136
for index in selected {
87137
run_score(&configs[index])?;
88138
}
89139

90140
outro("All done!")?;
91-
141+
92142
Ok(())
93143
}
94144

95145
fn visit_dir(dir: &Path, configs: &mut Vec<ScoreConfig>) -> Result<()> {
96-
for entry in fs::read_dir(dir)
97-
.with_context(|| format!("Failed to read directory {:?}", dir))?
98-
{
146+
for entry in fs::read_dir(dir).with_context(|| format!("Failed to read directory {:?}", dir))? {
99147
let entry = entry?;
100148
let path = entry.path();
101-
149+
102150
if path.is_symlink() {
103151
continue;
104152
}
105-
153+
106154
if path.is_dir() {
107155
visit_dir(&path, configs)?;
108156
continue;
109157
}
110-
158+
111159
if is_score_file(&path) {
112-
let content = fs::read_to_string(&path)
113-
.with_context(|| format!("Failed reading {:?}", path))?;
160+
let content =
161+
fs::read_to_string(&path).with_context(|| format!("Failed reading {:?}", path))?;
114162
let value: serde_json::Value = serde_json::from_str(&content)
115163
.with_context(|| format!("Invalid JSON in {:?}", path))?;
116164
if value.is_array() {
@@ -146,7 +194,12 @@ fn run_score(config: &ScoreConfig) -> Result<()> {
146194

147195
if let Some(delay_secs) = app.delay {
148196
if delay_secs > 0 {
149-
println!("{:?} App {}: waiting {} seconds before start...", now.elapsed(), i + 1, delay_secs);
197+
println!(
198+
"{:?} App {}: waiting {} seconds before start...",
199+
now.elapsed(),
200+
i + 1,
201+
delay_secs
202+
);
150203
std::thread::sleep(Duration::from_secs(delay_secs));
151204
}
152205
}

showcases/standalone/BUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ score_pkg_bundle(
1616
score_pkg_bundle(
1717
name = "kyron",
1818
package_dir = "standalone",
19-
bins = ["@score_kyron//src/kyron:select", "@score_kyron//src/kyron:safety_task", "@score_kyron//src/kyron:main_macro"], # TODO: kyron shall have public examples in examples folder
19+
bins = ["@score_kyron//examples:select", "@score_kyron//examples:safety_task", "@score_kyron//examples:main_macro"],
2020

2121
config_data = [
2222
"//showcases/standalone:kyron.score.json",

0 commit comments

Comments
 (0)