Added download and ls, formatted cli.rs

This commit is contained in:
JandereDev 2021-09-28 18:57:20 +02:00 committed by Ben Schattinger
parent fd6d7d87b6
commit cdd06cb3e6

View file

@ -1,10 +1,10 @@
use std::fs::File; use std::io::{Read, Write};
use std::io::Read;
use std::path::PathBuf; use std::path::PathBuf;
use std::{fs::File, path::Path};
use clap::Clap; use clap::Clap;
use indicatif::{ProgressBar, ProgressStyle}; use indicatif::{ProgressBar, ProgressStyle};
use libnspire::{PID, PID_CX2, VID}; use libnspire::{dir::EntryType, PID, PID_CX2, VID};
#[derive(Clap, Debug)] #[derive(Clap, Debug)]
#[clap(author, about, version)] #[clap(author, about, version)]
@ -16,11 +16,12 @@ struct Opt {
#[derive(Clap, Debug)] #[derive(Clap, Debug)]
enum SubCommand { enum SubCommand {
Upload(Upload), Upload(Upload),
Download(Download),
Mkdir(Mkdir), Mkdir(Mkdir),
Rmdir(Rmdir), Rmdir(Rmdir),
Ls(Ls),
/// View license information /// View license information
License, License,
// Download(Download),
} }
/// Upload files to the calculator /// Upload files to the calculator
@ -33,30 +34,37 @@ struct Upload {
dest: String, dest: String,
} }
// Create a directory /// Download files from the calculator
#[derive(Clap, Debug)]
struct Download {
/// Files to download
#[clap(required = true)]
files: Vec<String>,
/// Destination path
#[clap(required = true, parse(from_os_str))]
dest: PathBuf,
}
/// Create a directory
#[derive(Clap, Debug)] #[derive(Clap, Debug)]
struct Mkdir { struct Mkdir {
#[clap(required = true)] #[clap(required = true)]
path: String path: String,
} }
// Delete a directory /// Delete a directory
#[derive(Clap, Debug)] #[derive(Clap, Debug)]
struct Rmdir { struct Rmdir {
#[clap(required = true)] #[clap(required = true)]
path: String path: String,
} }
// /// Download files from the calculator /// List the contents of a directory
// #[derive(Clap, Debug)] #[derive(Clap, Debug)]
// struct Download { struct Ls {
// /// Files to download #[clap(required = true)]
// #[clap(required = true)] path: String,
// files: Vec<String>, }
// /// Destination path
// #[clap(parse(from_os_str))]
// dest: PathBuf,
// }
fn get_dev() -> Option<libnspire::Handle<rusb::GlobalContext>> { fn get_dev() -> Option<libnspire::Handle<rusb::GlobalContext>> {
rusb::devices() rusb::devices()
@ -106,20 +114,80 @@ pub fn run() -> bool {
if dest.ends_with('/') { if dest.ends_with('/') {
dest.remove(dest.len() - 1); dest.remove(dest.len() - 1);
} }
let res = handle let res = handle.write_file(&format!("{}/{}", dest, name), &buf, &mut |remaining| {
.write_file(&format!("{}/{}", dest, name), &buf, &mut |remaining| { bar.set_position((buf.len() - remaining) as u64)
bar.set_position((buf.len() - remaining) as u64) });
});
match res { match res {
Ok(_) => { Ok(_) => {
println!("Upload {}: Ok", dest); println!("Upload {}: Ok", dest);
} }
Err(error) => { Err(error) => {
bar.abandon_with_message(&format!("Failed: {}", error)); bar.abandon_with_message(&format!("Failed: {}", error));
}
}
bar.finish();
}
} else {
eprintln!("Couldn't find any device");
}
}
SubCommand::Download(Download { dest, files }) => {
if let Some(handle) = get_dev() {
for file in files {
let attr = handle.file_attr(&file);
match attr {
Ok(attr) => {
let path = Path::new(&file);
let dest_path = Path::join(&dest, path.file_name().unwrap().to_str().unwrap());
match File::create(dest_path) {
Ok(mut dest_file) => {
let mut buf = vec![0u8; attr.size() as usize];
let bar = ProgressBar::new(buf.len() as u64);
bar.set_style(ProgressStyle::default_bar().template("{spinner:.green} {msg} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})"));
bar.set_message(&format!(
"Download {}",
path.file_name().unwrap().to_str().unwrap()
));
bar.enable_steady_tick(100);
let len = buf.len();
let res = handle.read_file(&file, &mut buf, &mut |remaining| {
bar.set_position((len - remaining) as u64);
});
match res {
Ok(_) => {
bar.set_message("Writing file to disk");
match dest_file.write_all(&buf) {
Ok(_) => {
bar.finish_with_message("Transfer completed");
}
Err(error) => {
bar.abandon_with_message(&format!(
"Failed to write file to disk: {}",
error
));
}
}
}
Err(error) => {
bar.abandon_with_message(&format!("Failed to transfer file: {}", error))
}
}
}
Err(error) => {
eprintln!("Failed to open destination file: {}", error);
}
} }
} }
bar.finish(); Err(error) => {
eprintln!("Failed to read file info: {}", error);
}
}
} }
} else { } else {
eprintln!("Couldn't find any device"); eprintln!("Couldn't find any device");
@ -153,6 +221,27 @@ pub fn run() -> bool {
eprintln!("Couldn't find any device"); eprintln!("Couldn't find any device");
} }
} }
SubCommand::Ls(Ls { path }) => {
if let Some(handle) = get_dev() {
match handle.list_dir(&path) {
Ok(dir_list) => {
for i in 0..dir_list.len() {
let item = dir_list.get(i).unwrap();
let mut item_name = String::from(item.name().to_str().unwrap());
if item.entry_type() == EntryType::Directory {
item_name += "/";
}
println!("{}", item_name);
}
}
Err(error) => {
eprintln!("Failed to list directory: {}", error);
}
}
} else {
eprintln!("Couldn't find any device");
}
}
SubCommand::License => { SubCommand::License => {
println!("{}", include_str!("../../LICENSE")); println!("{}", include_str!("../../LICENSE"));
println!(include_str!("NOTICE.txt"), env!("CARGO_PKG_REPOSITORY")); println!(include_str!("NOTICE.txt"), env!("CARGO_PKG_REPOSITORY"));