nsg_cli/commands/
submit.rs1use anyhow::{Context, Result};
2use clap::Args;
3use colored::Colorize;
4use std::path::PathBuf;
5use crate::client::NsgClient;
6use crate::config::Credentials;
7
8#[derive(Debug, Args)]
9pub struct SubmitCommand {
10 #[arg(help = "Path to ZIP file containing job data")]
11 zip_file: PathBuf,
12
13 #[arg(short, long, default_value = "PY_EXPANSE", help = "NSG tool to use")]
14 tool: String,
15
16 #[arg(long, help = "Don't wait for job submission confirmation")]
17 no_wait: bool,
18}
19
20impl SubmitCommand {
21 pub fn execute(self) -> Result<()> {
22 if !self.zip_file.exists() {
23 anyhow::bail!("ZIP file not found: {}", self.zip_file.display());
24 }
25
26 if !self.zip_file.extension().map_or(false, |ext| ext == "zip") {
27 eprintln!("{} File does not have .zip extension", "⚠".yellow());
28 eprintln!(" Continuing anyway...");
29 eprintln!();
30 }
31
32 let credentials = Credentials::load()?;
33 let client = NsgClient::new(credentials.clone())?;
34
35 println!("{}", "NSG Job Submission".bold().cyan());
36 println!("{}", "=".repeat(80).cyan());
37 println!();
38 println!("Tool: {}", self.tool.bold());
39 println!("User: {}", credentials.username.cyan());
40 println!("File: {}", self.zip_file.display().to_string().cyan());
41 println!("Size: {} bytes", format_size(std::fs::metadata(&self.zip_file)?.len()));
42 println!();
43
44 println!("{} Submitting job to NSG...", "→".yellow().bold());
45
46 let status = client
47 .submit_job(&self.zip_file, &self.tool)
48 .context("Failed to submit job")?;
49
50 println!();
51 println!("{}", "=".repeat(80).green());
52 println!("{} Job submitted successfully!", "✓".green().bold());
53 println!("{}", "=".repeat(80).green());
54 println!();
55 println!("Job ID: {}", status.job_id.cyan().bold());
56 println!("Stage: {}", status.job_stage.bold());
57 println!("URL: {}", status.self_uri.dimmed());
58
59 if let Some(date) = &status.date_submitted {
60 println!("Submitted: {}", date);
61 }
62
63 println!();
64 println!("{}", "Next Steps:".bold());
65 println!(" 1. Check job status:");
66 println!(" {}", format!("nsg status {}", status.job_id).cyan());
67 println!();
68 println!(" 2. When completed, download results:");
69 println!(" {}", format!("nsg download {}", status.job_id).cyan());
70 println!();
71 println!(" 3. View all jobs:");
72 println!(" {}", "nsg list".cyan());
73 println!();
74 println!("{}", "NSG Portal:".bold());
75 println!(" {}", "https://www.nsgportal.org/".cyan());
76 println!();
77
78 Ok(())
79 }
80}
81
82fn format_size(bytes: u64) -> String {
83 const KB: u64 = 1024;
84 const MB: u64 = KB * 1024;
85 const GB: u64 = MB * 1024;
86
87 if bytes >= GB {
88 format!("{:.2} GB", bytes as f64 / GB as f64)
89 } else if bytes >= MB {
90 format!("{:.2} MB", bytes as f64 / MB as f64)
91 } else if bytes >= KB {
92 format!("{:.2} KB", bytes as f64 / KB as f64)
93 } else {
94 format!("{} B", bytes)
95 }
96}