├── .gitignore ├── .github ├── FUNDING.yml └── workflows │ ├── release-plz.yml │ └── release.yml ├── assets ├── conze.gif ├── conze.png ├── list.png ├── bridge.png ├── cal-cmp.png └── conze.tape ├── src ├── show ├── parser.rs ├── config.rs ├── list.rs ├── cli.rs ├── cal.rs ├── puente.rs └── main.rs ├── release-plz.toml ├── LICENSE ├── Cargo.toml ├── README.md ├── cliff.toml ├── CHANGELOG.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: k3ii 2 | buy_me_a_coffee: jainramchurn 3 | -------------------------------------------------------------------------------- /assets/conze.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k3ii/conze/HEAD/assets/conze.gif -------------------------------------------------------------------------------- /assets/conze.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k3ii/conze/HEAD/assets/conze.png -------------------------------------------------------------------------------- /assets/list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k3ii/conze/HEAD/assets/list.png -------------------------------------------------------------------------------- /assets/bridge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k3ii/conze/HEAD/assets/bridge.png -------------------------------------------------------------------------------- /assets/cal-cmp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k3ii/conze/HEAD/assets/cal-cmp.png -------------------------------------------------------------------------------- /src/show: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Loop through all files in the current directory 4 | for file in *; do 5 | # Check if it's a regular file 6 | if [ -f "$file" ]; then 7 | echo "File: $file" 8 | echo "--------------------" 9 | cat "$file" 10 | echo -e "\n" 11 | fi 12 | done 13 | 14 | -------------------------------------------------------------------------------- /release-plz.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | # path of the git-cliff configuration 3 | changelog_config = "cliff.toml" 4 | 5 | # enable changelog updates 6 | changelog_update = true 7 | 8 | # update dependencies with `cargo update` 9 | dependencies_update = true 10 | 11 | # create tags for the releases 12 | git_tag_enable = true 13 | 14 | # disable GitHub releases 15 | git_release_enable = false 16 | 17 | # labels for the release PR 18 | pr_labels = ["release"] 19 | 20 | # disallow updating repositories with uncommitted changes 21 | allow_dirty = false 22 | 23 | # disallow packaging with uncommitted changes 24 | publish_allow_dirty = false 25 | 26 | # disable running `cargo-semver-checks` 27 | semver_check = false 28 | -------------------------------------------------------------------------------- /.github/workflows/release-plz.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Deployment 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | release-plz: 10 | name: Release-plz 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v4 15 | with: 16 | fetch-depth: 0 17 | token: ${{ secrets.RELEASE_PLZ_TOKEN }} 18 | 19 | - name: Install Rust toolchain 20 | uses: dtolnay/rust-toolchain@stable 21 | 22 | - name: Run release-plz 23 | uses: MarcoIeni/release-plz-action@v0.5 24 | env: 25 | GITHUB_TOKEN: ${{ secrets.RELEASE_PLZ_TOKEN }} 26 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} 27 | -------------------------------------------------------------------------------- /assets/conze.tape: -------------------------------------------------------------------------------- 1 | Set Shell zsh 2 | Require conze 3 | Set FontSize 20 4 | Set Width 1300 5 | Set Height 1000 6 | Set Framerate 30 7 | Set PlaybackSpeed 0.5 8 | Sleep 500ms 9 | Type "conze" 10 | Sleep 500ms 11 | Enter 12 | Sleep 800ms 13 | Screenshot conze.png 14 | Type "conze ca" 15 | Sleep 500ms 16 | Type "lendar --compa" 17 | Sleep 500ms 18 | Type "r" 19 | Sleep 500ms 20 | Type "e " 21 | Sleep 500ms 22 | Type "ZA --month dec" 23 | Sleep 1s 24 | Enter 25 | Sleep 1s 26 | Screenshot cal-cmp.png 27 | Type "conze bridge" 28 | Sleep 1s 29 | Enter 30 | Sleep 1s 31 | Screenshot bridge.png 32 | Type "con" 33 | Sleep 500ms 34 | Type "ze bridge -c " 35 | Sleep 500ms 36 | Type "Za -y " 37 | Sleep 500ms 38 | Type "202" 39 | Sleep 500ms 40 | Type "5" 41 | Enter 42 | Sleep 1s 43 | Type "conze" 44 | Sleep 1s 45 | Type " list --country ZA -y 2025 " 46 | Sleep 2s 47 | Enter 48 | Sleep 2s 49 | Screenshot list.png 50 | Ctrl+D 51 | 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2024 Jain Ramchurn 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /src/parser.rs: -------------------------------------------------------------------------------- 1 | use regex::Regex; 2 | 3 | pub fn parse_month(month_str: &str) -> Option { 4 | // First, try to parse as a number 5 | if let Ok(month_num) = month_str.parse::() { 6 | if (1..=12).contains(&month_num) { 7 | return Some(month_num); 8 | } 9 | } 10 | 11 | // If not a number, try to match against month names or abbreviations 12 | let month_str_lower = month_str.to_lowercase(); 13 | let month_regex = 14 | Regex::new(r"^(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*$").unwrap(); 15 | 16 | if let Some(captures) = month_regex.captures(&month_str_lower) { 17 | match captures.get(1).unwrap().as_str() { 18 | "jan" => Some(1), 19 | "feb" => Some(2), 20 | "mar" => Some(3), 21 | "apr" => Some(4), 22 | "may" => Some(5), 23 | "jun" => Some(6), 24 | "jul" => Some(7), 25 | "aug" => Some(8), 26 | "sep" => Some(9), 27 | "oct" => Some(10), 28 | "nov" => Some(11), 29 | "dec" => Some(12), 30 | _ => None, 31 | } 32 | } else { 33 | None 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{Context, Result}; 2 | use serde::{Deserialize, Serialize}; 3 | use std::path::Path; 4 | 5 | #[derive(Debug, Serialize, Deserialize)] 6 | pub struct Config { 7 | #[serde( 8 | deserialize_with = "deserialize_uppercase", 9 | serialize_with = "serialize_uppercase" 10 | )] 11 | pub default_country: String, 12 | } 13 | 14 | impl Config { 15 | pub fn load(config_path: &Path) -> Result { 16 | let config = std::fs::read_to_string(config_path) 17 | .with_context(|| format!("Failed to read config file at {:?}", config_path))?; 18 | let config: Config = toml::from_str(&config).context("Failed to parse config file")?; 19 | Ok(config) 20 | } 21 | 22 | pub fn save(&self, config_path: &Path) -> Result<()> { 23 | let toml_string = toml::to_string(self)?; 24 | std::fs::create_dir_all(config_path.parent().unwrap())?; 25 | std::fs::write(config_path, toml_string)?; 26 | Ok(()) 27 | } 28 | } 29 | 30 | fn deserialize_uppercase<'de, D>(deserializer: D) -> Result 31 | where 32 | D: serde::Deserializer<'de>, 33 | { 34 | let s = String::deserialize(deserializer)?; 35 | Ok(s.to_uppercase()) 36 | } 37 | 38 | fn serialize_uppercase(value: &str, serializer: S) -> Result 39 | where 40 | S: serde::Serializer, 41 | { 42 | serializer.serialize_str(&value.to_uppercase()) 43 | } 44 | -------------------------------------------------------------------------------- /src/list.rs: -------------------------------------------------------------------------------- 1 | use crate::Holiday; 2 | use chrono::Datelike; 3 | use colored::Colorize; 4 | use comfy_table::{Cell, Color, ContentArrangement, Table}; 5 | 6 | pub fn list_holidays(holidays: &[Holiday], country: &str, year: i32) { 7 | let mut table = Table::new(); 8 | table 9 | .set_header(vec![ 10 | Cell::new("Date").fg(Color::Blue), 11 | Cell::new("Day").fg(Color::Blue), 12 | Cell::new("Holiday").fg(Color::Blue), 13 | ]) 14 | .load_preset(comfy_table::presets::UTF8_FULL) 15 | .apply_modifier(comfy_table::modifiers::UTF8_ROUND_CORNERS) 16 | .set_content_arrangement(ContentArrangement::Dynamic) 17 | .set_width(100); 18 | 19 | for holiday in holidays.iter().filter(|h| h.date.year() == year) { 20 | table.add_row(vec![ 21 | Cell::new(holiday.date.format("%d-%m-%Y").to_string()).fg(Color::Cyan), 22 | Cell::new(weekday_to_string(holiday.date.weekday())).fg(Color::Cyan), 23 | Cell::new(&holiday.name).fg(Color::Green), 24 | ]); 25 | } 26 | 27 | println!( 28 | "\n{}", 29 | format!("📅 Holidays for {} in {}", country, year) 30 | .bold() 31 | .yellow() 32 | ); 33 | println!("{table}"); 34 | println!( 35 | "\n{}", 36 | format!("Total holidays: {}", holidays.len()).bold().blue() 37 | ); 38 | } 39 | 40 | fn weekday_to_string(weekday: chrono::Weekday) -> String { 41 | match weekday { 42 | chrono::Weekday::Mon => "Monday", 43 | chrono::Weekday::Tue => "Tuesday", 44 | chrono::Weekday::Wed => "Wednesday", 45 | chrono::Weekday::Thu => "Thursday", 46 | chrono::Weekday::Fri => "Friday", 47 | chrono::Weekday::Sat => "Saturday", 48 | chrono::Weekday::Sun => "Sunday", 49 | } 50 | .to_string() 51 | } 52 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "conze" 3 | version = "0.1.3" 4 | edition = "2021" 5 | authors = ["Jain Ramchurn"] 6 | description = "Explore holidays" 7 | license = "MIT" 8 | repository = "https://github.com/k3ii/conze" 9 | homepage = "https://github.com/k3ii/conze" 10 | readme = "README.md" 11 | keywords = ["cli"] 12 | categories = ["command-line-utilities"] 13 | rust-version = "1.74.1" 14 | 15 | [dependencies] 16 | anyhow = "1.0.89" 17 | chrono = { version = "0.4.38", features = ["serde"] } 18 | clap = { version = "4.5.18", features = ["derive"] } 19 | colored = "2.1.0" 20 | comfy-table = "7.1.1" 21 | crossterm = "0.28.1" 22 | directories = "5.0.1" 23 | num-traits = "0.2.19" 24 | openssl = { version = "0.10.68", features = ["vendored"] } 25 | prettytable = "0.10.0" 26 | rand = "0.8.5" 27 | regex = "1.11.0" 28 | reqwest = { version = "0.12.7", features = ["json"] } 29 | serde = { version = "1.0.210", features = ["derive"] } 30 | serde_json = "1.0.128" 31 | tokio = { version = "1.40.0", features = ["full"] } 32 | toml = "0.8.19" 33 | 34 | # The profile that 'cargo dist' will build with 35 | [profile.dist] 36 | inherits = "release" 37 | lto = "thin" 38 | 39 | # Config for 'cargo dist' 40 | [workspace.metadata.dist] 41 | # The preferred cargo-dist version to use in CI (Cargo.toml SemVer syntax) 42 | cargo-dist-version = "0.21.1" 43 | # CI backends to support 44 | ci = "github" 45 | # The installers to generate for each app 46 | installers = ["shell", "powershell", "homebrew"] 47 | # Target platforms to build apps for (Rust target-triple syntax) 48 | targets = [ 49 | "aarch64-apple-darwin", 50 | "x86_64-apple-darwin", 51 | "x86_64-unknown-linux-gnu", 52 | "x86_64-pc-windows-msvc", 53 | ] 54 | # Path that installers should place binaries in 55 | install-path = "CARGO_HOME" 56 | # Whether to install an updater program 57 | install-updater = true 58 | # A GitHub repo to push Homebrew formulas to 59 | tap = "k3ii/homebrew-tap" 60 | # Publish jobs to run in CI 61 | publish-jobs = ["homebrew"] 62 | -------------------------------------------------------------------------------- /src/cli.rs: -------------------------------------------------------------------------------- 1 | use clap::{Arg, Command}; 2 | 3 | pub fn cli() -> Command { 4 | Command::new("conze") 5 | .version("0.1.2") 6 | .author("Jain Ramchurn") 7 | .subcommand( 8 | Command::new("bridge") 9 | .aliases(["pond", "pont", "pon", "puente"]) 10 | .arg(Arg::new("month").short('m').long("month").aliases(["mois"])) 11 | .arg(Arg::new("year").short('y').long("year").aliases(["lanner"])) 12 | .arg( 13 | Arg::new("country") 14 | .long("country") 15 | .short('c') 16 | .help("Specify country (e.g., MU for Mauritius, ZA for South Africa)"), 17 | ), 18 | ) 19 | .subcommand( 20 | Command::new("calendar") 21 | .aliases(["cal"]) 22 | .arg(Arg::new("month").short('m').long("month").aliases(["mois"])) 23 | .arg(Arg::new("year").short('y').long("year").aliases(["lanner"])) 24 | .arg( 25 | Arg::new("compare") 26 | .long("compare") 27 | .short('c') 28 | .aliases(["cmp", "cpm"]) 29 | .help("Compare holidays with another country (e.g., ZA for South Africa)"), 30 | ), 31 | ) 32 | .subcommand( 33 | Command::new("config") 34 | .arg( 35 | Arg::new("default-country") 36 | .long("default-country") 37 | .value_name("COUNTRY_CODE") 38 | .ignore_case(true) 39 | .help("Sets the default country. \nAvailable countries:\n - France (FR)\n - Mauritius (MU)\n - Turkey (TR)\n - Singapore (SG)\n - South Africa (ZA)"), 40 | ) 41 | .subcommand(Command::new("show").about("Displays the current configuration")), 42 | ) 43 | .subcommand( 44 | Command::new("list") 45 | .about("List holidays for a specific country and year") 46 | .arg( 47 | Arg::new("country") 48 | .long("country") 49 | .short('c') 50 | .help("Specify country (e.g., MU for Mauritius, ZA for South Africa)"), 51 | ) 52 | .arg( 53 | Arg::new("year") 54 | .short('y') 55 | .long("year") 56 | .help("Specify the year"), 57 | ), 58 | ) 59 | } 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Conze 2 | 3 | **Conze** is a command-line tool that allows you to view holidays and long weekends, and compare holiday schedules between countries from your terminal. 4 | ![demo](./assets/conze.gif) 5 | ## Features 6 | 7 | - **List holidays** for any supported country and year. 8 | - **Compare holidays** between different countries. 9 | - Explore holidays using subcommands like `bridge` for long weekends and `calendar` for holiday comparisons. 10 | - Configure a **default country** for convenience. 11 | 12 | ## Installation 13 | You can install `conze` using one of the following methods: 14 | 15 | ### Using Cargo 16 | 17 | If you have Rust's package manager, Cargo, installed, you can install `conze` with: 18 | 19 | ```bash 20 | cargo install conze 21 | ``` 22 | 23 | ### Using Homebrew 24 | 25 | For macOS users, you can install `conze` using Homebrew: 26 | 27 | ```bash 28 | brew install k3ii/tap/conze 29 | 30 | ``` 31 | 32 | Check the [release page](https://github.com/k3ii/conze/releases) to install the pre-built binaries. 33 | 34 | ## Getting starrted 35 | 36 | ### Configure Default Country 37 | 38 | To begin, set the default country using the following command: 39 | 40 | ```bash 41 | 42 | conze config --default-country MU 43 | ``` 44 | 45 | Currently, only the following countries are supported: 46 | * France (FR) 47 | * Mauritius (MU) 48 | * Turkey (TR) 49 | * South Africa (ZA) 50 | * Singapore (SG) 51 | 52 | This project has been possible thanks to the [dataset](https://github.com/nicolasstrands/data-konzer) by [Nicolas Strands](https://github.com/nicolasstrands). If you'd like support for another country, feel free to contribute to the dataset. 53 | 54 | You can check the current default country by running: 55 | ```bash 56 | conze config show 57 | ``` 58 | 59 | 60 | ## Examples of Commands 61 | 62 | ### List Holidays 63 | 64 | To list holidays for the current month and the default country: 65 | ```bash 66 | conze 67 | ``` 68 | ![conze](./assets/conze.png) 69 | 70 | You can also list holidays for a specific country and year: 71 | 72 | ```bash 73 | conze list --country ZA --year 2025 74 | ``` 75 | ![list](./assets/list.png) 76 | 77 | ### Compare Holidays Between Countries 78 | 79 | Compare holidays between countries (e.g., Mauritius and South Africa) for a specific month: 80 | ```bash 81 | conze calendar --compare ZA --month 12 82 | ``` 83 | ![compare](./assets/cal-cmp.png) 84 | ### View possible long weekends 85 | 86 | View long weekend for the current year and default country. 87 | 88 | ```bash 89 | conze bridge 90 | ``` 91 | ![bridge](./assets/bridge.png) 92 | 93 | To view long weekends for a different year and country: 94 | ```bash 95 | conze bridge --country ZA --year 2025 96 | ``` 97 | 98 | To view long weekends for a specific month and year in a different country: 99 | ```bash 100 | conze bridge --country FR --month jan --year 2026 101 | ``` 102 | 103 | 104 | ## Available Subcommands 105 | 106 | * `list`: Lists holidays for a specific country and year. 107 | * `calendar`: View and compare holidays between countries. 108 | * `bridge`: View possible long weekends (bridge holidays). 109 | * `config`: Configure the default country setting. 110 | * `help`: Show help information for all commands. 111 | 112 | ## Contributing 113 | 114 | Contributions are welcome! To get involved: 115 | 116 | * Fork the repository. 117 | * Create a new branch for your feature or bug fix. 118 | * Make your changes. 119 | * Submit a pull request. 120 | 121 | 122 | ## License 123 | 124 | This project is licensed under the MIT License. 125 | -------------------------------------------------------------------------------- /cliff.toml: -------------------------------------------------------------------------------- 1 | [changelog] 2 | # changelog header 3 | header = """ 4 | # Changelog\n 5 | All notable changes to this project will be documented in this file.\n 6 | """ 7 | # template for the changelog body 8 | # https://keats.github.io/tera/docs/#introduction 9 | body = """ 10 | {% if version %}\ 11 | {% if previous.version %}\ 12 | ## [{{ version | trim_start_matches(pat="v") }}](/compare/{{ previous.version }}..{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }} 13 | {% else %}\ 14 | ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} 15 | {% endif %}\ 16 | {% else %}\ 17 | ## [unreleased] 18 | {% endif %}\ 19 | 20 | {% macro commit(commit) -%} 21 | - {% if commit.scope %}*({{ commit.scope }})* {% endif %}{% if commit.breaking %}[**breaking**] {% endif %}\ 22 | {{ commit.message | upper_first }} - ([{{ commit.id | truncate(length=7, end="") }}](/commit/{{ commit.id }}))\ 23 | {% endmacro -%} 24 | 25 | {% for group, commits in commits | group_by(attribute="group") %} 26 | ### {{ group | striptags | trim | upper_first }} 27 | {% for commit in commits 28 | | filter(attribute="scope") 29 | | sort(attribute="scope") %} 30 | {{ self::commit(commit=commit) }} 31 | {%- endfor -%} 32 | {% raw %}\n{% endraw %}\ 33 | {%- for commit in commits %} 34 | {%- if not commit.scope -%} 35 | {{ self::commit(commit=commit) }} 36 | {% endif -%} 37 | {% endfor -%} 38 | {% endfor %}\n 39 | """ 40 | # remove the leading and trailing whitespace from the template 41 | trim = true 42 | # postprocessors 43 | postprocessors = [ 44 | { pattern = '', replace = "https://github.com/k3ii/revq" }, # replace repository URL 45 | ] 46 | 47 | [git] 48 | # parse the commits based on https://www.conventionalcommits.org 49 | conventional_commits = true 50 | # filter out the commits that are not conventional 51 | filter_unconventional = true 52 | # process each line of a commit as an individual commit 53 | split_commits = false 54 | # regex for preprocessing the commit messages 55 | commit_preprocessors = [ 56 | { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](/issues/${2}))" }, 57 | ] 58 | # regex for parsing and grouping commits 59 | commit_parsers = [ 60 | { message = "^feat", group = "📇 Features" }, 61 | { message = "^fix", group = "🐛 Bug Fixes" }, 62 | { message = "^doc", group = "📚 Documentation" }, 63 | { message = "^perf", group = "⚡ Performance" }, 64 | { message = "^refactor", group = "🚜 Refactor" }, 65 | { message = "^style", group = "🎨 Styling" }, 66 | { message = "^test", group = "🧪 Testing" }, 67 | { message = "^chore: release", skip = true }, 68 | { message = "^chore\\(deps\\)", skip = true }, 69 | { message = "^chore\\(pr\\)", skip = true }, 70 | { message = "^chore\\(pull\\)", skip = true }, 71 | { message = "^chore|ci", group = "⚙️ Miscellaneous Tasks" }, 72 | { body = ".*security", group = "🛡️ Security" }, 73 | { message = "^revert", group = "◀️ Revert" }, 74 | ] 75 | # protect breaking changes from being skipped due to matching a skipping commit_parser 76 | protect_breaking_commits = false 77 | # filter out the commits that are not matched by commit parsers 78 | filter_commits = true 79 | # glob pattern for matching git tags 80 | tag_pattern = "v[0-9]*" 81 | # regex for skipping tags 82 | skip_tags = "beta|alpha" 83 | # regex for ignoring tags 84 | ignore_tags = "rc|lib" 85 | # sort the tags topologically 86 | topo_order = false 87 | # sort the commits inside sections by oldest/newest order 88 | sort_commits = "newest" 89 | -------------------------------------------------------------------------------- /src/cal.rs: -------------------------------------------------------------------------------- 1 | use crate::CountryHolidays; 2 | use chrono::{Datelike, Month, NaiveDate}; 3 | use colored::{Color, ColoredString, Colorize}; 4 | use num_traits::FromPrimitive; 5 | use prettytable::{row, Table}; 6 | use std::collections::HashMap; 7 | 8 | pub fn print_calendar_comparison(month: u32, year: i32, country_holidays: &[CountryHolidays]) { 9 | let first_day = NaiveDate::from_ymd_opt(year, month, 1).unwrap(); 10 | let num_days_in_month = days_in_month(year, month); 11 | let start_day_of_week = first_day.weekday().num_days_from_sunday(); 12 | 13 | println!( 14 | "{} {}\nSu Mo Tu We Th Fr Sa", 15 | Month::from_u32(month).unwrap().name(), 16 | year 17 | ); 18 | 19 | // Assign a color for each country dynamically 20 | let colors = assign_colors(country_holidays); 21 | 22 | // Create a HashMap to store holidays for quick lookup 23 | let mut holiday_map: HashMap> = HashMap::new(); 24 | for country in country_holidays { 25 | for holiday in &country.holidays { 26 | if holiday.date.month() == month && holiday.date.year() == year { 27 | holiday_map 28 | .entry(holiday.date.day()) 29 | .or_insert_with(Vec::new) 30 | .push((&country.country, &holiday.name)); 31 | } 32 | } 33 | } 34 | 35 | // Calendar view 36 | for _ in 0..start_day_of_week { 37 | print!(" "); 38 | } 39 | 40 | for day in 1..=num_days_in_month { 41 | if (day + start_day_of_week - 1) % 7 == 0 { 42 | print!("\n"); 43 | } 44 | 45 | if let Some(holidays) = holiday_map.get(&day) { 46 | let colored_day = match holidays.len() { 47 | 1 => colorize_day(day, holidays[0].0, &colors), 48 | _ => day.to_string().magenta(), // Multiple holidays on the same day 49 | }; 50 | print!("{:2} ", colored_day); 51 | } else { 52 | print!("{:2} ", day); 53 | } 54 | } 55 | println!("\n"); 56 | 57 | // Print holidays for each country in a table format 58 | let mut table = Table::new(); 59 | table.add_row(row!["Country", "Date", "Holiday"]); 60 | 61 | for country in country_holidays { 62 | let holidays_this_month: Vec<_> = country 63 | .holidays 64 | .iter() 65 | .filter(|holiday| holiday.date.month() == month && holiday.date.year() == year) 66 | .collect(); 67 | 68 | for holiday in holidays_this_month { 69 | let colored_text = colorize_holiday(&holiday.name, &country.country, &colors); 70 | 71 | table.add_row(row![ 72 | &country.country, 73 | holiday.date.day().to_string(), 74 | colored_text 75 | ]); 76 | } 77 | } 78 | 79 | table.printstd(); // Print the table to standard output 80 | } 81 | 82 | fn assign_colors(country_holidays: &[CountryHolidays]) -> HashMap { 83 | let color_choices = vec![ 84 | Color::Green, 85 | Color::Blue, 86 | Color::Yellow, 87 | Color::Red, 88 | Color::Cyan, 89 | ]; 90 | 91 | let mut color_map = HashMap::new(); 92 | for (i, country) in country_holidays.iter().enumerate() { 93 | let color = color_choices 94 | .get(i % color_choices.len()) 95 | .unwrap_or(&Color::White); 96 | color_map.insert(country.country.clone(), *color); 97 | } 98 | 99 | color_map 100 | } 101 | 102 | fn colorize_day(day: u32, country: &str, colors: &HashMap) -> ColoredString { 103 | colors 104 | .get(country) 105 | .map(|&color| day.to_string().color(color)) 106 | .unwrap_or_else(|| day.to_string().normal()) 107 | } 108 | 109 | fn colorize_holiday( 110 | holiday_name: &str, 111 | country: &str, 112 | colors: &HashMap, 113 | ) -> ColoredString { 114 | colors 115 | .get(country) 116 | .map(|&color| holiday_name.color(color)) 117 | .unwrap_or_else(|| holiday_name.normal()) 118 | } 119 | 120 | fn days_in_month(year: i32, month: u32) -> u32 { 121 | NaiveDate::from_ymd_opt( 122 | match month { 123 | 12 => year + 1, 124 | _ => year, 125 | }, 126 | match month { 127 | 12 => 1, 128 | _ => month + 1, 129 | }, 130 | 1, 131 | ) 132 | .unwrap() 133 | .pred_opt() 134 | .unwrap() 135 | .day() 136 | } 137 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [0.1.2](https://github.com/k3ii/revq/compare/0.1.1..0.1.2) - 2025-01-22 6 | 7 | ### 📇 Features 8 | 9 | - Add dataset ref for Turkey and Singapore - ([9f66161](https://github.com/k3ii/revq/commit/9f66161090f25d94d1f8f45b9b710c0cff213fba)) 10 | 11 | ## [0.1.0] - 2024-10-21 12 | 13 | ### 📇 Features 14 | 15 | - *(bridge)* Enhance puente days display with past/future color distinction - ([8783309](https://github.com/k3ii/revq/commit/8783309b0b84a6417275f4feba95065c7f9c6c54)) 16 | - *(bridge)* Correct logic to filter out bridge days - ([11b9c0f](https://github.com/k3ii/revq/commit/11b9c0f5f38e2c8699f0f1de57c0bec29c891c91)) 17 | - *(bridge)* Order holiday chronologically - ([6608fd3](https://github.com/k3ii/revq/commit/6608fd38c7690446837513d5dad9c462e82c4a7f)) 18 | - *(bridge)* Remove deduplicate holidays - ([c5ab479](https://github.com/k3ii/revq/commit/c5ab479572c4ef17ce70f06d6a991815bf51e12b)) 19 | - *(bridge)* Extend puente logic to cover additional bridge days - ([57993d2](https://github.com/k3ii/revq/commit/57993d2aeab52f09229d2b01ead512b9d60f24f9)) 20 | - *(bridge)* Add subcommand aliases - ([4500269](https://github.com/k3ii/revq/commit/4500269d6a8de0a8c89c746e5d6182e5f6f078eb)) 21 | - *(cal)* Add other countries dataset - ([dc785e4](https://github.com/k3ii/revq/commit/dc785e450d5d902b035c16c7c535f7a2b25a1c61)) 22 | - *(cal)* Print table of holidays - ([3231e1f](https://github.com/k3ii/revq/commit/3231e1fa4ce377c0d41e134a71808d30757a971b)) 23 | - *(cli)* Add version - ([aa4bd75](https://github.com/k3ii/revq/commit/aa4bd75f2bbe078aa255e3a51746cad3a45b77df)) 24 | - *(cli)* Add arguments to subcommand calendar - ([0ce4edf](https://github.com/k3ii/revq/commit/0ce4edf7dd2184d022da0306cca3c97682f2eee6)) 25 | - *(cli)* Add arguments to subcommand bridge - ([07b6898](https://github.com/k3ii/revq/commit/07b689853aee6e9f5b39505c4bfdc4fdea15c240)) 26 | - Add calendar - ([cd4dc5d](https://github.com/k3ii/revq/commit/cd4dc5d5f7d5de1301747a703ff214760c594af0)) 27 | - Add cli - ([30ea1f8](https://github.com/k3ii/revq/commit/30ea1f85cc532d375519b176d807df2a4d4e285a)) 28 | - Add parser - ([4e57cdb](https://github.com/k3ii/revq/commit/4e57cdb88ba443fe486ded9f4b7b0875ce2d436a)) 29 | - Add main.rs - ([9084fcd](https://github.com/k3ii/revq/commit/9084fcd21731870e9a8a9c1a0f569b8fa82870dd)) 30 | 31 | ### 🐛 Bug Fixes 32 | 33 | - *(bridge)* Format output total holidays for month and year - ([5769da3](https://github.com/k3ii/revq/commit/5769da3525c3a6d68f7596e854f1cc9bb5b23e57)) 34 | - *(cli)* Add country code list to help of config --default-country - ([7f022f2](https://github.com/k3ii/revq/commit/7f022f24780df5823f1857dd182b2c34f23f6fc1)) 35 | - Return error when month is incorrectly input - ([9d6e9f8](https://github.com/k3ii/revq/commit/9d6e9f8d7de16df7e2d380be1f0cadcf9cb4ed88)) 36 | 37 | ### ⚙️ Miscellaneous Tasks 38 | 39 | - *(cargo)* Add openssl featured vendored - ([62d3f34](https://github.com/k3ii/revq/commit/62d3f34e94e660702abaeeb418f4d8757bacd9e2)) 40 | - *(cargo)* Add prettytable - ([3d375c8](https://github.com/k3ii/revq/commit/3d375c8038edfbfaac19c5b79dd015d0b0a173d7)) 41 | - *(cargo)* Add Dependencies - ([97e9f7d](https://github.com/k3ii/revq/commit/97e9f7de8a6f62252607dd305ec955f43902e8f7)) 42 | - *(gh)* Add fundings.yml - ([a03773b](https://github.com/k3ii/revq/commit/a03773b44f845a073717101a18cfd8ccfdaa4c68)) 43 | - Add release-plz - ([22b6fb5](https://github.com/k3ii/revq/commit/22b6fb571fef090cdd8c12ea20323eb7c0094bad)) 44 | - Add cliff.toml - ([fdc6a7f](https://github.com/k3ii/revq/commit/fdc6a7f9ae5e0d38edb5f36a1a60ab5b5e6f6a14)) 45 | - Add License - ([ce38fb5](https://github.com/k3ii/revq/commit/ce38fb5851197b03a2157367ae3130c29d368688)) 46 | - Add cargo metadata - ([35eec3a](https://github.com/k3ii/revq/commit/35eec3a3ba2b2fee96d66c1ddb6a80df5e48c0d7)) 47 | - Add GH workflows - ([cada1f4](https://github.com/k3ii/revq/commit/cada1f4e0d5b5406c52cd2d9904ad1f2e6725d8c)) 48 | - Update README - ([175d205](https://github.com/k3ii/revq/commit/175d2053a2b81a00f30a6d6b2f87ac20f35d11db)) 49 | - Add assets - ([ec5c2b6](https://github.com/k3ii/revq/commit/ec5c2b64320a87a49cb950ad5417f065b298de3f)) 50 | - Add .gitignore - ([8091f3a](https://github.com/k3ii/revq/commit/8091f3ad67925fd42f7a195053500151776a6f16)) 51 | 52 | ## [0.1.0] - 2024-10-21 53 | 54 | ### 📇 Features 55 | 56 | - *(bridge)* Enhance puente days display with past/future color distinction - ([8783309](https://github.com/k3ii/revq/commit/8783309b0b84a6417275f4feba95065c7f9c6c54)) 57 | - *(bridge)* Correct logic to filter out bridge days - ([11b9c0f](https://github.com/k3ii/revq/commit/11b9c0f5f38e2c8699f0f1de57c0bec29c891c91)) 58 | - *(bridge)* Order holiday chronologically - ([6608fd3](https://github.com/k3ii/revq/commit/6608fd38c7690446837513d5dad9c462e82c4a7f)) 59 | - *(bridge)* Remove deduplicate holidays - ([c5ab479](https://github.com/k3ii/revq/commit/c5ab479572c4ef17ce70f06d6a991815bf51e12b)) 60 | - *(bridge)* Extend puente logic to cover additional bridge days - ([57993d2](https://github.com/k3ii/revq/commit/57993d2aeab52f09229d2b01ead512b9d60f24f9)) 61 | - *(bridge)* Add subcommand aliases - ([4500269](https://github.com/k3ii/revq/commit/4500269d6a8de0a8c89c746e5d6182e5f6f078eb)) 62 | - *(cal)* Add other countries dataset - ([dc785e4](https://github.com/k3ii/revq/commit/dc785e450d5d902b035c16c7c535f7a2b25a1c61)) 63 | - *(cal)* Print table of holidays - ([3231e1f](https://github.com/k3ii/revq/commit/3231e1fa4ce377c0d41e134a71808d30757a971b)) 64 | - *(cli)* Add version - ([aa4bd75](https://github.com/k3ii/revq/commit/aa4bd75f2bbe078aa255e3a51746cad3a45b77df)) 65 | - *(cli)* Add arguments to subcommand calendar - ([0ce4edf](https://github.com/k3ii/revq/commit/0ce4edf7dd2184d022da0306cca3c97682f2eee6)) 66 | - *(cli)* Add arguments to subcommand bridge - ([07b6898](https://github.com/k3ii/revq/commit/07b689853aee6e9f5b39505c4bfdc4fdea15c240)) 67 | - Add calendar - ([cd4dc5d](https://github.com/k3ii/revq/commit/cd4dc5d5f7d5de1301747a703ff214760c594af0)) 68 | - Add cli - ([30ea1f8](https://github.com/k3ii/revq/commit/30ea1f85cc532d375519b176d807df2a4d4e285a)) 69 | - Add parser - ([4e57cdb](https://github.com/k3ii/revq/commit/4e57cdb88ba443fe486ded9f4b7b0875ce2d436a)) 70 | - Add main.rs - ([9084fcd](https://github.com/k3ii/revq/commit/9084fcd21731870e9a8a9c1a0f569b8fa82870dd)) 71 | 72 | ### 🐛 Bug Fixes 73 | 74 | - *(bridge)* Format output total holidays for month and year - ([5769da3](https://github.com/k3ii/revq/commit/5769da3525c3a6d68f7596e854f1cc9bb5b23e57)) 75 | - *(cli)* Add country code list to help of config --default-country - ([7f022f2](https://github.com/k3ii/revq/commit/7f022f24780df5823f1857dd182b2c34f23f6fc1)) 76 | - Return error when month is incorrectly input - ([9d6e9f8](https://github.com/k3ii/revq/commit/9d6e9f8d7de16df7e2d380be1f0cadcf9cb4ed88)) 77 | 78 | ### ⚙️ Miscellaneous Tasks 79 | 80 | - *(cargo)* Add openssl featured vendored - ([62d3f34](https://github.com/k3ii/revq/commit/62d3f34e94e660702abaeeb418f4d8757bacd9e2)) 81 | - *(cargo)* Add prettytable - ([3d375c8](https://github.com/k3ii/revq/commit/3d375c8038edfbfaac19c5b79dd015d0b0a173d7)) 82 | - *(cargo)* Add Dependencies - ([97e9f7d](https://github.com/k3ii/revq/commit/97e9f7de8a6f62252607dd305ec955f43902e8f7)) 83 | - *(gh)* Add fundings.yml - ([a03773b](https://github.com/k3ii/revq/commit/a03773b44f845a073717101a18cfd8ccfdaa4c68)) 84 | - Add release-plz - ([22b6fb5](https://github.com/k3ii/revq/commit/22b6fb571fef090cdd8c12ea20323eb7c0094bad)) 85 | - Add cliff.toml - ([fdc6a7f](https://github.com/k3ii/revq/commit/fdc6a7f9ae5e0d38edb5f36a1a60ab5b5e6f6a14)) 86 | - Add License - ([ce38fb5](https://github.com/k3ii/revq/commit/ce38fb5851197b03a2157367ae3130c29d368688)) 87 | - Add cargo metadata - ([35eec3a](https://github.com/k3ii/revq/commit/35eec3a3ba2b2fee96d66c1ddb6a80df5e48c0d7)) 88 | - Add GH workflows - ([cada1f4](https://github.com/k3ii/revq/commit/cada1f4e0d5b5406c52cd2d9904ad1f2e6725d8c)) 89 | - Update README - ([175d205](https://github.com/k3ii/revq/commit/175d2053a2b81a00f30a6d6b2f87ac20f35d11db)) 90 | - Add assets - ([ec5c2b6](https://github.com/k3ii/revq/commit/ec5c2b64320a87a49cb950ad5417f065b298de3f)) 91 | - Add .gitignore - ([8091f3a](https://github.com/k3ii/revq/commit/8091f3ad67925fd42f7a195053500151776a6f16)) 92 | 93 | -------------------------------------------------------------------------------- /src/puente.rs: -------------------------------------------------------------------------------- 1 | use crate::Holiday; 2 | use chrono::{Datelike, Local, Month, NaiveDate, Weekday}; 3 | use colored::Colorize; 4 | use comfy_table::{modifiers::UTF8_ROUND_CORNERS, presets, Cell, Color, ContentArrangement, Table}; 5 | use num_traits::FromPrimitive; 6 | use std::collections::{HashMap, HashSet}; 7 | 8 | #[derive(Debug, Hash, Eq, PartialEq)] 9 | struct PuenteDay { 10 | date: NaiveDate, 11 | related_holidays: Vec, 12 | } 13 | 14 | fn is_weekday(date: NaiveDate) -> bool { 15 | let weekday = date.weekday(); 16 | weekday != Weekday::Sat && weekday != Weekday::Sun 17 | } 18 | 19 | pub fn print_puente_days(month: Option, year: i32, holidays: &[&Holiday], country_code: &str) { 20 | let current_date = Local::now().date_naive(); 21 | let mut table = Table::new(); 22 | table 23 | .set_header(vec![ 24 | Cell::new("Holiday\nDates").fg(Color::Cyan), 25 | Cell::new("Holiday\nDays").fg(Color::Cyan), 26 | Cell::new("Holiday\nNames").fg(Color::Cyan), 27 | Cell::new("Bridge\nDates").fg(Color::Green), 28 | Cell::new("Bridge\nDays").fg(Color::Green), 29 | ]) 30 | .load_preset(presets::UTF8_FULL) 31 | .apply_modifier(UTF8_ROUND_CORNERS) 32 | .set_content_arrangement(ContentArrangement::Dynamic) 33 | .set_width(140); 34 | 35 | match month { 36 | Some(m) => println!( 37 | "\n{}", 38 | format!( 39 | "🌉 Bridge days for {} {} ({}):", 40 | Month::from_u32(m).unwrap().name(), 41 | year, 42 | country_code 43 | ) 44 | .bold() 45 | .yellow() 46 | ), 47 | None => println!( 48 | "\n{}", 49 | format!("🌉 Bridge days for the year {} ({}):", year, country_code) 50 | .bold() 51 | .yellow() 52 | ), 53 | } 54 | 55 | let mut unique_puentes = HashSet::new(); 56 | let mut puente_days = Vec::new(); 57 | 58 | // Collect all holiday dates for easier comparison 59 | let holiday_dates: HashSet = holidays.iter().map(|h| h.date).collect(); 60 | 61 | // Create a map of consecutive holidays (only weekdays) 62 | let mut consecutive_holidays: HashMap> = HashMap::new(); 63 | let mut sorted_holidays: Vec = holiday_dates 64 | .iter() 65 | .copied() 66 | .filter(|&date| is_weekday(date)) 67 | .collect(); 68 | sorted_holidays.sort(); 69 | 70 | // Find consecutive holidays (only considering weekdays) 71 | for window in sorted_holidays.windows(2) { 72 | if let [date1, date2] = window { 73 | if date2.signed_duration_since(*date1).num_days() == 1 { 74 | consecutive_holidays 75 | .entry(*date1) 76 | .or_insert_with(Vec::new) 77 | .push(*date2); 78 | } 79 | } 80 | } 81 | 82 | // Process regular puente scenarios 83 | for holiday in holidays { 84 | let holiday_date = holiday.date; 85 | if !is_weekday(holiday_date) { 86 | continue; // Skip weekend holidays for regular puente scenarios 87 | } 88 | 89 | let weekday = holiday_date.weekday(); 90 | 91 | // Case 1: Tuesday puente (Monday becomes puente) 92 | if weekday == Weekday::Tue { 93 | if let Some(puente_date) = holiday_date.pred_opt() { 94 | if !holiday_dates.contains(&puente_date) { 95 | add_puente( 96 | &mut unique_puentes, 97 | &mut puente_days, 98 | puente_date, 99 | vec![holiday_date], 100 | ); 101 | } 102 | } 103 | } 104 | 105 | // Case 2: Thursday puente (Friday becomes puente) 106 | if weekday == Weekday::Thu { 107 | if let Some(puente_date) = holiday_date.succ_opt() { 108 | if !holiday_dates.contains(&puente_date) { 109 | add_puente( 110 | &mut unique_puentes, 111 | &mut puente_days, 112 | puente_date, 113 | vec![holiday_date], 114 | ); 115 | } 116 | } 117 | } 118 | 119 | // Case 3: Monday holiday (previous Friday becomes puente) 120 | if weekday == Weekday::Mon { 121 | if let Some(puente_date) = holiday_date 122 | .pred_opt() 123 | .and_then(|d| d.pred_opt().and_then(|d| d.pred_opt())) 124 | { 125 | if !holiday_dates.contains(&puente_date) { 126 | add_puente( 127 | &mut unique_puentes, 128 | &mut puente_days, 129 | puente_date, 130 | vec![holiday_date], 131 | ); 132 | } 133 | } 134 | } 135 | 136 | // Case 4: Friday holiday (next Monday becomes puente) 137 | if weekday == Weekday::Fri { 138 | if let Some(puente_date) = holiday_date 139 | .succ_opt() 140 | .and_then(|d| d.succ_opt().and_then(|d| d.succ_opt())) 141 | { 142 | if !holiday_dates.contains(&puente_date) { 143 | add_puente( 144 | &mut unique_puentes, 145 | &mut puente_days, 146 | puente_date, 147 | vec![holiday_date], 148 | ); 149 | } 150 | } 151 | } 152 | } 153 | 154 | // Case 5: Sandwich days between holidays (only considering weekdays) 155 | for holiday1 in holidays { 156 | if !is_weekday(holiday1.date) { 157 | continue; 158 | } 159 | for holiday2 in holidays { 160 | if !is_weekday(holiday2.date) { 161 | continue; 162 | } 163 | if holiday1.date < holiday2.date { 164 | if let Some(middle_date) = holiday1.date.succ_opt() { 165 | if middle_date < holiday2.date 166 | && (holiday2 167 | .date 168 | .signed_duration_since(holiday1.date) 169 | .num_days() 170 | == 2) 171 | && !holiday_dates.contains(&middle_date) 172 | && is_weekday(middle_date) 173 | { 174 | add_puente( 175 | &mut unique_puentes, 176 | &mut puente_days, 177 | middle_date, 178 | vec![holiday1.date, holiday2.date], 179 | ); 180 | } 181 | } 182 | } 183 | } 184 | } 185 | 186 | // Case 6: Consecutive holidays (already filtered for weekdays only) 187 | for (first_holiday, consecutive) in consecutive_holidays { 188 | let related_holidays = std::iter::once(first_holiday) 189 | .chain(consecutive.iter().copied()) 190 | .collect::>(); 191 | 192 | // Check day before consecutive holidays 193 | if let Some(before_date) = first_holiday.pred_opt() { 194 | if !holiday_dates.contains(&before_date) && is_weekday(before_date) { 195 | add_puente( 196 | &mut unique_puentes, 197 | &mut puente_days, 198 | before_date, 199 | related_holidays.clone(), 200 | ); 201 | } 202 | } 203 | 204 | // Check day after consecutive holidays 205 | if let Some(last_holiday) = consecutive.last() { 206 | if let Some(after_date) = last_holiday.succ_opt() { 207 | if !holiday_dates.contains(&after_date) && is_weekday(after_date) { 208 | add_puente( 209 | &mut unique_puentes, 210 | &mut puente_days, 211 | after_date, 212 | related_holidays.clone(), 213 | ); 214 | } 215 | } 216 | } 217 | } 218 | 219 | // Sort puente_days by complete date 220 | puente_days.sort_by(|a, b| b.date.cmp(&a.date)); 221 | 222 | // Filter by month if specified 223 | let filtered_puente_days: Vec<&PuenteDay> = if let Some(m) = month { 224 | puente_days.iter().filter(|p| p.date.month() == m).collect() 225 | } else { 226 | puente_days.iter().collect() 227 | }; 228 | 229 | // Reverse the filtered days to show them in chronological order 230 | let filtered_puente_days: Vec<_> = filtered_puente_days.into_iter().rev().collect(); 231 | 232 | // Add rows to table 233 | for puente_day in &filtered_puente_days { 234 | let mut related_holidays = puente_day.related_holidays.clone(); 235 | related_holidays.sort(); // Sort related holidays by date 236 | add_row_to_table( 237 | &mut table, 238 | &related_holidays, 239 | holidays, 240 | puente_day.date, 241 | current_date, 242 | ); 243 | } 244 | 245 | if !filtered_puente_days.is_empty() { 246 | println!("{table}"); 247 | println!( 248 | "\n{}", 249 | format!( 250 | "🎯 Found {} bridge opportunities!", 251 | filtered_puente_days.len() 252 | ) 253 | .bold() 254 | .green() 255 | ); 256 | } else { 257 | println!("\n{}", "😢 No bridge days found.".bold().red()); 258 | } 259 | 260 | let total_holidays_message = match month { 261 | Some(m) => format!( 262 | "📅 Total holidays for this month: {}", 263 | holidays.iter().filter(|&h| h.date.month() == m).count() 264 | ), 265 | None => format!("📅 Total holidays for this year: {}", holidays.len()), 266 | }; 267 | 268 | println!("{}", total_holidays_message.bold().blue()); 269 | println!(); 270 | } 271 | 272 | fn add_puente( 273 | unique_puentes: &mut HashSet, 274 | puente_days: &mut Vec, 275 | puente_date: NaiveDate, 276 | related_holidays: Vec, 277 | ) { 278 | if unique_puentes.insert(puente_date) { 279 | puente_days.push(PuenteDay { 280 | date: puente_date, 281 | related_holidays, 282 | }); 283 | } 284 | } 285 | 286 | fn add_row_to_table( 287 | table: &mut Table, 288 | holiday_dates: &[NaiveDate], 289 | holidays: &[&Holiday], 290 | puente_date: NaiveDate, 291 | current_date: NaiveDate, 292 | ) { 293 | let is_past = puente_date < current_date; 294 | let color = if is_past { 295 | Color::DarkGrey 296 | } else { 297 | Color::Green 298 | }; 299 | 300 | let holiday_dates_str: String = holiday_dates 301 | .iter() 302 | .map(|d| d.format("%d-%m-%Y").to_string()) 303 | .collect::>() 304 | .join("\n"); 305 | 306 | let holiday_days_str: String = holiday_dates 307 | .iter() 308 | .map(|d| weekday_to_string(d.weekday())) 309 | .collect::>() 310 | .join("\n"); 311 | 312 | let holiday_names_str: String = holiday_dates 313 | .iter() 314 | .filter_map(|date| get_holiday_name(holidays, *date)) 315 | .collect::>() 316 | .join("\n"); 317 | 318 | let holiday_color = if is_past { 319 | Color::DarkGrey 320 | } else { 321 | Color::Cyan 322 | }; 323 | 324 | table.add_row(vec![ 325 | Cell::new(holiday_dates_str).fg(holiday_color), 326 | Cell::new(holiday_days_str).fg(holiday_color), 327 | Cell::new(holiday_names_str).fg(holiday_color), 328 | Cell::new(puente_date.format("%d-%m-%Y").to_string()).fg(color), 329 | Cell::new(weekday_to_string(puente_date.weekday())).fg(color), 330 | ]); 331 | } 332 | 333 | fn get_holiday_name(holidays: &[&Holiday], date: NaiveDate) -> Option { 334 | holidays 335 | .iter() 336 | .find(|h| h.date == date) 337 | .map(|h| h.name.clone()) 338 | } 339 | 340 | fn weekday_to_string(weekday: Weekday) -> String { 341 | match weekday { 342 | Weekday::Mon => "Monday", 343 | Weekday::Tue => "Tuesday", 344 | Weekday::Wed => "Wednesday", 345 | Weekday::Thu => "Thursday", 346 | Weekday::Fri => "Friday", 347 | Weekday::Sat => "Saturday", 348 | Weekday::Sun => "Sunday", 349 | } 350 | .to_string() 351 | } 352 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod cal; 2 | mod cli; 3 | mod config; 4 | mod list; 5 | mod parser; 6 | mod puente; 7 | 8 | use chrono::{Datelike, Local, NaiveDate}; 9 | use colored::Colorize; 10 | use directories::ProjectDirs; 11 | use rand::seq::SliceRandom; 12 | use serde::{Deserialize, Serialize}; 13 | use std::collections::HashMap; 14 | use std::path::PathBuf; 15 | 16 | use crate::cal::print_calendar_comparison; 17 | use crate::config::Config; 18 | use crate::parser::parse_month; 19 | use crate::puente::print_puente_days; 20 | 21 | #[derive(Debug, Serialize, Deserialize, Clone)] 22 | struct Holiday { 23 | name: String, 24 | date: NaiveDate, 25 | } 26 | 27 | #[derive(Debug, Serialize, Deserialize)] 28 | struct HolidaysByYear { 29 | #[serde(flatten)] 30 | years: HashMap>, 31 | } 32 | 33 | #[derive(Debug)] 34 | struct CountryHolidays { 35 | country: String, 36 | holidays: Vec, 37 | } 38 | 39 | fn get_config_path() -> Result> { 40 | let proj_dirs = 41 | ProjectDirs::from("", "", "conze").ok_or("Failed to get project directories")?; 42 | Ok(proj_dirs.config_dir().join("config.toml")) 43 | } 44 | 45 | async fn fetch_holidays(url: &str) -> Result { 46 | reqwest::Client::new().get(url).send().await?.json().await 47 | } 48 | 49 | #[tokio::main] 50 | async fn main() -> Result<(), Box> { 51 | let current_year = Local::now().year(); 52 | let current_month = Local::now().month(); 53 | let matches = cli::cli().get_matches(); 54 | 55 | let urls = HashMap::from([ 56 | ("MU", "https://raw.githubusercontent.com/k3ii/dataset-conze/refs/heads/main/data/public-holidays-mu.json"), 57 | ("ZA", "https://raw.githubusercontent.com/nicolasstrands/data-konzer/main/data/public-holidays-za.json"), 58 | ("FR", "https://raw.githubusercontent.com/nicolasstrands/data-konzer/main/data/public-holidays-fr.json"), 59 | ("TR", "https://raw.githubusercontent.com/nicolasstrands/data-konzer/main/data/public-holidays-tr.json"), 60 | ("SG", "https://raw.githubusercontent.com/nicolasstrands/data-konzer/main/data/public-holidays-sg.json"), 61 | ]); 62 | 63 | let config_path = get_config_path()?; 64 | let mut config = Config::load(&config_path).unwrap_or_else(|_| Config { 65 | default_country: "MU".to_string(), 66 | }); 67 | 68 | match matches.subcommand() { 69 | Some(("bridge", sub_matches)) => { 70 | let month = sub_matches.get_one::("month"); 71 | let year = sub_matches 72 | .get_one::("year") 73 | .and_then(|y| y.parse::().ok()) 74 | .unwrap_or(current_year); 75 | 76 | let country_code = sub_matches 77 | .get_one::("country") 78 | .map(|s| s.to_uppercase()) 79 | .unwrap_or_else(|| config.default_country.clone()); 80 | 81 | if let Some(url) = urls.get(country_code.as_str()) { 82 | if let Ok(holidays_data) = fetch_holidays(url).await { 83 | if let Some(holidays) = holidays_data.years.get(&year.to_string()) { 84 | match month.and_then(|m| parse_month(&m)) { 85 | Some(month) => { 86 | let holidays_for_month: Vec<&Holiday> = holidays 87 | .iter() 88 | .filter(|holiday| holiday.date.month() == month) 89 | .collect(); 90 | print_puente_days( 91 | Some(month), 92 | year, 93 | &holidays_for_month, 94 | &country_code, 95 | ); 96 | } 97 | None => { 98 | let holiday_refs: Vec<&Holiday> = holidays.iter().collect(); 99 | print_puente_days(None, year, &holiday_refs, &country_code); 100 | } 101 | } 102 | } else { 103 | println!("{}", bridge_pun(year)); 104 | } 105 | } else { 106 | println!("Failed to fetch holiday data for {}", country_code); 107 | } 108 | } else { 109 | println!("Unsupported country code: {}", country_code); 110 | println!("Available countries are:"); 111 | println!(" - Mauritius (MU)\n - South Africa (ZA)\n - France (FR) - Turkey (TR) - Singapore (SG)"); 112 | } 113 | } 114 | 115 | Some(("calendar", sub_matches)) => { 116 | let month_input = sub_matches.get_one::("month"); 117 | let year = sub_matches 118 | .get_one::("year") 119 | .and_then(|y| y.parse::().ok()) 120 | .unwrap_or(current_year); 121 | 122 | let month = match month_input { 123 | Some(m) => match parse_month(m) { 124 | Some(parsed_month) => parsed_month, 125 | None => { 126 | println!("Error: Invalid month input. Please use a number (1-12) or a month name."); 127 | return Ok(()); 128 | } 129 | }, 130 | None => current_month, 131 | }; 132 | 133 | let compare_country = sub_matches.get_one::("compare"); 134 | 135 | let mut country_holidays = Vec::new(); 136 | let mut missing_data = Vec::new(); 137 | 138 | // Fetch default country holidays 139 | if let Ok(default_holidays) = 140 | fetch_holidays(urls[config.default_country.as_str()]).await 141 | { 142 | if let Some(holidays) = default_holidays.years.get(&year.to_string()) { 143 | country_holidays.push(CountryHolidays { 144 | country: config.default_country.clone(), 145 | holidays: holidays.clone(), 146 | }); 147 | } else { 148 | missing_data.push(&config.default_country); 149 | } 150 | } 151 | 152 | // Fetch comparison country if specified 153 | if let Some(country_code) = compare_country { 154 | if let Some(url) = urls.get(country_code.as_str()) { 155 | if let Ok(country_data) = fetch_holidays(url).await { 156 | if let Some(holidays) = country_data.years.get(&year.to_string()) { 157 | country_holidays.push(CountryHolidays { 158 | country: country_code.to_string(), 159 | holidays: holidays.clone(), 160 | }); 161 | } else { 162 | missing_data.push(country_code); 163 | } 164 | } 165 | } else { 166 | println!("Unsupported country code: {}", country_code); 167 | println!("Available countries are:"); 168 | println!(" - Mauritius (MU)\n - South Africa (ZA)\n - France (FR) - Turkey (TR) - Singapore (SG)"); 169 | 170 | return Ok(()); 171 | } 172 | } 173 | 174 | if !missing_data.is_empty() { 175 | println!( 176 | "{}\n", 177 | format!( 178 | "⚠️ No data available for year {} in {}.", 179 | year, 180 | missing_data 181 | .iter() 182 | .map(|s| s.as_str()) 183 | .collect::>() 184 | .join(" and ") 185 | ) 186 | .bold() 187 | .yellow() 188 | ); 189 | 190 | // Print available years for each country with missing data 191 | for country in missing_data { 192 | let url = urls.get(country.as_str()).unwrap(); 193 | 194 | if let Ok(holiday_data) = fetch_holidays(url).await { 195 | let available_years: Vec<_> = holiday_data 196 | .years 197 | .keys() 198 | .map(|y| y.parse::().unwrap_or(0)) 199 | .collect(); 200 | 201 | if !available_years.is_empty() { 202 | let min_year = available_years.iter().min().unwrap(); 203 | let max_year = available_years.iter().max().unwrap(); 204 | println!( 205 | "{}", 206 | format!( 207 | "📅 Available years for {}: {} to {}", 208 | country, min_year, max_year 209 | ) 210 | .bold() 211 | .blue() 212 | ); 213 | } 214 | } 215 | } 216 | println!(); // Add a blank line for better formatting 217 | } 218 | 219 | if !country_holidays.is_empty() { 220 | cal::print_calendar_comparison(month, year, &country_holidays); 221 | } 222 | } 223 | 224 | Some(("config", sub_matches)) => { 225 | if let Some(default_country) = sub_matches.get_one::("default-country") { 226 | config.default_country = default_country.to_uppercase(); 227 | config.save(&config_path)?; 228 | println!("Default country set to: {}", config.default_country); 229 | } else if sub_matches.subcommand_matches("show").is_some() { 230 | println!("Default country: {}", config.default_country); 231 | } else { 232 | println!("Invalid config command. Use '--default-country' to set a new default country or 'show' to display the current configuration."); 233 | } 234 | } 235 | Some(("list", sub_matches)) => { 236 | let country_code = sub_matches 237 | .get_one::("country") 238 | .map(|s| s.to_uppercase()) 239 | .unwrap_or_else(|| config.default_country.clone()); 240 | 241 | let year = sub_matches 242 | .get_one::("year") 243 | .and_then(|y| y.parse::().ok()) 244 | .unwrap_or(current_year); 245 | 246 | if let Some(url) = urls.get(country_code.as_str()) { 247 | if let Ok(holidays_data) = fetch_holidays(url).await { 248 | if let Some(holidays) = holidays_data.years.get(&year.to_string()) { 249 | list::list_holidays(holidays, &country_code, year); 250 | } else { 251 | println!("No holiday data available for {} in {}", country_code, year); 252 | } 253 | } else { 254 | println!("Failed to fetch holiday data for {}", country_code); 255 | } 256 | } else { 257 | println!("Unsupported country code: {}", country_code); 258 | println!("Available countries are:"); 259 | println!(" - Mauritius (MU)\n - South Africa (ZA)\n - France (FR) - Turkey (TR) - Singapore (SG)"); 260 | } 261 | } 262 | 263 | _ => { 264 | // Handle the case where no arguments are provided 265 | if matches.subcommand_name().is_none() { 266 | let mut country_holidays = Vec::new(); 267 | 268 | // Fetch default country holidays 269 | if let Ok(default_holidays) = 270 | fetch_holidays(urls[config.default_country.as_str()]).await 271 | { 272 | if let Some(holidays) = default_holidays.years.get(¤t_year.to_string()) { 273 | country_holidays.push(CountryHolidays { 274 | country: config.default_country.clone(), 275 | holidays: holidays.clone(), 276 | }); 277 | } 278 | } 279 | 280 | // Print the calendar for the current month 281 | print_calendar_comparison(current_month, current_year, &country_holidays); 282 | } else { 283 | println!("Invalid command. Use 'bridge' or 'calendar'."); 284 | } 285 | } 286 | } 287 | 288 | Ok(()) 289 | } 290 | 291 | fn bridge_pun(year: i32) -> String { 292 | // Create a list of pun lines 293 | let pun_lines = [ 294 | format!("No holidays found for the year {}... looks like we'll have to bridge the gap to next year!", year), 295 | format!("No holidays found for the year {}... you'll have to find another bridge to escape!", year), 296 | format!("No holidays found for the year {}... guess it's time to build a new bridge to take a break!", year), 297 | format!("No holidays found for the year {}... looks like the holiday bridge is under construction!", year), 298 | format!("No holidays found for the year {}... looks like all bridges to time off are closed!", year), 299 | format!("No holidays found for the year {}... it’s a long road with no bridges in sight!", year), 300 | format!("No holidays found for the year {}... guess the bridge to holidays has been washed away!", year), 301 | ]; 302 | 303 | // Select a random pun line 304 | let random_pun = pun_lines.choose(&mut rand::thread_rng()).unwrap(); 305 | 306 | // Return the random pun line 307 | random_pun.to_string() // Convert to String for return 308 | } 309 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # This file was autogenerated by cargo-dist: https://opensource.axo.dev/cargo-dist/ 2 | # 3 | # Copyright 2022-2024, axodotdev 4 | # SPDX-License-Identifier: MIT or Apache-2.0 5 | # 6 | # CI that: 7 | # 8 | # * checks for a Git Tag that looks like a release 9 | # * builds artifacts with cargo-dist (archives, installers, hashes) 10 | # * uploads those artifacts to temporary workflow zip 11 | # * on success, uploads the artifacts to a GitHub Release 12 | # 13 | # Note that the GitHub Release will be created with a generated 14 | # title/body based on your changelogs. 15 | 16 | name: Release 17 | permissions: 18 | "contents": "write" 19 | 20 | # This task will run whenever you push a git tag that looks like a version 21 | # like "1.0.0", "v0.1.0-prerelease.1", "my-app/0.1.0", "releases/v1.0.0", etc. 22 | # Various formats will be parsed into a VERSION and an optional PACKAGE_NAME, where 23 | # PACKAGE_NAME must be the name of a Cargo package in your workspace, and VERSION 24 | # must be a Cargo-style SemVer Version (must have at least major.minor.patch). 25 | # 26 | # If PACKAGE_NAME is specified, then the announcement will be for that 27 | # package (erroring out if it doesn't have the given version or isn't cargo-dist-able). 28 | # 29 | # If PACKAGE_NAME isn't specified, then the announcement will be for all 30 | # (cargo-dist-able) packages in the workspace with that version (this mode is 31 | # intended for workspaces with only one dist-able package, or with all dist-able 32 | # packages versioned/released in lockstep). 33 | # 34 | # If you push multiple tags at once, separate instances of this workflow will 35 | # spin up, creating an independent announcement for each one. However, GitHub 36 | # will hard limit this to 3 tags per commit, as it will assume more tags is a 37 | # mistake. 38 | # 39 | # If there's a prerelease-style suffix to the version, then the release(s) 40 | # will be marked as a prerelease. 41 | on: 42 | pull_request: 43 | push: 44 | tags: 45 | - '**[0-9]+.[0-9]+.[0-9]+*' 46 | 47 | jobs: 48 | # Run 'cargo dist plan' (or host) to determine what tasks we need to do 49 | plan: 50 | runs-on: "ubuntu-20.04" 51 | outputs: 52 | val: ${{ steps.plan.outputs.manifest }} 53 | tag: ${{ !github.event.pull_request && github.ref_name || '' }} 54 | tag-flag: ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }} 55 | publishing: ${{ !github.event.pull_request }} 56 | env: 57 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 58 | steps: 59 | - uses: actions/checkout@v4 60 | with: 61 | submodules: recursive 62 | - name: Install cargo-dist 63 | # we specify bash to get pipefail; it guards against the `curl` command 64 | # failing. otherwise `sh` won't catch that `curl` returned non-0 65 | shell: bash 66 | run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.21.1/cargo-dist-installer.sh | sh" 67 | - name: Cache cargo-dist 68 | uses: actions/upload-artifact@v4 69 | with: 70 | name: cargo-dist-cache 71 | path: ~/.cargo/bin/cargo-dist 72 | # sure would be cool if github gave us proper conditionals... 73 | # so here's a doubly-nested ternary-via-truthiness to try to provide the best possible 74 | # functionality based on whether this is a pull_request, and whether it's from a fork. 75 | # (PRs run on the *source* but secrets are usually on the *target* -- that's *good* 76 | # but also really annoying to build CI around when it needs secrets to work right.) 77 | - id: plan 78 | run: | 79 | cargo dist ${{ (!github.event.pull_request && format('host --steps=create --tag={0}', github.ref_name)) || 'plan' }} --output-format=json > plan-dist-manifest.json 80 | echo "cargo dist ran successfully" 81 | cat plan-dist-manifest.json 82 | echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT" 83 | - name: "Upload dist-manifest.json" 84 | uses: actions/upload-artifact@v4 85 | with: 86 | name: artifacts-plan-dist-manifest 87 | path: plan-dist-manifest.json 88 | 89 | # Build and packages all the platform-specific things 90 | build-local-artifacts: 91 | name: build-local-artifacts (${{ join(matrix.targets, ', ') }}) 92 | # Let the initial task tell us to not run (currently very blunt) 93 | needs: 94 | - plan 95 | if: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.include != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }} 96 | strategy: 97 | fail-fast: false 98 | # Target platforms/runners are computed by cargo-dist in create-release. 99 | # Each member of the matrix has the following arguments: 100 | # 101 | # - runner: the github runner 102 | # - dist-args: cli flags to pass to cargo dist 103 | # - install-dist: expression to run to install cargo-dist on the runner 104 | # 105 | # Typically there will be: 106 | # - 1 "global" task that builds universal installers 107 | # - N "local" tasks that build each platform's binaries and platform-specific installers 108 | matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }} 109 | runs-on: ${{ matrix.runner }} 110 | env: 111 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 112 | BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json 113 | steps: 114 | - name: enable windows longpaths 115 | run: | 116 | git config --global core.longpaths true 117 | - uses: actions/checkout@v4 118 | with: 119 | submodules: recursive 120 | - name: Install cargo-dist 121 | run: ${{ matrix.install_dist }} 122 | # Get the dist-manifest 123 | - name: Fetch local artifacts 124 | uses: actions/download-artifact@v4 125 | with: 126 | pattern: artifacts-* 127 | path: target/distrib/ 128 | merge-multiple: true 129 | - name: Install dependencies 130 | run: | 131 | ${{ matrix.packages_install }} 132 | - name: Build artifacts 133 | run: | 134 | # Actually do builds and make zips and whatnot 135 | cargo dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json 136 | echo "cargo dist ran successfully" 137 | - id: cargo-dist 138 | name: Post-build 139 | # We force bash here just because github makes it really hard to get values up 140 | # to "real" actions without writing to env-vars, and writing to env-vars has 141 | # inconsistent syntax between shell and powershell. 142 | shell: bash 143 | run: | 144 | # Parse out what we just built and upload it to scratch storage 145 | echo "paths<> "$GITHUB_OUTPUT" 146 | jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT" 147 | echo "EOF" >> "$GITHUB_OUTPUT" 148 | 149 | cp dist-manifest.json "$BUILD_MANIFEST_NAME" 150 | - name: "Upload artifacts" 151 | uses: actions/upload-artifact@v4 152 | with: 153 | name: artifacts-build-local-${{ join(matrix.targets, '_') }} 154 | path: | 155 | ${{ steps.cargo-dist.outputs.paths }} 156 | ${{ env.BUILD_MANIFEST_NAME }} 157 | 158 | # Build and package all the platform-agnostic(ish) things 159 | build-global-artifacts: 160 | needs: 161 | - plan 162 | - build-local-artifacts 163 | runs-on: "ubuntu-20.04" 164 | env: 165 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 166 | BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json 167 | steps: 168 | - uses: actions/checkout@v4 169 | with: 170 | submodules: recursive 171 | - name: Install cached cargo-dist 172 | uses: actions/download-artifact@v4 173 | with: 174 | name: cargo-dist-cache 175 | path: ~/.cargo/bin/ 176 | - run: chmod +x ~/.cargo/bin/cargo-dist 177 | # Get all the local artifacts for the global tasks to use (for e.g. checksums) 178 | - name: Fetch local artifacts 179 | uses: actions/download-artifact@v4 180 | with: 181 | pattern: artifacts-* 182 | path: target/distrib/ 183 | merge-multiple: true 184 | - id: cargo-dist 185 | shell: bash 186 | run: | 187 | cargo dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json 188 | echo "cargo dist ran successfully" 189 | 190 | # Parse out what we just built and upload it to scratch storage 191 | echo "paths<> "$GITHUB_OUTPUT" 192 | jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT" 193 | echo "EOF" >> "$GITHUB_OUTPUT" 194 | 195 | cp dist-manifest.json "$BUILD_MANIFEST_NAME" 196 | - name: "Upload artifacts" 197 | uses: actions/upload-artifact@v4 198 | with: 199 | name: artifacts-build-global 200 | path: | 201 | ${{ steps.cargo-dist.outputs.paths }} 202 | ${{ env.BUILD_MANIFEST_NAME }} 203 | # Determines if we should publish/announce 204 | host: 205 | needs: 206 | - plan 207 | - build-local-artifacts 208 | - build-global-artifacts 209 | # Only run if we're "publishing", and only if local and global didn't fail (skipped is fine) 210 | if: ${{ always() && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }} 211 | env: 212 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 213 | runs-on: "ubuntu-20.04" 214 | outputs: 215 | val: ${{ steps.host.outputs.manifest }} 216 | steps: 217 | - uses: actions/checkout@v4 218 | with: 219 | submodules: recursive 220 | - name: Install cached cargo-dist 221 | uses: actions/download-artifact@v4 222 | with: 223 | name: cargo-dist-cache 224 | path: ~/.cargo/bin/ 225 | - run: chmod +x ~/.cargo/bin/cargo-dist 226 | # Fetch artifacts from scratch-storage 227 | - name: Fetch artifacts 228 | uses: actions/download-artifact@v4 229 | with: 230 | pattern: artifacts-* 231 | path: target/distrib/ 232 | merge-multiple: true 233 | - id: host 234 | shell: bash 235 | run: | 236 | cargo dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json 237 | echo "artifacts uploaded and released successfully" 238 | cat dist-manifest.json 239 | echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT" 240 | - name: "Upload dist-manifest.json" 241 | uses: actions/upload-artifact@v4 242 | with: 243 | # Overwrite the previous copy 244 | name: artifacts-dist-manifest 245 | path: dist-manifest.json 246 | # Create a GitHub Release while uploading all files to it 247 | - name: "Download GitHub Artifacts" 248 | uses: actions/download-artifact@v4 249 | with: 250 | pattern: artifacts-* 251 | path: artifacts 252 | merge-multiple: true 253 | - name: Cleanup 254 | run: | 255 | # Remove the granular manifests 256 | rm -f artifacts/*-dist-manifest.json 257 | - name: Create GitHub Release 258 | env: 259 | PRERELEASE_FLAG: "${{ fromJson(steps.host.outputs.manifest).announcement_is_prerelease && '--prerelease' || '' }}" 260 | ANNOUNCEMENT_TITLE: "${{ fromJson(steps.host.outputs.manifest).announcement_title }}" 261 | ANNOUNCEMENT_BODY: "${{ fromJson(steps.host.outputs.manifest).announcement_github_body }}" 262 | RELEASE_COMMIT: "${{ github.sha }}" 263 | run: | 264 | # Write and read notes from a file to avoid quoting breaking things 265 | echo "$ANNOUNCEMENT_BODY" > $RUNNER_TEMP/notes.txt 266 | 267 | gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/* 268 | 269 | publish-homebrew-formula: 270 | needs: 271 | - plan 272 | - host 273 | runs-on: "ubuntu-20.04" 274 | env: 275 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 276 | PLAN: ${{ needs.plan.outputs.val }} 277 | GITHUB_USER: "axo bot" 278 | GITHUB_EMAIL: "admin+bot@axo.dev" 279 | if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }} 280 | steps: 281 | - uses: actions/checkout@v4 282 | with: 283 | repository: "k3ii/homebrew-tap" 284 | token: ${{ secrets.HOMEBREW_TAP_TOKEN }} 285 | # So we have access to the formula 286 | - name: Fetch homebrew formulae 287 | uses: actions/download-artifact@v4 288 | with: 289 | pattern: artifacts-* 290 | path: Formula/ 291 | merge-multiple: true 292 | # This is extra complex because you can make your Formula name not match your app name 293 | # so we need to find releases with a *.rb file, and publish with that filename. 294 | - name: Commit formula files 295 | run: | 296 | git config --global user.name "${GITHUB_USER}" 297 | git config --global user.email "${GITHUB_EMAIL}" 298 | 299 | for release in $(echo "$PLAN" | jq --compact-output '.releases[] | select([.artifacts[] | endswith(".rb")] | any)'); do 300 | filename=$(echo "$release" | jq '.artifacts[] | select(endswith(".rb"))' --raw-output) 301 | name=$(echo "$filename" | sed "s/\.rb$//") 302 | version=$(echo "$release" | jq .app_version --raw-output) 303 | 304 | git add "Formula/${filename}" 305 | git commit -m "${name} ${version}" 306 | done 307 | git push 308 | 309 | announce: 310 | needs: 311 | - plan 312 | - host 313 | - publish-homebrew-formula 314 | # use "always() && ..." to allow us to wait for all publish jobs while 315 | # still allowing individual publish jobs to skip themselves (for prereleases). 316 | # "host" however must run to completion, no skipping allowed! 317 | if: ${{ always() && needs.host.result == 'success' && (needs.publish-homebrew-formula.result == 'skipped' || needs.publish-homebrew-formula.result == 'success') }} 318 | runs-on: "ubuntu-20.04" 319 | env: 320 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 321 | steps: 322 | - uses: actions/checkout@v4 323 | with: 324 | submodules: recursive 325 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 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 = "android-tzdata" 31 | version = "0.1.1" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 34 | 35 | [[package]] 36 | name = "android_system_properties" 37 | version = "0.1.5" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 40 | dependencies = [ 41 | "libc", 42 | ] 43 | 44 | [[package]] 45 | name = "anstream" 46 | version = "0.6.18" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" 49 | dependencies = [ 50 | "anstyle", 51 | "anstyle-parse", 52 | "anstyle-query", 53 | "anstyle-wincon", 54 | "colorchoice", 55 | "is_terminal_polyfill", 56 | "utf8parse", 57 | ] 58 | 59 | [[package]] 60 | name = "anstyle" 61 | version = "1.0.10" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" 64 | 65 | [[package]] 66 | name = "anstyle-parse" 67 | version = "0.2.6" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" 70 | dependencies = [ 71 | "utf8parse", 72 | ] 73 | 74 | [[package]] 75 | name = "anstyle-query" 76 | version = "1.1.2" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" 79 | dependencies = [ 80 | "windows-sys 0.59.0", 81 | ] 82 | 83 | [[package]] 84 | name = "anstyle-wincon" 85 | version = "3.0.7" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" 88 | dependencies = [ 89 | "anstyle", 90 | "once_cell", 91 | "windows-sys 0.59.0", 92 | ] 93 | 94 | [[package]] 95 | name = "anyhow" 96 | version = "1.0.95" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" 99 | 100 | [[package]] 101 | name = "atomic-waker" 102 | version = "1.1.2" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 105 | 106 | [[package]] 107 | name = "autocfg" 108 | version = "1.4.0" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 111 | 112 | [[package]] 113 | name = "backtrace" 114 | version = "0.3.74" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 117 | dependencies = [ 118 | "addr2line", 119 | "cfg-if", 120 | "libc", 121 | "miniz_oxide", 122 | "object", 123 | "rustc-demangle", 124 | "windows-targets 0.52.6", 125 | ] 126 | 127 | [[package]] 128 | name = "base64" 129 | version = "0.22.1" 130 | source = "registry+https://github.com/rust-lang/crates.io-index" 131 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 132 | 133 | [[package]] 134 | name = "bitflags" 135 | version = "2.8.0" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" 138 | 139 | [[package]] 140 | name = "bumpalo" 141 | version = "3.16.0" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 144 | 145 | [[package]] 146 | name = "byteorder" 147 | version = "1.5.0" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 150 | 151 | [[package]] 152 | name = "bytes" 153 | version = "1.9.0" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" 156 | 157 | [[package]] 158 | name = "cc" 159 | version = "1.2.10" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" 162 | dependencies = [ 163 | "shlex", 164 | ] 165 | 166 | [[package]] 167 | name = "cfg-if" 168 | version = "1.0.0" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 171 | 172 | [[package]] 173 | name = "chrono" 174 | version = "0.4.39" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" 177 | dependencies = [ 178 | "android-tzdata", 179 | "iana-time-zone", 180 | "js-sys", 181 | "num-traits", 182 | "serde", 183 | "wasm-bindgen", 184 | "windows-targets 0.52.6", 185 | ] 186 | 187 | [[package]] 188 | name = "clap" 189 | version = "4.5.27" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796" 192 | dependencies = [ 193 | "clap_builder", 194 | "clap_derive", 195 | ] 196 | 197 | [[package]] 198 | name = "clap_builder" 199 | version = "4.5.27" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" 202 | dependencies = [ 203 | "anstream", 204 | "anstyle", 205 | "clap_lex", 206 | "strsim", 207 | ] 208 | 209 | [[package]] 210 | name = "clap_derive" 211 | version = "4.5.24" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" 214 | dependencies = [ 215 | "heck", 216 | "proc-macro2", 217 | "quote", 218 | "syn", 219 | ] 220 | 221 | [[package]] 222 | name = "clap_lex" 223 | version = "0.7.4" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" 226 | 227 | [[package]] 228 | name = "colorchoice" 229 | version = "1.0.3" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" 232 | 233 | [[package]] 234 | name = "colored" 235 | version = "2.2.0" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" 238 | dependencies = [ 239 | "lazy_static", 240 | "windows-sys 0.59.0", 241 | ] 242 | 243 | [[package]] 244 | name = "comfy-table" 245 | version = "7.1.3" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "24f165e7b643266ea80cb858aed492ad9280e3e05ce24d4a99d7d7b889b6a4d9" 248 | dependencies = [ 249 | "crossterm", 250 | "strum", 251 | "strum_macros", 252 | "unicode-width 0.2.0", 253 | ] 254 | 255 | [[package]] 256 | name = "conze" 257 | version = "0.1.3" 258 | dependencies = [ 259 | "anyhow", 260 | "chrono", 261 | "clap", 262 | "colored", 263 | "comfy-table", 264 | "crossterm", 265 | "directories", 266 | "num-traits", 267 | "openssl", 268 | "prettytable", 269 | "rand", 270 | "regex", 271 | "reqwest", 272 | "serde", 273 | "serde_json", 274 | "tokio", 275 | "toml", 276 | ] 277 | 278 | [[package]] 279 | name = "core-foundation" 280 | version = "0.9.4" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 283 | dependencies = [ 284 | "core-foundation-sys", 285 | "libc", 286 | ] 287 | 288 | [[package]] 289 | name = "core-foundation-sys" 290 | version = "0.8.7" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 293 | 294 | [[package]] 295 | name = "crossterm" 296 | version = "0.28.1" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" 299 | dependencies = [ 300 | "bitflags", 301 | "crossterm_winapi", 302 | "mio", 303 | "parking_lot", 304 | "rustix", 305 | "signal-hook", 306 | "signal-hook-mio", 307 | "winapi", 308 | ] 309 | 310 | [[package]] 311 | name = "crossterm_winapi" 312 | version = "0.9.1" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" 315 | dependencies = [ 316 | "winapi", 317 | ] 318 | 319 | [[package]] 320 | name = "csv" 321 | version = "1.3.1" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" 324 | dependencies = [ 325 | "csv-core", 326 | "itoa", 327 | "ryu", 328 | "serde", 329 | ] 330 | 331 | [[package]] 332 | name = "csv-core" 333 | version = "0.1.11" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" 336 | dependencies = [ 337 | "memchr", 338 | ] 339 | 340 | [[package]] 341 | name = "directories" 342 | version = "5.0.1" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" 345 | dependencies = [ 346 | "dirs-sys", 347 | ] 348 | 349 | [[package]] 350 | name = "dirs-next" 351 | version = "2.0.0" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" 354 | dependencies = [ 355 | "cfg-if", 356 | "dirs-sys-next", 357 | ] 358 | 359 | [[package]] 360 | name = "dirs-sys" 361 | version = "0.4.1" 362 | source = "registry+https://github.com/rust-lang/crates.io-index" 363 | checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" 364 | dependencies = [ 365 | "libc", 366 | "option-ext", 367 | "redox_users", 368 | "windows-sys 0.48.0", 369 | ] 370 | 371 | [[package]] 372 | name = "dirs-sys-next" 373 | version = "0.1.2" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" 376 | dependencies = [ 377 | "libc", 378 | "redox_users", 379 | "winapi", 380 | ] 381 | 382 | [[package]] 383 | name = "displaydoc" 384 | version = "0.2.5" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 387 | dependencies = [ 388 | "proc-macro2", 389 | "quote", 390 | "syn", 391 | ] 392 | 393 | [[package]] 394 | name = "encode_unicode" 395 | version = "1.0.0" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" 398 | 399 | [[package]] 400 | name = "encoding_rs" 401 | version = "0.8.35" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" 404 | dependencies = [ 405 | "cfg-if", 406 | ] 407 | 408 | [[package]] 409 | name = "equivalent" 410 | version = "1.0.1" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 413 | 414 | [[package]] 415 | name = "errno" 416 | version = "0.3.10" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" 419 | dependencies = [ 420 | "libc", 421 | "windows-sys 0.59.0", 422 | ] 423 | 424 | [[package]] 425 | name = "fastrand" 426 | version = "2.3.0" 427 | source = "registry+https://github.com/rust-lang/crates.io-index" 428 | checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 429 | 430 | [[package]] 431 | name = "fnv" 432 | version = "1.0.7" 433 | source = "registry+https://github.com/rust-lang/crates.io-index" 434 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 435 | 436 | [[package]] 437 | name = "foreign-types" 438 | version = "0.3.2" 439 | source = "registry+https://github.com/rust-lang/crates.io-index" 440 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 441 | dependencies = [ 442 | "foreign-types-shared", 443 | ] 444 | 445 | [[package]] 446 | name = "foreign-types-shared" 447 | version = "0.1.1" 448 | source = "registry+https://github.com/rust-lang/crates.io-index" 449 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 450 | 451 | [[package]] 452 | name = "form_urlencoded" 453 | version = "1.2.1" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 456 | dependencies = [ 457 | "percent-encoding", 458 | ] 459 | 460 | [[package]] 461 | name = "futures-channel" 462 | version = "0.3.31" 463 | source = "registry+https://github.com/rust-lang/crates.io-index" 464 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 465 | dependencies = [ 466 | "futures-core", 467 | ] 468 | 469 | [[package]] 470 | name = "futures-core" 471 | version = "0.3.31" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 474 | 475 | [[package]] 476 | name = "futures-sink" 477 | version = "0.3.31" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 480 | 481 | [[package]] 482 | name = "futures-task" 483 | version = "0.3.31" 484 | source = "registry+https://github.com/rust-lang/crates.io-index" 485 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 486 | 487 | [[package]] 488 | name = "futures-util" 489 | version = "0.3.31" 490 | source = "registry+https://github.com/rust-lang/crates.io-index" 491 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 492 | dependencies = [ 493 | "futures-core", 494 | "futures-task", 495 | "pin-project-lite", 496 | "pin-utils", 497 | ] 498 | 499 | [[package]] 500 | name = "getrandom" 501 | version = "0.2.15" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 504 | dependencies = [ 505 | "cfg-if", 506 | "libc", 507 | "wasi", 508 | ] 509 | 510 | [[package]] 511 | name = "gimli" 512 | version = "0.31.1" 513 | source = "registry+https://github.com/rust-lang/crates.io-index" 514 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 515 | 516 | [[package]] 517 | name = "h2" 518 | version = "0.4.7" 519 | source = "registry+https://github.com/rust-lang/crates.io-index" 520 | checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" 521 | dependencies = [ 522 | "atomic-waker", 523 | "bytes", 524 | "fnv", 525 | "futures-core", 526 | "futures-sink", 527 | "http", 528 | "indexmap", 529 | "slab", 530 | "tokio", 531 | "tokio-util", 532 | "tracing", 533 | ] 534 | 535 | [[package]] 536 | name = "hashbrown" 537 | version = "0.15.2" 538 | source = "registry+https://github.com/rust-lang/crates.io-index" 539 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 540 | 541 | [[package]] 542 | name = "heck" 543 | version = "0.5.0" 544 | source = "registry+https://github.com/rust-lang/crates.io-index" 545 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 546 | 547 | [[package]] 548 | name = "hermit-abi" 549 | version = "0.4.0" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" 552 | 553 | [[package]] 554 | name = "http" 555 | version = "1.2.0" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" 558 | dependencies = [ 559 | "bytes", 560 | "fnv", 561 | "itoa", 562 | ] 563 | 564 | [[package]] 565 | name = "http-body" 566 | version = "1.0.1" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 569 | dependencies = [ 570 | "bytes", 571 | "http", 572 | ] 573 | 574 | [[package]] 575 | name = "http-body-util" 576 | version = "0.1.2" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" 579 | dependencies = [ 580 | "bytes", 581 | "futures-util", 582 | "http", 583 | "http-body", 584 | "pin-project-lite", 585 | ] 586 | 587 | [[package]] 588 | name = "httparse" 589 | version = "1.9.5" 590 | source = "registry+https://github.com/rust-lang/crates.io-index" 591 | checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" 592 | 593 | [[package]] 594 | name = "hyper" 595 | version = "1.5.2" 596 | source = "registry+https://github.com/rust-lang/crates.io-index" 597 | checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" 598 | dependencies = [ 599 | "bytes", 600 | "futures-channel", 601 | "futures-util", 602 | "h2", 603 | "http", 604 | "http-body", 605 | "httparse", 606 | "itoa", 607 | "pin-project-lite", 608 | "smallvec", 609 | "tokio", 610 | "want", 611 | ] 612 | 613 | [[package]] 614 | name = "hyper-rustls" 615 | version = "0.27.5" 616 | source = "registry+https://github.com/rust-lang/crates.io-index" 617 | checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" 618 | dependencies = [ 619 | "futures-util", 620 | "http", 621 | "hyper", 622 | "hyper-util", 623 | "rustls", 624 | "rustls-pki-types", 625 | "tokio", 626 | "tokio-rustls", 627 | "tower-service", 628 | ] 629 | 630 | [[package]] 631 | name = "hyper-tls" 632 | version = "0.6.0" 633 | source = "registry+https://github.com/rust-lang/crates.io-index" 634 | checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 635 | dependencies = [ 636 | "bytes", 637 | "http-body-util", 638 | "hyper", 639 | "hyper-util", 640 | "native-tls", 641 | "tokio", 642 | "tokio-native-tls", 643 | "tower-service", 644 | ] 645 | 646 | [[package]] 647 | name = "hyper-util" 648 | version = "0.1.10" 649 | source = "registry+https://github.com/rust-lang/crates.io-index" 650 | checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" 651 | dependencies = [ 652 | "bytes", 653 | "futures-channel", 654 | "futures-util", 655 | "http", 656 | "http-body", 657 | "hyper", 658 | "pin-project-lite", 659 | "socket2", 660 | "tokio", 661 | "tower-service", 662 | "tracing", 663 | ] 664 | 665 | [[package]] 666 | name = "iana-time-zone" 667 | version = "0.1.61" 668 | source = "registry+https://github.com/rust-lang/crates.io-index" 669 | checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" 670 | dependencies = [ 671 | "android_system_properties", 672 | "core-foundation-sys", 673 | "iana-time-zone-haiku", 674 | "js-sys", 675 | "wasm-bindgen", 676 | "windows-core", 677 | ] 678 | 679 | [[package]] 680 | name = "iana-time-zone-haiku" 681 | version = "0.1.2" 682 | source = "registry+https://github.com/rust-lang/crates.io-index" 683 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 684 | dependencies = [ 685 | "cc", 686 | ] 687 | 688 | [[package]] 689 | name = "icu_collections" 690 | version = "1.5.0" 691 | source = "registry+https://github.com/rust-lang/crates.io-index" 692 | checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" 693 | dependencies = [ 694 | "displaydoc", 695 | "yoke", 696 | "zerofrom", 697 | "zerovec", 698 | ] 699 | 700 | [[package]] 701 | name = "icu_locid" 702 | version = "1.5.0" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" 705 | dependencies = [ 706 | "displaydoc", 707 | "litemap", 708 | "tinystr", 709 | "writeable", 710 | "zerovec", 711 | ] 712 | 713 | [[package]] 714 | name = "icu_locid_transform" 715 | version = "1.5.0" 716 | source = "registry+https://github.com/rust-lang/crates.io-index" 717 | checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" 718 | dependencies = [ 719 | "displaydoc", 720 | "icu_locid", 721 | "icu_locid_transform_data", 722 | "icu_provider", 723 | "tinystr", 724 | "zerovec", 725 | ] 726 | 727 | [[package]] 728 | name = "icu_locid_transform_data" 729 | version = "1.5.0" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" 732 | 733 | [[package]] 734 | name = "icu_normalizer" 735 | version = "1.5.0" 736 | source = "registry+https://github.com/rust-lang/crates.io-index" 737 | checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" 738 | dependencies = [ 739 | "displaydoc", 740 | "icu_collections", 741 | "icu_normalizer_data", 742 | "icu_properties", 743 | "icu_provider", 744 | "smallvec", 745 | "utf16_iter", 746 | "utf8_iter", 747 | "write16", 748 | "zerovec", 749 | ] 750 | 751 | [[package]] 752 | name = "icu_normalizer_data" 753 | version = "1.5.0" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" 756 | 757 | [[package]] 758 | name = "icu_properties" 759 | version = "1.5.1" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" 762 | dependencies = [ 763 | "displaydoc", 764 | "icu_collections", 765 | "icu_locid_transform", 766 | "icu_properties_data", 767 | "icu_provider", 768 | "tinystr", 769 | "zerovec", 770 | ] 771 | 772 | [[package]] 773 | name = "icu_properties_data" 774 | version = "1.5.0" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" 777 | 778 | [[package]] 779 | name = "icu_provider" 780 | version = "1.5.0" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" 783 | dependencies = [ 784 | "displaydoc", 785 | "icu_locid", 786 | "icu_provider_macros", 787 | "stable_deref_trait", 788 | "tinystr", 789 | "writeable", 790 | "yoke", 791 | "zerofrom", 792 | "zerovec", 793 | ] 794 | 795 | [[package]] 796 | name = "icu_provider_macros" 797 | version = "1.5.0" 798 | source = "registry+https://github.com/rust-lang/crates.io-index" 799 | checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" 800 | dependencies = [ 801 | "proc-macro2", 802 | "quote", 803 | "syn", 804 | ] 805 | 806 | [[package]] 807 | name = "idna" 808 | version = "1.0.3" 809 | source = "registry+https://github.com/rust-lang/crates.io-index" 810 | checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 811 | dependencies = [ 812 | "idna_adapter", 813 | "smallvec", 814 | "utf8_iter", 815 | ] 816 | 817 | [[package]] 818 | name = "idna_adapter" 819 | version = "1.2.0" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" 822 | dependencies = [ 823 | "icu_normalizer", 824 | "icu_properties", 825 | ] 826 | 827 | [[package]] 828 | name = "indexmap" 829 | version = "2.7.1" 830 | source = "registry+https://github.com/rust-lang/crates.io-index" 831 | checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" 832 | dependencies = [ 833 | "equivalent", 834 | "hashbrown", 835 | ] 836 | 837 | [[package]] 838 | name = "ipnet" 839 | version = "2.11.0" 840 | source = "registry+https://github.com/rust-lang/crates.io-index" 841 | checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" 842 | 843 | [[package]] 844 | name = "is-terminal" 845 | version = "0.4.15" 846 | source = "registry+https://github.com/rust-lang/crates.io-index" 847 | checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37" 848 | dependencies = [ 849 | "hermit-abi", 850 | "libc", 851 | "windows-sys 0.59.0", 852 | ] 853 | 854 | [[package]] 855 | name = "is_terminal_polyfill" 856 | version = "1.70.1" 857 | source = "registry+https://github.com/rust-lang/crates.io-index" 858 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 859 | 860 | [[package]] 861 | name = "itoa" 862 | version = "1.0.14" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" 865 | 866 | [[package]] 867 | name = "js-sys" 868 | version = "0.3.77" 869 | source = "registry+https://github.com/rust-lang/crates.io-index" 870 | checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" 871 | dependencies = [ 872 | "once_cell", 873 | "wasm-bindgen", 874 | ] 875 | 876 | [[package]] 877 | name = "lazy_static" 878 | version = "1.5.0" 879 | source = "registry+https://github.com/rust-lang/crates.io-index" 880 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 881 | 882 | [[package]] 883 | name = "libc" 884 | version = "0.2.169" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" 887 | 888 | [[package]] 889 | name = "libredox" 890 | version = "0.1.3" 891 | source = "registry+https://github.com/rust-lang/crates.io-index" 892 | checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" 893 | dependencies = [ 894 | "bitflags", 895 | "libc", 896 | ] 897 | 898 | [[package]] 899 | name = "linux-raw-sys" 900 | version = "0.4.15" 901 | source = "registry+https://github.com/rust-lang/crates.io-index" 902 | checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" 903 | 904 | [[package]] 905 | name = "litemap" 906 | version = "0.7.4" 907 | source = "registry+https://github.com/rust-lang/crates.io-index" 908 | checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" 909 | 910 | [[package]] 911 | name = "lock_api" 912 | version = "0.4.12" 913 | source = "registry+https://github.com/rust-lang/crates.io-index" 914 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 915 | dependencies = [ 916 | "autocfg", 917 | "scopeguard", 918 | ] 919 | 920 | [[package]] 921 | name = "log" 922 | version = "0.4.25" 923 | source = "registry+https://github.com/rust-lang/crates.io-index" 924 | checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" 925 | 926 | [[package]] 927 | name = "memchr" 928 | version = "2.7.4" 929 | source = "registry+https://github.com/rust-lang/crates.io-index" 930 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 931 | 932 | [[package]] 933 | name = "mime" 934 | version = "0.3.17" 935 | source = "registry+https://github.com/rust-lang/crates.io-index" 936 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 937 | 938 | [[package]] 939 | name = "miniz_oxide" 940 | version = "0.8.3" 941 | source = "registry+https://github.com/rust-lang/crates.io-index" 942 | checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" 943 | dependencies = [ 944 | "adler2", 945 | ] 946 | 947 | [[package]] 948 | name = "mio" 949 | version = "1.0.3" 950 | source = "registry+https://github.com/rust-lang/crates.io-index" 951 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 952 | dependencies = [ 953 | "libc", 954 | "log", 955 | "wasi", 956 | "windows-sys 0.52.0", 957 | ] 958 | 959 | [[package]] 960 | name = "native-tls" 961 | version = "0.2.12" 962 | source = "registry+https://github.com/rust-lang/crates.io-index" 963 | checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" 964 | dependencies = [ 965 | "libc", 966 | "log", 967 | "openssl", 968 | "openssl-probe", 969 | "openssl-sys", 970 | "schannel", 971 | "security-framework", 972 | "security-framework-sys", 973 | "tempfile", 974 | ] 975 | 976 | [[package]] 977 | name = "num-traits" 978 | version = "0.2.19" 979 | source = "registry+https://github.com/rust-lang/crates.io-index" 980 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 981 | dependencies = [ 982 | "autocfg", 983 | ] 984 | 985 | [[package]] 986 | name = "object" 987 | version = "0.36.7" 988 | source = "registry+https://github.com/rust-lang/crates.io-index" 989 | checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 990 | dependencies = [ 991 | "memchr", 992 | ] 993 | 994 | [[package]] 995 | name = "once_cell" 996 | version = "1.20.2" 997 | source = "registry+https://github.com/rust-lang/crates.io-index" 998 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 999 | 1000 | [[package]] 1001 | name = "openssl" 1002 | version = "0.10.68" 1003 | source = "registry+https://github.com/rust-lang/crates.io-index" 1004 | checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" 1005 | dependencies = [ 1006 | "bitflags", 1007 | "cfg-if", 1008 | "foreign-types", 1009 | "libc", 1010 | "once_cell", 1011 | "openssl-macros", 1012 | "openssl-sys", 1013 | ] 1014 | 1015 | [[package]] 1016 | name = "openssl-macros" 1017 | version = "0.1.1" 1018 | source = "registry+https://github.com/rust-lang/crates.io-index" 1019 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 1020 | dependencies = [ 1021 | "proc-macro2", 1022 | "quote", 1023 | "syn", 1024 | ] 1025 | 1026 | [[package]] 1027 | name = "openssl-probe" 1028 | version = "0.1.5" 1029 | source = "registry+https://github.com/rust-lang/crates.io-index" 1030 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 1031 | 1032 | [[package]] 1033 | name = "openssl-src" 1034 | version = "300.4.1+3.4.0" 1035 | source = "registry+https://github.com/rust-lang/crates.io-index" 1036 | checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" 1037 | dependencies = [ 1038 | "cc", 1039 | ] 1040 | 1041 | [[package]] 1042 | name = "openssl-sys" 1043 | version = "0.9.104" 1044 | source = "registry+https://github.com/rust-lang/crates.io-index" 1045 | checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" 1046 | dependencies = [ 1047 | "cc", 1048 | "libc", 1049 | "openssl-src", 1050 | "pkg-config", 1051 | "vcpkg", 1052 | ] 1053 | 1054 | [[package]] 1055 | name = "option-ext" 1056 | version = "0.2.0" 1057 | source = "registry+https://github.com/rust-lang/crates.io-index" 1058 | checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" 1059 | 1060 | [[package]] 1061 | name = "parking_lot" 1062 | version = "0.12.3" 1063 | source = "registry+https://github.com/rust-lang/crates.io-index" 1064 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 1065 | dependencies = [ 1066 | "lock_api", 1067 | "parking_lot_core", 1068 | ] 1069 | 1070 | [[package]] 1071 | name = "parking_lot_core" 1072 | version = "0.9.10" 1073 | source = "registry+https://github.com/rust-lang/crates.io-index" 1074 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 1075 | dependencies = [ 1076 | "cfg-if", 1077 | "libc", 1078 | "redox_syscall", 1079 | "smallvec", 1080 | "windows-targets 0.52.6", 1081 | ] 1082 | 1083 | [[package]] 1084 | name = "percent-encoding" 1085 | version = "2.3.1" 1086 | source = "registry+https://github.com/rust-lang/crates.io-index" 1087 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1088 | 1089 | [[package]] 1090 | name = "pin-project-lite" 1091 | version = "0.2.16" 1092 | source = "registry+https://github.com/rust-lang/crates.io-index" 1093 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 1094 | 1095 | [[package]] 1096 | name = "pin-utils" 1097 | version = "0.1.0" 1098 | source = "registry+https://github.com/rust-lang/crates.io-index" 1099 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1100 | 1101 | [[package]] 1102 | name = "pkg-config" 1103 | version = "0.3.31" 1104 | source = "registry+https://github.com/rust-lang/crates.io-index" 1105 | checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" 1106 | 1107 | [[package]] 1108 | name = "ppv-lite86" 1109 | version = "0.2.20" 1110 | source = "registry+https://github.com/rust-lang/crates.io-index" 1111 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 1112 | dependencies = [ 1113 | "zerocopy", 1114 | ] 1115 | 1116 | [[package]] 1117 | name = "prettytable" 1118 | version = "0.10.0" 1119 | source = "registry+https://github.com/rust-lang/crates.io-index" 1120 | checksum = "46480520d1b77c9a3482d39939fcf96831537a250ec62d4fd8fbdf8e0302e781" 1121 | dependencies = [ 1122 | "csv", 1123 | "encode_unicode", 1124 | "is-terminal", 1125 | "lazy_static", 1126 | "term", 1127 | "unicode-width 0.1.14", 1128 | ] 1129 | 1130 | [[package]] 1131 | name = "proc-macro2" 1132 | version = "1.0.93" 1133 | source = "registry+https://github.com/rust-lang/crates.io-index" 1134 | checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" 1135 | dependencies = [ 1136 | "unicode-ident", 1137 | ] 1138 | 1139 | [[package]] 1140 | name = "quote" 1141 | version = "1.0.38" 1142 | source = "registry+https://github.com/rust-lang/crates.io-index" 1143 | checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" 1144 | dependencies = [ 1145 | "proc-macro2", 1146 | ] 1147 | 1148 | [[package]] 1149 | name = "rand" 1150 | version = "0.8.5" 1151 | source = "registry+https://github.com/rust-lang/crates.io-index" 1152 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1153 | dependencies = [ 1154 | "libc", 1155 | "rand_chacha", 1156 | "rand_core", 1157 | ] 1158 | 1159 | [[package]] 1160 | name = "rand_chacha" 1161 | version = "0.3.1" 1162 | source = "registry+https://github.com/rust-lang/crates.io-index" 1163 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1164 | dependencies = [ 1165 | "ppv-lite86", 1166 | "rand_core", 1167 | ] 1168 | 1169 | [[package]] 1170 | name = "rand_core" 1171 | version = "0.6.4" 1172 | source = "registry+https://github.com/rust-lang/crates.io-index" 1173 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1174 | dependencies = [ 1175 | "getrandom", 1176 | ] 1177 | 1178 | [[package]] 1179 | name = "redox_syscall" 1180 | version = "0.5.8" 1181 | source = "registry+https://github.com/rust-lang/crates.io-index" 1182 | checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" 1183 | dependencies = [ 1184 | "bitflags", 1185 | ] 1186 | 1187 | [[package]] 1188 | name = "redox_users" 1189 | version = "0.4.6" 1190 | source = "registry+https://github.com/rust-lang/crates.io-index" 1191 | checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" 1192 | dependencies = [ 1193 | "getrandom", 1194 | "libredox", 1195 | "thiserror", 1196 | ] 1197 | 1198 | [[package]] 1199 | name = "regex" 1200 | version = "1.11.1" 1201 | source = "registry+https://github.com/rust-lang/crates.io-index" 1202 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 1203 | dependencies = [ 1204 | "aho-corasick", 1205 | "memchr", 1206 | "regex-automata", 1207 | "regex-syntax", 1208 | ] 1209 | 1210 | [[package]] 1211 | name = "regex-automata" 1212 | version = "0.4.9" 1213 | source = "registry+https://github.com/rust-lang/crates.io-index" 1214 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 1215 | dependencies = [ 1216 | "aho-corasick", 1217 | "memchr", 1218 | "regex-syntax", 1219 | ] 1220 | 1221 | [[package]] 1222 | name = "regex-syntax" 1223 | version = "0.8.5" 1224 | source = "registry+https://github.com/rust-lang/crates.io-index" 1225 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 1226 | 1227 | [[package]] 1228 | name = "reqwest" 1229 | version = "0.12.12" 1230 | source = "registry+https://github.com/rust-lang/crates.io-index" 1231 | checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" 1232 | dependencies = [ 1233 | "base64", 1234 | "bytes", 1235 | "encoding_rs", 1236 | "futures-core", 1237 | "futures-util", 1238 | "h2", 1239 | "http", 1240 | "http-body", 1241 | "http-body-util", 1242 | "hyper", 1243 | "hyper-rustls", 1244 | "hyper-tls", 1245 | "hyper-util", 1246 | "ipnet", 1247 | "js-sys", 1248 | "log", 1249 | "mime", 1250 | "native-tls", 1251 | "once_cell", 1252 | "percent-encoding", 1253 | "pin-project-lite", 1254 | "rustls-pemfile", 1255 | "serde", 1256 | "serde_json", 1257 | "serde_urlencoded", 1258 | "sync_wrapper", 1259 | "system-configuration", 1260 | "tokio", 1261 | "tokio-native-tls", 1262 | "tower", 1263 | "tower-service", 1264 | "url", 1265 | "wasm-bindgen", 1266 | "wasm-bindgen-futures", 1267 | "web-sys", 1268 | "windows-registry", 1269 | ] 1270 | 1271 | [[package]] 1272 | name = "ring" 1273 | version = "0.17.8" 1274 | source = "registry+https://github.com/rust-lang/crates.io-index" 1275 | checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" 1276 | dependencies = [ 1277 | "cc", 1278 | "cfg-if", 1279 | "getrandom", 1280 | "libc", 1281 | "spin", 1282 | "untrusted", 1283 | "windows-sys 0.52.0", 1284 | ] 1285 | 1286 | [[package]] 1287 | name = "rustc-demangle" 1288 | version = "0.1.24" 1289 | source = "registry+https://github.com/rust-lang/crates.io-index" 1290 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1291 | 1292 | [[package]] 1293 | name = "rustix" 1294 | version = "0.38.44" 1295 | source = "registry+https://github.com/rust-lang/crates.io-index" 1296 | checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" 1297 | dependencies = [ 1298 | "bitflags", 1299 | "errno", 1300 | "libc", 1301 | "linux-raw-sys", 1302 | "windows-sys 0.59.0", 1303 | ] 1304 | 1305 | [[package]] 1306 | name = "rustls" 1307 | version = "0.23.21" 1308 | source = "registry+https://github.com/rust-lang/crates.io-index" 1309 | checksum = "8f287924602bf649d949c63dc8ac8b235fa5387d394020705b80c4eb597ce5b8" 1310 | dependencies = [ 1311 | "once_cell", 1312 | "rustls-pki-types", 1313 | "rustls-webpki", 1314 | "subtle", 1315 | "zeroize", 1316 | ] 1317 | 1318 | [[package]] 1319 | name = "rustls-pemfile" 1320 | version = "2.2.0" 1321 | source = "registry+https://github.com/rust-lang/crates.io-index" 1322 | checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" 1323 | dependencies = [ 1324 | "rustls-pki-types", 1325 | ] 1326 | 1327 | [[package]] 1328 | name = "rustls-pki-types" 1329 | version = "1.10.1" 1330 | source = "registry+https://github.com/rust-lang/crates.io-index" 1331 | checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" 1332 | 1333 | [[package]] 1334 | name = "rustls-webpki" 1335 | version = "0.102.8" 1336 | source = "registry+https://github.com/rust-lang/crates.io-index" 1337 | checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" 1338 | dependencies = [ 1339 | "ring", 1340 | "rustls-pki-types", 1341 | "untrusted", 1342 | ] 1343 | 1344 | [[package]] 1345 | name = "rustversion" 1346 | version = "1.0.19" 1347 | source = "registry+https://github.com/rust-lang/crates.io-index" 1348 | checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" 1349 | 1350 | [[package]] 1351 | name = "ryu" 1352 | version = "1.0.18" 1353 | source = "registry+https://github.com/rust-lang/crates.io-index" 1354 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1355 | 1356 | [[package]] 1357 | name = "schannel" 1358 | version = "0.1.27" 1359 | source = "registry+https://github.com/rust-lang/crates.io-index" 1360 | checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" 1361 | dependencies = [ 1362 | "windows-sys 0.59.0", 1363 | ] 1364 | 1365 | [[package]] 1366 | name = "scopeguard" 1367 | version = "1.2.0" 1368 | source = "registry+https://github.com/rust-lang/crates.io-index" 1369 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1370 | 1371 | [[package]] 1372 | name = "security-framework" 1373 | version = "2.11.1" 1374 | source = "registry+https://github.com/rust-lang/crates.io-index" 1375 | checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 1376 | dependencies = [ 1377 | "bitflags", 1378 | "core-foundation", 1379 | "core-foundation-sys", 1380 | "libc", 1381 | "security-framework-sys", 1382 | ] 1383 | 1384 | [[package]] 1385 | name = "security-framework-sys" 1386 | version = "2.14.0" 1387 | source = "registry+https://github.com/rust-lang/crates.io-index" 1388 | checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" 1389 | dependencies = [ 1390 | "core-foundation-sys", 1391 | "libc", 1392 | ] 1393 | 1394 | [[package]] 1395 | name = "serde" 1396 | version = "1.0.217" 1397 | source = "registry+https://github.com/rust-lang/crates.io-index" 1398 | checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" 1399 | dependencies = [ 1400 | "serde_derive", 1401 | ] 1402 | 1403 | [[package]] 1404 | name = "serde_derive" 1405 | version = "1.0.217" 1406 | source = "registry+https://github.com/rust-lang/crates.io-index" 1407 | checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" 1408 | dependencies = [ 1409 | "proc-macro2", 1410 | "quote", 1411 | "syn", 1412 | ] 1413 | 1414 | [[package]] 1415 | name = "serde_json" 1416 | version = "1.0.137" 1417 | source = "registry+https://github.com/rust-lang/crates.io-index" 1418 | checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" 1419 | dependencies = [ 1420 | "itoa", 1421 | "memchr", 1422 | "ryu", 1423 | "serde", 1424 | ] 1425 | 1426 | [[package]] 1427 | name = "serde_spanned" 1428 | version = "0.6.8" 1429 | source = "registry+https://github.com/rust-lang/crates.io-index" 1430 | checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" 1431 | dependencies = [ 1432 | "serde", 1433 | ] 1434 | 1435 | [[package]] 1436 | name = "serde_urlencoded" 1437 | version = "0.7.1" 1438 | source = "registry+https://github.com/rust-lang/crates.io-index" 1439 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1440 | dependencies = [ 1441 | "form_urlencoded", 1442 | "itoa", 1443 | "ryu", 1444 | "serde", 1445 | ] 1446 | 1447 | [[package]] 1448 | name = "shlex" 1449 | version = "1.3.0" 1450 | source = "registry+https://github.com/rust-lang/crates.io-index" 1451 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1452 | 1453 | [[package]] 1454 | name = "signal-hook" 1455 | version = "0.3.17" 1456 | source = "registry+https://github.com/rust-lang/crates.io-index" 1457 | checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" 1458 | dependencies = [ 1459 | "libc", 1460 | "signal-hook-registry", 1461 | ] 1462 | 1463 | [[package]] 1464 | name = "signal-hook-mio" 1465 | version = "0.2.4" 1466 | source = "registry+https://github.com/rust-lang/crates.io-index" 1467 | checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" 1468 | dependencies = [ 1469 | "libc", 1470 | "mio", 1471 | "signal-hook", 1472 | ] 1473 | 1474 | [[package]] 1475 | name = "signal-hook-registry" 1476 | version = "1.4.2" 1477 | source = "registry+https://github.com/rust-lang/crates.io-index" 1478 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 1479 | dependencies = [ 1480 | "libc", 1481 | ] 1482 | 1483 | [[package]] 1484 | name = "slab" 1485 | version = "0.4.9" 1486 | source = "registry+https://github.com/rust-lang/crates.io-index" 1487 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1488 | dependencies = [ 1489 | "autocfg", 1490 | ] 1491 | 1492 | [[package]] 1493 | name = "smallvec" 1494 | version = "1.13.2" 1495 | source = "registry+https://github.com/rust-lang/crates.io-index" 1496 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1497 | 1498 | [[package]] 1499 | name = "socket2" 1500 | version = "0.5.8" 1501 | source = "registry+https://github.com/rust-lang/crates.io-index" 1502 | checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" 1503 | dependencies = [ 1504 | "libc", 1505 | "windows-sys 0.52.0", 1506 | ] 1507 | 1508 | [[package]] 1509 | name = "spin" 1510 | version = "0.9.8" 1511 | source = "registry+https://github.com/rust-lang/crates.io-index" 1512 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1513 | 1514 | [[package]] 1515 | name = "stable_deref_trait" 1516 | version = "1.2.0" 1517 | source = "registry+https://github.com/rust-lang/crates.io-index" 1518 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1519 | 1520 | [[package]] 1521 | name = "strsim" 1522 | version = "0.11.1" 1523 | source = "registry+https://github.com/rust-lang/crates.io-index" 1524 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1525 | 1526 | [[package]] 1527 | name = "strum" 1528 | version = "0.26.3" 1529 | source = "registry+https://github.com/rust-lang/crates.io-index" 1530 | checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" 1531 | 1532 | [[package]] 1533 | name = "strum_macros" 1534 | version = "0.26.4" 1535 | source = "registry+https://github.com/rust-lang/crates.io-index" 1536 | checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" 1537 | dependencies = [ 1538 | "heck", 1539 | "proc-macro2", 1540 | "quote", 1541 | "rustversion", 1542 | "syn", 1543 | ] 1544 | 1545 | [[package]] 1546 | name = "subtle" 1547 | version = "2.6.1" 1548 | source = "registry+https://github.com/rust-lang/crates.io-index" 1549 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1550 | 1551 | [[package]] 1552 | name = "syn" 1553 | version = "2.0.96" 1554 | source = "registry+https://github.com/rust-lang/crates.io-index" 1555 | checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" 1556 | dependencies = [ 1557 | "proc-macro2", 1558 | "quote", 1559 | "unicode-ident", 1560 | ] 1561 | 1562 | [[package]] 1563 | name = "sync_wrapper" 1564 | version = "1.0.2" 1565 | source = "registry+https://github.com/rust-lang/crates.io-index" 1566 | checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 1567 | dependencies = [ 1568 | "futures-core", 1569 | ] 1570 | 1571 | [[package]] 1572 | name = "synstructure" 1573 | version = "0.13.1" 1574 | source = "registry+https://github.com/rust-lang/crates.io-index" 1575 | checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" 1576 | dependencies = [ 1577 | "proc-macro2", 1578 | "quote", 1579 | "syn", 1580 | ] 1581 | 1582 | [[package]] 1583 | name = "system-configuration" 1584 | version = "0.6.1" 1585 | source = "registry+https://github.com/rust-lang/crates.io-index" 1586 | checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" 1587 | dependencies = [ 1588 | "bitflags", 1589 | "core-foundation", 1590 | "system-configuration-sys", 1591 | ] 1592 | 1593 | [[package]] 1594 | name = "system-configuration-sys" 1595 | version = "0.6.0" 1596 | source = "registry+https://github.com/rust-lang/crates.io-index" 1597 | checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" 1598 | dependencies = [ 1599 | "core-foundation-sys", 1600 | "libc", 1601 | ] 1602 | 1603 | [[package]] 1604 | name = "tempfile" 1605 | version = "3.15.0" 1606 | source = "registry+https://github.com/rust-lang/crates.io-index" 1607 | checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" 1608 | dependencies = [ 1609 | "cfg-if", 1610 | "fastrand", 1611 | "getrandom", 1612 | "once_cell", 1613 | "rustix", 1614 | "windows-sys 0.59.0", 1615 | ] 1616 | 1617 | [[package]] 1618 | name = "term" 1619 | version = "0.7.0" 1620 | source = "registry+https://github.com/rust-lang/crates.io-index" 1621 | checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" 1622 | dependencies = [ 1623 | "dirs-next", 1624 | "rustversion", 1625 | "winapi", 1626 | ] 1627 | 1628 | [[package]] 1629 | name = "thiserror" 1630 | version = "1.0.69" 1631 | source = "registry+https://github.com/rust-lang/crates.io-index" 1632 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 1633 | dependencies = [ 1634 | "thiserror-impl", 1635 | ] 1636 | 1637 | [[package]] 1638 | name = "thiserror-impl" 1639 | version = "1.0.69" 1640 | source = "registry+https://github.com/rust-lang/crates.io-index" 1641 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 1642 | dependencies = [ 1643 | "proc-macro2", 1644 | "quote", 1645 | "syn", 1646 | ] 1647 | 1648 | [[package]] 1649 | name = "tinystr" 1650 | version = "0.7.6" 1651 | source = "registry+https://github.com/rust-lang/crates.io-index" 1652 | checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" 1653 | dependencies = [ 1654 | "displaydoc", 1655 | "zerovec", 1656 | ] 1657 | 1658 | [[package]] 1659 | name = "tokio" 1660 | version = "1.43.0" 1661 | source = "registry+https://github.com/rust-lang/crates.io-index" 1662 | checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" 1663 | dependencies = [ 1664 | "backtrace", 1665 | "bytes", 1666 | "libc", 1667 | "mio", 1668 | "parking_lot", 1669 | "pin-project-lite", 1670 | "signal-hook-registry", 1671 | "socket2", 1672 | "tokio-macros", 1673 | "windows-sys 0.52.0", 1674 | ] 1675 | 1676 | [[package]] 1677 | name = "tokio-macros" 1678 | version = "2.5.0" 1679 | source = "registry+https://github.com/rust-lang/crates.io-index" 1680 | checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 1681 | dependencies = [ 1682 | "proc-macro2", 1683 | "quote", 1684 | "syn", 1685 | ] 1686 | 1687 | [[package]] 1688 | name = "tokio-native-tls" 1689 | version = "0.3.1" 1690 | source = "registry+https://github.com/rust-lang/crates.io-index" 1691 | checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 1692 | dependencies = [ 1693 | "native-tls", 1694 | "tokio", 1695 | ] 1696 | 1697 | [[package]] 1698 | name = "tokio-rustls" 1699 | version = "0.26.1" 1700 | source = "registry+https://github.com/rust-lang/crates.io-index" 1701 | checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" 1702 | dependencies = [ 1703 | "rustls", 1704 | "tokio", 1705 | ] 1706 | 1707 | [[package]] 1708 | name = "tokio-util" 1709 | version = "0.7.13" 1710 | source = "registry+https://github.com/rust-lang/crates.io-index" 1711 | checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" 1712 | dependencies = [ 1713 | "bytes", 1714 | "futures-core", 1715 | "futures-sink", 1716 | "pin-project-lite", 1717 | "tokio", 1718 | ] 1719 | 1720 | [[package]] 1721 | name = "toml" 1722 | version = "0.8.19" 1723 | source = "registry+https://github.com/rust-lang/crates.io-index" 1724 | checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" 1725 | dependencies = [ 1726 | "serde", 1727 | "serde_spanned", 1728 | "toml_datetime", 1729 | "toml_edit", 1730 | ] 1731 | 1732 | [[package]] 1733 | name = "toml_datetime" 1734 | version = "0.6.8" 1735 | source = "registry+https://github.com/rust-lang/crates.io-index" 1736 | checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 1737 | dependencies = [ 1738 | "serde", 1739 | ] 1740 | 1741 | [[package]] 1742 | name = "toml_edit" 1743 | version = "0.22.22" 1744 | source = "registry+https://github.com/rust-lang/crates.io-index" 1745 | checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" 1746 | dependencies = [ 1747 | "indexmap", 1748 | "serde", 1749 | "serde_spanned", 1750 | "toml_datetime", 1751 | "winnow", 1752 | ] 1753 | 1754 | [[package]] 1755 | name = "tower" 1756 | version = "0.5.2" 1757 | source = "registry+https://github.com/rust-lang/crates.io-index" 1758 | checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" 1759 | dependencies = [ 1760 | "futures-core", 1761 | "futures-util", 1762 | "pin-project-lite", 1763 | "sync_wrapper", 1764 | "tokio", 1765 | "tower-layer", 1766 | "tower-service", 1767 | ] 1768 | 1769 | [[package]] 1770 | name = "tower-layer" 1771 | version = "0.3.3" 1772 | source = "registry+https://github.com/rust-lang/crates.io-index" 1773 | checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" 1774 | 1775 | [[package]] 1776 | name = "tower-service" 1777 | version = "0.3.3" 1778 | source = "registry+https://github.com/rust-lang/crates.io-index" 1779 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 1780 | 1781 | [[package]] 1782 | name = "tracing" 1783 | version = "0.1.41" 1784 | source = "registry+https://github.com/rust-lang/crates.io-index" 1785 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 1786 | dependencies = [ 1787 | "pin-project-lite", 1788 | "tracing-core", 1789 | ] 1790 | 1791 | [[package]] 1792 | name = "tracing-core" 1793 | version = "0.1.33" 1794 | source = "registry+https://github.com/rust-lang/crates.io-index" 1795 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 1796 | dependencies = [ 1797 | "once_cell", 1798 | ] 1799 | 1800 | [[package]] 1801 | name = "try-lock" 1802 | version = "0.2.5" 1803 | source = "registry+https://github.com/rust-lang/crates.io-index" 1804 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 1805 | 1806 | [[package]] 1807 | name = "unicode-ident" 1808 | version = "1.0.14" 1809 | source = "registry+https://github.com/rust-lang/crates.io-index" 1810 | checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" 1811 | 1812 | [[package]] 1813 | name = "unicode-width" 1814 | version = "0.1.14" 1815 | source = "registry+https://github.com/rust-lang/crates.io-index" 1816 | checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" 1817 | 1818 | [[package]] 1819 | name = "unicode-width" 1820 | version = "0.2.0" 1821 | source = "registry+https://github.com/rust-lang/crates.io-index" 1822 | checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" 1823 | 1824 | [[package]] 1825 | name = "untrusted" 1826 | version = "0.9.0" 1827 | source = "registry+https://github.com/rust-lang/crates.io-index" 1828 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1829 | 1830 | [[package]] 1831 | name = "url" 1832 | version = "2.5.4" 1833 | source = "registry+https://github.com/rust-lang/crates.io-index" 1834 | checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 1835 | dependencies = [ 1836 | "form_urlencoded", 1837 | "idna", 1838 | "percent-encoding", 1839 | ] 1840 | 1841 | [[package]] 1842 | name = "utf16_iter" 1843 | version = "1.0.5" 1844 | source = "registry+https://github.com/rust-lang/crates.io-index" 1845 | checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" 1846 | 1847 | [[package]] 1848 | name = "utf8_iter" 1849 | version = "1.0.4" 1850 | source = "registry+https://github.com/rust-lang/crates.io-index" 1851 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 1852 | 1853 | [[package]] 1854 | name = "utf8parse" 1855 | version = "0.2.2" 1856 | source = "registry+https://github.com/rust-lang/crates.io-index" 1857 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 1858 | 1859 | [[package]] 1860 | name = "vcpkg" 1861 | version = "0.2.15" 1862 | source = "registry+https://github.com/rust-lang/crates.io-index" 1863 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1864 | 1865 | [[package]] 1866 | name = "want" 1867 | version = "0.3.1" 1868 | source = "registry+https://github.com/rust-lang/crates.io-index" 1869 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1870 | dependencies = [ 1871 | "try-lock", 1872 | ] 1873 | 1874 | [[package]] 1875 | name = "wasi" 1876 | version = "0.11.0+wasi-snapshot-preview1" 1877 | source = "registry+https://github.com/rust-lang/crates.io-index" 1878 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1879 | 1880 | [[package]] 1881 | name = "wasm-bindgen" 1882 | version = "0.2.100" 1883 | source = "registry+https://github.com/rust-lang/crates.io-index" 1884 | checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" 1885 | dependencies = [ 1886 | "cfg-if", 1887 | "once_cell", 1888 | "rustversion", 1889 | "wasm-bindgen-macro", 1890 | ] 1891 | 1892 | [[package]] 1893 | name = "wasm-bindgen-backend" 1894 | version = "0.2.100" 1895 | source = "registry+https://github.com/rust-lang/crates.io-index" 1896 | checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" 1897 | dependencies = [ 1898 | "bumpalo", 1899 | "log", 1900 | "proc-macro2", 1901 | "quote", 1902 | "syn", 1903 | "wasm-bindgen-shared", 1904 | ] 1905 | 1906 | [[package]] 1907 | name = "wasm-bindgen-futures" 1908 | version = "0.4.50" 1909 | source = "registry+https://github.com/rust-lang/crates.io-index" 1910 | checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" 1911 | dependencies = [ 1912 | "cfg-if", 1913 | "js-sys", 1914 | "once_cell", 1915 | "wasm-bindgen", 1916 | "web-sys", 1917 | ] 1918 | 1919 | [[package]] 1920 | name = "wasm-bindgen-macro" 1921 | version = "0.2.100" 1922 | source = "registry+https://github.com/rust-lang/crates.io-index" 1923 | checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" 1924 | dependencies = [ 1925 | "quote", 1926 | "wasm-bindgen-macro-support", 1927 | ] 1928 | 1929 | [[package]] 1930 | name = "wasm-bindgen-macro-support" 1931 | version = "0.2.100" 1932 | source = "registry+https://github.com/rust-lang/crates.io-index" 1933 | checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" 1934 | dependencies = [ 1935 | "proc-macro2", 1936 | "quote", 1937 | "syn", 1938 | "wasm-bindgen-backend", 1939 | "wasm-bindgen-shared", 1940 | ] 1941 | 1942 | [[package]] 1943 | name = "wasm-bindgen-shared" 1944 | version = "0.2.100" 1945 | source = "registry+https://github.com/rust-lang/crates.io-index" 1946 | checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" 1947 | dependencies = [ 1948 | "unicode-ident", 1949 | ] 1950 | 1951 | [[package]] 1952 | name = "web-sys" 1953 | version = "0.3.77" 1954 | source = "registry+https://github.com/rust-lang/crates.io-index" 1955 | checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" 1956 | dependencies = [ 1957 | "js-sys", 1958 | "wasm-bindgen", 1959 | ] 1960 | 1961 | [[package]] 1962 | name = "winapi" 1963 | version = "0.3.9" 1964 | source = "registry+https://github.com/rust-lang/crates.io-index" 1965 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1966 | dependencies = [ 1967 | "winapi-i686-pc-windows-gnu", 1968 | "winapi-x86_64-pc-windows-gnu", 1969 | ] 1970 | 1971 | [[package]] 1972 | name = "winapi-i686-pc-windows-gnu" 1973 | version = "0.4.0" 1974 | source = "registry+https://github.com/rust-lang/crates.io-index" 1975 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1976 | 1977 | [[package]] 1978 | name = "winapi-x86_64-pc-windows-gnu" 1979 | version = "0.4.0" 1980 | source = "registry+https://github.com/rust-lang/crates.io-index" 1981 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1982 | 1983 | [[package]] 1984 | name = "windows-core" 1985 | version = "0.52.0" 1986 | source = "registry+https://github.com/rust-lang/crates.io-index" 1987 | checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 1988 | dependencies = [ 1989 | "windows-targets 0.52.6", 1990 | ] 1991 | 1992 | [[package]] 1993 | name = "windows-registry" 1994 | version = "0.2.0" 1995 | source = "registry+https://github.com/rust-lang/crates.io-index" 1996 | checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" 1997 | dependencies = [ 1998 | "windows-result", 1999 | "windows-strings", 2000 | "windows-targets 0.52.6", 2001 | ] 2002 | 2003 | [[package]] 2004 | name = "windows-result" 2005 | version = "0.2.0" 2006 | source = "registry+https://github.com/rust-lang/crates.io-index" 2007 | checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" 2008 | dependencies = [ 2009 | "windows-targets 0.52.6", 2010 | ] 2011 | 2012 | [[package]] 2013 | name = "windows-strings" 2014 | version = "0.1.0" 2015 | source = "registry+https://github.com/rust-lang/crates.io-index" 2016 | checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" 2017 | dependencies = [ 2018 | "windows-result", 2019 | "windows-targets 0.52.6", 2020 | ] 2021 | 2022 | [[package]] 2023 | name = "windows-sys" 2024 | version = "0.48.0" 2025 | source = "registry+https://github.com/rust-lang/crates.io-index" 2026 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 2027 | dependencies = [ 2028 | "windows-targets 0.48.5", 2029 | ] 2030 | 2031 | [[package]] 2032 | name = "windows-sys" 2033 | version = "0.52.0" 2034 | source = "registry+https://github.com/rust-lang/crates.io-index" 2035 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2036 | dependencies = [ 2037 | "windows-targets 0.52.6", 2038 | ] 2039 | 2040 | [[package]] 2041 | name = "windows-sys" 2042 | version = "0.59.0" 2043 | source = "registry+https://github.com/rust-lang/crates.io-index" 2044 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 2045 | dependencies = [ 2046 | "windows-targets 0.52.6", 2047 | ] 2048 | 2049 | [[package]] 2050 | name = "windows-targets" 2051 | version = "0.48.5" 2052 | source = "registry+https://github.com/rust-lang/crates.io-index" 2053 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 2054 | dependencies = [ 2055 | "windows_aarch64_gnullvm 0.48.5", 2056 | "windows_aarch64_msvc 0.48.5", 2057 | "windows_i686_gnu 0.48.5", 2058 | "windows_i686_msvc 0.48.5", 2059 | "windows_x86_64_gnu 0.48.5", 2060 | "windows_x86_64_gnullvm 0.48.5", 2061 | "windows_x86_64_msvc 0.48.5", 2062 | ] 2063 | 2064 | [[package]] 2065 | name = "windows-targets" 2066 | version = "0.52.6" 2067 | source = "registry+https://github.com/rust-lang/crates.io-index" 2068 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 2069 | dependencies = [ 2070 | "windows_aarch64_gnullvm 0.52.6", 2071 | "windows_aarch64_msvc 0.52.6", 2072 | "windows_i686_gnu 0.52.6", 2073 | "windows_i686_gnullvm", 2074 | "windows_i686_msvc 0.52.6", 2075 | "windows_x86_64_gnu 0.52.6", 2076 | "windows_x86_64_gnullvm 0.52.6", 2077 | "windows_x86_64_msvc 0.52.6", 2078 | ] 2079 | 2080 | [[package]] 2081 | name = "windows_aarch64_gnullvm" 2082 | version = "0.48.5" 2083 | source = "registry+https://github.com/rust-lang/crates.io-index" 2084 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 2085 | 2086 | [[package]] 2087 | name = "windows_aarch64_gnullvm" 2088 | version = "0.52.6" 2089 | source = "registry+https://github.com/rust-lang/crates.io-index" 2090 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 2091 | 2092 | [[package]] 2093 | name = "windows_aarch64_msvc" 2094 | version = "0.48.5" 2095 | source = "registry+https://github.com/rust-lang/crates.io-index" 2096 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 2097 | 2098 | [[package]] 2099 | name = "windows_aarch64_msvc" 2100 | version = "0.52.6" 2101 | source = "registry+https://github.com/rust-lang/crates.io-index" 2102 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 2103 | 2104 | [[package]] 2105 | name = "windows_i686_gnu" 2106 | version = "0.48.5" 2107 | source = "registry+https://github.com/rust-lang/crates.io-index" 2108 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 2109 | 2110 | [[package]] 2111 | name = "windows_i686_gnu" 2112 | version = "0.52.6" 2113 | source = "registry+https://github.com/rust-lang/crates.io-index" 2114 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 2115 | 2116 | [[package]] 2117 | name = "windows_i686_gnullvm" 2118 | version = "0.52.6" 2119 | source = "registry+https://github.com/rust-lang/crates.io-index" 2120 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 2121 | 2122 | [[package]] 2123 | name = "windows_i686_msvc" 2124 | version = "0.48.5" 2125 | source = "registry+https://github.com/rust-lang/crates.io-index" 2126 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 2127 | 2128 | [[package]] 2129 | name = "windows_i686_msvc" 2130 | version = "0.52.6" 2131 | source = "registry+https://github.com/rust-lang/crates.io-index" 2132 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 2133 | 2134 | [[package]] 2135 | name = "windows_x86_64_gnu" 2136 | version = "0.48.5" 2137 | source = "registry+https://github.com/rust-lang/crates.io-index" 2138 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 2139 | 2140 | [[package]] 2141 | name = "windows_x86_64_gnu" 2142 | version = "0.52.6" 2143 | source = "registry+https://github.com/rust-lang/crates.io-index" 2144 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 2145 | 2146 | [[package]] 2147 | name = "windows_x86_64_gnullvm" 2148 | version = "0.48.5" 2149 | source = "registry+https://github.com/rust-lang/crates.io-index" 2150 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 2151 | 2152 | [[package]] 2153 | name = "windows_x86_64_gnullvm" 2154 | version = "0.52.6" 2155 | source = "registry+https://github.com/rust-lang/crates.io-index" 2156 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 2157 | 2158 | [[package]] 2159 | name = "windows_x86_64_msvc" 2160 | version = "0.48.5" 2161 | source = "registry+https://github.com/rust-lang/crates.io-index" 2162 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 2163 | 2164 | [[package]] 2165 | name = "windows_x86_64_msvc" 2166 | version = "0.52.6" 2167 | source = "registry+https://github.com/rust-lang/crates.io-index" 2168 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2169 | 2170 | [[package]] 2171 | name = "winnow" 2172 | version = "0.6.24" 2173 | source = "registry+https://github.com/rust-lang/crates.io-index" 2174 | checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" 2175 | dependencies = [ 2176 | "memchr", 2177 | ] 2178 | 2179 | [[package]] 2180 | name = "write16" 2181 | version = "1.0.0" 2182 | source = "registry+https://github.com/rust-lang/crates.io-index" 2183 | checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" 2184 | 2185 | [[package]] 2186 | name = "writeable" 2187 | version = "0.5.5" 2188 | source = "registry+https://github.com/rust-lang/crates.io-index" 2189 | checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" 2190 | 2191 | [[package]] 2192 | name = "yoke" 2193 | version = "0.7.5" 2194 | source = "registry+https://github.com/rust-lang/crates.io-index" 2195 | checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" 2196 | dependencies = [ 2197 | "serde", 2198 | "stable_deref_trait", 2199 | "yoke-derive", 2200 | "zerofrom", 2201 | ] 2202 | 2203 | [[package]] 2204 | name = "yoke-derive" 2205 | version = "0.7.5" 2206 | source = "registry+https://github.com/rust-lang/crates.io-index" 2207 | checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" 2208 | dependencies = [ 2209 | "proc-macro2", 2210 | "quote", 2211 | "syn", 2212 | "synstructure", 2213 | ] 2214 | 2215 | [[package]] 2216 | name = "zerocopy" 2217 | version = "0.7.35" 2218 | source = "registry+https://github.com/rust-lang/crates.io-index" 2219 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 2220 | dependencies = [ 2221 | "byteorder", 2222 | "zerocopy-derive", 2223 | ] 2224 | 2225 | [[package]] 2226 | name = "zerocopy-derive" 2227 | version = "0.7.35" 2228 | source = "registry+https://github.com/rust-lang/crates.io-index" 2229 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 2230 | dependencies = [ 2231 | "proc-macro2", 2232 | "quote", 2233 | "syn", 2234 | ] 2235 | 2236 | [[package]] 2237 | name = "zerofrom" 2238 | version = "0.1.5" 2239 | source = "registry+https://github.com/rust-lang/crates.io-index" 2240 | checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" 2241 | dependencies = [ 2242 | "zerofrom-derive", 2243 | ] 2244 | 2245 | [[package]] 2246 | name = "zerofrom-derive" 2247 | version = "0.1.5" 2248 | source = "registry+https://github.com/rust-lang/crates.io-index" 2249 | checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" 2250 | dependencies = [ 2251 | "proc-macro2", 2252 | "quote", 2253 | "syn", 2254 | "synstructure", 2255 | ] 2256 | 2257 | [[package]] 2258 | name = "zeroize" 2259 | version = "1.8.1" 2260 | source = "registry+https://github.com/rust-lang/crates.io-index" 2261 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 2262 | 2263 | [[package]] 2264 | name = "zerovec" 2265 | version = "0.10.4" 2266 | source = "registry+https://github.com/rust-lang/crates.io-index" 2267 | checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" 2268 | dependencies = [ 2269 | "yoke", 2270 | "zerofrom", 2271 | "zerovec-derive", 2272 | ] 2273 | 2274 | [[package]] 2275 | name = "zerovec-derive" 2276 | version = "0.10.3" 2277 | source = "registry+https://github.com/rust-lang/crates.io-index" 2278 | checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" 2279 | dependencies = [ 2280 | "proc-macro2", 2281 | "quote", 2282 | "syn", 2283 | ] 2284 | --------------------------------------------------------------------------------