nsg_cli/commands/
submit.rs1use crate::client::NsgClient;
2use crate::config::Credentials;
3use anyhow::{Context, Result};
4use clap::Args;
5use colored::Colorize;
6use std::path::PathBuf;
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!(
42 "Size: {} bytes",
43 format_size(std::fs::metadata(&self.zip_file)?.len())
44 );
45 println!();
46
47 println!("{} Submitting job to NSG...", "→".yellow().bold());
48
49 let status = client
50 .submit_job(&self.zip_file, &self.tool)
51 .context("Failed to submit job")?;
52
53 println!();
54 println!("{}", "=".repeat(80).green());
55 println!("{} Job submitted successfully!", "✓".green().bold());
56 println!("{}", "=".repeat(80).green());
57 println!();
58 println!("Job ID: {}", status.job_id.cyan().bold());
59 println!("Stage: {}", status.job_stage.bold());
60 println!("URL: {}", status.self_uri.dimmed());
61
62 if let Some(date) = &status.date_submitted {
63 println!("Submitted: {}", date);
64 }
65
66 println!();
67 println!("{}", "Next Steps:".bold());
68 println!(" 1. Check job status:");
69 println!(" {}", format!("nsg status {}", status.job_id).cyan());
70 println!();
71 println!(" 2. When completed, download results:");
72 println!(" {}", format!("nsg download {}", status.job_id).cyan());
73 println!();
74 println!(" 3. View all jobs:");
75 println!(" {}", "nsg list".cyan());
76 println!();
77 println!("{}", "NSG Portal:".bold());
78 println!(" {}", "https://www.nsgportal.org/".cyan());
79 println!();
80
81 Ok(())
82 }
83}
84
85fn format_size(bytes: u64) -> String {
86 const KB: u64 = 1024;
87 const MB: u64 = KB * 1024;
88 const GB: u64 = MB * 1024;
89
90 if bytes >= GB {
91 format!("{:.2} GB", bytes as f64 / GB as f64)
92 } else if bytes >= MB {
93 format!("{:.2} MB", bytes as f64 / MB as f64)
94 } else if bytes >= KB {
95 format!("{:.2} KB", bytes as f64 / KB as f64)
96 } else {
97 format!("{} B", bytes)
98 }
99}