mecha10_cli/
paths.rs

1//! Centralized path definitions for the CLI
2//!
3//! All hardcoded paths should be defined here to ensure consistency
4//! and make it easy to update paths across the codebase.
5//!
6//! # Organization
7//!
8//! - **Project paths**: Paths relative to project root (mecha10.json location)
9//! - **User paths**: Paths in user's home directory (~/.mecha10)
10//! - **Docker paths**: Paths used inside Docker containers
11//! - **Framework paths**: Paths within the mecha10 framework source
12
13// Allow dead code during migration - paths will be used incrementally
14#![allow(dead_code)]
15
16use std::path::{Path, PathBuf};
17
18// =============================================================================
19// Project Structure - Paths relative to project root
20// =============================================================================
21
22/// Project configuration file
23pub const PROJECT_CONFIG: &str = "mecha10.json";
24
25/// Project directories
26pub mod project {
27    /// Node source code directory
28    pub const NODES_DIR: &str = "nodes";
29
30    /// Driver source code directory
31    pub const DRIVERS_DIR: &str = "drivers";
32
33    /// Types directory
34    pub const TYPES_DIR: &str = "types";
35
36    /// Behavior trees directory
37    pub const BEHAVIORS_DIR: &str = "behaviors";
38
39    /// Assets directory
40    pub const ASSETS_DIR: &str = "assets";
41
42    /// Assets images subdirectory
43    pub const ASSETS_IMAGES_DIR: &str = "assets/images";
44
45    /// Models directory (ONNX models, etc.)
46    pub const MODELS_DIR: &str = "models";
47
48    /// Logs directory
49    pub const LOGS_DIR: &str = "logs";
50
51    /// Simulation directory
52    pub const SIMULATION_DIR: &str = "simulation";
53
54    /// Simulation models directory
55    pub const SIMULATION_MODELS_DIR: &str = "simulation/models";
56
57    /// Simulation environments directory
58    pub const SIMULATION_ENVIRONMENTS_DIR: &str = "simulation/environments";
59
60    /// Get path to a model's config file
61    pub fn model_config(model_name: &str) -> String {
62        format!("simulation/models/{}/model.json", model_name)
63    }
64
65    /// Get path to an environment's config file
66    pub fn environment_config(env_name: &str) -> String {
67        format!("simulation/environments/{}/environment.json", env_name)
68    }
69
70    /// Simulation Godot project directory
71    pub const SIMULATION_GODOT_DIR: &str = "simulation/godot";
72
73    /// Cargo build target directory
74    pub const TARGET_DIR: &str = "target";
75
76    /// Source directory
77    pub const SRC_DIR: &str = "src";
78}
79
80/// Configuration paths within project
81pub mod config {
82    /// Base configs directory
83    pub const DIR: &str = "configs";
84
85    /// Node configs base directory
86    pub const NODES_DIR: &str = "configs/nodes";
87
88    /// Framework node configs (@mecha10 scope)
89    pub const NODES_MECHA10_DIR: &str = "configs/nodes/@mecha10";
90
91    /// Local node configs (@local scope)
92    pub const NODES_LOCAL_DIR: &str = "configs/nodes/@local";
93
94    /// Simulation configs directory
95    pub const SIMULATION_DIR: &str = "configs/simulation";
96
97    /// Simulation config file
98    pub const SIMULATION_CONFIG: &str = "configs/simulation/config.json";
99
100    /// Get config path for a framework node
101    pub fn framework_node(node_name: &str) -> String {
102        format!("configs/nodes/@mecha10/{}/config.json", node_name)
103    }
104
105    /// Get config path for a local node
106    pub fn local_node(node_name: &str) -> String {
107        format!("configs/nodes/@local/{}/config.json", node_name)
108    }
109
110    /// Get config path for a project node (plain name)
111    pub fn project_node(node_name: &str) -> String {
112        format!("configs/nodes/{}/config.json", node_name)
113    }
114}
115
116/// Docker-related paths within project
117pub mod docker {
118    /// Docker directory
119    pub const DIR: &str = "docker";
120
121    /// Main docker-compose file
122    pub const COMPOSE_FILE: &str = "docker/docker-compose.yml";
123
124    /// Remote nodes docker-compose file
125    pub const COMPOSE_REMOTE_FILE: &str = "docker/docker-compose.remote.yml";
126
127    /// Remote nodes Dockerfile
128    pub const DOCKERFILE_REMOTE: &str = "docker/Dockerfile.remote";
129}
130
131/// Environment files
132pub mod env {
133    /// Environment example file
134    pub const EXAMPLE: &str = ".env.example";
135
136    /// Environment file
137    pub const FILE: &str = ".env";
138}
139
140/// Meta files (README, gitignore, etc.)
141pub mod meta {
142    /// README file
143    pub const README: &str = "README.md";
144
145    /// Git ignore file
146    pub const GITIGNORE: &str = ".gitignore";
147
148    /// Package.json for Node.js tooling
149    pub const PACKAGE_JSON: &str = "package.json";
150
151    /// Python requirements
152    pub const REQUIREMENTS_TXT: &str = "requirements.txt";
153
154    /// Lint config
155    pub const LS_LINT_CONFIG: &str = ".ls-lint.yml";
156}
157
158/// Rust project files
159pub mod rust {
160    /// Cargo workspace manifest
161    pub const CARGO_TOML: &str = "Cargo.toml";
162
163    /// Cargo lock file
164    pub const CARGO_LOCK: &str = "Cargo.lock";
165
166    /// Main entry point
167    pub const MAIN_RS: &str = "src/main.rs";
168
169    /// Library entry point
170    pub const LIB_RS: &str = "src/lib.rs";
171
172    /// Build script
173    pub const BUILD_RS: &str = "build.rs";
174
175    /// Rustfmt config
176    pub const RUSTFMT_TOML: &str = "rustfmt.toml";
177
178    /// Cargo config directory
179    pub const CARGO_CONFIG_DIR: &str = ".cargo";
180
181    /// Cargo config file
182    pub const CARGO_CONFIG: &str = ".cargo/config.toml";
183}
184
185/// Model files within a model directory
186pub mod model {
187    /// ONNX model file
188    pub const ONNX_FILE: &str = "model.onnx";
189
190    /// Labels file
191    pub const LABELS_FILE: &str = "labels.txt";
192
193    /// Model config file
194    pub const CONFIG_FILE: &str = "config.json";
195}
196
197// =============================================================================
198// User Home Paths - Paths in ~/.mecha10
199// =============================================================================
200
201/// User-level paths in home directory
202pub mod user {
203    use std::path::PathBuf;
204
205    /// Base mecha10 directory in user home
206    pub const MECHA10_DIR: &str = ".mecha10";
207
208    /// Credentials file
209    pub const CREDENTIALS_FILE: &str = ".mecha10/credentials.json";
210
211    /// Templates cache directory
212    pub const TEMPLATES_DIR: &str = ".mecha10/templates";
213
214    /// Simulation assets cache directory
215    pub const SIMULATION_DIR: &str = ".mecha10/simulation";
216
217    /// Current simulation assets symlink
218    pub const SIMULATION_CURRENT: &str = ".mecha10/simulation/current";
219
220    /// Simulation version file
221    pub const SIMULATION_VERSION: &str = ".mecha10/simulation/version";
222
223    /// Binary installation directory
224    pub const BIN_DIR: &str = ".mecha10/bin";
225
226    /// Get the base mecha10 directory path
227    pub fn mecha10_dir() -> PathBuf {
228        dirs::home_dir()
229            .unwrap_or_else(|| PathBuf::from("."))
230            .join(MECHA10_DIR)
231    }
232
233    /// Get the credentials file path
234    pub fn credentials_file() -> PathBuf {
235        dirs::home_dir()
236            .unwrap_or_else(|| PathBuf::from("."))
237            .join(CREDENTIALS_FILE)
238    }
239
240    /// Get the templates cache directory
241    pub fn templates_dir() -> PathBuf {
242        mecha10_dir().join("templates")
243    }
244
245    /// Get the simulation assets directory
246    pub fn simulation_dir() -> PathBuf {
247        mecha10_dir().join("simulation")
248    }
249
250    /// Get the current simulation assets path
251    pub fn simulation_current() -> PathBuf {
252        mecha10_dir().join("simulation/current")
253    }
254
255    /// Get the binary directory
256    pub fn bin_dir() -> PathBuf {
257        mecha10_dir().join("bin")
258    }
259
260    /// Get path to a binary in the mecha10 bin directory
261    pub fn bin(name: &str) -> PathBuf {
262        bin_dir().join(name)
263    }
264
265    /// Get path to a binary in cargo bin directory
266    pub fn cargo_bin(name: &str) -> PathBuf {
267        dirs::home_dir()
268            .unwrap_or_else(|| PathBuf::from("."))
269            .join(".cargo/bin")
270            .join(name)
271    }
272
273    /// Get path to a binary in local bin directory
274    pub fn local_bin(name: &str) -> PathBuf {
275        dirs::home_dir()
276            .unwrap_or_else(|| PathBuf::from("."))
277            .join(".local/bin")
278            .join(name)
279    }
280}
281
282// =============================================================================
283// Docker Container Paths - Paths used inside containers
284// =============================================================================
285
286/// Paths used inside Docker containers
287pub mod container {
288    /// Project mount point in container
289    pub const PROJECT_ROOT: &str = "/project";
290
291    /// Framework mount point in container
292    pub const FRAMEWORK_ROOT: &str = "/mecha10";
293
294    /// App directory (for mecha10-remote)
295    pub const APP_ROOT: &str = "/app";
296
297    /// Config file in mecha10-remote container
298    pub const REMOTE_CONFIG: &str = "/app/mecha10.json";
299
300    /// Framework Godot project path (new structure)
301    pub const FRAMEWORK_GODOT_PROJECT: &str = "/mecha10/packages/simulation/godot-project";
302
303    /// Framework Godot project path (legacy)
304    pub const FRAMEWORK_GODOT_PROJECT_LEGACY: &str = "/mecha10/godot-project";
305
306    /// Get project-relative path inside container
307    pub fn project_path(relative: &str) -> String {
308        format!("{}/{}", PROJECT_ROOT, relative)
309    }
310
311    /// Get framework-relative path inside container
312    pub fn framework_path(relative: &str) -> String {
313        format!("{}/{}", FRAMEWORK_ROOT, relative)
314    }
315}
316
317// =============================================================================
318// Framework Paths - Paths within mecha10 framework source
319// =============================================================================
320
321/// Paths within the mecha10 framework source
322pub mod framework {
323    /// Packages directory
324    pub const PACKAGES_DIR: &str = "packages";
325
326    /// Nodes package directory
327    pub const NODES_DIR: &str = "packages/nodes";
328
329    /// Drivers package directory
330    pub const DRIVERS_DIR: &str = "packages/drivers";
331
332    /// Services package directory
333    pub const SERVICES_DIR: &str = "packages/services";
334
335    /// Simulation package directory
336    pub const SIMULATION_DIR: &str = "packages/simulation";
337
338    /// Simulation Godot project
339    pub const SIMULATION_GODOT_DIR: &str = "packages/simulation/godot-project";
340
341    /// Simulation models directory
342    pub const SIMULATION_MODELS_DIR: &str = "packages/simulation/models";
343
344    /// Simulation environments directory
345    pub const SIMULATION_ENVIRONMENTS_DIR: &str = "packages/simulation/environments";
346
347    /// Robot tasks environments directory (for environment matching)
348    pub const ROBOT_TASKS_DIR: &str = "packages/simulation/environments/robot-tasks";
349
350    /// Robot tasks catalog file
351    pub const ROBOT_TASKS_CATALOG: &str = "packages/simulation/environments/robot-tasks/catalog.json";
352
353    /// Python taskrunner package
354    pub const TASKRUNNER_DIR: &str = "packages/taskrunner";
355
356    /// Release binary
357    pub const RELEASE_BINARY: &str = "target/release/mecha10";
358
359    /// Debug binary
360    pub const DEBUG_BINARY: &str = "target/debug/mecha10";
361
362    /// Node runner release binary
363    pub const NODE_RUNNER_RELEASE: &str = "target/release/mecha10-node-runner";
364
365    /// Node runner debug binary
366    pub const NODE_RUNNER_DEBUG: &str = "target/debug/mecha10-node-runner";
367
368    /// Get node package path
369    pub fn node_package(node_name: &str) -> String {
370        format!("packages/nodes/{}", node_name)
371    }
372
373    /// Get node config path within framework
374    pub fn node_config(node_name: &str) -> String {
375        format!("packages/nodes/{}/configs/config.json", node_name)
376    }
377
378    /// Get node lib.rs path within framework
379    pub fn node_lib_rs(node_name: &str) -> String {
380        format!("packages/nodes/{}/src/lib.rs", node_name)
381    }
382}
383
384// =============================================================================
385// External URLs
386// =============================================================================
387
388/// External service URLs
389pub mod urls {
390    /// GitHub repository for user-tools (templates, assets)
391    pub const USER_TOOLS_REPO: &str = "mecha-industries/user-tools";
392
393    /// Remote image manifest URL
394    pub const REMOTE_MANIFEST: &str =
395        "https://raw.githubusercontent.com/laboratory-one/user-tools/main/mecha10-remote/manifest.json";
396
397    /// Default authentication URL
398    pub const AUTH_URL: &str = "https://mecha.industries/api/auth";
399}
400
401// =============================================================================
402// Helper Functions
403// =============================================================================
404
405/// Build a target output path
406pub fn target_path(profile: &str, binary: &str) -> String {
407    format!("target/{}/{}", profile, binary)
408}
409
410/// Build a target output path with optional target triple
411pub fn target_path_with_triple(target: Option<&str>, profile: &str) -> String {
412    match target {
413        Some(t) => format!("target/{}/{}", t, profile),
414        None => format!("target/{}", profile),
415    }
416}
417
418/// Get the project root by finding mecha10.json
419pub fn find_project_root(start: &Path) -> Option<PathBuf> {
420    let mut current = start.to_path_buf();
421    loop {
422        if current.join(PROJECT_CONFIG).exists() {
423            return Some(current);
424        }
425        if !current.pop() {
426            return None;
427        }
428    }
429}
430
431/// Check if a directory is a mecha10 project
432pub fn is_project_dir(dir: &Path) -> bool {
433    dir.join(PROJECT_CONFIG).exists()
434}
435
436#[cfg(test)]
437mod tests {
438    use super::*;
439
440    #[test]
441    fn test_config_paths() {
442        assert_eq!(
443            config::framework_node("object-detector"),
444            "configs/nodes/@mecha10/object-detector/config.json"
445        );
446        assert_eq!(
447            config::local_node("my-node"),
448            "configs/nodes/@local/my-node/config.json"
449        );
450        assert_eq!(
451            config::project_node("camera"),
452            "configs/nodes/camera/config.json"
453        );
454    }
455
456    #[test]
457    fn test_target_path() {
458        assert_eq!(target_path("release", "my-node"), "target/release/my-node");
459        assert_eq!(
460            target_path_with_triple(Some("aarch64-unknown-linux-gnu"), "release"),
461            "target/aarch64-unknown-linux-gnu/release"
462        );
463        assert_eq!(target_path_with_triple(None, "debug"), "target/debug");
464    }
465
466    #[test]
467    fn test_container_paths() {
468        assert_eq!(
469            container::project_path("configs/test.json"),
470            "/project/configs/test.json"
471        );
472        assert_eq!(
473            container::framework_path("packages/core"),
474            "/mecha10/packages/core"
475        );
476    }
477}