Skip to main content

palladium/package/
cli.rs

1// Package manager CLI for Palladium
2// "Command line interface for legendary package management"
3
4use super::{
5    build::{BuildConfig, BuildSystem},
6    PackageManager,
7};
8use crate::errors::Result;
9use clap::{Parser, Subcommand};
10use std::path::PathBuf;
11
12/// Palladium package manager
13#[derive(Parser)]
14#[command(name = "pdm")]
15#[command(about = "Palladium package manager - Manage your legendary packages")]
16#[command(version)]
17pub struct Cli {
18    #[command(subcommand)]
19    pub command: Commands,
20}
21
22#[derive(Subcommand)]
23pub enum Commands {
24    /// Create a new Palladium package
25    New {
26        /// Package name
27        name: String,
28        /// Path to create the package (defaults to package name)
29        #[arg(long)]
30        path: Option<PathBuf>,
31    },
32
33    /// Initialize a new package in the current directory
34    Init {
35        /// Package name (defaults to directory name)
36        #[arg(long)]
37        name: Option<String>,
38    },
39
40    /// Build the current package
41    Build {
42        /// Build in release mode
43        #[arg(long, short)]
44        release: bool,
45        /// Use LLVM backend
46        #[arg(long)]
47        llvm: bool,
48        /// Verbose output
49        #[arg(long, short)]
50        verbose: bool,
51        /// Number of parallel jobs
52        #[arg(long, short, default_value_t = 0)]
53        jobs: usize,
54        /// Features to enable
55        #[arg(long)]
56        features: Vec<String>,
57    },
58
59    /// Run the current package
60    Run {
61        /// Build in release mode
62        #[arg(long, short)]
63        release: bool,
64        /// Arguments to pass to the program
65        #[arg(trailing_var_arg = true)]
66        args: Vec<String>,
67    },
68
69    /// Run tests
70    Test {
71        /// Test name filter
72        filter: Option<String>,
73        /// Build in release mode
74        #[arg(long, short)]
75        release: bool,
76        /// Verbose output
77        #[arg(long, short)]
78        verbose: bool,
79    },
80
81    /// Clean build artifacts
82    Clean,
83
84    /// Add a dependency
85    Add {
86        /// Dependency name
87        name: String,
88        /// Version requirement
89        #[arg(default_value = "*")]
90        version: String,
91        /// Add as dev dependency
92        #[arg(long)]
93        dev: bool,
94    },
95
96    /// Remove a dependency
97    Remove {
98        /// Dependency name
99        name: String,
100        /// Remove from dev dependencies
101        #[arg(long)]
102        dev: bool,
103    },
104
105    /// Update dependencies
106    Update {
107        /// Package to update (updates all if not specified)
108        package: Option<String>,
109    },
110
111    /// Search for packages in the registry
112    Search {
113        /// Search query
114        query: String,
115        /// Maximum number of results
116        #[arg(long, default_value_t = 10)]
117        limit: usize,
118    },
119
120    /// Show package information
121    Info {
122        /// Package name
123        name: String,
124    },
125
126    /// Publish a package to the registry
127    Publish {
128        /// Dry run (don't actually publish)
129        #[arg(long)]
130        dry_run: bool,
131    },
132
133    /// Install a package globally
134    Install {
135        /// Package name
136        name: String,
137        /// Version to install
138        #[arg(long)]
139        version: Option<String>,
140    },
141
142    /// Uninstall a global package
143    Uninstall {
144        /// Package name
145        name: String,
146    },
147
148    /// List installed packages
149    List {
150        /// Show global packages
151        #[arg(long)]
152        global: bool,
153        /// Show dependency tree
154        #[arg(long)]
155        tree: bool,
156    },
157}
158
159impl Cli {
160    /// Execute the CLI command
161    pub fn execute(self) -> Result<()> {
162        match self.command {
163            Commands::New { name, path } => {
164                let target_path = path.unwrap_or_else(|| PathBuf::from(&name));
165
166                if target_path.exists() {
167                    return Err(crate::errors::CompileError::Generic(format!(
168                        "Directory '{}' already exists",
169                        target_path.display()
170                    )));
171                }
172
173                std::fs::create_dir_all(&target_path)?;
174                PackageManager::init(&name, &target_path)?;
175
176                println!("\n๐Ÿ“ Next steps:");
177                println!("   cd {}", target_path.display());
178                println!("   pdm build");
179                println!("   pdm run");
180            }
181
182            Commands::Init { name } => {
183                let current_dir = std::env::current_dir()?;
184                let package_name = name.unwrap_or_else(|| {
185                    current_dir
186                        .file_name()
187                        .and_then(|n| n.to_str())
188                        .unwrap_or("my_package")
189                        .to_string()
190                });
191
192                PackageManager::init(&package_name, &current_dir)?;
193            }
194
195            Commands::Build {
196                release,
197                llvm,
198                verbose,
199                jobs,
200                features,
201            } => {
202                let config = BuildConfig {
203                    release,
204                    use_llvm: llvm,
205                    verbose,
206                    jobs: if jobs == 0 {
207                        super::build::num_cpus::get()
208                    } else {
209                        jobs
210                    },
211                    features: features.into_iter().collect(),
212                    ..Default::default()
213                };
214
215                let mut build_system = BuildSystem::new(config);
216                build_system.build()?;
217            }
218
219            Commands::Run { release, args } => {
220                let config = BuildConfig {
221                    release,
222                    ..Default::default()
223                };
224
225                let mut build_system = BuildSystem::new(config);
226                build_system.run(args)?;
227            }
228
229            Commands::Test {
230                filter,
231                release,
232                verbose,
233            } => {
234                let config = BuildConfig {
235                    release,
236                    verbose,
237                    ..Default::default()
238                };
239
240                let mut build_system = BuildSystem::new(config);
241                build_system.test(filter.as_deref())?;
242            }
243
244            Commands::Clean => {
245                let build_system = BuildSystem::new(BuildConfig::default());
246                build_system.clean()?;
247            }
248
249            Commands::Add { name, version, dev } => {
250                let mut pm = PackageManager::new()?;
251                pm.add_dependency(&name, &version, dev)?;
252            }
253
254            Commands::Remove { name: _, dev: _ } => {
255                println!("๐Ÿšง Remove command not yet implemented");
256                // TODO: Implement dependency removal
257            }
258
259            Commands::Update { package: _ } => {
260                println!("๐Ÿšง Update command not yet implemented");
261                // TODO: Implement dependency updates
262            }
263
264            Commands::Search { query, limit } => {
265                println!("๐Ÿ” Searching for '{}'...", query);
266                println!("๐Ÿšง Search functionality not yet implemented");
267                println!("   (Would show up to {} results)", limit);
268                // TODO: Implement package search
269            }
270
271            Commands::Info { name } => {
272                println!("๐Ÿ“ฆ Package: {}", name);
273                println!("๐Ÿšง Info command not yet implemented");
274                // TODO: Implement package info
275            }
276
277            Commands::Publish { dry_run } => {
278                if dry_run {
279                    println!("๐Ÿงช Dry run mode");
280                }
281                println!("๐Ÿšง Publish command not yet implemented");
282                // TODO: Implement package publishing
283            }
284
285            Commands::Install { name, version } => {
286                println!(
287                    "๐Ÿ“ฅ Installing {} {}",
288                    name,
289                    version.as_deref().unwrap_or("latest")
290                );
291                println!("๐Ÿšง Install command not yet implemented");
292                // TODO: Implement global package installation
293            }
294
295            Commands::Uninstall { name } => {
296                println!("๐Ÿ“ค Uninstalling {}", name);
297                println!("๐Ÿšง Uninstall command not yet implemented");
298                // TODO: Implement global package uninstallation
299            }
300
301            Commands::List { global, tree } => {
302                if global {
303                    println!("๐ŸŒ Global packages:");
304                } else {
305                    println!("๐Ÿ“ฆ Local dependencies:");
306                }
307
308                if tree {
309                    println!("๐ŸŒณ Dependency tree view");
310                }
311
312                println!("๐Ÿšง List command not yet implemented");
313                // TODO: Implement package listing
314            }
315        }
316
317        Ok(())
318    }
319}
320
321/// Run the package manager CLI
322pub fn run_cli() -> Result<()> {
323    let cli = Cli::parse();
324    cli.execute()
325}
326
327#[cfg(test)]
328mod tests {
329    use super::*;
330
331    #[test]
332    fn test_cli_parsing() {
333        // Test that CLI can be parsed
334        let _cli = Cli::try_parse_from(&["pdm", "build", "--release"]);
335    }
336}