├── src ├── lib.rs ├── constants.rs ├── main.rs ├── file_management.rs ├── upload.rs └── utils.rs ├── .gitignore ├── img └── shuk.png ├── trabant.jpeg ├── .cargo └── config.toml ├── Cargo.toml ├── BUILDING.md ├── README.md ├── CHANGELOG.md ├── install_script.sh ├── .github └── workflows │ └── release.yml └── Cargo.lock /src/lib.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /img/shuk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darko-mesaros/shuk/HEAD/img/shuk.png -------------------------------------------------------------------------------- /trabant.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darko-mesaros/shuk/HEAD/trabant.jpeg -------------------------------------------------------------------------------- /src/constants.rs: -------------------------------------------------------------------------------- 1 | // CONFIGURATION FILES 2 | pub static CONFIG_DIR_NAME: &str = "shuk"; 3 | pub static CONFIG_FILE_NAME: &str = "shuk.toml"; 4 | 5 | // UPDATED: 2024-04-20 6 | pub static CONFIG_FILE: &str = r#"bucket_name = "foo" 7 | bucket_prefix = "bar" 8 | presigned_time = 86400 9 | aws_profile = "default" 10 | use_clipboard = false 11 | fallback_region = "us-east-1" 12 | "#; 13 | -------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.x86_64-unknown-linux-musl] 2 | rustflags = ["-C", "target-feature=+crt-static"] 3 | [target.x86_64-pc-windows-msvc] 4 | rustflags = ["-C", "target-feature=+crt-static"] 5 | [target.x86_64-apple-darwin] 6 | rustflags = ["-C", "target-feature=+crt-static"] 7 | [target.aarch64-apple-darwin] 8 | rustflags = ["-C", "target-feature=+crt-static"] 9 | [target.aarch64-unknown-linux-musl] 10 | rustflags = ["-C", "target-feature=+crt-static"] 11 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "shuk" 3 | description = "A command line tool that uploads files to Amazon S3 buckets, and generates presigned URLs for easy sharing." 4 | version = "0.4.7" 5 | edition = "2021" 6 | authors = ["Darko Mesaros "] 7 | license = "MIT OR Apache-2.0" 8 | keywords = ["aws", "s3", "filesharing"] 9 | categories = ["command-line-utilities"] 10 | readme = "README.md" 11 | homepage = "https://rup12.net" 12 | repository = "https://github.com/darko-mesaros/shuk" 13 | exclude = [ 14 | "img/*" 15 | ] 16 | 17 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 18 | 19 | [build-dependencies] 20 | pkg-config = "0.3.31" 21 | 22 | [dependencies] 23 | anyhow = "1.0.80" 24 | aws-config = "1.5.10" 25 | aws-sdk-s3 = { version = "1.61.0", features = ["rt-tokio"] } 26 | aws-smithy-runtime-api = { version = "1.7.3", features = ["client"] } 27 | aws-smithy-types = { version = "1.2.9", features = ["http-body-0-4-x"] } 28 | aws-types = "1.3.3" 29 | bytes = "1.5.0" 30 | chrono = "0.4.38" 31 | clap = { version = "4.5.2", features = ["derive"] } 32 | colored = "2.1.0" 33 | dirs = "5.0.1" 34 | env_logger = "0.11.5" 35 | http = "0.2.12" 36 | http-body = "0.4.6" 37 | indicatif = "0.17.8" 38 | log = "0.4.22" 39 | md5 = "0.7.0" 40 | pin-project = "1.1.5" 41 | serde = { version = "1.0.197", features = ["derive"] } 42 | serde_derive = "1.0.197" 43 | tokio = { version = "1.36.0", features = ["full"] } 44 | toml = "0.8.11" 45 | tracing = "0.1.40" 46 | tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } 47 | -------------------------------------------------------------------------------- /BUILDING.md: -------------------------------------------------------------------------------- 1 | # Compilation instructions 2 | 3 | To create a statically linked binary, you'll need different approaches depending on the target platform. Here are the methods for each OS: 4 | 5 | For Linux (using musl): 6 | ```bash 7 | # Install musl target 8 | rustup target add x86_64-unknown-linux-musl 9 | 10 | # Build 11 | cargo build --target x86_64-unknown-linux-musl --release 12 | ``` 13 | 14 | For macOS (static linking is not fully possible due to OS restrictions): 15 | ```bash 16 | # The best we can do on macOS is use the native target 17 | cargo build --release 18 | ``` 19 | 20 | For Windows: 21 | ```bash 22 | # Install the MSVC target 23 | rustup target add x86_64-pc-windows-msvc 24 | 25 | # Build 26 | cargo build --target x86_64-pc-windows-msvc --release 27 | ``` 28 | 29 | To make this easier, you can create a `.cargo/config.toml` file in your project: 30 | 31 | ```toml 32 | [target.x86_64-unknown-linux-musl] 33 | rustflags = ["-C", "target-feature=+crt-static"] 34 | 35 | [target.x86_64-pc-windows-msvc] 36 | rustflags = ["-C", "target-feature=+crt-static"] 37 | 38 | [target.x86_64-apple-darwin] 39 | rustflags = ["-C", "target-feature=+crt-static"] 40 | ``` 41 | 42 | For Linux, you might also need to install some dependencies: 43 | ```bash 44 | # Ubuntu/Debian 45 | sudo apt install musl-tools 46 | 47 | # Fedora 48 | sudo dnf install musl-gcc 49 | ``` 50 | 51 | To verify that your binary is statically linked on Linux: 52 | ```bash 53 | ldd target/x86_64-unknown-linux-musl/release/your_binary 54 | # Should output "not a dynamic executable" 55 | ``` 56 | 57 | Remember that since we're using system commands (`xclip`, `pbcopy`, `clip`), the binary itself will be static but will still require these system utilities to be present on the target system. 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Shuk 💾 ➡️ 🪣 2 | 3 | ![screenshot of shuk](/img/shuk.png) 4 | 5 | ⚠️**BETA SOFTWARE**⚠️ 6 | 7 | *Shuk* is used to upload files *of any size* to [Amazon S3](https://aws.amazon.com/s3/) and have them shared with others via a [presigned URL](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPreSignedURL.html). If the same file already exists at the same location, it will **only presign it**. 8 | 9 | ## Installation 💾 10 | 11 | To install this tool, make sure you have `rust` and `cargo` installed and run: 12 | ``` 13 | cargo install shuk 14 | ``` 15 | 16 | > **NOTE**: Whenever installing a new version, run `shuk --init` for best results. Sometimes new configuration options are added. 17 | 18 | ## Usage 🚀 19 | ``` 20 | Usage: shuk [OPTIONS] [FILENAME] 21 | 22 | Arguments: 23 | [FILENAME] 24 | 25 | Options: 26 | --init 27 | -v, --verbose Enable verbose logging 28 | -h, --help Print help 29 | -V, --version Print version 30 | ``` 31 | 32 | Just pass the filename as the argument to `shuk`: 33 | ```bash 34 | shuk filename.bla 35 | ``` 36 | 37 | ## Configuration 🔧 38 | 39 | All the configuration is located in the `$HOME/.config/shuk.shuk.toml` file. 40 | 41 | ```toml 42 | # The bucket name where the files will be uploaded 43 | bucket_name = "alan-ford-bucket" 44 | # The prefix (folder) for the uploads. Leave blank "" for the root of the bucket 45 | bucket_prefix = "shuk" 46 | # Length of time in seconds on how long will the presigned URL be valid for 47 | presigned_time = 86400 48 | # The AWS profile shuk will use 49 | aws_profile = "default" 50 | # Should the presigned URL be stored directly to the clipboard or not 51 | use_clipboard = false 52 | # Set the fallback region 53 | fallback_region = "us-east-1" 54 | ``` 55 | 56 | To automatically configure this file just run `shuk --init` 57 | 58 | ## Build Notes 59 | 60 | Check the `BUILDING.md` file in this repo. 61 | 62 | ## Troubleshooting 63 | 64 | This project uses the [log](https://crates.io/crates/log) crate. To get different levels of logging set the `SHUK_LOG` environment variable to either `trace`, `warn`, `info`, `debug`, or `error`. By default it is using the `warn` level. 65 | 66 | Or better yet, just pass the `--verbose` flag, as this will run the `trace` level output. Be careful, there will be a lot of stuff on your screen. 67 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## TODO 📋 11 | 12 | - TODO: Ability to delete objects 13 | - TODO: Ability to archive objects 14 | - TODO: Have the progress bar remain on screen, or show summary of upload. 15 | - TODO: Have the ability to configure the chunk size for multi-part uploads 16 | - TODO: User configurable tags 17 | 18 | ## [0.4.7] - 2024-12-10 19 | 20 | ### Changed 21 | - Reworked the way copy to clipboard works. Now we use native tools within the OS (`xclip`, `pbcopy`, `clip.exe`) 22 | - Configured the build to be statically linked 23 | 24 | ## [0.4.6] - 2024-11-17 25 | ### Added 26 | - Shuk now checks if a file is already uploaded, and if it is it just presigns it again. 27 | - Proper tracing and logging using the log crate 28 | 29 | ### Changed 30 | - Cleaned up some code 31 | - Updated the AWS Crates to latest 32 | - Fixed region selection during the SDK configuration - MAKE SURE TO UPDATE YOUR CONFIG FILE 33 | 34 | ## [0.4.4] - 2024-07-31 35 | ### Changed 36 | - Improved some error handling 37 | 38 | ## [0.4.2] - 2024-07-14 39 | ### Added 40 | - Ability to directly save the presigned URL to the system clipboard 41 | 42 | ## [0.4.1] - 2024-06-10 43 | ### Changed 44 | - Improved the way we read and write the AWS Profile 45 | - Fixed the way we write to the `shuk.toml` config file 46 | 47 | ### Thanks <3 48 | - kaumnen 49 | - noc7c9 50 | - Research_DEV 51 | 52 | ## [0.4.0] - 2024-06-01 53 | ### Added 54 | - The tool is now able to be installed and configured locally. 55 | - You can run `--init` to set up the local configuration file in `~/.config/shuk` 56 | 57 | 58 | ## [0.3.1] - 2024-06-01 59 | ### Added 60 | - AWS Profile selection from the config file 61 | - The uploaded objects are now tagged with `deployed_by:shuk` 62 | - Added the ability to define a prefix (folder) where to upload the files 63 | 64 | ### Changed 65 | - Uses the AWS region from the profile first, then falls back to `us-west-2` 66 | - Cleaned up the upload function, now its only a single one with the logic inside. 67 | - Improved the path handling (works with non UTF-8 characters) 68 | 69 | ## [0.3.0] - 2024-05-31 70 | ### Added 71 | - Can upload files larger than 5GB (thanks to multi-part uploads) 72 | 73 | ## [0.2.0] - 2024-03-12 74 | ### Added 75 | - Can now parse filename from arguments 76 | - We have a configuration file for bucket name 77 | - Can presign file when uploaded. 78 | 79 | ## [0.1.0] - 2024-03-11 80 | ### Added 81 | - Basic functionality 82 | - Uploads fixed files to fixed buckets 83 | -------------------------------------------------------------------------------- /install_script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Universal installer script 3 | set -e 4 | 5 | # REQUIREMENTS: 6 | # curl 7 | 8 | # Configuration 9 | GITHUB_REPO="darko-mesaros/shuk" 10 | BINARY_NAME="shuk" 11 | INSTALL_DIR="$HOME/.local/bin" 12 | 13 | # Print error and exit 14 | error() { 15 | echo "Error: $1" 16 | exit 1 17 | } 18 | 19 | # Detect OS and architecture 20 | detect_platform() { 21 | local os arch 22 | 23 | # Detect OS 24 | case "$(uname -s)" in 25 | Linux) 26 | os="unknown-linux-musl" 27 | ;; 28 | Darwin) 29 | os="apple-darwin" 30 | ;; 31 | MINGW*|MSYS*|CYGWIN*) 32 | os="pc-windows-msvc" 33 | ;; 34 | *) 35 | error "unsupported OS: $(uname -s)" 36 | ;; 37 | esac 38 | 39 | # Detect architecture 40 | case "$(uname -m)" in 41 | x86_64|amd64) 42 | arch="x86_64" 43 | ;; 44 | arm64|aarch64) 45 | arch="aarch64" 46 | ;; 47 | *) 48 | error "unsupported architecture: $(uname -m)" 49 | ;; 50 | esac 51 | 52 | echo "${arch}-${os}" 53 | } 54 | 55 | # Get latest version from GitHub 56 | get_latest_version() { 57 | curl --silent "https://api.github.com/repos/${GITHUB_REPO}/releases/latest" | 58 | grep '"tag_name":' | 59 | sed -E 's/.*"([^"]+)".*/\1/' 60 | } 61 | 62 | # Download and install the binary 63 | install() { 64 | local platform="$1" 65 | local version="$2" 66 | local tmp_dir 67 | local ext 68 | 69 | # Determine file extension 70 | case "$platform" in 71 | *windows*) 72 | ext=".exe" 73 | ;; 74 | *) 75 | ext="" 76 | ;; 77 | esac 78 | 79 | # Create temporary directory 80 | tmp_dir=$(mktemp -d) 81 | trap 'rm -rf "$tmp_dir"' EXIT 82 | 83 | echo "Downloading ${BINARY_NAME} ${version} for ${platform}..." 84 | 85 | # Download and extract 86 | # https://github.com/darko-mesaros/shuk/releases/download/v0.4.6/shuk-x86_64-unknown-linux-gnu.tar.gz 87 | curl -sL "https://github.com/${GITHUB_REPO}/releases/download/${version}/${BINARY_NAME}-${platform}.tar.gz" | 88 | tar xz -C "$tmp_dir" 89 | 90 | # Create install directory if it doesn't exist 91 | mkdir -p "$INSTALL_DIR" 92 | 93 | # Install binary 94 | mv "${tmp_dir}/${BINARY_NAME}${ext}" "${INSTALL_DIR}/${BINARY_NAME}${ext}" 95 | chmod +x "${INSTALL_DIR}/${BINARY_NAME}${ext}" 96 | 97 | echo "Successfully installed ${BINARY_NAME} to ${INSTALL_DIR}/${BINARY_NAME}${ext}" 98 | } 99 | 100 | # Check if curl is available 101 | command -v curl >/dev/null 2>&1 || error "curl is required but not installed" 102 | 103 | # Detect platform 104 | PLATFORM=$(detect_platform) 105 | 106 | # Get latest version if not specified 107 | VERSION=${1:-$(get_latest_version)} 108 | 109 | # Install 110 | install "$PLATFORM" "$VERSION" 111 | 112 | # Add to PATH instructions 113 | case "$(uname -s)" in 114 | MINGW*|MSYS*|CYGWIN*) 115 | echo " 116 | Please add ${INSTALL_DIR} to your PATH: 117 | setx PATH \"%PATH%;${INSTALL_DIR}\" 118 | " 119 | ;; 120 | *) 121 | echo " 122 | Please add ${INSTALL_DIR} to your PATH: 123 | export PATH=\"\$PATH:${INSTALL_DIR}\" 124 | 125 | You can add this line to your ~/.bashrc or ~/.zshrc file to make it permanent. 126 | " 127 | ;; 128 | esac 129 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Test Release 2 | permissions: 3 | contents: write 4 | on: 5 | release: 6 | types: [created] 7 | workflow_dispatch: 8 | inputs: 9 | test_mode: 10 | description: 'Run in test mode (skips actual release creation)' 11 | type: boolean 12 | default: true 13 | test_version: 14 | description: 'Test version number (e.g., 0.0.0-test)' 15 | type: string 16 | default: '0.0.0-test' 17 | jobs: 18 | create-release: 19 | runs-on: ubuntu-latest 20 | if: ${{ !inputs.test_mode }} 21 | steps: 22 | - uses: actions/checkout@v4 23 | - uses: taiki-e/create-gh-release-action@v1 24 | with: 25 | changelog: CHANGELOG.md 26 | token: ${{ secrets.GITHUB_TOKEN }} 27 | test-release: 28 | runs-on: ubuntu-latest 29 | if: ${{ inputs.test_mode }} 30 | steps: 31 | - uses: actions/checkout@v4 32 | - name: Simulate release creation 33 | run: | 34 | echo "Testing release process for version ${{ inputs.test_version }}" 35 | echo "Checking CHANGELOG.md exists" 36 | test -f CHANGELOG.md || (echo "CHANGELOG.md not found" && exit 1) 37 | upload-assets: 38 | needs: [create-release, test-release] 39 | if: ${{ always() && (needs.create-release.result == 'success' || needs.test-release.result == 'success') }} 40 | strategy: 41 | matrix: 42 | include: 43 | # x86_64 targets 44 | - target: x86_64-unknown-linux-musl 45 | os: ubuntu-latest 46 | - target: x86_64-apple-darwin 47 | os: macos-latest 48 | - target: x86_64-pc-windows-msvc 49 | os: windows-latest 50 | # ARM64 targets 51 | - target: aarch64-unknown-linux-musl 52 | os: ubuntu-latest 53 | - target: aarch64-apple-darwin 54 | os: macos-latest 55 | # Universal macOS binary 56 | #- target: universal-apple-darwin 57 | # os: macos-latest 58 | runs-on: ${{ matrix.os }} 59 | steps: 60 | - uses: actions/checkout@v4 61 | 62 | # Install cross-compilation tools for ARM on Linux 63 | - name: Install Linux dependencies 64 | if: contains(matrix.os, 'ubuntu') 65 | run: | 66 | sudo apt-get update 67 | sudo apt-get install -y musl-tools pkg-config gcc-aarch64-linux-gnu 68 | wget https://ziglang.org/download/0.13.0/zig-linux-x86_64-0.13.0.tar.xz 69 | tar xf zig-linux-x86_64-0.13.0.tar.xz 70 | echo "$PWD/zig-linux-x86_64-0.13.0" >> $GITHUB_PATH 71 | 72 | 73 | # Install Rust 74 | - name: Install Rust 75 | uses: actions-rs/toolchain@v1 76 | with: 77 | toolchain: stable 78 | target: ${{ matrix.target }} 79 | override: true 80 | 81 | # Install cargo-zigbuild for better musl support 82 | - name: Install cargo-zigbuild (Linux) 83 | if: contains(matrix.target, 'linux-musl') 84 | run: cargo install cargo-zigbuild 85 | 86 | # Build steps 87 | - name: Build (Linux musl) 88 | if: contains(matrix.target, 'linux-musl') 89 | run: | 90 | zig version 91 | cargo zigbuild --target ${{ matrix.target }} --release 92 | 93 | - name: Build (non-Linux) 94 | if: "!contains(matrix.target, 'linux-musl')" 95 | uses: actions-rs/cargo@v1 96 | with: 97 | command: build 98 | args: --target ${{ matrix.target }} --release 99 | 100 | # Test step (skip for cross-compiled targets) 101 | - name: Test 102 | if: "!contains(matrix.target, 'aarch64') && matrix.target != 'universal-apple-darwin'" 103 | uses: actions-rs/cargo@v1 104 | with: 105 | command: test 106 | args: --target ${{ matrix.target }} 107 | 108 | # Upload for actual releases 109 | - uses: taiki-e/upload-rust-binary-action@v1 110 | if: ${{ !inputs.test_mode }} 111 | with: 112 | bin: shuk 113 | target: ${{ matrix.target }} 114 | token: ${{ secrets.GITHUB_TOKEN }} 115 | 116 | # Package for test mode 117 | - name: Package binary (Test Mode) 118 | if: ${{ inputs.test_mode }} 119 | run: | 120 | cd target/${{ matrix.target }}/release 121 | tar czf ../../../shuk-${{ matrix.target }}.tar.gz shuk* 122 | cd ../../.. 123 | shell: bash 124 | 125 | # Upload artifacts for test mode 126 | - name: Upload artifact (Test Mode) 127 | if: ${{ inputs.test_mode }} 128 | uses: actions/upload-artifact@v3 129 | with: 130 | name: shuk-${{ matrix.target }} 131 | path: shuk-${{ matrix.target }}.tar.gz 132 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | pub mod constants; 2 | pub mod file_management; 3 | pub mod upload; 4 | pub mod utils; 5 | 6 | use clap::Parser; 7 | use std::io; 8 | use std::io::Write; 9 | use upload::upload_object; 10 | use utils::check_for_config; 11 | use utils::initialize_config; 12 | use utils::print_warning; 13 | 14 | #[tokio::main] 15 | async fn main() -> Result<(), anyhow::Error> { 16 | // Configure Logging 17 | let arguments = utils::Args::parse(); 18 | utils::setup_logging(arguments.verbose); 19 | log::trace!("Arguments parsed: {:?} ", &arguments); 20 | 21 | // Checking for the `--init` flag and then initializing the configuration 22 | if arguments.init { 23 | log::trace!("The --init parameter has been passed"); 24 | if check_for_config() { 25 | log::trace!("The configuration already exists"); 26 | print_warning("****************************************"); 27 | print_warning("WARNING:"); 28 | println!("You are trying to initialize the Shuk configuration"); 29 | println!("This will overwrite your configuration files in $HOME/.config/shuk/"); 30 | print!("ARE YOU SURE YOU WANT DO TO THIS? Y/N: "); 31 | io::stdout().flush()?; // so the answers are typed on the same line as above 32 | 33 | let mut confirmation = String::new(); 34 | io::stdin().read_line(&mut confirmation)?; 35 | if confirmation.trim().eq_ignore_ascii_case("y") { 36 | print_warning("I ask AGAIN"); 37 | print!("ARE YOU SURE YOU WANT DO TO THIS? Y/N: "); 38 | io::stdout().flush()?; // so the answers are typed on the same line as above 39 | 40 | let mut confirmation = String::new(); 41 | io::stdin().read_line(&mut confirmation)?; 42 | 43 | if confirmation.trim().eq_ignore_ascii_case("y") { 44 | println!("----------------------------------------"); 45 | println!("📜 | Initializing Shuk configuration."); 46 | initialize_config().await?; 47 | } 48 | } 49 | } else { 50 | log::trace!("The configuration does not exist"); 51 | println!("----------------------------------------"); 52 | println!("📜 | Initializing Shuk configuration."); 53 | initialize_config().await?; 54 | } 55 | print_warning("Shuk will now exit"); 56 | std::process::exit(0); 57 | } 58 | 59 | // parse configuration 60 | let shuk_config = match utils::Config::load_config() { 61 | Ok(config) => { 62 | log::trace!("The configuration is loaded from the file: {:#?}", &config); 63 | config 64 | }, 65 | Err(e) => { 66 | eprintln!("Failed to load configuration. Make sure that your config file is located at ~/.config/shuk: {}", e); 67 | std::process::exit(1); 68 | } 69 | }; 70 | // configure aws 71 | let config = utils::configure_aws( 72 | shuk_config 73 | .fallback_region 74 | .as_deref() 75 | .unwrap_or("us-east-1") 76 | .to_string(), 77 | shuk_config.aws_profile.as_ref(), 78 | ) 79 | .await; 80 | // setup the bedrock-runtime client 81 | let s3_client = aws_sdk_s3::Client::new(&config); 82 | 83 | let key = arguments.filename.clone(); 84 | let file_name = arguments 85 | .filename 86 | .expect("Unable to determine the file name from the command line parameters"); 87 | // NOTE: Getting just the key (file name) 88 | let key_file_name = key 89 | .as_ref() 90 | .and_then(|path| path.file_name()) 91 | .and_then(|name| name.to_str()) 92 | .map(|s| s.trim_matches('"')) 93 | .ok_or_else(|| anyhow::anyhow!("Invalid filename provided"))?; 94 | 95 | let key_full = if shuk_config.bucket_prefix.is_some() { 96 | format!( 97 | "{}{}", 98 | &shuk_config 99 | .bucket_prefix 100 | .clone() 101 | .unwrap_or_else(|| "".into()), 102 | &key_file_name 103 | ) 104 | } else { 105 | key_file_name.to_string() 106 | }; 107 | 108 | // Calculate partial MD5 of the local file 109 | let md5_of_file = file_management::calculate_partial_hash(&file_name.clone())?; 110 | // Prep the tags 111 | let file_tags = file_management::ObjectTags { 112 | managed_by: "shuk".into(), 113 | start_hash: md5_of_file.start_hash, 114 | end_hash: md5_of_file.end_hash, 115 | }; 116 | log::trace!("File tags defined: {:#?}", &file_tags); 117 | 118 | let just_upload = match file_management::file_exists_in_s3( 119 | &s3_client, 120 | &shuk_config.bucket_name, 121 | key_full.as_str(), 122 | ) 123 | .await 124 | { 125 | // Call was a success 126 | Ok(o) => { 127 | log::trace!("The call to check if the file exists has been a success"); 128 | if o { 129 | // It exists - lets see if it is the same 130 | if file_management::quick_compare( 131 | &file_name, 132 | &shuk_config.bucket_name, 133 | key_full.as_str(), 134 | &file_tags, 135 | &s3_client, 136 | ) 137 | .await? 138 | { 139 | // They are the same - just presing 140 | true 141 | } else { 142 | // They are not the same, upload 143 | false 144 | } 145 | } else { 146 | // File does not exist 147 | // Just upload the file 148 | false 149 | } 150 | } 151 | // The SDK call failed 152 | Err(e) => { 153 | eprintln!("Error: Could not determine if a the file exists - {}", e); 154 | false 155 | } 156 | }; 157 | 158 | match upload_object( 159 | &s3_client, 160 | &file_name, 161 | key_file_name, 162 | file_tags, 163 | just_upload, 164 | &shuk_config, 165 | ) 166 | .await 167 | { 168 | Ok(presigned_url) => { 169 | if shuk_config.use_clipboard.unwrap_or(false) { 170 | if let Err(e) = utils::set_into_clipboard(presigned_url) { 171 | eprintln!("Error setting clipboard: {}", e); 172 | } 173 | } 174 | } 175 | Err(e) => { 176 | eprintln!("Error uploading file: {}", e); 177 | std::process::exit(1); 178 | } 179 | } 180 | 181 | Ok(()) 182 | } 183 | -------------------------------------------------------------------------------- /src/file_management.rs: -------------------------------------------------------------------------------- 1 | use aws_sdk_s3::error::SdkError; 2 | use aws_sdk_s3::operation::head_object::HeadObjectError; 3 | use aws_sdk_s3::presigning::PresigningConfig; 4 | use aws_sdk_s3::Client; 5 | use md5; 6 | use std::fs::File; 7 | use std::io::{Read, Seek, SeekFrom}; 8 | use std::{path::Path, time::Duration}; 9 | 10 | use colored::Colorize; 11 | 12 | #[derive(Debug)] 13 | pub struct ObjectTags { 14 | pub managed_by: String, 15 | pub start_hash: String, 16 | pub end_hash: String, 17 | } 18 | 19 | // This converst the Struct into a list of tags the way the API accepts it 20 | // NOTE: Maybe I can create a dedicated function for this instead of using Dispay 21 | impl std::fmt::Display for ObjectTags { 22 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 23 | write!( 24 | f, 25 | "managed_by={}&start_hash={}&end_hash={}", 26 | self.managed_by, self.start_hash, self.end_hash 27 | ) 28 | } 29 | } 30 | 31 | // Needed for the tagging 32 | impl From<&ObjectTags> for String { 33 | fn from(tags: &ObjectTags) -> String { 34 | tags.to_string() // This uses your Display implementation 35 | } 36 | } 37 | 38 | pub async fn presign_file( 39 | client: &Client, 40 | bucket_name: &str, 41 | key: &str, 42 | prefix: Option, 43 | presigned_time: u64, 44 | ) -> Result { 45 | log::trace!( 46 | "Presigning file: {:?}/{} in bucket {} for duration of {}", 47 | &prefix, 48 | &key, 49 | &bucket_name, 50 | &presigned_time 51 | ); 52 | let expires_in = Duration::from_secs(presigned_time); 53 | log::trace!("Sending get_object request that will presing the file"); 54 | let presigned_request = client 55 | .get_object() 56 | .bucket(bucket_name) 57 | .key(format!("{}{}", prefix.unwrap_or("".into()), key)) 58 | .presigned(PresigningConfig::expires_in(expires_in)?) 59 | .await?; 60 | 61 | Ok(presigned_request.uri().to_string()) 62 | } 63 | 64 | pub fn calculate_file_md5>(path: P) -> Result { 65 | // Open and read the entire file 66 | let mut file = File::open(path)?; 67 | let mut contents = Vec::new(); 68 | file.read_to_end(&mut contents)?; 69 | 70 | // Calculate MD5 71 | let digest = md5::compute(&contents); 72 | 73 | // Convert to hex string 74 | Ok(format!("{:x}", digest)) 75 | } 76 | 77 | // Just used to store the partial file hash 78 | #[derive(Debug)] 79 | pub struct PartialFileHash { 80 | pub start_hash: String, 81 | pub end_hash: String, 82 | pub file_size: u64, 83 | } 84 | 85 | pub fn calculate_partial_hash(local_path: &Path) -> Result { 86 | log::trace!("Calculating partial hash of {:?}", &local_path); 87 | const SAMPLE_SIZE: usize = 8192; 88 | 89 | let mut file = File::open(local_path)?; 90 | let file_size = file.metadata()?.len(); 91 | log::trace!("File size of {:?} is {:?}", &local_path, &file_size); 92 | 93 | let mut start_buffer = vec![0; SAMPLE_SIZE]; 94 | let start_bytes_read = file.read(&mut start_buffer)?; 95 | start_buffer.truncate(start_bytes_read); 96 | let start_hash = format!("{:x}", md5::compute(&start_buffer)); 97 | log::trace!("Start hash of {:?} is {:?}", &local_path, &start_hash); 98 | 99 | // This is just a check if the file is too small (less than 8KB as is the sample size by 100 | // default). 101 | // This should not happen, but is here just in case. 102 | let end_hash = if file_size > SAMPLE_SIZE as u64 { 103 | // Move to the end of file - SAMPLE_SIZE 104 | file.seek(SeekFrom::End(-(SAMPLE_SIZE as i64)))?; 105 | let mut end_buffer = vec![0; SAMPLE_SIZE]; 106 | let end_bytes_read = file.read(&mut end_buffer)?; 107 | end_buffer.truncate(end_bytes_read); 108 | format!("{:x}", md5::compute(&end_buffer)) 109 | } else { 110 | // The file is too small just use the start_hash 111 | log::warn!("The file seems to be smaller than the sample size for hashing. Not sure how we got here."); 112 | start_hash.clone() 113 | }; 114 | log::trace!("End hash of {:?} is {:?}", &local_path, &end_hash); 115 | 116 | Ok(PartialFileHash { 117 | start_hash, 118 | end_hash, 119 | file_size, 120 | }) 121 | } 122 | 123 | pub async fn file_exists_in_s3( 124 | client: &Client, 125 | bucket: &str, 126 | key: &str, 127 | ) -> Result { 128 | log::trace!("Testing if {:?} exists in bucket {:?}", &key, &bucket); 129 | match client.head_object().bucket(bucket).key(key).send().await { 130 | Ok(_) => { 131 | log::trace!("File {:?} has been found in bucket {:?}", &key, &bucket); 132 | Ok(true) 133 | } 134 | Err(err) => { 135 | match err { 136 | SdkError::ServiceError(err) => { 137 | match err.err() { 138 | // If the error NotFound is returned - return false 139 | HeadObjectError::NotFound(_) => { 140 | log::trace!("File {:?} not found in bucket {:?}", &key, &bucket); 141 | Ok(false) 142 | } 143 | other_err => { 144 | log::warn!("There was a service error when checking for file {:?} in bucket {:?}", &key, &bucket); 145 | Err(anyhow::anyhow!("S3 service error: {:?}", other_err)) 146 | } 147 | } 148 | } 149 | other_err => { 150 | log::warn!( 151 | "There was a SDK when checking for file {:?} in bucket {:?}", 152 | &key, 153 | &bucket 154 | ); 155 | Err(anyhow::anyhow!("S3 SDK error: {:?}", other_err)) 156 | } 157 | } 158 | } 159 | } 160 | } 161 | 162 | // If you need metadata version: 163 | async fn get_file_metadata( 164 | client: &Client, 165 | bucket: &str, 166 | key: &str, 167 | ) -> Result, anyhow::Error> { 168 | log::trace!("Getting file metadata for {}:{}", &bucket, &key); 169 | match client.head_object().bucket(bucket).key(key).send().await { 170 | Ok(output) => { 171 | log::trace!( 172 | "Metadata has been extracted for {:?} in bucket {:?}", 173 | &key, 174 | &bucket 175 | ); 176 | Ok(Some(output)) 177 | } 178 | Err(err) => { 179 | match err { 180 | SdkError::ServiceError(err) => match err.err() { 181 | HeadObjectError::NotFound(_) => { 182 | log::warn!("Unable to find {:?} in bucket {:?}, there seems to be an issue getting metadata", &key, &bucket); 183 | Ok(None) 184 | } 185 | other_err => { 186 | log::warn!("There was a service error when gettinf metadata for file {:?} in bucket {:?}", &key, &bucket); 187 | Err(anyhow::anyhow!("S3 service error: {:?}", other_err)) 188 | } 189 | }, 190 | other_err => { 191 | log::warn!("There was a S3 SDK error when gettinf metadata for file {:?} in bucket {:?}", &key, &bucket); 192 | Err(anyhow::anyhow!("S3 SDK error: {:?}", other_err)) 193 | } 194 | } 195 | } 196 | } 197 | } 198 | 199 | // If you need metadata version: 200 | async fn get_file_tags( 201 | client: &Client, 202 | bucket: &str, 203 | key: &str, 204 | ) -> Result, anyhow::Error> 205 | { 206 | log::trace!("Getting file tags for {}:{}", &bucket, &key); 207 | match client 208 | .get_object_tagging() 209 | .bucket(bucket) 210 | .key(key) 211 | .send() 212 | .await 213 | { 214 | Ok(output) => { 215 | log::trace!( 216 | "Tags for {} in {} were succesfully retrieved.", 217 | &key, 218 | &bucket 219 | ); 220 | Ok(Some(output)) 221 | } 222 | Err(err) => { 223 | log::warn!( 224 | "There was a S3 Service error when getting tags for {} in {}.", 225 | &key, 226 | &bucket 227 | ); 228 | Err(anyhow::anyhow!("S3 service error: {:?}", err)) 229 | } 230 | } 231 | } 232 | 233 | pub async fn quick_compare( 234 | local_path: &Path, 235 | bucket_name: &str, 236 | key: &str, 237 | local_object_tags: &ObjectTags, 238 | c: &Client, 239 | ) -> Result { 240 | log::trace!( 241 | "Comparing local and remote files: {:?} and {}/{}", 242 | &local_path, 243 | &bucket_name, 244 | &key 245 | ); 246 | // Get file metadata 247 | let file = File::open(local_path)?; 248 | let file_size = file.metadata()?.len(); 249 | log::trace!("Local file {:?} size: {:?}", &local_path, &file_size); 250 | 251 | let object_metadata = get_file_metadata(c, bucket_name, key).await?; 252 | log::trace!( 253 | "Remote file {}{} metadata: {:#?}", 254 | &bucket_name, 255 | &key, 256 | &object_metadata 257 | ); 258 | let object_tags = get_file_tags(c, bucket_name, key).await?; 259 | log::trace!( 260 | "Remote file {}{} tags: {:#?}", 261 | &bucket_name, 262 | &key, 263 | &object_metadata 264 | ); 265 | 266 | // NOTE: Very complex way of making sure the length of my remote file is extracted 267 | // if I cannot do it, I just return 0 and we reupload 268 | let s3_object_len = match object_metadata { 269 | None => { 270 | println!("I was unable to determine the file size of the remote object, something went wrong, we are uploading it again"); 271 | 0 272 | } 273 | Some(metadata) => match metadata.content_length() { 274 | None => { 275 | println!("I was unable to determine the file size of the remote object, something went wrong, we are uploading it again"); 276 | 0 277 | } 278 | Some(len) => match len.try_into() { 279 | Ok(size) => size, 280 | Err(_) => { 281 | println!("I was unable to determine the file size of the remote object, something went wrong, we are uploading it again"); 282 | 0 283 | } 284 | }, 285 | }, 286 | }; 287 | log::trace!( 288 | "The size of the remote file {}{}: {}", 289 | &bucket_name, 290 | &key, 291 | &s3_object_len 292 | ); 293 | 294 | // Extracting the hash tags 295 | let tags = object_tags.unwrap(); 296 | let remote_start_hash = tags 297 | .tag_set() 298 | .iter() 299 | .find(|tag| tag.key() == "start_hash") 300 | .map(|tag| tag.value()) 301 | .unwrap_or_default(); 302 | log::trace!( 303 | "Remote file {}{} start_hash: {}", 304 | &bucket_name, 305 | &key, 306 | &remote_start_hash 307 | ); 308 | 309 | let remote_end_hash = tags 310 | .tag_set() 311 | .iter() 312 | .find(|tag| tag.key() == "end_hash") 313 | .map(|tag| tag.value()) 314 | .unwrap_or_default(); 315 | log::trace!( 316 | "Remote file {}{} end_hash: {}", 317 | &bucket_name, 318 | &key, 319 | &remote_end_hash 320 | ); 321 | 322 | // Compare the file size 323 | if file_size == s3_object_len { 324 | // If Same 325 | // Compare partial hash 326 | if local_object_tags.start_hash == remote_start_hash 327 | && local_object_tags.end_hash == remote_end_hash 328 | { 329 | // If the same - presign 330 | log::trace!("Both file are the same: local_object_tags.start_hash = {} == remote_start_hash {}; local_object_tags.end_hash = {} == remote_end_hash = {} ", &local_object_tags.start_hash, &remote_start_hash, &local_object_tags.end_hash, &remote_end_hash); 331 | Ok(true) 332 | } else { 333 | log::trace!("The filenames are the same, but their partial hashes differ: local_object_tags.start_hash = {} != remote_start_hash {}; local_object_tags.end_hash = {} != remote_end_hash = {} ", &local_object_tags.start_hash, &remote_start_hash, &local_object_tags.end_hash, &remote_end_hash); 334 | println!("{} | There seems to be a file with the same filename already at the destination. They are, also, the same sizes. HOWEVER, their partial hashes differ. I will assume that that they are different, so I will upload this one", "NOTE".yellow()); 335 | Ok(false) 336 | } 337 | } else { 338 | log::trace!( 339 | "The filenames are the same, but their sizes differ: file_size {} != s3_object_len {}", 340 | &file_size, 341 | &s3_object_len 342 | ); 343 | println!("{} | There seems to be a file with the same filename already at the destination. They differ in sizes, I will assume that that they are different, so I will upload this one", "NOTE".yellow()); 344 | Ok(false) 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /src/upload.rs: -------------------------------------------------------------------------------- 1 | use aws_sdk_s3::{ 2 | operation::create_multipart_upload::CreateMultipartUploadOutput, 3 | primitives::SdkBody, 4 | types::{CompletedMultipartUpload, CompletedPart}, 5 | Client, 6 | }; 7 | use aws_smithy_runtime_api::http::Request; 8 | use aws_smithy_types::byte_stream::{ByteStream, Length}; 9 | use std::{ 10 | convert::Infallible, 11 | fmt::Write, 12 | fs::File, 13 | io::prelude::*, 14 | path::{Path, PathBuf}, 15 | pin::Pin, 16 | task::{Context, Poll}, 17 | }; 18 | 19 | use bytes::Bytes; 20 | use http_body::{Body, SizeHint}; 21 | 22 | use indicatif::{ProgressBar, ProgressState, ProgressStyle}; 23 | 24 | use crate::file_management; 25 | use crate::utils; 26 | 27 | // NOTE: Anything smaller than 5MB causes the uploads to be slow(er) 28 | // The PART_SIZE needs to be at least 5MB 29 | const PART_SIZE: u64 = 5 * 1024 * 1024; // 5MB 30 | 31 | // NOTE: The upload with progress is from this example: 32 | // https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/rustv1/examples/s3/src/bin/put-object-progress.rs 33 | // It currently (2024-03-11) relies on older versions of `http` and `http-body` crates (0.x.x) 34 | // I have not managed to get it working with the latest ones due to the `SdkBody` not implementing 35 | // `Body` from these latest versions. 36 | // TODO: Speak to the AWS Rust SDK team to get this working 37 | struct ProgressTracker { 38 | bytes_written: u64, 39 | content_length: u64, 40 | bar: ProgressBar, 41 | } 42 | 43 | impl ProgressTracker { 44 | fn track(&mut self, len: u64) { 45 | self.bytes_written += len; 46 | let progress = self.bytes_written as f64 / self.content_length as f64; 47 | log::info!("Read {} bytes, progress: {:.2}&", len, progress * 100.0); 48 | if self.content_length != self.bytes_written { 49 | self.bar.set_position(self.bytes_written); 50 | } else { 51 | self.bar.finish_with_message("GOODBYE UPLOAD"); 52 | } 53 | } 54 | } 55 | 56 | // NOTE: I have no idea what Pin projection is 57 | // TODO: Learn what Pin projection is 58 | #[pin_project::pin_project] 59 | pub struct ProgressBody { 60 | #[pin] 61 | inner: InnerBody, 62 | progress_tracker: ProgressTracker, 63 | } 64 | 65 | impl ProgressBody { 66 | pub fn replace(value: Request) -> Result, Infallible> { 67 | let value = value.map(|body| { 68 | let len = body.content_length().expect("upload body sized"); // TODO:panics 69 | let body = ProgressBody::new(body, len); 70 | SdkBody::from_body_0_4(body) 71 | }); 72 | Ok(value) 73 | } 74 | } 75 | 76 | // inner body is an implementation of `Body` as far as i understand 77 | impl ProgressBody 78 | where 79 | InnerBody: Body, 80 | { 81 | pub fn new(body: InnerBody, content_length: u64) -> Self { 82 | // creating the progress bar for uploads: 83 | let bar = ProgressBar::new(content_length); 84 | bar.set_style(ProgressStyle::with_template("{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})") 85 | .unwrap() 86 | .with_key("eta", |state: &ProgressState, w: &mut dyn Write| write!(w,"{:.1}s", state.eta().as_secs_f64()).unwrap()) 87 | .progress_chars("#>-")); 88 | 89 | Self { 90 | inner: body, 91 | progress_tracker: ProgressTracker { 92 | bytes_written: 0, 93 | content_length, 94 | bar, 95 | }, 96 | } 97 | } 98 | } 99 | 100 | // Implementing `http_body::Body` for ProgressBody 101 | impl Body for ProgressBody 102 | where 103 | InnerBody: Body, 104 | { 105 | type Data = Bytes; 106 | type Error = aws_smithy_types::body::Error; 107 | 108 | fn poll_data( 109 | self: Pin<&mut Self>, 110 | cx: &mut Context<'_>, 111 | ) -> Poll>> { 112 | let mut this = self.project(); 113 | let result = match this.inner.as_mut().poll_data(cx) { 114 | //match this.inner.poll_data(cx) { 115 | Poll::Ready(Some(Ok(data))) => { 116 | this.progress_tracker.track(data.len() as u64); 117 | Poll::Ready(Some(Ok(data))) 118 | } 119 | Poll::Ready(None) => { 120 | // TODO: Figure out how to print something 121 | // at the end of the upload. Like a summary or whatever 122 | Poll::Ready(None) 123 | } 124 | Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))), 125 | Poll::Pending => Poll::Pending, 126 | }; 127 | result 128 | } 129 | 130 | fn poll_trailers( 131 | self: Pin<&mut Self>, 132 | cx: &mut Context<'_>, 133 | ) -> Poll, Self::Error>> { 134 | self.project().inner.poll_trailers(cx) 135 | } 136 | 137 | fn size_hint(&self) -> http_body::SizeHint { 138 | SizeHint::with_exact(self.progress_tracker.content_length) 139 | } 140 | } 141 | 142 | // FIX: Function has too many arguments 143 | pub async fn upload_object( 144 | client: &Client, 145 | file_name: &PathBuf, 146 | key: &str, 147 | tags: file_management::ObjectTags, 148 | just_presign: bool, 149 | shuk_config: &utils::Config, 150 | ) -> Result { 151 | // Getting file info so we can determine if we will do multi-part or not 152 | log::trace!( 153 | "Start of uploading {:?} to {}", 154 | &file_name, 155 | &shuk_config.bucket_name 156 | ); 157 | 158 | log::trace!("Opening {:?}", &file_name); 159 | let mut file = match File::open(file_name) { 160 | Ok(file) => file, 161 | Err(e) => { 162 | return Err(anyhow::anyhow!("Failed to open file: {}", e)); 163 | } 164 | }; 165 | log::trace!("Getting {:?} metadata", &file_name); 166 | let metadata = match file.metadata() { 167 | Ok(metadata) => metadata, 168 | Err(e) => { 169 | return Err(anyhow::anyhow!("Failed to get file metadata: {}", e)); 170 | } 171 | }; 172 | log::trace!("{:?} metadata: {:?}", &file_name, &metadata); 173 | let file_size = metadata.len(); 174 | log::trace!("{:?} size: {:?}", &file_name, &file_size); 175 | 176 | let pref_key = format!( 177 | "{}{}", 178 | &shuk_config.bucket_prefix.clone().unwrap_or("".into()), 179 | key 180 | ); 181 | log::trace!("Full Prefix key: {}", &pref_key); 182 | 183 | // We should only presign the file 184 | let presigned_url: String = if just_presign { 185 | log::trace!("The file needs to only be presigned."); 186 | 187 | let presigned_url = file_management::presign_file( 188 | client, 189 | &shuk_config.bucket_name, 190 | key, 191 | shuk_config.bucket_prefix.clone(), 192 | shuk_config.presigned_time, 193 | ) 194 | .await?; 195 | println!("========================================"); 196 | println!("📋 | Your file is already uploaded, re-pre-signing: "); 197 | println!("📋 | {}", presigned_url); 198 | 199 | presigned_url 200 | } else { 201 | log::trace!("The file needs to be uploaded."); 202 | // Actually upload the file 203 | // We need to do multi-part upload if file is larger than 4GB 204 | if file_size > 4294967296 { 205 | log::trace!( 206 | "The file is bigger than 4294967296. Size: {}. Using multi-part upload.", 207 | &file_size 208 | ); 209 | 210 | println!("========================================"); 211 | println!("💾 | File size is bigger than 4GB"); 212 | println!("💾 | Using multi-part upload"); 213 | println!( 214 | "🚀 | Uploading file: {}, to S3 Bucket: {} | 🚀", 215 | key, &shuk_config.bucket_name 216 | ); 217 | println!("========================================"); 218 | 219 | // A new bar is created here as we cannot use the same approach as with non multi-part 220 | // uploads 221 | let bar = ProgressBar::new(file_size); 222 | bar.set_style(ProgressStyle::with_template("{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})") 223 | .unwrap() 224 | .with_key("eta", |state: &ProgressState, w: &mut dyn Write| write!(w,"{:.1}s", state.eta().as_secs_f64()).unwrap()) 225 | .progress_chars("#>-")); 226 | 227 | let multipart_upload_res: CreateMultipartUploadOutput = client 228 | .create_multipart_upload() 229 | .bucket(&shuk_config.bucket_name) 230 | .key(&pref_key) 231 | .set_tagging(Some(tags.to_string())) 232 | .send() 233 | .await?; 234 | 235 | let upload_id = multipart_upload_res 236 | .upload_id() 237 | .ok_or_else(|| anyhow::anyhow!("Failed to get upload ID"))?; 238 | log::trace!( 239 | "Generated the upload_id for multi-part uploads: {}", 240 | &upload_id 241 | ); 242 | 243 | let mut completed_parts = Vec::new(); 244 | let mut part_number = 1; 245 | let mut file_position: u64 = 0; 246 | 247 | // main loop for file chunks 248 | log::trace!("Main loop for uploading file chunks starting..."); 249 | while file_position < file_size { 250 | log::trace!("File Position: {}", &file_position); 251 | let bytes_remaining = file_size - file_position; 252 | log::trace!("Bytes Remaining: {}", &bytes_remaining); 253 | let part_size = std::cmp::min(bytes_remaining, PART_SIZE); 254 | log::trace!("Size of part: {}", &part_size); 255 | log::trace!("Part number : {}", &part_number); 256 | 257 | let mut part_data = vec![0; part_size as usize]; 258 | if let Err(e) = file.read_exact(&mut part_data) { 259 | return Err(anyhow::anyhow!("Failed to read file: {}", e)); 260 | } 261 | 262 | let stream = ByteStream::read_from() 263 | .path(file_name) 264 | .offset(file_position) 265 | .length(Length::Exact(part_size)) 266 | .build() 267 | .await 268 | .unwrap(); 269 | 270 | bar.set_position(file_position); 271 | 272 | let upload_part_res = client 273 | .upload_part() 274 | .bucket(&shuk_config.bucket_name) 275 | .key(&pref_key) 276 | .upload_id(upload_id) 277 | .part_number(part_number) 278 | .body(stream) 279 | .send() 280 | .await?; 281 | 282 | let completed_part = CompletedPart::builder() 283 | .part_number(part_number) 284 | .e_tag(upload_part_res.e_tag.expect("Was unable to upload part")) 285 | .build(); 286 | 287 | completed_parts.push(completed_part); 288 | 289 | file_position += part_size; 290 | part_number += 1; 291 | } 292 | log::trace!("Completed chunk uploads"); 293 | 294 | let completed_multipart_upload = CompletedMultipartUpload::builder() 295 | .set_parts(Some(completed_parts)) 296 | .build(); 297 | 298 | log::trace!("Sending complete_multipart_upload API call to S3 "); 299 | let _complete_multipart_upload_res = client 300 | .complete_multipart_upload() 301 | .bucket(&shuk_config.bucket_name) 302 | .key(&pref_key) 303 | .multipart_upload(completed_multipart_upload) 304 | .upload_id(upload_id) 305 | .send() 306 | .await 307 | .unwrap(); 308 | } else { 309 | // There is no need for multi-part uploads, as the file is smaller than 4GB 310 | log::trace!( 311 | "The file is smaller than 4294967296. Size: {}. No need for multi-part upload.", 312 | &file_size 313 | ); 314 | println!("========================================"); 315 | println!( 316 | "🚀 | Uploading file: {}, to S3 Bucket: {} | 🚀", 317 | key, &shuk_config.bucket_name 318 | ); 319 | println!("========================================"); 320 | 321 | log::trace!("Reading file into body"); 322 | let body = match ByteStream::read_from() 323 | .path(Path::new(file_name)) 324 | .buffer_size(2048) 325 | .build() 326 | .await 327 | { 328 | Ok(stream) => stream, 329 | Err(e) => return Err(anyhow::anyhow!("Failed to create ByteStream: {}", e)), 330 | }; 331 | 332 | log::trace!("Sending put_object API call to S3"); 333 | let request = client 334 | .put_object() 335 | .bucket(&shuk_config.bucket_name) 336 | .key(&pref_key) 337 | .set_tagging(Some(tags.to_string())) 338 | .body(body); 339 | 340 | // for the progress bar 341 | let customized = request 342 | .customize() 343 | .map_request(ProgressBody::::replace); 344 | let out = customized.send().await?; 345 | log::debug!("PutObjectOutput: {:?}", out); 346 | } 347 | 348 | // NOTE: Not sure if this should exist in this upload_object function 349 | // or do I move the logic away from here into the main.rs or some 350 | // wrapped function 351 | // 352 | // presign the file and return the URL 353 | let presigned_url = file_management::presign_file( 354 | client, 355 | &shuk_config.bucket_name, 356 | key, 357 | shuk_config.bucket_prefix.clone(), 358 | shuk_config.presigned_time, 359 | ) 360 | .await?; 361 | println!("========================================"); 362 | println!("📋 | Good job, here is your file: "); 363 | println!("📋 | {}", presigned_url); 364 | 365 | presigned_url 366 | }; 367 | 368 | Ok(presigned_url) 369 | } 370 | -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | use aws_config::environment::credentials::EnvironmentVariableCredentialsProvider; 2 | use aws_config::imds::credentials::ImdsCredentialsProvider; 3 | use aws_config::meta::credentials::CredentialsProviderChain; 4 | use aws_config::meta::region::RegionProviderChain; 5 | use aws_config::profile::ProfileFileCredentialsProvider; 6 | use aws_config::profile::ProfileFileRegionProvider; 7 | use aws_config::BehaviorVersion; 8 | use aws_types::region::Region; 9 | 10 | use std::fs; 11 | use std::io; 12 | use std::io::Write; 13 | use std::path::PathBuf; 14 | use std::process::exit; 15 | 16 | use clap::Parser; 17 | 18 | use serde::Deserialize; 19 | use serde::Deserializer; 20 | use serde::Serialize; 21 | 22 | use crate::constants; 23 | use colored::*; 24 | use dirs::home_dir; 25 | 26 | use chrono; 27 | 28 | use std::process::{Command, Stdio}; 29 | 30 | // Configure logging 31 | pub fn setup_logging(verbose: bool) { 32 | let env = 33 | env_logger::Env::default().filter_or("SHUK_LOG", if verbose { "trace" } else { "warn" }); 34 | 35 | // TODO: Need to add some color here 36 | env_logger::Builder::from_env(env) 37 | .format(|buf, record| { 38 | writeln!( 39 | buf, 40 | "{} [{}] {}", 41 | chrono::Local::now().format("%Y-%m-%d %H:%M:%S"), 42 | record.level(), 43 | record.args() 44 | ) 45 | }) 46 | .init(); 47 | } 48 | 49 | //======================================== AWS 50 | pub async fn configure_aws( 51 | fallback_region: String, 52 | profile_name: Option<&String>, 53 | ) -> aws_config::SdkConfig { 54 | let profile = profile_name.map(|s| s.as_str()).unwrap_or("default"); 55 | let region_provider = RegionProviderChain::first_try( 56 | ProfileFileRegionProvider::builder() 57 | .profile_name(profile) 58 | .build(), 59 | ) 60 | .or_else(aws_config::environment::EnvironmentVariableRegionProvider::new()) 61 | .or_else(aws_config::imds::region::ImdsRegionProvider::builder().build()) 62 | .or_else(Region::new(fallback_region)); 63 | 64 | let credentials_provider = CredentialsProviderChain::first_try( 65 | "Environment", 66 | EnvironmentVariableCredentialsProvider::new(), 67 | ) 68 | .or_else( 69 | "Profile", 70 | ProfileFileCredentialsProvider::builder() 71 | .profile_name(profile) 72 | .build(), 73 | ) 74 | .or_else("IMDS", ImdsCredentialsProvider::builder().build()); 75 | 76 | aws_config::defaults(BehaviorVersion::latest()) 77 | .credentials_provider(credentials_provider) 78 | .region(region_provider) 79 | .load() 80 | .await 81 | } 82 | 83 | //======================================== END AWS 84 | //======================================== CONFIG PARSING 85 | //NOTE: 86 | //Thank you maroider_ <3 87 | //When the user runs the application it should look for the config file. 88 | //if the file does not exist in `$HOME/.config/shuk/` inform the user, 89 | //tell them to run `shuk --init` and then just ask for the bucketname. 90 | //For the `--init` option, create the configuration file in the users 91 | //`.config` directory from a `CONST` right here in the code. 92 | #[derive(Debug, Deserialize, Serialize)] 93 | pub struct Config { 94 | pub bucket_name: String, 95 | #[serde(deserialize_with = "deserialize_prefix")] 96 | pub bucket_prefix: Option, 97 | pub presigned_time: u64, 98 | pub aws_profile: Option, 99 | pub use_clipboard: Option, 100 | pub fallback_region: Option, 101 | } 102 | 103 | // This function exists so we can append "/" to any prefix we read from the configuration file. 104 | fn deserialize_prefix<'de, D>(deserializer: D) -> Result, D::Error> 105 | where 106 | D: Deserializer<'de>, 107 | { 108 | let mut prefix = String::deserialize(deserializer)?; 109 | // if its just "" then return none 110 | if prefix.is_empty() { 111 | Ok(None) 112 | } else if prefix.ends_with('/') { 113 | // check if by some chance we already have '/' 114 | Ok(Some(prefix)) 115 | } else { 116 | // append '/' to the prefix 117 | prefix = format!("{}/", prefix); 118 | Ok(Some(prefix)) 119 | } 120 | } 121 | 122 | impl Config { 123 | pub fn load_config() -> Result { 124 | log::trace!("Parsing the configuration file"); 125 | let home_dir = home_dir().expect("Failed to get HOME directory"); 126 | log::trace!("Home directory: {:?}", &home_dir); 127 | let config_dir = home_dir.join(".config/shuk"); 128 | log::trace!("Config directory: {:?}", &config_dir); 129 | let config_file_path = config_dir.join(constants::CONFIG_FILE_NAME); 130 | log::trace!("Config file path: {:?}", &config_file_path); 131 | 132 | if check_for_config() { 133 | let _contents: String = match fs::read_to_string(config_file_path) { 134 | Ok(c) => { 135 | let config: Config = toml::from_str::(&c).unwrap(); 136 | return Ok(config); 137 | } 138 | Err(e) => { 139 | eprintln!("Could not read config file! {}", e); 140 | eprintln!("Your configuration file needs to be in $HOME/.config/shuk/shuk.toml; Please run the configuration command: shuk --init"); 141 | exit(1); 142 | } 143 | }; 144 | } else { 145 | eprintln!("Could not read config file!"); 146 | eprintln!("Your configuration file needs to be in $HOME/.config/shuk/shuk.toml; Please run the configuration command: shuk --init"); 147 | exit(1); 148 | } 149 | } 150 | } 151 | //======================================== END CONFIG PARSING 152 | // 153 | pub fn check_for_config() -> bool { 154 | log::trace!("Checking for the configuration file"); 155 | let home_dir = home_dir().expect("Failed to get HOME directory"); 156 | log::trace!("Home directory: {:?}", &home_dir); 157 | let config_dir = home_dir.join(".config/shuk"); 158 | log::trace!("Config directory: {:?}", &config_dir); 159 | let config_file_path = config_dir.join(constants::CONFIG_FILE_NAME); 160 | log::trace!("Config file path: {:?}", &config_file_path); 161 | 162 | // returns true or false 163 | match config_file_path.try_exists() { 164 | Ok(b) => { 165 | log::trace!("Config file path: {:?} exists", &config_file_path); 166 | b 167 | } 168 | Err(e) => { 169 | log::warn!( 170 | "I was unable to determine if the config file path: {:?} exists", 171 | &config_file_path 172 | ); 173 | eprintln!("Was unable to determine if the config file exists: {}", e); 174 | exit(1); 175 | } 176 | } 177 | } 178 | 179 | // function that creates the configuration files during the `init` command 180 | pub async fn initialize_config() -> Result<(), anyhow::Error> { 181 | log::trace!("Initializing the configuration"); 182 | let home_dir = home_dir().expect("Failed to get HOME directory"); 183 | log::trace!("Home directory: {:?}", &home_dir); 184 | let config_dir = home_dir.join(format!(".config/{}", constants::CONFIG_DIR_NAME)); 185 | log::trace!("Config directory: {:?}", &config_dir); 186 | log::trace!("Creating the config directory: {:?}", &config_dir); 187 | fs::create_dir_all(&config_dir)?; 188 | 189 | let config_file_path = config_dir.join(constants::CONFIG_FILE_NAME); 190 | log::trace!("Config file path: {:?}", &config_file_path); 191 | let config_content = constants::CONFIG_FILE.to_string(); 192 | log::trace!("Config file contents: {:?}", &config_content); 193 | 194 | log::trace!("Parsing default config into TOML"); 195 | let mut default_config: Config = 196 | toml::from_str::(&config_content).expect("default config must be valid"); 197 | 198 | // Prompt the user for details 199 | let mut bucket_name = String::new(); 200 | print!("Enter the name of the bucket you wish to use for file uploads: "); 201 | io::stdout().flush()?; // so the answers are typed on the same line as above 202 | io::stdin().read_line(&mut bucket_name)?; 203 | default_config.bucket_name = bucket_name.trim().to_string(); 204 | log::trace!("Using bucket name: {}", &default_config.bucket_name); 205 | 206 | let mut bucket_prefix = String::new(); 207 | print!("Enter the prefix (folder) in that bucket where the files will be uploaded (leave blank for the root of the bucket): "); 208 | io::stdout().flush()?; // so the answers are typed on the same line as above 209 | io::stdin().read_line(&mut bucket_prefix)?; 210 | default_config.bucket_prefix = Some(bucket_prefix.trim().to_string()); 211 | log::trace!("Using bucket prefix: {:?}", &default_config.bucket_prefix); 212 | 213 | let mut config_profile = String::new(); 214 | print!("Enter the AWS profile name (enter for None): "); 215 | io::stdout().flush()?; // so the answers are typed on the same line as above 216 | io::stdin().read_line(&mut config_profile)?; 217 | let config_profile = config_profile.trim(); 218 | default_config.aws_profile = if config_profile.is_empty() { 219 | None 220 | } else { 221 | Some(config_profile.to_string()) 222 | }; 223 | log::trace!("Using profile : {:?}", &default_config.aws_profile); 224 | 225 | fs::write(&config_file_path, toml::to_string_pretty(&default_config)?)?; 226 | println!( 227 | "⏳| Shuk configuration file created at: {:?}", 228 | config_file_path 229 | ); 230 | println!("This file is used to store configuration items for the shuk application."); 231 | 232 | println!("✅ | Shuk configuration has been initialized in ~/.config/shuk. You may now use it as normal."); 233 | Ok(()) 234 | } 235 | 236 | pub fn print_warning(s: &str) { 237 | println!("{}", s.yellow()); 238 | } 239 | 240 | // Store the prisigned url into clipboard 241 | pub fn set_into_clipboard(s: String) -> Result<(), Box> { 242 | log::trace!("Attempting to set clipboard content"); 243 | log::debug!("Content length to be copied: {}", s.len()); 244 | 245 | match std::env::consts::OS { 246 | "linux" => { 247 | log::trace!("Detected Linux OS, attempting clipboard operations"); 248 | 249 | // Try Wayland first 250 | log::debug!("Attempting Wayland clipboard (wl-copy)"); 251 | if let Ok(output) = Command::new("wl-copy") 252 | .stdin(Stdio::piped()) 253 | .arg(&s) 254 | .output() 255 | { 256 | if output.status.success() { 257 | log::debug!("Successfully copied to Wayland clipboard"); 258 | return Ok(()); 259 | } 260 | log::debug!("Wayland clipboard attempt failed, falling back to X11"); 261 | } else { 262 | log::debug!("wl-copy not available, falling back to X11"); 263 | } 264 | 265 | // Fall back to X11 using xclip 266 | log::debug!("Attempting X11 clipboard (xclip)"); 267 | let mut child = Command::new("xclip") 268 | .arg("-selection") 269 | .arg("clipboard") 270 | .stdin(Stdio::piped()) 271 | .spawn() 272 | .map_err(|e| { 273 | log::error!("Failed to spawn xclip: {}", e); 274 | format!("Failed to spawn xclip (is it installed?): {}", e) 275 | })?; 276 | 277 | if let Some(mut stdin) = child.stdin.take() { 278 | stdin.write_all(s.as_bytes()).map_err(|e| { 279 | log::error!("Failed to write to xclip stdin: {}", e); 280 | format!("Failed to write to xclip: {}", e) 281 | })?; 282 | } else { 283 | log::error!("Failed to open stdin for xclip"); 284 | return Err("Failed to open stdin for xclip".into()); 285 | } 286 | 287 | let status = child.wait().map_err(|e| { 288 | log::error!("Failed to wait for xclip process: {}", e); 289 | format!("Failed to wait for xclip: {}", e) 290 | })?; 291 | 292 | if !status.success() { 293 | log::error!("xclip process failed with status: {}", status); 294 | return Err(format!("xclip failed with status: {}", status).into()); 295 | } 296 | 297 | log::debug!("Successfully copied to X11 clipboard"); 298 | }, 299 | "macos" => { 300 | log::trace!("Detected macOS, attempting clipboard operation with pbcopy"); 301 | let mut child = Command::new("pbcopy") 302 | .stdin(Stdio::piped()) 303 | .spawn() 304 | .map_err(|e| { 305 | log::error!("Failed to spawn pbcopy: {}", e); 306 | format!("Failed to spawn pbcopy: {}", e) 307 | })?; 308 | 309 | if let Some(mut stdin) = child.stdin.take() { 310 | stdin.write_all(s.as_bytes()).map_err(|e| { 311 | log::error!("Failed to write to pbcopy stdin: {}", e); 312 | format!("Failed to write to pbcopy: {}", e) 313 | })?; 314 | } else { 315 | log::error!("Failed to open stdin for pbcopy"); 316 | return Err("Failed to open stdin for pbcopy".into()); 317 | } 318 | 319 | let status = child.wait().map_err(|e| { 320 | log::error!("Failed to wait for pbcopy process: {}", e); 321 | format!("Failed to wait for pbcopy: {}", e) 322 | })?; 323 | 324 | if !status.success() { 325 | log::error!("pbcopy process failed with status: {}", status); 326 | return Err(format!("pbcopy failed with status: {}", status).into()); 327 | } 328 | 329 | log::debug!("Successfully copied to macOS clipboard"); 330 | }, 331 | "windows" => { 332 | log::trace!("Detected Windows, attempting clipboard operation with clip.exe"); 333 | let mut child = Command::new("clip") 334 | .stdin(Stdio::piped()) 335 | .spawn() 336 | .map_err(|e| { 337 | log::error!("Failed to spawn clip.exe: {}", e); 338 | format!("Failed to spawn clip.exe: {}", e) 339 | })?; 340 | 341 | if let Some(mut stdin) = child.stdin.take() { 342 | stdin.write_all(s.as_bytes()).map_err(|e| { 343 | log::error!("Failed to write to clip.exe stdin: {}", e); 344 | format!("Failed to write to clip.exe: {}", e) 345 | })?; 346 | } else { 347 | log::error!("Failed to open stdin for clip.exe"); 348 | return Err("Failed to open stdin for clip.exe".into()); 349 | } 350 | 351 | let status = child.wait().map_err(|e| { 352 | log::error!("Failed to wait for clip.exe process: {}", e); 353 | format!("Failed to wait for clip.exe: {}", e) 354 | })?; 355 | 356 | if !status.success() { 357 | log::error!("clip.exe process failed with status: {}", status); 358 | return Err(format!("clip.exe failed with status: {}", status).into()); 359 | } 360 | 361 | log::debug!("Successfully copied to Windows clipboard"); 362 | }, 363 | os => { 364 | log::error!("Unsupported operating system: {}", os); 365 | return Err(format!("Unsupported operating system: {}", os).into()); 366 | } 367 | } 368 | 369 | log::trace!("Clipboard operation completed successfully"); 370 | Ok(()) 371 | } 372 | 373 | //======================================== ARGUMENT PARSING 374 | #[derive(Debug, Parser, Default)] 375 | #[command(version, about, long_about = None)] 376 | pub struct Args { 377 | #[arg(required_unless_present("init"))] 378 | pub filename: Option, 379 | // the init flag. So we can copy the config files locally 380 | #[arg(long, conflicts_with("filename"))] 381 | pub init: bool, 382 | #[arg(short, long, help = "Enable verbose logging")] 383 | pub verbose: bool, 384 | } 385 | //=========================ALPHA=============== END ARGUMENT PARSING 386 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 | 20 | [[package]] 21 | name = "aho-corasick" 22 | version = "1.1.3" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 25 | dependencies = [ 26 | "memchr", 27 | ] 28 | 29 | [[package]] 30 | name = "allocator-api2" 31 | version = "0.2.20" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" 34 | 35 | [[package]] 36 | name = "android-tzdata" 37 | version = "0.1.1" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 40 | 41 | [[package]] 42 | name = "android_system_properties" 43 | version = "0.1.5" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 46 | dependencies = [ 47 | "libc", 48 | ] 49 | 50 | [[package]] 51 | name = "anstream" 52 | version = "0.6.18" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" 55 | dependencies = [ 56 | "anstyle", 57 | "anstyle-parse", 58 | "anstyle-query", 59 | "anstyle-wincon", 60 | "colorchoice", 61 | "is_terminal_polyfill", 62 | "utf8parse", 63 | ] 64 | 65 | [[package]] 66 | name = "anstyle" 67 | version = "1.0.10" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" 70 | 71 | [[package]] 72 | name = "anstyle-parse" 73 | version = "0.2.6" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" 76 | dependencies = [ 77 | "utf8parse", 78 | ] 79 | 80 | [[package]] 81 | name = "anstyle-query" 82 | version = "1.1.2" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" 85 | dependencies = [ 86 | "windows-sys 0.59.0", 87 | ] 88 | 89 | [[package]] 90 | name = "anstyle-wincon" 91 | version = "3.0.6" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" 94 | dependencies = [ 95 | "anstyle", 96 | "windows-sys 0.59.0", 97 | ] 98 | 99 | [[package]] 100 | name = "anyhow" 101 | version = "1.0.93" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" 104 | 105 | [[package]] 106 | name = "autocfg" 107 | version = "1.4.0" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 110 | 111 | [[package]] 112 | name = "aws-config" 113 | version = "1.5.10" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "9b49afaa341e8dd8577e1a2200468f98956d6eda50bcf4a53246cc00174ba924" 116 | dependencies = [ 117 | "aws-credential-types", 118 | "aws-runtime", 119 | "aws-sdk-sso", 120 | "aws-sdk-ssooidc", 121 | "aws-sdk-sts", 122 | "aws-smithy-async", 123 | "aws-smithy-http", 124 | "aws-smithy-json", 125 | "aws-smithy-runtime", 126 | "aws-smithy-runtime-api", 127 | "aws-smithy-types", 128 | "aws-types", 129 | "bytes", 130 | "fastrand", 131 | "hex", 132 | "http 0.2.12", 133 | "ring", 134 | "time", 135 | "tokio", 136 | "tracing", 137 | "url", 138 | "zeroize", 139 | ] 140 | 141 | [[package]] 142 | name = "aws-credential-types" 143 | version = "1.2.1" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "60e8f6b615cb5fc60a98132268508ad104310f0cfb25a1c22eee76efdf9154da" 146 | dependencies = [ 147 | "aws-smithy-async", 148 | "aws-smithy-runtime-api", 149 | "aws-smithy-types", 150 | "zeroize", 151 | ] 152 | 153 | [[package]] 154 | name = "aws-runtime" 155 | version = "1.4.3" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "a10d5c055aa540164d9561a0e2e74ad30f0dcf7393c3a92f6733ddf9c5762468" 158 | dependencies = [ 159 | "aws-credential-types", 160 | "aws-sigv4", 161 | "aws-smithy-async", 162 | "aws-smithy-eventstream", 163 | "aws-smithy-http", 164 | "aws-smithy-runtime", 165 | "aws-smithy-runtime-api", 166 | "aws-smithy-types", 167 | "aws-types", 168 | "bytes", 169 | "fastrand", 170 | "http 0.2.12", 171 | "http-body 0.4.6", 172 | "once_cell", 173 | "percent-encoding", 174 | "pin-project-lite", 175 | "tracing", 176 | "uuid", 177 | ] 178 | 179 | [[package]] 180 | name = "aws-sdk-s3" 181 | version = "1.61.0" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "0e531658a0397d22365dfe26c3e1c0c8448bf6a3a2d8a098ded802f2b1261615" 184 | dependencies = [ 185 | "aws-credential-types", 186 | "aws-runtime", 187 | "aws-sigv4", 188 | "aws-smithy-async", 189 | "aws-smithy-checksums", 190 | "aws-smithy-eventstream", 191 | "aws-smithy-http", 192 | "aws-smithy-json", 193 | "aws-smithy-runtime", 194 | "aws-smithy-runtime-api", 195 | "aws-smithy-types", 196 | "aws-smithy-xml", 197 | "aws-types", 198 | "bytes", 199 | "fastrand", 200 | "hex", 201 | "hmac", 202 | "http 0.2.12", 203 | "http-body 0.4.6", 204 | "lru", 205 | "once_cell", 206 | "percent-encoding", 207 | "regex-lite", 208 | "sha2", 209 | "tracing", 210 | "url", 211 | ] 212 | 213 | [[package]] 214 | name = "aws-sdk-sso" 215 | version = "1.49.0" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "09677244a9da92172c8dc60109b4a9658597d4d298b188dd0018b6a66b410ca4" 218 | dependencies = [ 219 | "aws-credential-types", 220 | "aws-runtime", 221 | "aws-smithy-async", 222 | "aws-smithy-http", 223 | "aws-smithy-json", 224 | "aws-smithy-runtime", 225 | "aws-smithy-runtime-api", 226 | "aws-smithy-types", 227 | "aws-types", 228 | "bytes", 229 | "http 0.2.12", 230 | "once_cell", 231 | "regex-lite", 232 | "tracing", 233 | ] 234 | 235 | [[package]] 236 | name = "aws-sdk-ssooidc" 237 | version = "1.50.0" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "81fea2f3a8bb3bd10932ae7ad59cc59f65f270fc9183a7e91f501dc5efbef7ee" 240 | dependencies = [ 241 | "aws-credential-types", 242 | "aws-runtime", 243 | "aws-smithy-async", 244 | "aws-smithy-http", 245 | "aws-smithy-json", 246 | "aws-smithy-runtime", 247 | "aws-smithy-runtime-api", 248 | "aws-smithy-types", 249 | "aws-types", 250 | "bytes", 251 | "http 0.2.12", 252 | "once_cell", 253 | "regex-lite", 254 | "tracing", 255 | ] 256 | 257 | [[package]] 258 | name = "aws-sdk-sts" 259 | version = "1.50.0" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "6ada54e5f26ac246dc79727def52f7f8ed38915cb47781e2a72213957dc3a7d5" 262 | dependencies = [ 263 | "aws-credential-types", 264 | "aws-runtime", 265 | "aws-smithy-async", 266 | "aws-smithy-http", 267 | "aws-smithy-json", 268 | "aws-smithy-query", 269 | "aws-smithy-runtime", 270 | "aws-smithy-runtime-api", 271 | "aws-smithy-types", 272 | "aws-smithy-xml", 273 | "aws-types", 274 | "http 0.2.12", 275 | "once_cell", 276 | "regex-lite", 277 | "tracing", 278 | ] 279 | 280 | [[package]] 281 | name = "aws-sigv4" 282 | version = "1.2.5" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "5619742a0d8f253be760bfbb8e8e8368c69e3587e4637af5754e488a611499b1" 285 | dependencies = [ 286 | "aws-credential-types", 287 | "aws-smithy-eventstream", 288 | "aws-smithy-http", 289 | "aws-smithy-runtime-api", 290 | "aws-smithy-types", 291 | "bytes", 292 | "crypto-bigint 0.5.5", 293 | "form_urlencoded", 294 | "hex", 295 | "hmac", 296 | "http 0.2.12", 297 | "http 1.1.0", 298 | "once_cell", 299 | "p256", 300 | "percent-encoding", 301 | "ring", 302 | "sha2", 303 | "subtle", 304 | "time", 305 | "tracing", 306 | "zeroize", 307 | ] 308 | 309 | [[package]] 310 | name = "aws-smithy-async" 311 | version = "1.2.1" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "62220bc6e97f946ddd51b5f1361f78996e704677afc518a4ff66b7a72ea1378c" 314 | dependencies = [ 315 | "futures-util", 316 | "pin-project-lite", 317 | "tokio", 318 | ] 319 | 320 | [[package]] 321 | name = "aws-smithy-checksums" 322 | version = "0.60.13" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "ba1a71073fca26775c8b5189175ea8863afb1c9ea2cceb02a5de5ad9dfbaa795" 325 | dependencies = [ 326 | "aws-smithy-http", 327 | "aws-smithy-types", 328 | "bytes", 329 | "crc32c", 330 | "crc32fast", 331 | "hex", 332 | "http 0.2.12", 333 | "http-body 0.4.6", 334 | "md-5", 335 | "pin-project-lite", 336 | "sha1", 337 | "sha2", 338 | "tracing", 339 | ] 340 | 341 | [[package]] 342 | name = "aws-smithy-eventstream" 343 | version = "0.60.5" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "cef7d0a272725f87e51ba2bf89f8c21e4df61b9e49ae1ac367a6d69916ef7c90" 346 | dependencies = [ 347 | "aws-smithy-types", 348 | "bytes", 349 | "crc32fast", 350 | ] 351 | 352 | [[package]] 353 | name = "aws-smithy-http" 354 | version = "0.60.11" 355 | source = "registry+https://github.com/rust-lang/crates.io-index" 356 | checksum = "5c8bc3e8fdc6b8d07d976e301c02fe553f72a39b7a9fea820e023268467d7ab6" 357 | dependencies = [ 358 | "aws-smithy-eventstream", 359 | "aws-smithy-runtime-api", 360 | "aws-smithy-types", 361 | "bytes", 362 | "bytes-utils", 363 | "futures-core", 364 | "http 0.2.12", 365 | "http-body 0.4.6", 366 | "once_cell", 367 | "percent-encoding", 368 | "pin-project-lite", 369 | "pin-utils", 370 | "tracing", 371 | ] 372 | 373 | [[package]] 374 | name = "aws-smithy-json" 375 | version = "0.60.7" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "4683df9469ef09468dad3473d129960119a0d3593617542b7d52086c8486f2d6" 378 | dependencies = [ 379 | "aws-smithy-types", 380 | ] 381 | 382 | [[package]] 383 | name = "aws-smithy-query" 384 | version = "0.60.7" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "f2fbd61ceb3fe8a1cb7352e42689cec5335833cd9f94103a61e98f9bb61c64bb" 387 | dependencies = [ 388 | "aws-smithy-types", 389 | "urlencoding", 390 | ] 391 | 392 | [[package]] 393 | name = "aws-smithy-runtime" 394 | version = "1.7.3" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | checksum = "be28bd063fa91fd871d131fc8b68d7cd4c5fa0869bea68daca50dcb1cbd76be2" 397 | dependencies = [ 398 | "aws-smithy-async", 399 | "aws-smithy-http", 400 | "aws-smithy-runtime-api", 401 | "aws-smithy-types", 402 | "bytes", 403 | "fastrand", 404 | "h2", 405 | "http 0.2.12", 406 | "http-body 0.4.6", 407 | "http-body 1.0.1", 408 | "httparse", 409 | "hyper", 410 | "hyper-rustls", 411 | "once_cell", 412 | "pin-project-lite", 413 | "pin-utils", 414 | "rustls", 415 | "tokio", 416 | "tracing", 417 | ] 418 | 419 | [[package]] 420 | name = "aws-smithy-runtime-api" 421 | version = "1.7.3" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "92165296a47a812b267b4f41032ff8069ab7ff783696d217f0994a0d7ab585cd" 424 | dependencies = [ 425 | "aws-smithy-async", 426 | "aws-smithy-types", 427 | "bytes", 428 | "http 0.2.12", 429 | "http 1.1.0", 430 | "pin-project-lite", 431 | "tokio", 432 | "tracing", 433 | "zeroize", 434 | ] 435 | 436 | [[package]] 437 | name = "aws-smithy-types" 438 | version = "1.2.9" 439 | source = "registry+https://github.com/rust-lang/crates.io-index" 440 | checksum = "4fbd94a32b3a7d55d3806fe27d98d3ad393050439dd05eb53ece36ec5e3d3510" 441 | dependencies = [ 442 | "base64-simd", 443 | "bytes", 444 | "bytes-utils", 445 | "futures-core", 446 | "http 0.2.12", 447 | "http 1.1.0", 448 | "http-body 0.4.6", 449 | "http-body 1.0.1", 450 | "http-body-util", 451 | "itoa", 452 | "num-integer", 453 | "pin-project-lite", 454 | "pin-utils", 455 | "ryu", 456 | "serde", 457 | "time", 458 | "tokio", 459 | "tokio-util", 460 | ] 461 | 462 | [[package]] 463 | name = "aws-smithy-xml" 464 | version = "0.60.9" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "ab0b0166827aa700d3dc519f72f8b3a91c35d0b8d042dc5d643a91e6f80648fc" 467 | dependencies = [ 468 | "xmlparser", 469 | ] 470 | 471 | [[package]] 472 | name = "aws-types" 473 | version = "1.3.3" 474 | source = "registry+https://github.com/rust-lang/crates.io-index" 475 | checksum = "5221b91b3e441e6675310829fd8984801b772cb1546ef6c0e54dec9f1ac13fef" 476 | dependencies = [ 477 | "aws-credential-types", 478 | "aws-smithy-async", 479 | "aws-smithy-runtime-api", 480 | "aws-smithy-types", 481 | "rustc_version", 482 | "tracing", 483 | ] 484 | 485 | [[package]] 486 | name = "backtrace" 487 | version = "0.3.74" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 490 | dependencies = [ 491 | "addr2line", 492 | "cfg-if", 493 | "libc", 494 | "miniz_oxide", 495 | "object", 496 | "rustc-demangle", 497 | "windows-targets 0.52.6", 498 | ] 499 | 500 | [[package]] 501 | name = "base16ct" 502 | version = "0.1.1" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" 505 | 506 | [[package]] 507 | name = "base64" 508 | version = "0.21.7" 509 | source = "registry+https://github.com/rust-lang/crates.io-index" 510 | checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" 511 | 512 | [[package]] 513 | name = "base64-simd" 514 | version = "0.8.0" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" 517 | dependencies = [ 518 | "outref", 519 | "vsimd", 520 | ] 521 | 522 | [[package]] 523 | name = "base64ct" 524 | version = "1.6.0" 525 | source = "registry+https://github.com/rust-lang/crates.io-index" 526 | checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" 527 | 528 | [[package]] 529 | name = "bitflags" 530 | version = "2.6.0" 531 | source = "registry+https://github.com/rust-lang/crates.io-index" 532 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 533 | 534 | [[package]] 535 | name = "block-buffer" 536 | version = "0.10.4" 537 | source = "registry+https://github.com/rust-lang/crates.io-index" 538 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 539 | dependencies = [ 540 | "generic-array", 541 | ] 542 | 543 | [[package]] 544 | name = "bumpalo" 545 | version = "3.16.0" 546 | source = "registry+https://github.com/rust-lang/crates.io-index" 547 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 548 | 549 | [[package]] 550 | name = "bytes" 551 | version = "1.8.0" 552 | source = "registry+https://github.com/rust-lang/crates.io-index" 553 | checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" 554 | 555 | [[package]] 556 | name = "bytes-utils" 557 | version = "0.1.4" 558 | source = "registry+https://github.com/rust-lang/crates.io-index" 559 | checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" 560 | dependencies = [ 561 | "bytes", 562 | "either", 563 | ] 564 | 565 | [[package]] 566 | name = "cc" 567 | version = "1.2.1" 568 | source = "registry+https://github.com/rust-lang/crates.io-index" 569 | checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" 570 | dependencies = [ 571 | "shlex", 572 | ] 573 | 574 | [[package]] 575 | name = "cfg-if" 576 | version = "1.0.0" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 579 | 580 | [[package]] 581 | name = "chrono" 582 | version = "0.4.38" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" 585 | dependencies = [ 586 | "android-tzdata", 587 | "iana-time-zone", 588 | "js-sys", 589 | "num-traits", 590 | "wasm-bindgen", 591 | "windows-targets 0.52.6", 592 | ] 593 | 594 | [[package]] 595 | name = "clap" 596 | version = "4.5.21" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" 599 | dependencies = [ 600 | "clap_builder", 601 | "clap_derive", 602 | ] 603 | 604 | [[package]] 605 | name = "clap_builder" 606 | version = "4.5.21" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" 609 | dependencies = [ 610 | "anstream", 611 | "anstyle", 612 | "clap_lex", 613 | "strsim", 614 | ] 615 | 616 | [[package]] 617 | name = "clap_derive" 618 | version = "4.5.18" 619 | source = "registry+https://github.com/rust-lang/crates.io-index" 620 | checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" 621 | dependencies = [ 622 | "heck", 623 | "proc-macro2", 624 | "quote", 625 | "syn", 626 | ] 627 | 628 | [[package]] 629 | name = "clap_lex" 630 | version = "0.7.3" 631 | source = "registry+https://github.com/rust-lang/crates.io-index" 632 | checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" 633 | 634 | [[package]] 635 | name = "colorchoice" 636 | version = "1.0.3" 637 | source = "registry+https://github.com/rust-lang/crates.io-index" 638 | checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" 639 | 640 | [[package]] 641 | name = "colored" 642 | version = "2.1.0" 643 | source = "registry+https://github.com/rust-lang/crates.io-index" 644 | checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" 645 | dependencies = [ 646 | "lazy_static", 647 | "windows-sys 0.48.0", 648 | ] 649 | 650 | [[package]] 651 | name = "console" 652 | version = "0.15.8" 653 | source = "registry+https://github.com/rust-lang/crates.io-index" 654 | checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" 655 | dependencies = [ 656 | "encode_unicode", 657 | "lazy_static", 658 | "libc", 659 | "unicode-width 0.1.14", 660 | "windows-sys 0.52.0", 661 | ] 662 | 663 | [[package]] 664 | name = "const-oid" 665 | version = "0.9.6" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" 668 | 669 | [[package]] 670 | name = "core-foundation" 671 | version = "0.9.4" 672 | source = "registry+https://github.com/rust-lang/crates.io-index" 673 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 674 | dependencies = [ 675 | "core-foundation-sys", 676 | "libc", 677 | ] 678 | 679 | [[package]] 680 | name = "core-foundation-sys" 681 | version = "0.8.7" 682 | source = "registry+https://github.com/rust-lang/crates.io-index" 683 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 684 | 685 | [[package]] 686 | name = "cpufeatures" 687 | version = "0.2.15" 688 | source = "registry+https://github.com/rust-lang/crates.io-index" 689 | checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" 690 | dependencies = [ 691 | "libc", 692 | ] 693 | 694 | [[package]] 695 | name = "crc32c" 696 | version = "0.6.8" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "3a47af21622d091a8f0fb295b88bc886ac74efcc613efc19f5d0b21de5c89e47" 699 | dependencies = [ 700 | "rustc_version", 701 | ] 702 | 703 | [[package]] 704 | name = "crc32fast" 705 | version = "1.4.2" 706 | source = "registry+https://github.com/rust-lang/crates.io-index" 707 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 708 | dependencies = [ 709 | "cfg-if", 710 | ] 711 | 712 | [[package]] 713 | name = "crypto-bigint" 714 | version = "0.4.9" 715 | source = "registry+https://github.com/rust-lang/crates.io-index" 716 | checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" 717 | dependencies = [ 718 | "generic-array", 719 | "rand_core", 720 | "subtle", 721 | "zeroize", 722 | ] 723 | 724 | [[package]] 725 | name = "crypto-bigint" 726 | version = "0.5.5" 727 | source = "registry+https://github.com/rust-lang/crates.io-index" 728 | checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" 729 | dependencies = [ 730 | "rand_core", 731 | "subtle", 732 | ] 733 | 734 | [[package]] 735 | name = "crypto-common" 736 | version = "0.1.6" 737 | source = "registry+https://github.com/rust-lang/crates.io-index" 738 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 739 | dependencies = [ 740 | "generic-array", 741 | "typenum", 742 | ] 743 | 744 | [[package]] 745 | name = "der" 746 | version = "0.6.1" 747 | source = "registry+https://github.com/rust-lang/crates.io-index" 748 | checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" 749 | dependencies = [ 750 | "const-oid", 751 | "zeroize", 752 | ] 753 | 754 | [[package]] 755 | name = "deranged" 756 | version = "0.3.11" 757 | source = "registry+https://github.com/rust-lang/crates.io-index" 758 | checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" 759 | dependencies = [ 760 | "powerfmt", 761 | ] 762 | 763 | [[package]] 764 | name = "digest" 765 | version = "0.10.7" 766 | source = "registry+https://github.com/rust-lang/crates.io-index" 767 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 768 | dependencies = [ 769 | "block-buffer", 770 | "crypto-common", 771 | "subtle", 772 | ] 773 | 774 | [[package]] 775 | name = "dirs" 776 | version = "5.0.1" 777 | source = "registry+https://github.com/rust-lang/crates.io-index" 778 | checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" 779 | dependencies = [ 780 | "dirs-sys", 781 | ] 782 | 783 | [[package]] 784 | name = "dirs-sys" 785 | version = "0.4.1" 786 | source = "registry+https://github.com/rust-lang/crates.io-index" 787 | checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" 788 | dependencies = [ 789 | "libc", 790 | "option-ext", 791 | "redox_users", 792 | "windows-sys 0.48.0", 793 | ] 794 | 795 | [[package]] 796 | name = "displaydoc" 797 | version = "0.2.5" 798 | source = "registry+https://github.com/rust-lang/crates.io-index" 799 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 800 | dependencies = [ 801 | "proc-macro2", 802 | "quote", 803 | "syn", 804 | ] 805 | 806 | [[package]] 807 | name = "ecdsa" 808 | version = "0.14.8" 809 | source = "registry+https://github.com/rust-lang/crates.io-index" 810 | checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" 811 | dependencies = [ 812 | "der", 813 | "elliptic-curve", 814 | "rfc6979", 815 | "signature", 816 | ] 817 | 818 | [[package]] 819 | name = "either" 820 | version = "1.13.0" 821 | source = "registry+https://github.com/rust-lang/crates.io-index" 822 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 823 | 824 | [[package]] 825 | name = "elliptic-curve" 826 | version = "0.12.3" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" 829 | dependencies = [ 830 | "base16ct", 831 | "crypto-bigint 0.4.9", 832 | "der", 833 | "digest", 834 | "ff", 835 | "generic-array", 836 | "group", 837 | "pkcs8", 838 | "rand_core", 839 | "sec1", 840 | "subtle", 841 | "zeroize", 842 | ] 843 | 844 | [[package]] 845 | name = "encode_unicode" 846 | version = "0.3.6" 847 | source = "registry+https://github.com/rust-lang/crates.io-index" 848 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 849 | 850 | [[package]] 851 | name = "env_filter" 852 | version = "0.1.2" 853 | source = "registry+https://github.com/rust-lang/crates.io-index" 854 | checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" 855 | dependencies = [ 856 | "log", 857 | "regex", 858 | ] 859 | 860 | [[package]] 861 | name = "env_logger" 862 | version = "0.11.5" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" 865 | dependencies = [ 866 | "anstream", 867 | "anstyle", 868 | "env_filter", 869 | "humantime", 870 | "log", 871 | ] 872 | 873 | [[package]] 874 | name = "equivalent" 875 | version = "1.0.1" 876 | source = "registry+https://github.com/rust-lang/crates.io-index" 877 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 878 | 879 | [[package]] 880 | name = "fastrand" 881 | version = "2.2.0" 882 | source = "registry+https://github.com/rust-lang/crates.io-index" 883 | checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" 884 | 885 | [[package]] 886 | name = "ff" 887 | version = "0.12.1" 888 | source = "registry+https://github.com/rust-lang/crates.io-index" 889 | checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" 890 | dependencies = [ 891 | "rand_core", 892 | "subtle", 893 | ] 894 | 895 | [[package]] 896 | name = "fnv" 897 | version = "1.0.7" 898 | source = "registry+https://github.com/rust-lang/crates.io-index" 899 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 900 | 901 | [[package]] 902 | name = "foldhash" 903 | version = "0.1.3" 904 | source = "registry+https://github.com/rust-lang/crates.io-index" 905 | checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" 906 | 907 | [[package]] 908 | name = "form_urlencoded" 909 | version = "1.2.1" 910 | source = "registry+https://github.com/rust-lang/crates.io-index" 911 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 912 | dependencies = [ 913 | "percent-encoding", 914 | ] 915 | 916 | [[package]] 917 | name = "futures-channel" 918 | version = "0.3.31" 919 | source = "registry+https://github.com/rust-lang/crates.io-index" 920 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 921 | dependencies = [ 922 | "futures-core", 923 | ] 924 | 925 | [[package]] 926 | name = "futures-core" 927 | version = "0.3.31" 928 | source = "registry+https://github.com/rust-lang/crates.io-index" 929 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 930 | 931 | [[package]] 932 | name = "futures-sink" 933 | version = "0.3.31" 934 | source = "registry+https://github.com/rust-lang/crates.io-index" 935 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 936 | 937 | [[package]] 938 | name = "futures-task" 939 | version = "0.3.31" 940 | source = "registry+https://github.com/rust-lang/crates.io-index" 941 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 942 | 943 | [[package]] 944 | name = "futures-util" 945 | version = "0.3.31" 946 | source = "registry+https://github.com/rust-lang/crates.io-index" 947 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 948 | dependencies = [ 949 | "futures-core", 950 | "futures-task", 951 | "pin-project-lite", 952 | "pin-utils", 953 | ] 954 | 955 | [[package]] 956 | name = "generic-array" 957 | version = "0.14.7" 958 | source = "registry+https://github.com/rust-lang/crates.io-index" 959 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 960 | dependencies = [ 961 | "typenum", 962 | "version_check", 963 | ] 964 | 965 | [[package]] 966 | name = "getrandom" 967 | version = "0.2.15" 968 | source = "registry+https://github.com/rust-lang/crates.io-index" 969 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 970 | dependencies = [ 971 | "cfg-if", 972 | "libc", 973 | "wasi", 974 | ] 975 | 976 | [[package]] 977 | name = "gimli" 978 | version = "0.31.1" 979 | source = "registry+https://github.com/rust-lang/crates.io-index" 980 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 981 | 982 | [[package]] 983 | name = "group" 984 | version = "0.12.1" 985 | source = "registry+https://github.com/rust-lang/crates.io-index" 986 | checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" 987 | dependencies = [ 988 | "ff", 989 | "rand_core", 990 | "subtle", 991 | ] 992 | 993 | [[package]] 994 | name = "h2" 995 | version = "0.3.26" 996 | source = "registry+https://github.com/rust-lang/crates.io-index" 997 | checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" 998 | dependencies = [ 999 | "bytes", 1000 | "fnv", 1001 | "futures-core", 1002 | "futures-sink", 1003 | "futures-util", 1004 | "http 0.2.12", 1005 | "indexmap", 1006 | "slab", 1007 | "tokio", 1008 | "tokio-util", 1009 | "tracing", 1010 | ] 1011 | 1012 | [[package]] 1013 | name = "hashbrown" 1014 | version = "0.15.1" 1015 | source = "registry+https://github.com/rust-lang/crates.io-index" 1016 | checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" 1017 | dependencies = [ 1018 | "allocator-api2", 1019 | "equivalent", 1020 | "foldhash", 1021 | ] 1022 | 1023 | [[package]] 1024 | name = "heck" 1025 | version = "0.5.0" 1026 | source = "registry+https://github.com/rust-lang/crates.io-index" 1027 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 1028 | 1029 | [[package]] 1030 | name = "hermit-abi" 1031 | version = "0.3.9" 1032 | source = "registry+https://github.com/rust-lang/crates.io-index" 1033 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" 1034 | 1035 | [[package]] 1036 | name = "hex" 1037 | version = "0.4.3" 1038 | source = "registry+https://github.com/rust-lang/crates.io-index" 1039 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 1040 | 1041 | [[package]] 1042 | name = "hmac" 1043 | version = "0.12.1" 1044 | source = "registry+https://github.com/rust-lang/crates.io-index" 1045 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 1046 | dependencies = [ 1047 | "digest", 1048 | ] 1049 | 1050 | [[package]] 1051 | name = "http" 1052 | version = "0.2.12" 1053 | source = "registry+https://github.com/rust-lang/crates.io-index" 1054 | checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" 1055 | dependencies = [ 1056 | "bytes", 1057 | "fnv", 1058 | "itoa", 1059 | ] 1060 | 1061 | [[package]] 1062 | name = "http" 1063 | version = "1.1.0" 1064 | source = "registry+https://github.com/rust-lang/crates.io-index" 1065 | checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" 1066 | dependencies = [ 1067 | "bytes", 1068 | "fnv", 1069 | "itoa", 1070 | ] 1071 | 1072 | [[package]] 1073 | name = "http-body" 1074 | version = "0.4.6" 1075 | source = "registry+https://github.com/rust-lang/crates.io-index" 1076 | checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" 1077 | dependencies = [ 1078 | "bytes", 1079 | "http 0.2.12", 1080 | "pin-project-lite", 1081 | ] 1082 | 1083 | [[package]] 1084 | name = "http-body" 1085 | version = "1.0.1" 1086 | source = "registry+https://github.com/rust-lang/crates.io-index" 1087 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 1088 | dependencies = [ 1089 | "bytes", 1090 | "http 1.1.0", 1091 | ] 1092 | 1093 | [[package]] 1094 | name = "http-body-util" 1095 | version = "0.1.2" 1096 | source = "registry+https://github.com/rust-lang/crates.io-index" 1097 | checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" 1098 | dependencies = [ 1099 | "bytes", 1100 | "futures-util", 1101 | "http 1.1.0", 1102 | "http-body 1.0.1", 1103 | "pin-project-lite", 1104 | ] 1105 | 1106 | [[package]] 1107 | name = "httparse" 1108 | version = "1.9.5" 1109 | source = "registry+https://github.com/rust-lang/crates.io-index" 1110 | checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" 1111 | 1112 | [[package]] 1113 | name = "httpdate" 1114 | version = "1.0.3" 1115 | source = "registry+https://github.com/rust-lang/crates.io-index" 1116 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 1117 | 1118 | [[package]] 1119 | name = "humantime" 1120 | version = "2.1.0" 1121 | source = "registry+https://github.com/rust-lang/crates.io-index" 1122 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 1123 | 1124 | [[package]] 1125 | name = "hyper" 1126 | version = "0.14.31" 1127 | source = "registry+https://github.com/rust-lang/crates.io-index" 1128 | checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" 1129 | dependencies = [ 1130 | "bytes", 1131 | "futures-channel", 1132 | "futures-core", 1133 | "futures-util", 1134 | "h2", 1135 | "http 0.2.12", 1136 | "http-body 0.4.6", 1137 | "httparse", 1138 | "httpdate", 1139 | "itoa", 1140 | "pin-project-lite", 1141 | "socket2", 1142 | "tokio", 1143 | "tower-service", 1144 | "tracing", 1145 | "want", 1146 | ] 1147 | 1148 | [[package]] 1149 | name = "hyper-rustls" 1150 | version = "0.24.2" 1151 | source = "registry+https://github.com/rust-lang/crates.io-index" 1152 | checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" 1153 | dependencies = [ 1154 | "futures-util", 1155 | "http 0.2.12", 1156 | "hyper", 1157 | "log", 1158 | "rustls", 1159 | "rustls-native-certs", 1160 | "tokio", 1161 | "tokio-rustls", 1162 | ] 1163 | 1164 | [[package]] 1165 | name = "iana-time-zone" 1166 | version = "0.1.61" 1167 | source = "registry+https://github.com/rust-lang/crates.io-index" 1168 | checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" 1169 | dependencies = [ 1170 | "android_system_properties", 1171 | "core-foundation-sys", 1172 | "iana-time-zone-haiku", 1173 | "js-sys", 1174 | "wasm-bindgen", 1175 | "windows-core", 1176 | ] 1177 | 1178 | [[package]] 1179 | name = "iana-time-zone-haiku" 1180 | version = "0.1.2" 1181 | source = "registry+https://github.com/rust-lang/crates.io-index" 1182 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 1183 | dependencies = [ 1184 | "cc", 1185 | ] 1186 | 1187 | [[package]] 1188 | name = "icu_collections" 1189 | version = "1.5.0" 1190 | source = "registry+https://github.com/rust-lang/crates.io-index" 1191 | checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" 1192 | dependencies = [ 1193 | "displaydoc", 1194 | "yoke", 1195 | "zerofrom", 1196 | "zerovec", 1197 | ] 1198 | 1199 | [[package]] 1200 | name = "icu_locid" 1201 | version = "1.5.0" 1202 | source = "registry+https://github.com/rust-lang/crates.io-index" 1203 | checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" 1204 | dependencies = [ 1205 | "displaydoc", 1206 | "litemap", 1207 | "tinystr", 1208 | "writeable", 1209 | "zerovec", 1210 | ] 1211 | 1212 | [[package]] 1213 | name = "icu_locid_transform" 1214 | version = "1.5.0" 1215 | source = "registry+https://github.com/rust-lang/crates.io-index" 1216 | checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" 1217 | dependencies = [ 1218 | "displaydoc", 1219 | "icu_locid", 1220 | "icu_locid_transform_data", 1221 | "icu_provider", 1222 | "tinystr", 1223 | "zerovec", 1224 | ] 1225 | 1226 | [[package]] 1227 | name = "icu_locid_transform_data" 1228 | version = "1.5.0" 1229 | source = "registry+https://github.com/rust-lang/crates.io-index" 1230 | checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" 1231 | 1232 | [[package]] 1233 | name = "icu_normalizer" 1234 | version = "1.5.0" 1235 | source = "registry+https://github.com/rust-lang/crates.io-index" 1236 | checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" 1237 | dependencies = [ 1238 | "displaydoc", 1239 | "icu_collections", 1240 | "icu_normalizer_data", 1241 | "icu_properties", 1242 | "icu_provider", 1243 | "smallvec", 1244 | "utf16_iter", 1245 | "utf8_iter", 1246 | "write16", 1247 | "zerovec", 1248 | ] 1249 | 1250 | [[package]] 1251 | name = "icu_normalizer_data" 1252 | version = "1.5.0" 1253 | source = "registry+https://github.com/rust-lang/crates.io-index" 1254 | checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" 1255 | 1256 | [[package]] 1257 | name = "icu_properties" 1258 | version = "1.5.1" 1259 | source = "registry+https://github.com/rust-lang/crates.io-index" 1260 | checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" 1261 | dependencies = [ 1262 | "displaydoc", 1263 | "icu_collections", 1264 | "icu_locid_transform", 1265 | "icu_properties_data", 1266 | "icu_provider", 1267 | "tinystr", 1268 | "zerovec", 1269 | ] 1270 | 1271 | [[package]] 1272 | name = "icu_properties_data" 1273 | version = "1.5.0" 1274 | source = "registry+https://github.com/rust-lang/crates.io-index" 1275 | checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" 1276 | 1277 | [[package]] 1278 | name = "icu_provider" 1279 | version = "1.5.0" 1280 | source = "registry+https://github.com/rust-lang/crates.io-index" 1281 | checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" 1282 | dependencies = [ 1283 | "displaydoc", 1284 | "icu_locid", 1285 | "icu_provider_macros", 1286 | "stable_deref_trait", 1287 | "tinystr", 1288 | "writeable", 1289 | "yoke", 1290 | "zerofrom", 1291 | "zerovec", 1292 | ] 1293 | 1294 | [[package]] 1295 | name = "icu_provider_macros" 1296 | version = "1.5.0" 1297 | source = "registry+https://github.com/rust-lang/crates.io-index" 1298 | checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" 1299 | dependencies = [ 1300 | "proc-macro2", 1301 | "quote", 1302 | "syn", 1303 | ] 1304 | 1305 | [[package]] 1306 | name = "idna" 1307 | version = "1.0.3" 1308 | source = "registry+https://github.com/rust-lang/crates.io-index" 1309 | checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 1310 | dependencies = [ 1311 | "idna_adapter", 1312 | "smallvec", 1313 | "utf8_iter", 1314 | ] 1315 | 1316 | [[package]] 1317 | name = "idna_adapter" 1318 | version = "1.2.0" 1319 | source = "registry+https://github.com/rust-lang/crates.io-index" 1320 | checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" 1321 | dependencies = [ 1322 | "icu_normalizer", 1323 | "icu_properties", 1324 | ] 1325 | 1326 | [[package]] 1327 | name = "indexmap" 1328 | version = "2.6.0" 1329 | source = "registry+https://github.com/rust-lang/crates.io-index" 1330 | checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" 1331 | dependencies = [ 1332 | "equivalent", 1333 | "hashbrown", 1334 | ] 1335 | 1336 | [[package]] 1337 | name = "indicatif" 1338 | version = "0.17.9" 1339 | source = "registry+https://github.com/rust-lang/crates.io-index" 1340 | checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281" 1341 | dependencies = [ 1342 | "console", 1343 | "number_prefix", 1344 | "portable-atomic", 1345 | "unicode-width 0.2.0", 1346 | "web-time", 1347 | ] 1348 | 1349 | [[package]] 1350 | name = "is_terminal_polyfill" 1351 | version = "1.70.1" 1352 | source = "registry+https://github.com/rust-lang/crates.io-index" 1353 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 1354 | 1355 | [[package]] 1356 | name = "itoa" 1357 | version = "1.0.11" 1358 | source = "registry+https://github.com/rust-lang/crates.io-index" 1359 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 1360 | 1361 | [[package]] 1362 | name = "js-sys" 1363 | version = "0.3.72" 1364 | source = "registry+https://github.com/rust-lang/crates.io-index" 1365 | checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" 1366 | dependencies = [ 1367 | "wasm-bindgen", 1368 | ] 1369 | 1370 | [[package]] 1371 | name = "lazy_static" 1372 | version = "1.5.0" 1373 | source = "registry+https://github.com/rust-lang/crates.io-index" 1374 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 1375 | 1376 | [[package]] 1377 | name = "libc" 1378 | version = "0.2.162" 1379 | source = "registry+https://github.com/rust-lang/crates.io-index" 1380 | checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" 1381 | 1382 | [[package]] 1383 | name = "libredox" 1384 | version = "0.1.3" 1385 | source = "registry+https://github.com/rust-lang/crates.io-index" 1386 | checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" 1387 | dependencies = [ 1388 | "bitflags", 1389 | "libc", 1390 | ] 1391 | 1392 | [[package]] 1393 | name = "litemap" 1394 | version = "0.7.3" 1395 | source = "registry+https://github.com/rust-lang/crates.io-index" 1396 | checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" 1397 | 1398 | [[package]] 1399 | name = "lock_api" 1400 | version = "0.4.12" 1401 | source = "registry+https://github.com/rust-lang/crates.io-index" 1402 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 1403 | dependencies = [ 1404 | "autocfg", 1405 | "scopeguard", 1406 | ] 1407 | 1408 | [[package]] 1409 | name = "log" 1410 | version = "0.4.22" 1411 | source = "registry+https://github.com/rust-lang/crates.io-index" 1412 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 1413 | 1414 | [[package]] 1415 | name = "lru" 1416 | version = "0.12.5" 1417 | source = "registry+https://github.com/rust-lang/crates.io-index" 1418 | checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" 1419 | dependencies = [ 1420 | "hashbrown", 1421 | ] 1422 | 1423 | [[package]] 1424 | name = "matchers" 1425 | version = "0.1.0" 1426 | source = "registry+https://github.com/rust-lang/crates.io-index" 1427 | checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" 1428 | dependencies = [ 1429 | "regex-automata 0.1.10", 1430 | ] 1431 | 1432 | [[package]] 1433 | name = "md-5" 1434 | version = "0.10.6" 1435 | source = "registry+https://github.com/rust-lang/crates.io-index" 1436 | checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" 1437 | dependencies = [ 1438 | "cfg-if", 1439 | "digest", 1440 | ] 1441 | 1442 | [[package]] 1443 | name = "md5" 1444 | version = "0.7.0" 1445 | source = "registry+https://github.com/rust-lang/crates.io-index" 1446 | checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" 1447 | 1448 | [[package]] 1449 | name = "memchr" 1450 | version = "2.7.4" 1451 | source = "registry+https://github.com/rust-lang/crates.io-index" 1452 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 1453 | 1454 | [[package]] 1455 | name = "miniz_oxide" 1456 | version = "0.8.0" 1457 | source = "registry+https://github.com/rust-lang/crates.io-index" 1458 | checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" 1459 | dependencies = [ 1460 | "adler2", 1461 | ] 1462 | 1463 | [[package]] 1464 | name = "mio" 1465 | version = "1.0.2" 1466 | source = "registry+https://github.com/rust-lang/crates.io-index" 1467 | checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" 1468 | dependencies = [ 1469 | "hermit-abi", 1470 | "libc", 1471 | "wasi", 1472 | "windows-sys 0.52.0", 1473 | ] 1474 | 1475 | [[package]] 1476 | name = "nu-ansi-term" 1477 | version = "0.46.0" 1478 | source = "registry+https://github.com/rust-lang/crates.io-index" 1479 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 1480 | dependencies = [ 1481 | "overload", 1482 | "winapi", 1483 | ] 1484 | 1485 | [[package]] 1486 | name = "num-conv" 1487 | version = "0.1.0" 1488 | source = "registry+https://github.com/rust-lang/crates.io-index" 1489 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 1490 | 1491 | [[package]] 1492 | name = "num-integer" 1493 | version = "0.1.46" 1494 | source = "registry+https://github.com/rust-lang/crates.io-index" 1495 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 1496 | dependencies = [ 1497 | "num-traits", 1498 | ] 1499 | 1500 | [[package]] 1501 | name = "num-traits" 1502 | version = "0.2.19" 1503 | source = "registry+https://github.com/rust-lang/crates.io-index" 1504 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 1505 | dependencies = [ 1506 | "autocfg", 1507 | ] 1508 | 1509 | [[package]] 1510 | name = "number_prefix" 1511 | version = "0.4.0" 1512 | source = "registry+https://github.com/rust-lang/crates.io-index" 1513 | checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" 1514 | 1515 | [[package]] 1516 | name = "object" 1517 | version = "0.36.5" 1518 | source = "registry+https://github.com/rust-lang/crates.io-index" 1519 | checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" 1520 | dependencies = [ 1521 | "memchr", 1522 | ] 1523 | 1524 | [[package]] 1525 | name = "once_cell" 1526 | version = "1.20.2" 1527 | source = "registry+https://github.com/rust-lang/crates.io-index" 1528 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 1529 | 1530 | [[package]] 1531 | name = "openssl-probe" 1532 | version = "0.1.5" 1533 | source = "registry+https://github.com/rust-lang/crates.io-index" 1534 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 1535 | 1536 | [[package]] 1537 | name = "option-ext" 1538 | version = "0.2.0" 1539 | source = "registry+https://github.com/rust-lang/crates.io-index" 1540 | checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" 1541 | 1542 | [[package]] 1543 | name = "outref" 1544 | version = "0.5.1" 1545 | source = "registry+https://github.com/rust-lang/crates.io-index" 1546 | checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a" 1547 | 1548 | [[package]] 1549 | name = "overload" 1550 | version = "0.1.1" 1551 | source = "registry+https://github.com/rust-lang/crates.io-index" 1552 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 1553 | 1554 | [[package]] 1555 | name = "p256" 1556 | version = "0.11.1" 1557 | source = "registry+https://github.com/rust-lang/crates.io-index" 1558 | checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" 1559 | dependencies = [ 1560 | "ecdsa", 1561 | "elliptic-curve", 1562 | "sha2", 1563 | ] 1564 | 1565 | [[package]] 1566 | name = "parking_lot" 1567 | version = "0.12.3" 1568 | source = "registry+https://github.com/rust-lang/crates.io-index" 1569 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 1570 | dependencies = [ 1571 | "lock_api", 1572 | "parking_lot_core", 1573 | ] 1574 | 1575 | [[package]] 1576 | name = "parking_lot_core" 1577 | version = "0.9.10" 1578 | source = "registry+https://github.com/rust-lang/crates.io-index" 1579 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 1580 | dependencies = [ 1581 | "cfg-if", 1582 | "libc", 1583 | "redox_syscall", 1584 | "smallvec", 1585 | "windows-targets 0.52.6", 1586 | ] 1587 | 1588 | [[package]] 1589 | name = "percent-encoding" 1590 | version = "2.3.1" 1591 | source = "registry+https://github.com/rust-lang/crates.io-index" 1592 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1593 | 1594 | [[package]] 1595 | name = "pin-project" 1596 | version = "1.1.7" 1597 | source = "registry+https://github.com/rust-lang/crates.io-index" 1598 | checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" 1599 | dependencies = [ 1600 | "pin-project-internal", 1601 | ] 1602 | 1603 | [[package]] 1604 | name = "pin-project-internal" 1605 | version = "1.1.7" 1606 | source = "registry+https://github.com/rust-lang/crates.io-index" 1607 | checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" 1608 | dependencies = [ 1609 | "proc-macro2", 1610 | "quote", 1611 | "syn", 1612 | ] 1613 | 1614 | [[package]] 1615 | name = "pin-project-lite" 1616 | version = "0.2.15" 1617 | source = "registry+https://github.com/rust-lang/crates.io-index" 1618 | checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" 1619 | 1620 | [[package]] 1621 | name = "pin-utils" 1622 | version = "0.1.0" 1623 | source = "registry+https://github.com/rust-lang/crates.io-index" 1624 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1625 | 1626 | [[package]] 1627 | name = "pkcs8" 1628 | version = "0.9.0" 1629 | source = "registry+https://github.com/rust-lang/crates.io-index" 1630 | checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" 1631 | dependencies = [ 1632 | "der", 1633 | "spki", 1634 | ] 1635 | 1636 | [[package]] 1637 | name = "pkg-config" 1638 | version = "0.3.31" 1639 | source = "registry+https://github.com/rust-lang/crates.io-index" 1640 | checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" 1641 | 1642 | [[package]] 1643 | name = "portable-atomic" 1644 | version = "1.9.0" 1645 | source = "registry+https://github.com/rust-lang/crates.io-index" 1646 | checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" 1647 | 1648 | [[package]] 1649 | name = "powerfmt" 1650 | version = "0.2.0" 1651 | source = "registry+https://github.com/rust-lang/crates.io-index" 1652 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 1653 | 1654 | [[package]] 1655 | name = "proc-macro2" 1656 | version = "1.0.89" 1657 | source = "registry+https://github.com/rust-lang/crates.io-index" 1658 | checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" 1659 | dependencies = [ 1660 | "unicode-ident", 1661 | ] 1662 | 1663 | [[package]] 1664 | name = "quote" 1665 | version = "1.0.37" 1666 | source = "registry+https://github.com/rust-lang/crates.io-index" 1667 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 1668 | dependencies = [ 1669 | "proc-macro2", 1670 | ] 1671 | 1672 | [[package]] 1673 | name = "rand_core" 1674 | version = "0.6.4" 1675 | source = "registry+https://github.com/rust-lang/crates.io-index" 1676 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1677 | dependencies = [ 1678 | "getrandom", 1679 | ] 1680 | 1681 | [[package]] 1682 | name = "redox_syscall" 1683 | version = "0.5.7" 1684 | source = "registry+https://github.com/rust-lang/crates.io-index" 1685 | checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" 1686 | dependencies = [ 1687 | "bitflags", 1688 | ] 1689 | 1690 | [[package]] 1691 | name = "redox_users" 1692 | version = "0.4.6" 1693 | source = "registry+https://github.com/rust-lang/crates.io-index" 1694 | checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" 1695 | dependencies = [ 1696 | "getrandom", 1697 | "libredox", 1698 | "thiserror", 1699 | ] 1700 | 1701 | [[package]] 1702 | name = "regex" 1703 | version = "1.11.1" 1704 | source = "registry+https://github.com/rust-lang/crates.io-index" 1705 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 1706 | dependencies = [ 1707 | "aho-corasick", 1708 | "memchr", 1709 | "regex-automata 0.4.9", 1710 | "regex-syntax 0.8.5", 1711 | ] 1712 | 1713 | [[package]] 1714 | name = "regex-automata" 1715 | version = "0.1.10" 1716 | source = "registry+https://github.com/rust-lang/crates.io-index" 1717 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 1718 | dependencies = [ 1719 | "regex-syntax 0.6.29", 1720 | ] 1721 | 1722 | [[package]] 1723 | name = "regex-automata" 1724 | version = "0.4.9" 1725 | source = "registry+https://github.com/rust-lang/crates.io-index" 1726 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 1727 | dependencies = [ 1728 | "aho-corasick", 1729 | "memchr", 1730 | "regex-syntax 0.8.5", 1731 | ] 1732 | 1733 | [[package]] 1734 | name = "regex-lite" 1735 | version = "0.1.6" 1736 | source = "registry+https://github.com/rust-lang/crates.io-index" 1737 | checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" 1738 | 1739 | [[package]] 1740 | name = "regex-syntax" 1741 | version = "0.6.29" 1742 | source = "registry+https://github.com/rust-lang/crates.io-index" 1743 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" 1744 | 1745 | [[package]] 1746 | name = "regex-syntax" 1747 | version = "0.8.5" 1748 | source = "registry+https://github.com/rust-lang/crates.io-index" 1749 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 1750 | 1751 | [[package]] 1752 | name = "rfc6979" 1753 | version = "0.3.1" 1754 | source = "registry+https://github.com/rust-lang/crates.io-index" 1755 | checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" 1756 | dependencies = [ 1757 | "crypto-bigint 0.4.9", 1758 | "hmac", 1759 | "zeroize", 1760 | ] 1761 | 1762 | [[package]] 1763 | name = "ring" 1764 | version = "0.17.8" 1765 | source = "registry+https://github.com/rust-lang/crates.io-index" 1766 | checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" 1767 | dependencies = [ 1768 | "cc", 1769 | "cfg-if", 1770 | "getrandom", 1771 | "libc", 1772 | "spin", 1773 | "untrusted", 1774 | "windows-sys 0.52.0", 1775 | ] 1776 | 1777 | [[package]] 1778 | name = "rustc-demangle" 1779 | version = "0.1.24" 1780 | source = "registry+https://github.com/rust-lang/crates.io-index" 1781 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1782 | 1783 | [[package]] 1784 | name = "rustc_version" 1785 | version = "0.4.1" 1786 | source = "registry+https://github.com/rust-lang/crates.io-index" 1787 | checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" 1788 | dependencies = [ 1789 | "semver", 1790 | ] 1791 | 1792 | [[package]] 1793 | name = "rustls" 1794 | version = "0.21.12" 1795 | source = "registry+https://github.com/rust-lang/crates.io-index" 1796 | checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" 1797 | dependencies = [ 1798 | "log", 1799 | "ring", 1800 | "rustls-webpki", 1801 | "sct", 1802 | ] 1803 | 1804 | [[package]] 1805 | name = "rustls-native-certs" 1806 | version = "0.6.3" 1807 | source = "registry+https://github.com/rust-lang/crates.io-index" 1808 | checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" 1809 | dependencies = [ 1810 | "openssl-probe", 1811 | "rustls-pemfile", 1812 | "schannel", 1813 | "security-framework", 1814 | ] 1815 | 1816 | [[package]] 1817 | name = "rustls-pemfile" 1818 | version = "1.0.4" 1819 | source = "registry+https://github.com/rust-lang/crates.io-index" 1820 | checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" 1821 | dependencies = [ 1822 | "base64", 1823 | ] 1824 | 1825 | [[package]] 1826 | name = "rustls-webpki" 1827 | version = "0.101.7" 1828 | source = "registry+https://github.com/rust-lang/crates.io-index" 1829 | checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" 1830 | dependencies = [ 1831 | "ring", 1832 | "untrusted", 1833 | ] 1834 | 1835 | [[package]] 1836 | name = "ryu" 1837 | version = "1.0.18" 1838 | source = "registry+https://github.com/rust-lang/crates.io-index" 1839 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1840 | 1841 | [[package]] 1842 | name = "schannel" 1843 | version = "0.1.26" 1844 | source = "registry+https://github.com/rust-lang/crates.io-index" 1845 | checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" 1846 | dependencies = [ 1847 | "windows-sys 0.59.0", 1848 | ] 1849 | 1850 | [[package]] 1851 | name = "scopeguard" 1852 | version = "1.2.0" 1853 | source = "registry+https://github.com/rust-lang/crates.io-index" 1854 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1855 | 1856 | [[package]] 1857 | name = "sct" 1858 | version = "0.7.1" 1859 | source = "registry+https://github.com/rust-lang/crates.io-index" 1860 | checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" 1861 | dependencies = [ 1862 | "ring", 1863 | "untrusted", 1864 | ] 1865 | 1866 | [[package]] 1867 | name = "sec1" 1868 | version = "0.3.0" 1869 | source = "registry+https://github.com/rust-lang/crates.io-index" 1870 | checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" 1871 | dependencies = [ 1872 | "base16ct", 1873 | "der", 1874 | "generic-array", 1875 | "pkcs8", 1876 | "subtle", 1877 | "zeroize", 1878 | ] 1879 | 1880 | [[package]] 1881 | name = "security-framework" 1882 | version = "2.11.1" 1883 | source = "registry+https://github.com/rust-lang/crates.io-index" 1884 | checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 1885 | dependencies = [ 1886 | "bitflags", 1887 | "core-foundation", 1888 | "core-foundation-sys", 1889 | "libc", 1890 | "security-framework-sys", 1891 | ] 1892 | 1893 | [[package]] 1894 | name = "security-framework-sys" 1895 | version = "2.12.1" 1896 | source = "registry+https://github.com/rust-lang/crates.io-index" 1897 | checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" 1898 | dependencies = [ 1899 | "core-foundation-sys", 1900 | "libc", 1901 | ] 1902 | 1903 | [[package]] 1904 | name = "semver" 1905 | version = "1.0.23" 1906 | source = "registry+https://github.com/rust-lang/crates.io-index" 1907 | checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" 1908 | 1909 | [[package]] 1910 | name = "serde" 1911 | version = "1.0.215" 1912 | source = "registry+https://github.com/rust-lang/crates.io-index" 1913 | checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" 1914 | dependencies = [ 1915 | "serde_derive", 1916 | ] 1917 | 1918 | [[package]] 1919 | name = "serde_derive" 1920 | version = "1.0.215" 1921 | source = "registry+https://github.com/rust-lang/crates.io-index" 1922 | checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" 1923 | dependencies = [ 1924 | "proc-macro2", 1925 | "quote", 1926 | "syn", 1927 | ] 1928 | 1929 | [[package]] 1930 | name = "serde_spanned" 1931 | version = "0.6.8" 1932 | source = "registry+https://github.com/rust-lang/crates.io-index" 1933 | checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" 1934 | dependencies = [ 1935 | "serde", 1936 | ] 1937 | 1938 | [[package]] 1939 | name = "sha1" 1940 | version = "0.10.6" 1941 | source = "registry+https://github.com/rust-lang/crates.io-index" 1942 | checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 1943 | dependencies = [ 1944 | "cfg-if", 1945 | "cpufeatures", 1946 | "digest", 1947 | ] 1948 | 1949 | [[package]] 1950 | name = "sha2" 1951 | version = "0.10.8" 1952 | source = "registry+https://github.com/rust-lang/crates.io-index" 1953 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 1954 | dependencies = [ 1955 | "cfg-if", 1956 | "cpufeatures", 1957 | "digest", 1958 | ] 1959 | 1960 | [[package]] 1961 | name = "sharded-slab" 1962 | version = "0.1.7" 1963 | source = "registry+https://github.com/rust-lang/crates.io-index" 1964 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 1965 | dependencies = [ 1966 | "lazy_static", 1967 | ] 1968 | 1969 | [[package]] 1970 | name = "shlex" 1971 | version = "1.3.0" 1972 | source = "registry+https://github.com/rust-lang/crates.io-index" 1973 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1974 | 1975 | [[package]] 1976 | name = "shuk" 1977 | version = "0.4.7" 1978 | dependencies = [ 1979 | "anyhow", 1980 | "aws-config", 1981 | "aws-sdk-s3", 1982 | "aws-smithy-runtime-api", 1983 | "aws-smithy-types", 1984 | "aws-types", 1985 | "bytes", 1986 | "chrono", 1987 | "clap", 1988 | "colored", 1989 | "dirs", 1990 | "env_logger", 1991 | "http 0.2.12", 1992 | "http-body 0.4.6", 1993 | "indicatif", 1994 | "log", 1995 | "md5", 1996 | "pin-project", 1997 | "pkg-config", 1998 | "serde", 1999 | "serde_derive", 2000 | "tokio", 2001 | "toml", 2002 | "tracing", 2003 | "tracing-subscriber", 2004 | ] 2005 | 2006 | [[package]] 2007 | name = "signal-hook-registry" 2008 | version = "1.4.2" 2009 | source = "registry+https://github.com/rust-lang/crates.io-index" 2010 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 2011 | dependencies = [ 2012 | "libc", 2013 | ] 2014 | 2015 | [[package]] 2016 | name = "signature" 2017 | version = "1.6.4" 2018 | source = "registry+https://github.com/rust-lang/crates.io-index" 2019 | checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" 2020 | dependencies = [ 2021 | "digest", 2022 | "rand_core", 2023 | ] 2024 | 2025 | [[package]] 2026 | name = "slab" 2027 | version = "0.4.9" 2028 | source = "registry+https://github.com/rust-lang/crates.io-index" 2029 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 2030 | dependencies = [ 2031 | "autocfg", 2032 | ] 2033 | 2034 | [[package]] 2035 | name = "smallvec" 2036 | version = "1.13.2" 2037 | source = "registry+https://github.com/rust-lang/crates.io-index" 2038 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 2039 | 2040 | [[package]] 2041 | name = "socket2" 2042 | version = "0.5.7" 2043 | source = "registry+https://github.com/rust-lang/crates.io-index" 2044 | checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" 2045 | dependencies = [ 2046 | "libc", 2047 | "windows-sys 0.52.0", 2048 | ] 2049 | 2050 | [[package]] 2051 | name = "spin" 2052 | version = "0.9.8" 2053 | source = "registry+https://github.com/rust-lang/crates.io-index" 2054 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 2055 | 2056 | [[package]] 2057 | name = "spki" 2058 | version = "0.6.0" 2059 | source = "registry+https://github.com/rust-lang/crates.io-index" 2060 | checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" 2061 | dependencies = [ 2062 | "base64ct", 2063 | "der", 2064 | ] 2065 | 2066 | [[package]] 2067 | name = "stable_deref_trait" 2068 | version = "1.2.0" 2069 | source = "registry+https://github.com/rust-lang/crates.io-index" 2070 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 2071 | 2072 | [[package]] 2073 | name = "strsim" 2074 | version = "0.11.1" 2075 | source = "registry+https://github.com/rust-lang/crates.io-index" 2076 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 2077 | 2078 | [[package]] 2079 | name = "subtle" 2080 | version = "2.6.1" 2081 | source = "registry+https://github.com/rust-lang/crates.io-index" 2082 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 2083 | 2084 | [[package]] 2085 | name = "syn" 2086 | version = "2.0.87" 2087 | source = "registry+https://github.com/rust-lang/crates.io-index" 2088 | checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" 2089 | dependencies = [ 2090 | "proc-macro2", 2091 | "quote", 2092 | "unicode-ident", 2093 | ] 2094 | 2095 | [[package]] 2096 | name = "synstructure" 2097 | version = "0.13.1" 2098 | source = "registry+https://github.com/rust-lang/crates.io-index" 2099 | checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" 2100 | dependencies = [ 2101 | "proc-macro2", 2102 | "quote", 2103 | "syn", 2104 | ] 2105 | 2106 | [[package]] 2107 | name = "thiserror" 2108 | version = "1.0.69" 2109 | source = "registry+https://github.com/rust-lang/crates.io-index" 2110 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 2111 | dependencies = [ 2112 | "thiserror-impl", 2113 | ] 2114 | 2115 | [[package]] 2116 | name = "thiserror-impl" 2117 | version = "1.0.69" 2118 | source = "registry+https://github.com/rust-lang/crates.io-index" 2119 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 2120 | dependencies = [ 2121 | "proc-macro2", 2122 | "quote", 2123 | "syn", 2124 | ] 2125 | 2126 | [[package]] 2127 | name = "thread_local" 2128 | version = "1.1.8" 2129 | source = "registry+https://github.com/rust-lang/crates.io-index" 2130 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 2131 | dependencies = [ 2132 | "cfg-if", 2133 | "once_cell", 2134 | ] 2135 | 2136 | [[package]] 2137 | name = "time" 2138 | version = "0.3.36" 2139 | source = "registry+https://github.com/rust-lang/crates.io-index" 2140 | checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" 2141 | dependencies = [ 2142 | "deranged", 2143 | "num-conv", 2144 | "powerfmt", 2145 | "serde", 2146 | "time-core", 2147 | "time-macros", 2148 | ] 2149 | 2150 | [[package]] 2151 | name = "time-core" 2152 | version = "0.1.2" 2153 | source = "registry+https://github.com/rust-lang/crates.io-index" 2154 | checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" 2155 | 2156 | [[package]] 2157 | name = "time-macros" 2158 | version = "0.2.18" 2159 | source = "registry+https://github.com/rust-lang/crates.io-index" 2160 | checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" 2161 | dependencies = [ 2162 | "num-conv", 2163 | "time-core", 2164 | ] 2165 | 2166 | [[package]] 2167 | name = "tinystr" 2168 | version = "0.7.6" 2169 | source = "registry+https://github.com/rust-lang/crates.io-index" 2170 | checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" 2171 | dependencies = [ 2172 | "displaydoc", 2173 | "zerovec", 2174 | ] 2175 | 2176 | [[package]] 2177 | name = "tokio" 2178 | version = "1.41.1" 2179 | source = "registry+https://github.com/rust-lang/crates.io-index" 2180 | checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" 2181 | dependencies = [ 2182 | "backtrace", 2183 | "bytes", 2184 | "libc", 2185 | "mio", 2186 | "parking_lot", 2187 | "pin-project-lite", 2188 | "signal-hook-registry", 2189 | "socket2", 2190 | "tokio-macros", 2191 | "windows-sys 0.52.0", 2192 | ] 2193 | 2194 | [[package]] 2195 | name = "tokio-macros" 2196 | version = "2.4.0" 2197 | source = "registry+https://github.com/rust-lang/crates.io-index" 2198 | checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" 2199 | dependencies = [ 2200 | "proc-macro2", 2201 | "quote", 2202 | "syn", 2203 | ] 2204 | 2205 | [[package]] 2206 | name = "tokio-rustls" 2207 | version = "0.24.1" 2208 | source = "registry+https://github.com/rust-lang/crates.io-index" 2209 | checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" 2210 | dependencies = [ 2211 | "rustls", 2212 | "tokio", 2213 | ] 2214 | 2215 | [[package]] 2216 | name = "tokio-util" 2217 | version = "0.7.12" 2218 | source = "registry+https://github.com/rust-lang/crates.io-index" 2219 | checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" 2220 | dependencies = [ 2221 | "bytes", 2222 | "futures-core", 2223 | "futures-sink", 2224 | "pin-project-lite", 2225 | "tokio", 2226 | ] 2227 | 2228 | [[package]] 2229 | name = "toml" 2230 | version = "0.8.19" 2231 | source = "registry+https://github.com/rust-lang/crates.io-index" 2232 | checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" 2233 | dependencies = [ 2234 | "serde", 2235 | "serde_spanned", 2236 | "toml_datetime", 2237 | "toml_edit", 2238 | ] 2239 | 2240 | [[package]] 2241 | name = "toml_datetime" 2242 | version = "0.6.8" 2243 | source = "registry+https://github.com/rust-lang/crates.io-index" 2244 | checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 2245 | dependencies = [ 2246 | "serde", 2247 | ] 2248 | 2249 | [[package]] 2250 | name = "toml_edit" 2251 | version = "0.22.22" 2252 | source = "registry+https://github.com/rust-lang/crates.io-index" 2253 | checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" 2254 | dependencies = [ 2255 | "indexmap", 2256 | "serde", 2257 | "serde_spanned", 2258 | "toml_datetime", 2259 | "winnow", 2260 | ] 2261 | 2262 | [[package]] 2263 | name = "tower-service" 2264 | version = "0.3.3" 2265 | source = "registry+https://github.com/rust-lang/crates.io-index" 2266 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 2267 | 2268 | [[package]] 2269 | name = "tracing" 2270 | version = "0.1.40" 2271 | source = "registry+https://github.com/rust-lang/crates.io-index" 2272 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 2273 | dependencies = [ 2274 | "pin-project-lite", 2275 | "tracing-attributes", 2276 | "tracing-core", 2277 | ] 2278 | 2279 | [[package]] 2280 | name = "tracing-attributes" 2281 | version = "0.1.27" 2282 | source = "registry+https://github.com/rust-lang/crates.io-index" 2283 | checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" 2284 | dependencies = [ 2285 | "proc-macro2", 2286 | "quote", 2287 | "syn", 2288 | ] 2289 | 2290 | [[package]] 2291 | name = "tracing-core" 2292 | version = "0.1.32" 2293 | source = "registry+https://github.com/rust-lang/crates.io-index" 2294 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 2295 | dependencies = [ 2296 | "once_cell", 2297 | "valuable", 2298 | ] 2299 | 2300 | [[package]] 2301 | name = "tracing-log" 2302 | version = "0.2.0" 2303 | source = "registry+https://github.com/rust-lang/crates.io-index" 2304 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 2305 | dependencies = [ 2306 | "log", 2307 | "once_cell", 2308 | "tracing-core", 2309 | ] 2310 | 2311 | [[package]] 2312 | name = "tracing-subscriber" 2313 | version = "0.3.18" 2314 | source = "registry+https://github.com/rust-lang/crates.io-index" 2315 | checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" 2316 | dependencies = [ 2317 | "matchers", 2318 | "nu-ansi-term", 2319 | "once_cell", 2320 | "regex", 2321 | "sharded-slab", 2322 | "smallvec", 2323 | "thread_local", 2324 | "tracing", 2325 | "tracing-core", 2326 | "tracing-log", 2327 | ] 2328 | 2329 | [[package]] 2330 | name = "try-lock" 2331 | version = "0.2.5" 2332 | source = "registry+https://github.com/rust-lang/crates.io-index" 2333 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 2334 | 2335 | [[package]] 2336 | name = "typenum" 2337 | version = "1.17.0" 2338 | source = "registry+https://github.com/rust-lang/crates.io-index" 2339 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 2340 | 2341 | [[package]] 2342 | name = "unicode-ident" 2343 | version = "1.0.13" 2344 | source = "registry+https://github.com/rust-lang/crates.io-index" 2345 | checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" 2346 | 2347 | [[package]] 2348 | name = "unicode-width" 2349 | version = "0.1.14" 2350 | source = "registry+https://github.com/rust-lang/crates.io-index" 2351 | checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" 2352 | 2353 | [[package]] 2354 | name = "unicode-width" 2355 | version = "0.2.0" 2356 | source = "registry+https://github.com/rust-lang/crates.io-index" 2357 | checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" 2358 | 2359 | [[package]] 2360 | name = "untrusted" 2361 | version = "0.9.0" 2362 | source = "registry+https://github.com/rust-lang/crates.io-index" 2363 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 2364 | 2365 | [[package]] 2366 | name = "url" 2367 | version = "2.5.3" 2368 | source = "registry+https://github.com/rust-lang/crates.io-index" 2369 | checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" 2370 | dependencies = [ 2371 | "form_urlencoded", 2372 | "idna", 2373 | "percent-encoding", 2374 | ] 2375 | 2376 | [[package]] 2377 | name = "urlencoding" 2378 | version = "2.1.3" 2379 | source = "registry+https://github.com/rust-lang/crates.io-index" 2380 | checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" 2381 | 2382 | [[package]] 2383 | name = "utf16_iter" 2384 | version = "1.0.5" 2385 | source = "registry+https://github.com/rust-lang/crates.io-index" 2386 | checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" 2387 | 2388 | [[package]] 2389 | name = "utf8_iter" 2390 | version = "1.0.4" 2391 | source = "registry+https://github.com/rust-lang/crates.io-index" 2392 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 2393 | 2394 | [[package]] 2395 | name = "utf8parse" 2396 | version = "0.2.2" 2397 | source = "registry+https://github.com/rust-lang/crates.io-index" 2398 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 2399 | 2400 | [[package]] 2401 | name = "uuid" 2402 | version = "1.11.0" 2403 | source = "registry+https://github.com/rust-lang/crates.io-index" 2404 | checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" 2405 | 2406 | [[package]] 2407 | name = "valuable" 2408 | version = "0.1.0" 2409 | source = "registry+https://github.com/rust-lang/crates.io-index" 2410 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 2411 | 2412 | [[package]] 2413 | name = "version_check" 2414 | version = "0.9.5" 2415 | source = "registry+https://github.com/rust-lang/crates.io-index" 2416 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 2417 | 2418 | [[package]] 2419 | name = "vsimd" 2420 | version = "0.8.0" 2421 | source = "registry+https://github.com/rust-lang/crates.io-index" 2422 | checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" 2423 | 2424 | [[package]] 2425 | name = "want" 2426 | version = "0.3.1" 2427 | source = "registry+https://github.com/rust-lang/crates.io-index" 2428 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 2429 | dependencies = [ 2430 | "try-lock", 2431 | ] 2432 | 2433 | [[package]] 2434 | name = "wasi" 2435 | version = "0.11.0+wasi-snapshot-preview1" 2436 | source = "registry+https://github.com/rust-lang/crates.io-index" 2437 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 2438 | 2439 | [[package]] 2440 | name = "wasm-bindgen" 2441 | version = "0.2.95" 2442 | source = "registry+https://github.com/rust-lang/crates.io-index" 2443 | checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" 2444 | dependencies = [ 2445 | "cfg-if", 2446 | "once_cell", 2447 | "wasm-bindgen-macro", 2448 | ] 2449 | 2450 | [[package]] 2451 | name = "wasm-bindgen-backend" 2452 | version = "0.2.95" 2453 | source = "registry+https://github.com/rust-lang/crates.io-index" 2454 | checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" 2455 | dependencies = [ 2456 | "bumpalo", 2457 | "log", 2458 | "once_cell", 2459 | "proc-macro2", 2460 | "quote", 2461 | "syn", 2462 | "wasm-bindgen-shared", 2463 | ] 2464 | 2465 | [[package]] 2466 | name = "wasm-bindgen-macro" 2467 | version = "0.2.95" 2468 | source = "registry+https://github.com/rust-lang/crates.io-index" 2469 | checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" 2470 | dependencies = [ 2471 | "quote", 2472 | "wasm-bindgen-macro-support", 2473 | ] 2474 | 2475 | [[package]] 2476 | name = "wasm-bindgen-macro-support" 2477 | version = "0.2.95" 2478 | source = "registry+https://github.com/rust-lang/crates.io-index" 2479 | checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" 2480 | dependencies = [ 2481 | "proc-macro2", 2482 | "quote", 2483 | "syn", 2484 | "wasm-bindgen-backend", 2485 | "wasm-bindgen-shared", 2486 | ] 2487 | 2488 | [[package]] 2489 | name = "wasm-bindgen-shared" 2490 | version = "0.2.95" 2491 | source = "registry+https://github.com/rust-lang/crates.io-index" 2492 | checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" 2493 | 2494 | [[package]] 2495 | name = "web-time" 2496 | version = "1.1.0" 2497 | source = "registry+https://github.com/rust-lang/crates.io-index" 2498 | checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" 2499 | dependencies = [ 2500 | "js-sys", 2501 | "wasm-bindgen", 2502 | ] 2503 | 2504 | [[package]] 2505 | name = "winapi" 2506 | version = "0.3.9" 2507 | source = "registry+https://github.com/rust-lang/crates.io-index" 2508 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2509 | dependencies = [ 2510 | "winapi-i686-pc-windows-gnu", 2511 | "winapi-x86_64-pc-windows-gnu", 2512 | ] 2513 | 2514 | [[package]] 2515 | name = "winapi-i686-pc-windows-gnu" 2516 | version = "0.4.0" 2517 | source = "registry+https://github.com/rust-lang/crates.io-index" 2518 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2519 | 2520 | [[package]] 2521 | name = "winapi-x86_64-pc-windows-gnu" 2522 | version = "0.4.0" 2523 | source = "registry+https://github.com/rust-lang/crates.io-index" 2524 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2525 | 2526 | [[package]] 2527 | name = "windows-core" 2528 | version = "0.52.0" 2529 | source = "registry+https://github.com/rust-lang/crates.io-index" 2530 | checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 2531 | dependencies = [ 2532 | "windows-targets 0.52.6", 2533 | ] 2534 | 2535 | [[package]] 2536 | name = "windows-sys" 2537 | version = "0.48.0" 2538 | source = "registry+https://github.com/rust-lang/crates.io-index" 2539 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 2540 | dependencies = [ 2541 | "windows-targets 0.48.5", 2542 | ] 2543 | 2544 | [[package]] 2545 | name = "windows-sys" 2546 | version = "0.52.0" 2547 | source = "registry+https://github.com/rust-lang/crates.io-index" 2548 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2549 | dependencies = [ 2550 | "windows-targets 0.52.6", 2551 | ] 2552 | 2553 | [[package]] 2554 | name = "windows-sys" 2555 | version = "0.59.0" 2556 | source = "registry+https://github.com/rust-lang/crates.io-index" 2557 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 2558 | dependencies = [ 2559 | "windows-targets 0.52.6", 2560 | ] 2561 | 2562 | [[package]] 2563 | name = "windows-targets" 2564 | version = "0.48.5" 2565 | source = "registry+https://github.com/rust-lang/crates.io-index" 2566 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 2567 | dependencies = [ 2568 | "windows_aarch64_gnullvm 0.48.5", 2569 | "windows_aarch64_msvc 0.48.5", 2570 | "windows_i686_gnu 0.48.5", 2571 | "windows_i686_msvc 0.48.5", 2572 | "windows_x86_64_gnu 0.48.5", 2573 | "windows_x86_64_gnullvm 0.48.5", 2574 | "windows_x86_64_msvc 0.48.5", 2575 | ] 2576 | 2577 | [[package]] 2578 | name = "windows-targets" 2579 | version = "0.52.6" 2580 | source = "registry+https://github.com/rust-lang/crates.io-index" 2581 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 2582 | dependencies = [ 2583 | "windows_aarch64_gnullvm 0.52.6", 2584 | "windows_aarch64_msvc 0.52.6", 2585 | "windows_i686_gnu 0.52.6", 2586 | "windows_i686_gnullvm", 2587 | "windows_i686_msvc 0.52.6", 2588 | "windows_x86_64_gnu 0.52.6", 2589 | "windows_x86_64_gnullvm 0.52.6", 2590 | "windows_x86_64_msvc 0.52.6", 2591 | ] 2592 | 2593 | [[package]] 2594 | name = "windows_aarch64_gnullvm" 2595 | version = "0.48.5" 2596 | source = "registry+https://github.com/rust-lang/crates.io-index" 2597 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 2598 | 2599 | [[package]] 2600 | name = "windows_aarch64_gnullvm" 2601 | version = "0.52.6" 2602 | source = "registry+https://github.com/rust-lang/crates.io-index" 2603 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 2604 | 2605 | [[package]] 2606 | name = "windows_aarch64_msvc" 2607 | version = "0.48.5" 2608 | source = "registry+https://github.com/rust-lang/crates.io-index" 2609 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 2610 | 2611 | [[package]] 2612 | name = "windows_aarch64_msvc" 2613 | version = "0.52.6" 2614 | source = "registry+https://github.com/rust-lang/crates.io-index" 2615 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 2616 | 2617 | [[package]] 2618 | name = "windows_i686_gnu" 2619 | version = "0.48.5" 2620 | source = "registry+https://github.com/rust-lang/crates.io-index" 2621 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 2622 | 2623 | [[package]] 2624 | name = "windows_i686_gnu" 2625 | version = "0.52.6" 2626 | source = "registry+https://github.com/rust-lang/crates.io-index" 2627 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 2628 | 2629 | [[package]] 2630 | name = "windows_i686_gnullvm" 2631 | version = "0.52.6" 2632 | source = "registry+https://github.com/rust-lang/crates.io-index" 2633 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 2634 | 2635 | [[package]] 2636 | name = "windows_i686_msvc" 2637 | version = "0.48.5" 2638 | source = "registry+https://github.com/rust-lang/crates.io-index" 2639 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 2640 | 2641 | [[package]] 2642 | name = "windows_i686_msvc" 2643 | version = "0.52.6" 2644 | source = "registry+https://github.com/rust-lang/crates.io-index" 2645 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 2646 | 2647 | [[package]] 2648 | name = "windows_x86_64_gnu" 2649 | version = "0.48.5" 2650 | source = "registry+https://github.com/rust-lang/crates.io-index" 2651 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 2652 | 2653 | [[package]] 2654 | name = "windows_x86_64_gnu" 2655 | version = "0.52.6" 2656 | source = "registry+https://github.com/rust-lang/crates.io-index" 2657 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 2658 | 2659 | [[package]] 2660 | name = "windows_x86_64_gnullvm" 2661 | version = "0.48.5" 2662 | source = "registry+https://github.com/rust-lang/crates.io-index" 2663 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 2664 | 2665 | [[package]] 2666 | name = "windows_x86_64_gnullvm" 2667 | version = "0.52.6" 2668 | source = "registry+https://github.com/rust-lang/crates.io-index" 2669 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 2670 | 2671 | [[package]] 2672 | name = "windows_x86_64_msvc" 2673 | version = "0.48.5" 2674 | source = "registry+https://github.com/rust-lang/crates.io-index" 2675 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 2676 | 2677 | [[package]] 2678 | name = "windows_x86_64_msvc" 2679 | version = "0.52.6" 2680 | source = "registry+https://github.com/rust-lang/crates.io-index" 2681 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2682 | 2683 | [[package]] 2684 | name = "winnow" 2685 | version = "0.6.20" 2686 | source = "registry+https://github.com/rust-lang/crates.io-index" 2687 | checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" 2688 | dependencies = [ 2689 | "memchr", 2690 | ] 2691 | 2692 | [[package]] 2693 | name = "write16" 2694 | version = "1.0.0" 2695 | source = "registry+https://github.com/rust-lang/crates.io-index" 2696 | checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" 2697 | 2698 | [[package]] 2699 | name = "writeable" 2700 | version = "0.5.5" 2701 | source = "registry+https://github.com/rust-lang/crates.io-index" 2702 | checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" 2703 | 2704 | [[package]] 2705 | name = "xmlparser" 2706 | version = "0.13.6" 2707 | source = "registry+https://github.com/rust-lang/crates.io-index" 2708 | checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" 2709 | 2710 | [[package]] 2711 | name = "yoke" 2712 | version = "0.7.4" 2713 | source = "registry+https://github.com/rust-lang/crates.io-index" 2714 | checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" 2715 | dependencies = [ 2716 | "serde", 2717 | "stable_deref_trait", 2718 | "yoke-derive", 2719 | "zerofrom", 2720 | ] 2721 | 2722 | [[package]] 2723 | name = "yoke-derive" 2724 | version = "0.7.4" 2725 | source = "registry+https://github.com/rust-lang/crates.io-index" 2726 | checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" 2727 | dependencies = [ 2728 | "proc-macro2", 2729 | "quote", 2730 | "syn", 2731 | "synstructure", 2732 | ] 2733 | 2734 | [[package]] 2735 | name = "zerofrom" 2736 | version = "0.1.4" 2737 | source = "registry+https://github.com/rust-lang/crates.io-index" 2738 | checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" 2739 | dependencies = [ 2740 | "zerofrom-derive", 2741 | ] 2742 | 2743 | [[package]] 2744 | name = "zerofrom-derive" 2745 | version = "0.1.4" 2746 | source = "registry+https://github.com/rust-lang/crates.io-index" 2747 | checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" 2748 | dependencies = [ 2749 | "proc-macro2", 2750 | "quote", 2751 | "syn", 2752 | "synstructure", 2753 | ] 2754 | 2755 | [[package]] 2756 | name = "zeroize" 2757 | version = "1.8.1" 2758 | source = "registry+https://github.com/rust-lang/crates.io-index" 2759 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 2760 | 2761 | [[package]] 2762 | name = "zerovec" 2763 | version = "0.10.4" 2764 | source = "registry+https://github.com/rust-lang/crates.io-index" 2765 | checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" 2766 | dependencies = [ 2767 | "yoke", 2768 | "zerofrom", 2769 | "zerovec-derive", 2770 | ] 2771 | 2772 | [[package]] 2773 | name = "zerovec-derive" 2774 | version = "0.10.3" 2775 | source = "registry+https://github.com/rust-lang/crates.io-index" 2776 | checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" 2777 | dependencies = [ 2778 | "proc-macro2", 2779 | "quote", 2780 | "syn", 2781 | ] 2782 | --------------------------------------------------------------------------------