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    /// Robot builder Dockerfile (for cross-compilation)
131    pub const DOCKERFILE_ROBOT_BUILDER: &str = "docker/robot-builder.Dockerfile";
132}
133
134/// Environment files
135pub mod env {
136    /// Environment example file
137    pub const EXAMPLE: &str = ".env.example";
138
139    /// Environment file
140    pub const FILE: &str = ".env";
141}
142
143/// Meta files (README, gitignore, etc.)
144pub mod meta {
145    /// README file
146    pub const README: &str = "README.md";
147
148    /// Git ignore file
149    pub const GITIGNORE: &str = ".gitignore";
150
151    /// Package.json for Node.js tooling
152    pub const PACKAGE_JSON: &str = "package.json";
153
154    /// Python requirements
155    pub const REQUIREMENTS_TXT: &str = "requirements.txt";
156
157    /// Lint config
158    pub const LS_LINT_CONFIG: &str = ".ls-lint.yml";
159}
160
161/// Rust project files
162pub mod rust {
163    /// Cargo workspace manifest
164    pub const CARGO_TOML: &str = "Cargo.toml";
165
166    /// Cargo lock file
167    pub const CARGO_LOCK: &str = "Cargo.lock";
168
169    /// Main entry point
170    pub const MAIN_RS: &str = "src/main.rs";
171
172    /// Library entry point
173    pub const LIB_RS: &str = "src/lib.rs";
174
175    /// Build script
176    pub const BUILD_RS: &str = "build.rs";
177
178    /// Rustfmt config
179    pub const RUSTFMT_TOML: &str = "rustfmt.toml";
180
181    /// Cargo config directory
182    pub const CARGO_CONFIG_DIR: &str = ".cargo";
183
184    /// Cargo config file
185    pub const CARGO_CONFIG: &str = ".cargo/config.toml";
186}
187
188/// Model files within a model directory
189pub mod model {
190    /// ONNX model file
191    pub const ONNX_FILE: &str = "model.onnx";
192
193    /// Labels file
194    pub const LABELS_FILE: &str = "labels.txt";
195
196    /// Model config file
197    pub const CONFIG_FILE: &str = "config.json";
198}
199
200// =============================================================================
201// User Home Paths - Paths in ~/.mecha10
202// =============================================================================
203
204/// User-level paths in home directory
205pub mod user {
206    use std::path::PathBuf;
207
208    /// Base mecha10 directory in user home
209    pub const MECHA10_DIR: &str = ".mecha10";
210
211    /// Credentials file
212    pub const CREDENTIALS_FILE: &str = ".mecha10/credentials.json";
213
214    /// Templates cache directory
215    pub const TEMPLATES_DIR: &str = ".mecha10/templates";
216
217    /// Simulation assets cache directory
218    pub const SIMULATION_DIR: &str = ".mecha10/simulation";
219
220    /// Current simulation assets symlink
221    pub const SIMULATION_CURRENT: &str = ".mecha10/simulation/current";
222
223    /// Simulation version file
224    pub const SIMULATION_VERSION: &str = ".mecha10/simulation/version";
225
226    /// Binary installation directory
227    pub const BIN_DIR: &str = ".mecha10/bin";
228
229    /// Get the base mecha10 directory path
230    pub fn mecha10_dir() -> PathBuf {
231        dirs::home_dir().unwrap_or_else(|| PathBuf::from(".")).join(MECHA10_DIR)
232    }
233
234    /// Get the credentials file path
235    pub fn credentials_file() -> PathBuf {
236        dirs::home_dir()
237            .unwrap_or_else(|| PathBuf::from("."))
238            .join(CREDENTIALS_FILE)
239    }
240
241    /// Get the templates cache directory
242    pub fn templates_dir() -> PathBuf {
243        mecha10_dir().join("templates")
244    }
245
246    /// Get the simulation assets directory
247    pub fn simulation_dir() -> PathBuf {
248        mecha10_dir().join("simulation")
249    }
250
251    /// Get the current simulation assets path
252    pub fn simulation_current() -> PathBuf {
253        mecha10_dir().join("simulation/current")
254    }
255
256    /// Get the binary directory
257    pub fn bin_dir() -> PathBuf {
258        mecha10_dir().join("bin")
259    }
260
261    /// Get path to a binary in the mecha10 bin directory
262    pub fn bin(name: &str) -> PathBuf {
263        bin_dir().join(name)
264    }
265
266    /// Get path to a binary in cargo bin directory
267    pub fn cargo_bin(name: &str) -> PathBuf {
268        dirs::home_dir()
269            .unwrap_or_else(|| PathBuf::from("."))
270            .join(".cargo/bin")
271            .join(name)
272    }
273
274    /// Get path to a binary in local bin directory
275    pub fn local_bin(name: &str) -> PathBuf {
276        dirs::home_dir()
277            .unwrap_or_else(|| PathBuf::from("."))
278            .join(".local/bin")
279            .join(name)
280    }
281}
282
283// =============================================================================
284// Docker Container Paths - Paths used inside containers
285// =============================================================================
286
287/// Paths used inside Docker containers
288pub mod container {
289    /// Project mount point in container
290    pub const PROJECT_ROOT: &str = "/project";
291
292    /// Framework mount point in container
293    pub const FRAMEWORK_ROOT: &str = "/mecha10";
294
295    /// App directory (for mecha10-remote)
296    pub const APP_ROOT: &str = "/app";
297
298    /// Config file in mecha10-remote container
299    pub const REMOTE_CONFIG: &str = "/app/mecha10.json";
300
301    /// Framework Godot project path (new structure)
302    pub const FRAMEWORK_GODOT_PROJECT: &str = "/mecha10/packages/simulation/godot-project";
303
304    /// Framework Godot project path (legacy)
305    pub const FRAMEWORK_GODOT_PROJECT_LEGACY: &str = "/mecha10/godot-project";
306
307    /// Get project-relative path inside container
308    pub fn project_path(relative: &str) -> String {
309        format!("{}/{}", PROJECT_ROOT, relative)
310    }
311
312    /// Get framework-relative path inside container
313    pub fn framework_path(relative: &str) -> String {
314        format!("{}/{}", FRAMEWORK_ROOT, relative)
315    }
316}
317
318// =============================================================================
319// Framework Paths - Paths within mecha10 framework source
320// =============================================================================
321
322/// Paths within the mecha10 framework source
323pub mod framework {
324    /// Packages directory
325    pub const PACKAGES_DIR: &str = "packages";
326
327    /// Nodes package directory
328    pub const NODES_DIR: &str = "packages/nodes";
329
330    /// Drivers package directory
331    pub const DRIVERS_DIR: &str = "packages/drivers";
332
333    /// Services package directory
334    pub const SERVICES_DIR: &str = "packages/services";
335
336    /// Simulation package directory
337    pub const SIMULATION_DIR: &str = "packages/simulation";
338
339    /// Simulation Godot project
340    pub const SIMULATION_GODOT_DIR: &str = "packages/simulation/godot-project";
341
342    /// Simulation models directory
343    pub const SIMULATION_MODELS_DIR: &str = "packages/simulation/models";
344
345    /// Simulation environments directory
346    pub const SIMULATION_ENVIRONMENTS_DIR: &str = "packages/simulation/environments";
347
348    /// Robot tasks environments directory (for environment matching)
349    pub const ROBOT_TASKS_DIR: &str = "packages/simulation/environments/robot-tasks";
350
351    /// Robot tasks catalog file
352    pub const ROBOT_TASKS_CATALOG: &str = "packages/simulation/environments/robot-tasks/catalog.json";
353
354    /// Python taskrunner package
355    pub const TASKRUNNER_DIR: &str = "packages/taskrunner";
356
357    /// Release binary
358    pub const RELEASE_BINARY: &str = "target/release/mecha10";
359
360    /// Debug binary
361    pub const DEBUG_BINARY: &str = "target/debug/mecha10";
362
363    /// Node runner release binary
364    pub const NODE_RUNNER_RELEASE: &str = "target/release/mecha10-node-runner";
365
366    /// Node runner debug binary
367    pub const NODE_RUNNER_DEBUG: &str = "target/debug/mecha10-node-runner";
368
369    /// Get node package path
370    pub fn node_package(node_name: &str) -> String {
371        format!("packages/nodes/{}", node_name)
372    }
373
374    /// Get node config path within framework
375    pub fn node_config(node_name: &str) -> String {
376        format!("packages/nodes/{}/configs/config.json", node_name)
377    }
378
379    /// Get node lib.rs path within framework
380    pub fn node_lib_rs(node_name: &str) -> String {
381        format!("packages/nodes/{}/src/lib.rs", node_name)
382    }
383}
384
385// =============================================================================
386// External URLs
387// =============================================================================
388
389/// External service URLs
390pub mod urls {
391    /// GitHub repository for user-tools (templates, assets)
392    pub const USER_TOOLS_REPO: &str = "mecha-industries/user-tools";
393
394    /// Remote image manifest URL
395    pub const REMOTE_MANIFEST: &str =
396        "https://raw.githubusercontent.com/mecha-industries/user-tools/main/mecha10-remote/manifest.json";
397
398    /// Default authentication URL
399    pub const AUTH_URL: &str = "https://mecha.industries/api/auth";
400}
401
402// =============================================================================
403// Helper Functions
404// =============================================================================
405
406/// Build a target output path
407pub fn target_path(profile: &str, binary: &str) -> String {
408    format!("target/{}/{}", profile, binary)
409}
410
411/// Build a target output path with optional target triple
412pub fn target_path_with_triple(target: Option<&str>, profile: &str) -> String {
413    match target {
414        Some(t) => format!("target/{}/{}", t, profile),
415        None => format!("target/{}", profile),
416    }
417}
418
419/// Get the project root by finding mecha10.json
420pub fn find_project_root(start: &Path) -> Option<PathBuf> {
421    let mut current = start.to_path_buf();
422    loop {
423        if current.join(PROJECT_CONFIG).exists() {
424            return Some(current);
425        }
426        if !current.pop() {
427            return None;
428        }
429    }
430}
431
432/// Check if a directory is a mecha10 project
433pub fn is_project_dir(dir: &Path) -> bool {
434    dir.join(PROJECT_CONFIG).exists()
435}
436
437#[cfg(test)]
438mod tests {
439    use super::*;
440
441    #[test]
442    fn test_config_paths() {
443        assert_eq!(
444            config::framework_node("object-detector"),
445            "configs/nodes/@mecha10/object-detector/config.json"
446        );
447        assert_eq!(
448            config::local_node("my-node"),
449            "configs/nodes/@local/my-node/config.json"
450        );
451        assert_eq!(config::project_node("camera"), "configs/nodes/camera/config.json");
452    }
453
454    #[test]
455    fn test_target_path() {
456        assert_eq!(target_path("release", "my-node"), "target/release/my-node");
457        assert_eq!(
458            target_path_with_triple(Some("aarch64-unknown-linux-gnu"), "release"),
459            "target/aarch64-unknown-linux-gnu/release"
460        );
461        assert_eq!(target_path_with_triple(None, "debug"), "target/debug");
462    }
463
464    #[test]
465    fn test_container_paths() {
466        assert_eq!(
467            container::project_path("configs/test.json"),
468            "/project/configs/test.json"
469        );
470        assert_eq!(container::framework_path("packages/core"), "/mecha10/packages/core");
471    }
472}