Skip to main content

raps_cli/commands/da/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2024-2025 Dmytro Yemelianov
3
4//! Design Automation commands
5//!
6//! Commands for managing engines, app bundles, activities, and work items.
7
8mod activities;
9mod appbundles;
10mod engines;
11mod workitems;
12
13use std::collections::HashMap;
14use std::path::PathBuf;
15
16use anyhow::Result;
17use clap::Subcommand;
18use serde::Deserialize;
19
20use crate::output::OutputFormat;
21use raps_da::DesignAutomationClient;
22
23#[derive(Debug, Subcommand)]
24pub enum DaCommands {
25    /// List available engines
26    Engines,
27
28    /// List app bundles
29    Appbundles,
30
31    /// Create an app bundle
32    #[command(name = "appbundle-create")]
33    AppbundleCreate {
34        /// App bundle ID
35        #[arg(short, long)]
36        id: Option<String>,
37
38        /// Engine ID (e.g., Autodesk.AutoCAD+24)
39        #[arg(short, long)]
40        engine: Option<String>,
41
42        /// Description
43        #[arg(short, long)]
44        description: Option<String>,
45    },
46
47    /// Delete an app bundle
48    #[command(name = "appbundle-delete")]
49    AppbundleDelete {
50        /// App bundle ID to delete
51        id: String,
52    },
53
54    /// Upload a .zip archive for an app bundle
55    #[command(name = "appbundle-upload")]
56    AppbundleUpload {
57        /// App bundle ID (must already exist -- use appbundle-create first)
58        id: String,
59
60        /// Path to the .zip archive to upload
61        #[arg(short, long)]
62        file: PathBuf,
63
64        /// Engine ID (e.g., Autodesk.AutoCAD+24)
65        #[arg(short, long)]
66        engine: String,
67
68        /// Description for the new version
69        #[arg(short, long)]
70        description: Option<String>,
71    },
72
73    /// List activities
74    Activities,
75
76    /// Create an activity from JSON or YAML definition
77    #[command(name = "activity-create")]
78    ActivityCreate {
79        /// Path to JSON or YAML activity definition file (use `-` for stdin, parsed as YAML)
80        #[arg(short, long)]
81        file: Option<PathBuf>,
82
83        /// Activity ID (required if not using --file)
84        #[arg(long)]
85        id: Option<String>,
86
87        /// Engine ID (required if not using --file)
88        #[arg(long)]
89        engine: Option<String>,
90
91        /// App bundle ID to use (required if not using --file)
92        #[arg(long)]
93        appbundle: Option<String>,
94
95        /// Command line (required if not using --file)
96        #[arg(long)]
97        command: Option<String>,
98
99        /// Description
100        #[arg(long)]
101        description: Option<String>,
102    },
103
104    /// Delete an activity
105    #[command(name = "activity-delete")]
106    ActivityDelete {
107        /// Activity ID to delete
108        id: String,
109    },
110
111    /// Submit a work item to run an activity
112    #[command(name = "run")]
113    Run {
114        /// Activity ID (fully qualified, e.g., owner.activity+alias)
115        activity: String,
116
117        /// Input arguments as key=value pairs (use @file.dwg for file inputs)
118        #[arg(short, long, value_parser = parse_argument)]
119        input: Vec<(String, String)>,
120
121        /// Output arguments as key=value pairs (local file paths)
122        #[arg(long = "out-arg", value_parser = parse_argument)]
123        out_arg: Vec<(String, String)>,
124
125        /// Wait for completion and download results
126        #[arg(short, long)]
127        wait: bool,
128    },
129
130    /// List recent workitems
131    Workitems,
132
133    /// Check work item status
134    Status {
135        /// Work item ID
136        workitem_id: String,
137
138        /// Wait for completion
139        #[arg(short, long)]
140        wait: bool,
141
142        /// Download outputs on completion
143        #[arg(short, long)]
144        download: bool,
145
146        /// Output directory for downloads
147        #[arg(long)]
148        output_dir: Option<PathBuf>,
149    },
150}
151
152/// Parse key=value argument pairs
153fn parse_argument(s: &str) -> Result<(String, String), String> {
154    let parts: Vec<&str> = s.splitn(2, '=').collect();
155    if parts.len() != 2 {
156        return Err(format!("Invalid argument format '{}'. Use key=value", s));
157    }
158    Ok((parts[0].to_string(), parts[1].to_string()))
159}
160
161/// Activity definition structure for JSON/YAML parsing
162#[derive(Debug, Clone, Deserialize)]
163#[serde(rename_all = "camelCase")]
164pub(super) struct ActivityDefinition {
165    pub(super) id: String,
166    pub(super) engine: String,
167    #[serde(default)]
168    pub(super) command_line: Vec<String>,
169    #[serde(default)]
170    pub(super) app_bundles: Vec<String>,
171    #[serde(default)]
172    pub(super) parameters: HashMap<String, ParameterDefinition>,
173    pub(super) description: Option<String>,
174}
175
176#[derive(Debug, Clone, Deserialize)]
177#[serde(rename_all = "camelCase")]
178pub(super) struct ParameterDefinition {
179    pub(super) verb: String,
180    pub(super) local_name: Option<String>,
181    pub(super) description: Option<String>,
182    pub(super) required: Option<bool>,
183    pub(super) zip: Option<bool>,
184}
185
186impl DaCommands {
187    pub async fn execute(
188        self,
189        client: &DesignAutomationClient,
190        output_format: OutputFormat,
191    ) -> Result<()> {
192        match self {
193            DaCommands::Engines => engines::list_engines(client, output_format).await,
194            DaCommands::Appbundles => appbundles::list_appbundles(client, output_format).await,
195            DaCommands::AppbundleCreate {
196                id,
197                engine,
198                description,
199            } => appbundles::create_appbundle(client, id, engine, description, output_format).await,
200            DaCommands::AppbundleDelete { id } => {
201                appbundles::delete_appbundle(client, &id, output_format).await
202            }
203            DaCommands::AppbundleUpload {
204                id,
205                file,
206                engine,
207                description,
208            } => {
209                appbundles::upload_appbundle(
210                    client,
211                    &id,
212                    &file,
213                    &engine,
214                    description,
215                    output_format,
216                )
217                .await
218            }
219            DaCommands::Activities => activities::list_activities(client, output_format).await,
220            DaCommands::ActivityCreate {
221                file,
222                id,
223                engine,
224                appbundle,
225                command,
226                description,
227            } => {
228                activities::create_activity(
229                    client,
230                    file,
231                    id,
232                    engine,
233                    appbundle,
234                    command,
235                    description,
236                    output_format,
237                )
238                .await
239            }
240            DaCommands::ActivityDelete { id } => {
241                activities::delete_activity(client, &id, output_format).await
242            }
243            DaCommands::Workitems => workitems::list_workitems(client, output_format).await,
244            DaCommands::Run {
245                activity,
246                input,
247                out_arg,
248                wait,
249            } => {
250                workitems::run_workitem(client, &activity, input, out_arg, wait, output_format)
251                    .await
252            }
253            DaCommands::Status {
254                workitem_id,
255                wait,
256                download,
257                output_dir,
258            } => {
259                workitems::check_status(
260                    client,
261                    &workitem_id,
262                    wait,
263                    download,
264                    output_dir,
265                    output_format,
266                )
267                .await
268            }
269        }
270    }
271}