-
Notifications
You must be signed in to change notification settings - Fork 102
feat: add host-based upload support to rattler_upload
#1580
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
magentaqin
wants to merge
44
commits into
conda:main
Choose a base branch
from
magentaqin:feature/upload-url
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 18 commits
Commits
Show all changes
44 commits
Select commit
Hold shift + click to select a range
c2ecece
feat: add auth_store for UploadOpts and update get_auth_store
magentaqin 7796ddd
fix: fix linting
magentaqin d05406c
feat: add regex package
magentaqin a490759
feat: check server type by host
magentaqin 9e1a01a
feat: extract Quetz and Artifactory info from host
magentaqin 676a6f7
feat: extract prefix base_url and channel from host
magentaqin 63f33ee
feat: move pixi_progress to rattler
magentaqin 29a1f5c
feat: extract s3 info
magentaqin fc4a790
feat: make host and server_type optional in UploadOpts
magentaqin 96ea212
feat: prefix upload supports rattler_progress
magentaqin 7718b02
fix: update rattler_progress name
magentaqin cfc2690
feat: detect server type and extract components from host
magentaqin 9f3b4bb
feat: update Cargo.toml
magentaqin 05e9c12
fix: fix Cargo.toml
magentaqin 00d0a45
fix: fix s3 type
magentaqin 0bf614c
fix: fix import error
magentaqin af31a6a
chore: cargo fmt
magentaqin 9c8c525
fix: fix linting error
magentaqin 1c0fdd8
fix: fix 'auth_store' type
magentaqin 09777b0
fix: fix linting issue
magentaqin 4573261
Merge branch 'feature/upload-auth-store' into feature/upload-url
magentaqin 1ead736
chore: sync cargo.lock
magentaqin 5f71202
Merge branch 'main' into feature/upload-url
magentaqin d23039e
refactor: replace RegExp with URL parsing
magentaqin 0958d9f
chore: update default region
magentaqin db59292
Merge main
magentaqin 8b5e6e8
fmt
magentaqin 99dd9e7
Merge main
magentaqin 9eadb87
refactor: remove unecessary 'rattler_progress'
magentaqin bb464fb
Merge main and update s3 api
magentaqin c709b62
fmt
magentaqin 5a824b4
fix: fix the region not working
magentaqin 3ae4aef
Merge main and solve conflicts
magentaqin d18ba47
feat: optimize progressbar for S3 uploading and responds when package…
magentaqin 09ddbb4
fix: fix lint err
magentaqin 059db57
Merge branch 'feature/upload-url' of github.com:magentaqin/rattler in…
magentaqin 16d1fd0
fix: fix S3 force option
magentaqin 9d62564
feat: add addressing_style for 'S3Opts'
magentaqin e3fa364
Merge main
magentaqin 54c5c18
Merge main
magentaqin 9bf9bb2
Merge main
magentaqin 5fc6195
refactor: reuse the S3CredentialsOpts
magentaqin 14a0e82
chore: remove crate 'regex'
magentaqin 7650fa2
remove S3 related changes for now
wolfv File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
[package] | ||
name = "rattler_progress" | ||
version = "0.1.0" | ||
edition.workspace = true | ||
authors = ["Bas Zalmstra <[email protected]>", "Magenta Qin <[email protected]>"] | ||
description = "A crate to show progress bar" | ||
categories.workspace = true | ||
homepage.workspace = true | ||
repository.workspace = true | ||
license.workspace = true | ||
readme.workspace = true | ||
|
||
|
||
[dependencies] | ||
indicatif = { workspace = true } | ||
parking_lot = { workspace = true } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,247 @@ | ||
mod placement; | ||
pub mod style; | ||
|
||
use std::{ | ||
borrow::Cow, | ||
fmt::Write, | ||
future::Future, | ||
sync::{Arc, LazyLock}, | ||
time::Duration, | ||
}; | ||
|
||
use indicatif::{HumanBytes, MultiProgress, ProgressBar, ProgressDrawTarget, ProgressState}; | ||
use parking_lot::Mutex; | ||
pub use placement::ProgressBarPlacement; | ||
|
||
/// A helper macro to print a message to the console. If a multi-progress bar | ||
/// is currently active, this macro will suspend the progress bar, print the | ||
/// message and continue the progress bar. This ensures the output does not | ||
/// interfere with the progress bar. | ||
/// | ||
/// If the progress bar is hidden, the message will be printed to `stderr` | ||
/// instead. | ||
#[macro_export] | ||
macro_rules! println { | ||
() => { | ||
let mp = $crate::global_multi_progress(); | ||
if mp.is_hidden() { | ||
eprintln!(); | ||
} else { | ||
// Ignore any error | ||
let _err = mp.println(""); | ||
} | ||
}; | ||
($($arg:tt)*) => { | ||
let mp = $crate::global_multi_progress(); | ||
if mp.is_hidden() { | ||
eprintln!($($arg)*); | ||
} else { | ||
// Ignore any error | ||
let _err = mp.println(format!($($arg)*)); | ||
} | ||
} | ||
} | ||
|
||
/// Returns a global instance of [`indicatif::MultiProgress`]. | ||
/// | ||
/// Although you can always create an instance yourself any logging will | ||
/// interrupt pending progressbars. To fix this issue, logging has been | ||
/// configured in such a way to it will not interfere if you use the | ||
/// [`indicatif::MultiProgress`] returning by this function. | ||
pub fn global_multi_progress() -> MultiProgress { | ||
static GLOBAL_MP: LazyLock<MultiProgress> = LazyLock::new(|| { | ||
let mp = MultiProgress::new(); | ||
mp.set_draw_target(ProgressDrawTarget::stderr_with_hz(20)); | ||
mp | ||
}); | ||
GLOBAL_MP.clone() | ||
} | ||
|
||
/// Returns the style to use for a progressbar that is currently in progress. | ||
pub fn default_bytes_style() -> indicatif::ProgressStyle { | ||
indicatif::ProgressStyle::default_bar() | ||
.template(" {spinner:.dim} {prefix:20!} [{elapsed_precise}] [{bar:20!.bright.yellow/dim.white}] {bytes:>8} @ {smoothed_bytes_per_sec:8}").unwrap() | ||
.progress_chars("━━╾─") | ||
.with_key( | ||
"smoothed_bytes_per_sec", | ||
|s: &ProgressState, w: &mut dyn Write| match (s.pos(), s.elapsed().as_millis()) { | ||
(pos, elapsed_ms) if elapsed_ms > 0 => { | ||
write!(w, "{}/s", HumanBytes((pos as f64 * 1000_f64 / elapsed_ms as f64) as u64)).unwrap(); | ||
} | ||
_ => write!(w, "-").unwrap(), | ||
}, | ||
) | ||
} | ||
|
||
/// Returns the style to use for a progressbar that is currently in progress. | ||
pub fn default_progress_style() -> indicatif::ProgressStyle { | ||
indicatif::ProgressStyle::default_bar() | ||
.template(" {spinner:.dim} {prefix:20!} [{elapsed_precise}] [{bar:20!.bright.yellow/dim.white}] {pos:>4}/{len:4} {wide_msg:.dim}").unwrap() | ||
.progress_chars("━━╾─") | ||
} | ||
|
||
/// Returns the style to use for a progressbar that is indeterminate and simply | ||
/// shows a spinner. | ||
pub fn long_running_progress_style() -> indicatif::ProgressStyle { | ||
indicatif::ProgressStyle::with_template("{prefix}{spinner:.green} {msg}").unwrap() | ||
} | ||
|
||
/// Displays a spinner with the given message while running the specified | ||
/// function to completion. | ||
pub fn wrap_in_progress<T, F: FnOnce() -> T>(msg: impl Into<Cow<'static, str>>, func: F) -> T { | ||
let pb = global_multi_progress().add(ProgressBar::new_spinner()); | ||
pb.enable_steady_tick(Duration::from_millis(100)); | ||
pb.set_style(long_running_progress_style()); | ||
pb.set_message(msg); | ||
let result = func(); | ||
pb.finish_and_clear(); | ||
result | ||
} | ||
|
||
/// Displays a spinner with the given message while running the specified | ||
/// function to completion. | ||
pub async fn await_in_progress<T, F: FnOnce(ProgressBar) -> Fut, Fut: Future<Output = T>>( | ||
msg: impl Into<Cow<'static, str>>, | ||
future: F, | ||
) -> T { | ||
let msg = msg.into(); | ||
let (prefix, msg) = match msg.find(|c: char| !c.is_whitespace()) { | ||
Some(idx) if idx > 0 => msg.split_at(idx), | ||
_ => ("", msg.as_ref()), | ||
}; | ||
|
||
let pb = global_multi_progress().add(ProgressBar::new_spinner()); | ||
pb.enable_steady_tick(Duration::from_millis(100)); | ||
pb.set_style(long_running_progress_style()); | ||
pb.set_prefix(prefix.to_string()); | ||
pb.set_message(msg.to_string()); | ||
let result = future(pb.clone()).await; | ||
pb.finish_and_clear(); | ||
result | ||
} | ||
|
||
/// Style an existing progress bar with a warning style and the given message. | ||
pub fn style_warning_pb(pb: ProgressBar, warning_msg: String) -> ProgressBar { | ||
pb.set_style( | ||
indicatif::ProgressStyle::default_spinner() // Or default_bar() if you used ProgressBar::new(length) | ||
.template(" {spinner:.yellow} {wide_msg:.yellow}") // Yellow spinner, clear message | ||
.expect("failed to set a progress bar template"), | ||
); | ||
pb.set_message(warning_msg); | ||
pb.enable_steady_tick(Duration::from_millis(100)); | ||
pb | ||
} | ||
|
||
/// A struct that can be used to format the message part of a progress bar. | ||
/// | ||
/// It's primary usecase is when you have a single progress bar but multiple | ||
/// tasks that are running and which you want to communicate to the user. This | ||
/// struct will set the message part of the passed progress bar to the oldest | ||
/// unfinished task and include a the number of pending tasks. | ||
#[derive(Debug)] | ||
pub struct ProgressBarMessageFormatter { | ||
state: Arc<Mutex<State>>, | ||
} | ||
|
||
/// Internal state kept by the [`ProgressBarMessageFormatter`] and derived | ||
/// state. | ||
/// | ||
/// This contains the state of the formatter and allows updating the progress | ||
/// bar. | ||
#[derive(Debug)] | ||
struct State { | ||
pb: ProgressBar, | ||
pending: Vec<String>, | ||
} | ||
|
||
impl State { | ||
/// Notify the state that a certain operation happened. | ||
fn notify(&mut self, msg: Operation) { | ||
match msg { | ||
Operation::Started(op) => self.pending.push(op), | ||
Operation::Finished(op) => { | ||
let Some(idx) = self.pending.iter().position(|p| p == &op) else { | ||
panic!("operation {op} was never started"); | ||
}; | ||
self.pending.remove(idx); | ||
} | ||
} | ||
|
||
if self.pending.is_empty() { | ||
self.pb.set_message(""); | ||
} else if self.pending.len() == 1 { | ||
self.pb.set_message(self.pending[0].clone()); | ||
} else { | ||
self.pb.set_message(format!( | ||
"{} (+{})", | ||
self.pending.last().unwrap(), | ||
self.pending.len() - 1 | ||
)); | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
enum Operation { | ||
Started(String), | ||
Finished(String), | ||
} | ||
|
||
pub struct ScopedTask { | ||
state: Option<Arc<Mutex<State>>>, | ||
name: String, | ||
} | ||
|
||
impl ScopedTask { | ||
fn start(name: String, state: Arc<Mutex<State>>) -> Self { | ||
state.lock().notify(Operation::Started(name.clone())); | ||
Self { | ||
state: Some(state), | ||
name, | ||
} | ||
} | ||
|
||
/// Finishes the execution of the task. | ||
pub fn finish(self) { | ||
drop(self); | ||
} | ||
} | ||
|
||
impl Drop for ScopedTask { | ||
fn drop(&mut self) { | ||
if let Some(state) = self.state.take() { | ||
state | ||
.lock() | ||
.notify(Operation::Finished(std::mem::take(&mut self.name))); | ||
} | ||
} | ||
} | ||
|
||
impl ProgressBarMessageFormatter { | ||
/// Allows the user to specify a custom capacity for the internal channel. | ||
pub fn new(pb: ProgressBar) -> Self { | ||
Self { | ||
state: Arc::new(Mutex::new(State { | ||
pb, | ||
pending: Vec::new(), | ||
})), | ||
} | ||
} | ||
|
||
/// Adds the start of another task to the progress bar and returns an object | ||
/// that is used to mark the lifetime of the task. If the object is | ||
/// dropped the task is considered finished. | ||
#[must_use] | ||
pub fn start(&self, op: String) -> ScopedTask { | ||
ScopedTask::start(op, self.state.clone()) | ||
} | ||
|
||
/// Wraps an future into a task which starts when the task starts and ends | ||
/// when the future returns. | ||
pub async fn wrap<T, F: Future<Output = T>>(&self, name: impl Into<String>, fut: F) -> T { | ||
let task = self.start(name.into()); | ||
let result = fut.await; | ||
task.finish(); | ||
result | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
use indicatif::{MultiProgress, ProgressBar}; | ||
|
||
#[derive(Default, Clone)] | ||
pub enum ProgressBarPlacement { | ||
/// The progress bar is placed as the first progress bar. | ||
Top, | ||
/// The progress bar is placed as the last progress bar. | ||
#[default] | ||
Bottom, | ||
/// The progress bar is placed after the given progress bar. | ||
After(ProgressBar), | ||
/// The progress bar is placed before the given progress bar. | ||
Before(ProgressBar), | ||
} | ||
|
||
impl ProgressBarPlacement { | ||
/// Add the specified progress bar to the given multi progress instance | ||
pub fn insert(&self, multi_progress: MultiProgress, progress_bar: ProgressBar) -> ProgressBar { | ||
match self { | ||
ProgressBarPlacement::After(after) => multi_progress.insert_after(after, progress_bar), | ||
ProgressBarPlacement::Before(before) => { | ||
multi_progress.insert_before(before, progress_bar) | ||
} | ||
ProgressBarPlacement::Top => multi_progress.insert(0, progress_bar), | ||
ProgressBarPlacement::Bottom => multi_progress.add(progress_bar), | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
//! Defines some functions that can be used to style indicatif progress bars. | ||
|
||
/// The characters to use to show progress in the progress bar. | ||
const DEFAULT_PROGRESS_CHARS: &str = "━━╾─"; | ||
|
||
/// The characters that make up animation of a spinner that should be used when | ||
/// the progress bar is currently making progress. | ||
const DEFAULT_RUNNING_SPINNER_CHARS: &str = "⠁⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠠⠠⠤⠦⠖⠒⠐⠐⠒⠓⠋⠉⠈⠈ "; | ||
|
||
/// The characters that make up an animation of a spinner that should be used | ||
/// when the progress bar is currently paused or not making progress. | ||
const DEFAULT_PAUSED_SPINNER_CHARS: &str = "▪▪"; | ||
|
||
/// Returns the "tick chars" that are used to represent a spinner animation of a | ||
/// progress bar. | ||
pub fn tick_chars(active: bool) -> &'static str { | ||
if active { | ||
DEFAULT_RUNNING_SPINNER_CHARS | ||
} else { | ||
DEFAULT_PAUSED_SPINNER_CHARS | ||
} | ||
} | ||
|
||
/// Returns the "progress chars" that are used to render a progress bar. | ||
pub fn progress_chars(_active: bool) -> &'static str { | ||
DEFAULT_PROGRESS_CHARS | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll remove it. It was used before refactor.