mark and eliminate some unwrap
This commit is contained in:
parent
faea74241d
commit
39560eeeed
6 changed files with 36 additions and 110 deletions
|
|
@ -42,7 +42,8 @@
|
||||||
"terminal.integrated.defaultProfile.linux": "zsh"
|
"terminal.integrated.defaultProfile.linux": "zsh"
|
||||||
},
|
},
|
||||||
"extensions": [
|
"extensions": [
|
||||||
"mhutchie.git-graph"
|
"mhutchie.git-graph",
|
||||||
|
"Gruntfuggly.todo-tree"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
Diese Konversation wurde mit Duck.ai (https://duck.ai) unter Verwendung des o3-mini-Modells von OpenAI generiert. KI-Chats zeigen möglicherweise falsche oder anstößige Informationen an (weitere Informationen siehe https://duckduckgo.com/duckai/privacy-terms).
|
|
||||||
|
|
||||||
====================
|
|
||||||
|
|
||||||
Benutzereingabe 1 von 2 - 5.6.2025, 02:27:36:
|
|
||||||
in Rust, what can I use to display multiple progress bars in the terminal?
|
|
||||||
|
|
||||||
o3-mini:
|
|
||||||
You can use the indicatif crate, which provides a MultiProgress type that lets you manage and display multiple progress bars concurrently in a terminal.
|
|
||||||
|
|
||||||
Below is a simple example of how to use indicatif’s MultiProgress to display multiple progress bars:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
|
||||||
use std::{thread, time::Duration};
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// Create a MultiProgress container.
|
|
||||||
let m = MultiProgress::new();
|
|
||||||
|
|
||||||
// Create several progress bars.
|
|
||||||
let pb1 = m.add(ProgressBar::new(100));
|
|
||||||
pb1.set_style(
|
|
||||||
ProgressStyle::default_bar()
|
|
||||||
.template("{msg} {bar:40.cyan/blue} {pos:>3}/{len:3}")
|
|
||||||
.expect("Failed to set progress bar style"),
|
|
||||||
);
|
|
||||||
pb1.set_message("Downloading");
|
|
||||||
|
|
||||||
let pb2 = m.add(ProgressBar::new(50));
|
|
||||||
pb2.set_style(
|
|
||||||
ProgressStyle::default_bar()
|
|
||||||
.template("{msg} {bar:40.green/black} {pos:>3}/{len:3}")
|
|
||||||
.expect("Failed to set progress bar style"),
|
|
||||||
);
|
|
||||||
pb2.set_message("Processing");
|
|
||||||
|
|
||||||
// Optionally, spawn threads to update the progress bars concurrently.
|
|
||||||
let h1 = std::thread::spawn(move || {
|
|
||||||
for i in 0..=100 {
|
|
||||||
pb1.set_position(i);
|
|
||||||
thread::sleep(Duration::from_millis(50));
|
|
||||||
}
|
|
||||||
pb1.finish_with_message("Download complete");
|
|
||||||
});
|
|
||||||
|
|
||||||
let h2 = std::thread::spawn(move || {
|
|
||||||
for i in 0..=50 {
|
|
||||||
pb2.set_position(i);
|
|
||||||
thread::sleep(Duration::from_millis(100));
|
|
||||||
}
|
|
||||||
pb2.finish_with_message("Processing complete");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Wait for threads to complete. MultiProgress takes care of rendering.
|
|
||||||
h1.join().expect("Thread 1 panicked");
|
|
||||||
h2.join().expect("Thread 2 panicked");
|
|
||||||
|
|
||||||
// You may also iterate on the multi-progress which blocks until all bars finish:
|
|
||||||
// m.join().unwrap();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Steps Explained
|
|
||||||
|
|
||||||
1. **MultiProgress Container**:
|
|
||||||
Create a `MultiProgress` instance which is used to manage multiple progress bars.
|
|
||||||
|
|
||||||
2. **Progress Bars**:
|
|
||||||
Create individual progress bars using `MultiProgress::add()`. You can customize each progress bar with a message, style, and length.
|
|
||||||
|
|
||||||
3. **Concurrent Updates**:
|
|
||||||
The example spawns two threads – one for each progress bar. Each thread updates its progress bar independently using `set_position()` and finishes the progress bar with `finish_with_message()`.
|
|
||||||
|
|
||||||
4. **Thread Joining**:
|
|
||||||
Ensure the main thread waits for the worker threads to complete to prevent the program from exiting prematurely.
|
|
||||||
|
|
||||||
### Installation
|
|
||||||
|
|
||||||
Make sure to add indicatif to your Cargo.toml:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[dependencies]
|
|
||||||
indicatif = "0.17" # or the latest version available on crates.io
|
|
||||||
```
|
|
||||||
|
|
||||||
This crate provides many options for customizing and using progress bars in a concurrent and effective manner. The documentation is available at [indicatif on docs.rs](https://docs.rs/indicatif) for further details and advanced usage.
|
|
||||||
|
|
@ -41,6 +41,18 @@ impl FileState {
|
||||||
FileState::U(uploading) => uploading.file_name(),
|
FileState::U(uploading) => uploading.file_name(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn start_upload(
|
||||||
|
self,
|
||||||
|
http: &ureq::Agent,
|
||||||
|
alias: &Alias,
|
||||||
|
share: &Share,
|
||||||
|
) -> io::Result<FileUploading> {
|
||||||
|
match self {
|
||||||
|
FileState::C(checked) => checked.start_upload(http, alias, share),
|
||||||
|
FileState::U(uploading) => Ok(uploading),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppState {
|
impl AppState {
|
||||||
|
|
@ -110,12 +122,10 @@ impl AppState {
|
||||||
http: &ureq::Agent,
|
http: &ureq::Agent,
|
||||||
chunk_size: usize,
|
chunk_size: usize,
|
||||||
) -> Result<Option<()>, UploadError> {
|
) -> Result<Option<()>, UploadError> {
|
||||||
let uploading = match self.files.pop_front() {
|
let uploading = if let Some(state) = self.files.pop_front() {
|
||||||
Some(FileState::C(checked)) => checked
|
state.start_upload(http, &self.alias, &self.share).unwrap() // HACK unwrap
|
||||||
.start_upload(http, &self.alias, &self.share)
|
} else {
|
||||||
.unwrap(),
|
return Ok(None);
|
||||||
Some(FileState::U(uploading)) => uploading,
|
|
||||||
None => return Ok(None),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("{uploading} chunk {chunk_size}");
|
debug!("{uploading} chunk {chunk_size}");
|
||||||
|
|
@ -156,7 +166,7 @@ impl AppState {
|
||||||
debug!("Finished {:?}!", path.display());
|
debug!("Finished {:?}!", path.display());
|
||||||
bar.finish();
|
bar.finish();
|
||||||
self.progress = None;
|
self.progress = None;
|
||||||
self.share.notify(http, &self.alias).unwrap();
|
self.share.notify(http, &self.alias).unwrap(); // HACK unwrap
|
||||||
|
|
||||||
Ok(self.files.front().map(drop))
|
Ok(self.files.front().map(drop))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ fn main() {
|
||||||
|
|
||||||
match AppState::from_args(&args, &agent) {
|
match AppState::from_args(&args, &agent) {
|
||||||
Ok(state) => {
|
Ok(state) => {
|
||||||
state.save().unwrap();
|
state.save().unwrap(); // HACK unwrap
|
||||||
state
|
state
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
@ -98,13 +98,13 @@ fn main() {
|
||||||
Err(e) => error!("error: {e:?}"),
|
Err(e) => error!("error: {e:?}"),
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
info!("all uploads done");
|
info!("all uploads done");
|
||||||
state.clear().unwrap();
|
state.clear().unwrap(); // HACK unwrap
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
state.save().unwrap();
|
state.save().unwrap(); // HACK unwrap
|
||||||
stop.load(Ordering::SeqCst).then(|| exit(0));
|
stop.load(Ordering::SeqCst).then(|| exit(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use std::{
|
use std::{
|
||||||
ffi::OsStr,
|
ffi::OsStr,
|
||||||
fs,
|
fs, io,
|
||||||
io::{self, ErrorKind},
|
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -25,14 +24,17 @@ impl FileChecked {
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(io::Error::new(
|
Err(io::Error::new(
|
||||||
ErrorKind::InvalidInput,
|
io::ErrorKind::InvalidInput,
|
||||||
"Not a regular file",
|
"Not a regular file",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_name(&self) -> &str {
|
pub fn file_name(&self) -> &str {
|
||||||
self.path.file_name().unwrap().to_str().unwrap()
|
self.path
|
||||||
|
.file_name()
|
||||||
|
.and_then(OsStr::to_str)
|
||||||
|
.expect("bad file name")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_upload(
|
pub fn start_upload(
|
||||||
|
|
@ -46,13 +48,9 @@ impl FileChecked {
|
||||||
let res = {
|
let res = {
|
||||||
let endpoint = alias.get_endpoint(format!("alias/upload/{}/files/tus", share.id));
|
let endpoint = alias.get_endpoint(format!("alias/upload/{}/files/tus", share.id));
|
||||||
|
|
||||||
let name = (self.path.file_name().and_then(OsStr::to_str))
|
|
||||||
.ok_or_else(|| io::Error::new(ErrorKind::NotFound, "bad file name"))?
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
(http.post(endpoint))
|
(http.post(endpoint))
|
||||||
.sharry_header(alias)
|
.sharry_header(alias)
|
||||||
.header("Sharry-File-Name", &name)
|
.header("Sharry-File-Name", self.file_name())
|
||||||
.header("Upload-Length", size)
|
.header("Upload-Length", size)
|
||||||
.send_empty()
|
.send_empty()
|
||||||
.map_err(io::Error::other)?
|
.map_err(io::Error::other)?
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use std::{
|
use std::{
|
||||||
|
ffi::OsStr,
|
||||||
fmt::{Debug, Display},
|
fmt::{Debug, Display},
|
||||||
fs::File,
|
fs,
|
||||||
io::{self, Read, Seek, SeekFrom},
|
io::{self, Read, Seek, SeekFrom},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
};
|
};
|
||||||
|
|
@ -58,7 +59,7 @@ impl FileUploading {
|
||||||
fn read_chunk(&self, chunk_size: usize) -> io::Result<Vec<u8>> {
|
fn read_chunk(&self, chunk_size: usize) -> io::Result<Vec<u8>> {
|
||||||
let offset = u64::try_from(self.offset).map_err(io::Error::other)?;
|
let offset = u64::try_from(self.offset).map_err(io::Error::other)?;
|
||||||
|
|
||||||
let mut f = File::open(&self.path)?;
|
let mut f = fs::File::open(&self.path)?;
|
||||||
f.seek(SeekFrom::Start(offset))?;
|
f.seek(SeekFrom::Start(offset))?;
|
||||||
|
|
||||||
let mut bytes = vec![0; chunk_size];
|
let mut bytes = vec![0; chunk_size];
|
||||||
|
|
@ -69,7 +70,10 @@ impl FileUploading {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_name(&self) -> &str {
|
pub fn file_name(&self) -> &str {
|
||||||
self.path.file_name().unwrap().to_str().unwrap()
|
self.path
|
||||||
|
.file_name()
|
||||||
|
.and_then(OsStr::to_str)
|
||||||
|
.expect("bad file name")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn offset<T>(&self) -> T
|
pub fn offset<T>(&self) -> T
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue