1use super::{RunOpts, handle_run_command};
3use crate::settings::Settings;
4use anyhow::{Context, Result, ensure};
5use clap::Subcommand;
6use include_dir::{Dir, DirEntry, include_dir};
7use std::fs;
8use std::path::{Path, PathBuf};
9use tempfile::TempDir;
10
11const EXAMPLES_DIR: Dir = include_dir!("examples");
13
14#[derive(Subcommand)]
16pub enum ExampleSubcommands {
17 List,
19 Info {
21 name: String,
23 },
24 Extract {
26 name: String,
28 new_path: Option<PathBuf>,
30 },
31 Run {
33 name: String,
35 #[command(flatten)]
37 opts: RunOpts,
38 },
39}
40
41impl ExampleSubcommands {
42 pub fn execute(self) -> Result<()> {
44 match self {
45 Self::List => handle_example_list_command(),
46 Self::Info { name } => handle_example_info_command(&name)?,
47 Self::Extract {
48 name,
49 new_path: dest,
50 } => handle_example_extract_command(&name, dest.as_deref())?,
51 Self::Run { name, opts } => handle_example_run_command(&name, &opts, None)?,
52 }
53
54 Ok(())
55 }
56}
57
58fn handle_example_list_command() {
60 for entry in EXAMPLES_DIR.dirs() {
61 println!("{}", entry.path().display());
62 }
63}
64
65fn handle_example_info_command(name: &str) -> Result<()> {
67 let path: PathBuf = [name, "README.txt"].iter().collect();
68 let readme = EXAMPLES_DIR
69 .get_file(path)
70 .context("Example not found.")?
71 .contents_utf8()
72 .expect("README.txt is not UTF-8 encoded");
73
74 print!("{readme}");
75
76 Ok(())
77}
78
79fn handle_example_extract_command(name: &str, dest: Option<&Path>) -> Result<()> {
81 let dest = dest.unwrap_or(Path::new(name));
82 extract_example(name, dest)
83}
84
85fn extract_example(name: &str, new_path: &Path) -> Result<()> {
87 let sub_dir = EXAMPLES_DIR.get_dir(name).context("Example not found.")?;
89
90 ensure!(
91 !new_path.exists(),
92 "Destination directory {} already exists",
93 new_path.display()
94 );
95
96 fs::create_dir(new_path)?;
98 for entry in sub_dir.entries() {
99 match entry {
100 DirEntry::Dir(_) => panic!("Subdirectories in examples not supported"),
101 DirEntry::File(f) => {
102 let file_name = f.path().file_name().unwrap();
103 let file_path = new_path.join(file_name);
104 fs::write(&file_path, f.contents())?;
105 }
106 }
107 }
108
109 Ok(())
110}
111
112pub fn handle_example_run_command(
114 name: &str,
115 opts: &RunOpts,
116 settings: Option<Settings>,
117) -> Result<()> {
118 let temp_dir = TempDir::new().context("Failed to create temporary directory.")?;
119 let model_path = temp_dir.path().join(name);
120 extract_example(name, &model_path)?;
121 handle_run_command(&model_path, opts, settings)
122}