├── .gitignore ├── i18n.toml ├── src ├── main.rs ├── frontend │ ├── mod.rs │ ├── cli.rs │ └── tui.rs ├── desktop │ ├── mod.rs │ └── kde5.rs ├── i18n.rs ├── parser.rs ├── pk │ ├── packagekit.rs │ ├── packagekit_tx.rs │ └── mod.rs ├── network.rs └── pm.rs ├── README.md ├── .github └── workflows │ └── ci.yml ├── io.aosc.atm.apply.policy ├── Cargo.toml ├── i18n ├── zh-CN │ └── atm.ftl └── en-US │ └── atm.ftl ├── dbus-xml └── org.freedesktop.PackageKit.xml └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /i18n.toml: -------------------------------------------------------------------------------- 1 | fallback_language = "en-US" 2 | 3 | # Use the fluent localization system. 4 | [fluent] 5 | # The paths inside the assets directory should be structured like so: 6 | # `assets_dir/{language}/{domain}.ftl` 7 | assets_dir = "i18n" 8 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod desktop; 2 | mod frontend; 3 | mod i18n; 4 | mod network; 5 | mod parser; 6 | mod pk; 7 | mod pm; 8 | 9 | use i18n::I18N_LOADER; 10 | 11 | fn main() { 12 | let cli_result = frontend::cli::cli_main(); 13 | if !cli_result { 14 | frontend::tui::tui_main(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/frontend/mod.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | use time::{format_description::FormatItem, macros::format_description}; 3 | 4 | pub mod cli; 5 | pub mod tui; 6 | 7 | const DATE_FORMAT: &[FormatItem] = format_description!("[year]-[month repr:numerical]-[day]"); 8 | 9 | #[inline] 10 | pub(crate) fn format_timestamp(t: i64) -> Result { 11 | Ok(time::OffsetDateTime::from_unix_timestamp(t)?.format(&DATE_FORMAT)?) 12 | } 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AOSC OS APT Topic Manager 2 | 3 | This is the AOSC OS APT topic manager. It manages the topics selection for the AOSC OS. 4 | 5 | This project is part of the AOSC infrastructures. 6 | 7 | ## Building 8 | 9 | Just run `cargo build --release` and wait. 10 | 11 | ## Usage 12 | 13 | Run `./atm` to operate. 14 | 15 | This program features a TUI interface, use arrow keys to navigate and Enter key to select/deselect a topic. 16 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Install dependencies 20 | run: sudo apt-get install -y libncurses5-dev pkg-config libdbus-1-dev 21 | - name: Build 22 | run: cargo build 23 | - name: Run tests 24 | run: cargo test 25 | -------------------------------------------------------------------------------- /src/desktop/mod.rs: -------------------------------------------------------------------------------- 1 | mod kde5; 2 | 3 | pub trait ProgressTracker { 4 | fn set_percent(&mut self, percent: u32); 5 | fn set_general_description(&mut self, description: &str); 6 | fn set_message(&mut self, label: &str, message: &str); 7 | fn terminate(&mut self, message: &str); 8 | } 9 | 10 | pub use kde5::KF5Tracker; 11 | 12 | pub struct DummyTracker; 13 | 14 | impl ProgressTracker for DummyTracker { 15 | fn set_percent(&mut self, _: u32) {} 16 | 17 | fn set_general_description(&mut self, _: &str) {} 18 | 19 | fn set_message(&mut self, _: &str, _: &str) {} 20 | 21 | fn terminate(&mut self, _: &str) {} 22 | } 23 | 24 | impl DummyTracker { 25 | pub fn new() -> Self { 26 | Self {} 27 | } 28 | } 29 | 30 | pub fn select_best_tracker() -> Box { 31 | let kf5 = KF5Tracker::new("atm"); 32 | match kf5 { 33 | Ok(t) => Box::new(t), 34 | Err(_) => Box::new(DummyTracker::new()), 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /io.aosc.atm.apply.policy: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | Anthon Open Source Community 7 | https://github.com/AOSC-Dev/atm 8 | 9 | 10 | Apply ATM configurations 11 | 应用 ATM 的配置 12 | Authentication is required to apply topic changes 13 | ATM 需要您的授权才能应用分支修改 14 | preferences-system 15 | 16 | no 17 | no 18 | auth_admin_keep 19 | 20 | /usr/bin/atm 21 | refresh 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/i18n.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | use i18n_embed::{ 3 | fluent::{fluent_language_loader, FluentLanguageLoader}, 4 | DesktopLanguageRequester, LanguageLoader, 5 | }; 6 | use lazy_static::lazy_static; 7 | use rust_embed::RustEmbed; 8 | 9 | #[macro_export] 10 | macro_rules! fl { 11 | ($message_id:literal) => {{ 12 | i18n_embed_fl::fl!($crate::I18N_LOADER, $message_id) 13 | }}; 14 | 15 | ($message_id:literal, $($args:expr),*) => {{ 16 | i18n_embed_fl::fl!($crate::I18N_LOADER, $message_id, $($args), *) 17 | }}; 18 | } 19 | 20 | lazy_static! { 21 | pub static ref I18N_LOADER: FluentLanguageLoader = 22 | load_i18n().expect("Unable to load i18n strings."); 23 | } 24 | 25 | #[derive(RustEmbed)] 26 | #[folder = "i18n"] 27 | struct Localizations; 28 | 29 | fn load_i18n() -> Result { 30 | let language_loader: FluentLanguageLoader = fluent_language_loader!(); 31 | let mut requested_languages = DesktopLanguageRequester::requested_languages(); 32 | requested_languages.push("en-US".parse().unwrap()); 33 | language_loader.load_languages(&Localizations, &requested_languages)?; 34 | 35 | Ok(language_loader) 36 | } 37 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "atm" 3 | version = "0.6.2" 4 | authors = ["liushuyu "] 5 | edition = "2018" 6 | 7 | 8 | [dependencies] 9 | anyhow = "1.0" 10 | time = { version = "0.3", features = ["formatting", "macros"] } 11 | serde = { version = "1.0", features = ["derive"] } 12 | serde_json = "1.0" 13 | lazy_static = "1.5" 14 | reqwest = { version = "0.12", features = ["json"] } 15 | winnow = "0.7" 16 | nix = { version = "0.29", features = ["user"] } 17 | tempfile = "3.19" 18 | sha2 = "0.10" 19 | # tui 20 | cursive = { version = "0.21", features = ["crossterm-backend"], default-features = false } 21 | cursive_table_view = "0.15" 22 | cursive-async-view = "0.8" 23 | indexmap = { version = "^2", features = ["serde"] } 24 | dashmap = "^6" 25 | # cli 26 | argh = "0.1" 27 | tabwriter = "^1" 28 | # packagekit related 29 | zbus = { version = "^5", default-features = false, features = ["tokio"] } 30 | tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros", "fs", "process"] } 31 | futures = "0.3" 32 | # i18n 33 | i18n-embed = { version = "0.15", features = ["fluent-system", "desktop-requester"]} 34 | i18n-embed-fl = "0.9" 35 | rust-embed = "^8" 36 | unic-langid = "0.9" 37 | 38 | [profile.release] 39 | lto = true 40 | -------------------------------------------------------------------------------- /i18n/zh-CN/atm.ftl: -------------------------------------------------------------------------------- 1 | message = 信息 2 | exit = 退出 3 | cancel = 取消 4 | proceed = 继续 5 | error = 错误 6 | ok = 确定 7 | closed = [已关闭] 8 | name = 名称 9 | date = 日期 10 | description = 描述 11 | topic_selection = 选择尝鲜分支 12 | topic-selection-description = 如下是当前可用于测试的尝鲜分支列表。选中一个或多个尝鲜分支即可获得测试用更新, 13 | 反选即可回滚软件包到稳定版本。请使用方向键浏览,并用回车键 (Enter) 选择分支。 14 | topic_selection_closed_topic_warning = 检测到已关闭或已合并的尝鲜分支,ATM 将会把受影响的包回滚到稳定版本。 15 | 16 | refresh-manifest = 正在下载分支信息…… 17 | refresh-apt = 正在下载软件包信息…… 18 | error-initialize = 无法初始化 D-Bus 接口:{$error}. 19 | nothing = 无待办事项。 20 | dpkg_error = dpkg 返回错误码:{$status} 21 | no_stable_version = 提示:无法降级 {$count} 个软件包到稳定版本。 22 | install_count = 将额外安装 {$count} 个软件包 23 | erase_count = 将卸载 {$count} 个软件包 24 | update_count = 将升级或降级 {$count} 个软件包 25 | package_path_error = 无法解析软件包路径。 26 | disk_space_decrease = 该操作将使用 {$size} 存储空间。 27 | disk_space_increase = 该操作将释放 {$size} 存储空间。 28 | details = 详情 29 | tx_title = 操作详情 30 | tx_body = 将进行如下操作: 31 | tx_hold = 保持不变:{$package}(无稳定版本) 32 | tx_install = 安装:{$package}({$version}) 33 | tx_upgrade = 升级:{$package}(至 {$version}) 34 | tx_downgrade = 降级:{$package}(至 {$version}) 35 | tx_erase = 卸载:{$package}({$version}) 36 | 37 | pk_metered_network = 您似乎正在使用计费网络或移动数据流量。 38 | 39 | ATM 在执行任务时可能会从网络下载大量数据。您确定要继续吗? 40 | pk_battery = 您的电脑目前似乎正在使用电池供电。 41 | 42 | ATM 在执行任务时可能会消耗大量电量,推荐您接入交流电源以防断电导致数据损坏。 43 | 您确定要继续吗? 44 | pk_inhibit_message = ATM 正在点钞 45 | pk_dbus_error = 无法连接到系统 D-Bus 总线:{$error} 46 | pk_comm_error_mid_tx = PackageKit 守护程序连接丢失或在执行任务时突然崩溃。 47 | 48 | 您的系统目前可能处于不稳定状态并需要您手动修复。请退出 ATM 并在终端中运行 49 | 50 | `apt install -f` 51 | 52 | 以尝试解决问题。 53 | 54 | 错误信息:{$error} 55 | pk_comm_error = 无法与 PackageKit 守护程序通信:{$error} 56 | pk_tx_error = PackageKit 守护程序报错:{$error} 57 | pk_comm_no_response = PackageKit 守护程序无响应。 58 | pk_invalid_id = 包名 "{$name}" 无效。 59 | 60 | 程序发生了未预期错误,请于 https://github.com/AOSC-Dev/atm/issues/new 报告该问题。 61 | 62 | exe-title = 正在执行任务 63 | exe-prepare = 正在准备 …… 64 | exe-overall = 总进度: 65 | exe_download = 正在下载 {$name} …… 66 | exe-install = 正在安装 {$name} …… 67 | exe-setup = 正在配置 {$name} …… 68 | info-status = 当前状态 69 | info-title = ATM 正在应用系统更改 …… 70 | exe_download_file_error = 无法下载:{$name} 71 | exe_download_error = 无法下载文件 72 | #exe_verify_error = 校验出错:{$name} 73 | #exe_path_error = 未知文件名:{$name} 74 | #exe_batch_error = 无法下载软件包 75 | 76 | apt_finished = APT 配置信息更新成功。 77 | install_error = 安装软件包时发生错误:{$error} 78 | 79 | #press_enter_to_return = 请按 Enter 键返回主菜单。 80 | press_enter_to_bail = 请按 Enter 键退出程序。 81 | 82 | ## CLI messages 83 | 84 | needs-root = 请使用 root 用户运行本程序! 85 | topic-table-hint = `*` 标记代表已选中或订阅该尝鲜分支。 86 | fetch-error-fallback = [!] 无法获取可用尝鲜分支列表,目前只显示了已订阅的尝鲜分支。 87 | 88 | ## Authentication messages 89 | 90 | await-authentication = 正在等待认证 …… 91 | authentication-failure = 认证失败:{$reason} 92 | -run-me-as-root-workaround = 目前的更改尚未生效。 93 | 94 | 请使用 root 用户运行 ATM 解决此问题。 95 | sudo-failure = ATM 无法找到任何可用的提权工具。 96 | 97 | { -run-me-as-root-workaround } 98 | headless-sudo-unsupported = ATM 不支持无交互提权。 99 | 100 | { -run-me-as-root-workaround } 101 | 102 | file-header = 本文件由 AOSC Topic Manager 生成,请勿修改! 103 | -------------------------------------------------------------------------------- /src/parser.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{anyhow, Result}; 2 | use std::collections::HashSet; 3 | use winnow::{ 4 | ascii::space0, 5 | combinator::{repeat, separated_pair, terminated}, 6 | token::{literal, one_of, take_until}, 7 | Parser, Result as IResult, 8 | }; 9 | 10 | #[inline] 11 | fn key_name<'a>(input: &mut &'a [u8]) -> IResult<&'a [u8]> { 12 | take_until(0.., ":") 13 | .verify(|input: &[u8]| !input.is_empty() && input[0] != b'\n') 14 | .parse_next(input) 15 | } 16 | 17 | #[inline] 18 | fn separator(input: &mut &[u8]) -> IResult<()> { 19 | (one_of(':'), space0).void().parse_next(input) 20 | } 21 | 22 | #[inline] 23 | fn single_line<'a>(input: &mut &'a [u8]) -> IResult<&'a [u8]> { 24 | take_until(0.., "\n").parse_next(input) 25 | } 26 | 27 | #[inline] 28 | fn key_value<'a>(input: &mut &'a [u8]) -> IResult<(&'a [u8], &'a [u8])> { 29 | separated_pair(key_name, separator, single_line).parse_next(input) 30 | } 31 | 32 | #[inline] 33 | fn single_package<'a>(input: &mut &'a [u8]) -> IResult> { 34 | repeat(1.., terminated(key_value, literal("\n"))).parse_next(input) 35 | } 36 | 37 | #[inline] 38 | fn extract_name<'a>(input: &mut &'a [u8]) -> IResult<&'a [u8]> { 39 | let info = single_package(input)?; 40 | let mut found: Option<&[u8]> = None; 41 | for i in info { 42 | if i.0 == &b"Package"[..] { 43 | found = Some(i.1); 44 | } 45 | if i.0 == &b"Status"[..] && i.1.len() > 8 && i.1[..8] == b"install "[..] && found.is_some() 46 | { 47 | return Ok(found.unwrap()); 48 | } 49 | } 50 | 51 | Ok(&[]) 52 | } 53 | 54 | #[inline] 55 | pub fn extract_all_names<'a>(input: &mut &'a [u8]) -> IResult> { 56 | repeat(1.., terminated(extract_name, literal("\n"))).parse_next(input) 57 | } 58 | 59 | pub fn list_installed(input: &mut &[u8]) -> Result> { 60 | let names = extract_all_names(input); 61 | let mut result: HashSet = HashSet::new(); 62 | for name in names.map_err(|_| anyhow!("Failed to parse dpkg status file"))? { 63 | if name.is_empty() { 64 | continue; 65 | } 66 | result.insert(String::from_utf8_lossy(name).to_string()); 67 | } 68 | 69 | Ok(result) 70 | } 71 | 72 | // tests 73 | #[test] 74 | fn test_key_name() { 75 | let mut test = &b"name: value"[..]; 76 | assert_eq!(key_name(&mut test), Ok(&b"name"[..])); 77 | } 78 | 79 | #[test] 80 | fn test_seperator() { 81 | let mut test = &b": value"[..]; 82 | let mut test_2 = &b": \tvalue"[..]; 83 | assert_eq!(separator(&mut test), Ok(())); 84 | assert_eq!(separator(&mut test_2), Ok(())); 85 | } 86 | 87 | #[test] 88 | fn test_single_line() { 89 | let mut test = &b"value\n"[..]; 90 | let mut test_2 = &b"value\t\r\n"[..]; 91 | let mut test_3 = &b"value \x23\xff\n"[..]; 92 | assert_eq!(single_line(&mut test), Ok(&b"value"[..])); 93 | assert_eq!(single_line(&mut test_2), Ok(&b"value\t\r"[..])); 94 | assert_eq!(single_line(&mut test_3), Ok(&b"value \x23\xff"[..])); 95 | } 96 | 97 | #[test] 98 | fn test_key_value() { 99 | let mut test = &b"name1: value\n"[..]; 100 | let mut test_2 = &b"name2: value\t\r\n"[..]; 101 | let mut test_3 = &b"name3: value \x23\xff\n"[..]; 102 | assert_eq!(key_value(&mut test), Ok((&b"name1"[..], &b"value"[..]))); 103 | assert_eq!( 104 | key_value(&mut test_2), 105 | Ok((&b"name2"[..], &b"value\t\r"[..])) 106 | ); 107 | assert_eq!( 108 | key_value(&mut test_3), 109 | Ok((&b"name3"[..], &b"value \x23\xff"[..])) 110 | ); 111 | } 112 | 113 | #[test] 114 | fn test_package() { 115 | let test = &b"Package: zsync\nVersion: 0.6.2-1\nStatus: install ok installed\nArchitecture: amd64\nInstalled-Size: 256\n\n"[..]; 116 | assert_eq!( 117 | single_package(&mut test.as_ref()), 118 | Ok(vec![ 119 | (&b"Package"[..], &b"zsync"[..]), 120 | (&b"Version"[..], &b"0.6.2-1"[..]), 121 | (&b"Status"[..], &b"install ok installed"[..]), 122 | (&b"Architecture"[..], &b"amd64"[..]), 123 | (&b"Installed-Size"[..], &b"256"[..]) 124 | ]) 125 | ); 126 | assert_eq!(extract_name(&mut test.as_ref()), Ok(&b"zsync"[..])); 127 | } 128 | 129 | #[test] 130 | fn test_multi_package() { 131 | let mut test = 132 | &b"Package: zsync\nStatus: b\n\nPackage: rsync\nStatus: install ok installed\n\n"[..]; 133 | assert_eq!( 134 | extract_all_names(&mut test), 135 | Ok(vec![&b""[..], &b"rsync"[..]]) 136 | ); 137 | } 138 | -------------------------------------------------------------------------------- /src/desktop/kde5.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] // for generated code 2 | 3 | use zbus::proxy; 4 | 5 | // generated code --> 6 | 7 | #[proxy( 8 | interface = "org.kde.JobViewServerV2", 9 | default_service = "org.kde.kuiserver", 10 | default_path = "/JobViewServer" 11 | )] 12 | trait JobViewServerV2 { 13 | /// requestView method 14 | #[zbus(name = "requestView", object = "JobViewV2")] 15 | fn request_view( 16 | &self, 17 | desktopEntry: &str, 18 | capabilities: i32, 19 | hints: std::collections::HashMap<&str, zbus::zvariant::Value<'_>>, 20 | ) -> zbus::Result; 21 | } 22 | 23 | #[proxy(interface = "org.kde.JobViewV2", default_service = "org.kde.kuiserver")] 24 | trait JobViewV2 { 25 | /// clearDescriptionField method 26 | fn clear_description_field(&self, number: u32) -> zbus::Result<()>; 27 | 28 | /// setDescriptionField method 29 | #[zbus(name = "setDescriptionField")] 30 | fn set_description_field(&self, number: u32, name: &str, value: &str) -> zbus::Result; 31 | 32 | /// setDestUrl method 33 | // fn set_dest_url(&self, destUrl: &zbus::zvariant::Value<'_>) -> zbus::Result<()>; 34 | 35 | /// setError method 36 | // fn set_error(&self, errorCode: u32) -> zbus::Result<()>; 37 | 38 | /// setInfoMessage method 39 | #[zbus(name = "setInfoMessage")] 40 | fn set_info_message(&self, message: &str) -> zbus::Result<()>; 41 | 42 | /// setPercent method 43 | #[zbus(name = "setPercent")] 44 | fn set_percent(&self, percent: u32) -> zbus::Result<()>; 45 | 46 | /// setProcessedAmount method 47 | fn set_processed_amount(&self, amount: u64, unit: &str) -> zbus::Result<()>; 48 | 49 | /// setSpeed method 50 | // fn set_speed(&self, bytesPerSecond: u64) -> zbus::Result<()>; 51 | 52 | /// setSuspended method 53 | fn set_suspended(&self, suspended: bool) -> zbus::Result<()>; 54 | 55 | /// setTotalAmount method 56 | fn set_total_amount(&self, amount: u64, unit: &str) -> zbus::Result<()>; 57 | 58 | /// terminate method 59 | #[zbus(name = "terminate")] 60 | fn terminate(&self, errorMessage: &str) -> zbus::Result<()>; 61 | 62 | /// cancelRequested signal 63 | #[zbus(signal)] 64 | fn cancel_requested(&self) -> zbus::Result<()>; 65 | 66 | /// resumeRequested signal 67 | #[zbus(signal)] 68 | fn resume_requested(&self) -> zbus::Result<()>; 69 | 70 | /// suspendRequested signal 71 | #[zbus(signal)] 72 | fn suspend_requested(&self) -> zbus::Result<()>; 73 | } 74 | 75 | // <-- end of generated code 76 | 77 | // implementation for progress tracker 78 | use super::ProgressTracker; 79 | 80 | use anyhow::Result; 81 | 82 | pub struct KF5Tracker<'a> { 83 | async_runner: tokio::runtime::Runtime, 84 | // pub dbus_connection: zbus::Connection, 85 | job_proxy: JobViewV2Proxy<'a>, 86 | } 87 | 88 | impl ProgressTracker for KF5Tracker<'_> { 89 | fn set_percent(&mut self, percent: u32) { 90 | self.async_runner 91 | .block_on(self.job_proxy.set_percent(percent)) 92 | .ok(); 93 | } 94 | 95 | fn set_general_description(&mut self, description: &str) { 96 | self.async_runner 97 | .block_on(self.job_proxy.set_info_message(description)) 98 | .ok(); 99 | } 100 | 101 | fn set_message(&mut self, label: &str, message: &str) { 102 | self.async_runner 103 | .block_on(self.job_proxy.set_description_field(0, label, message)) 104 | .ok(); 105 | } 106 | 107 | fn terminate(&mut self, message: &str) { 108 | self.async_runner 109 | .block_on(self.job_proxy.terminate(message)) 110 | .ok(); 111 | } 112 | } 113 | 114 | fn create_async_runner() -> Result { 115 | tokio::runtime::Builder::new_current_thread() 116 | .enable_all() 117 | .build() 118 | } 119 | 120 | impl KF5Tracker<'_> { 121 | pub fn new(app_id: &str) -> Result { 122 | let runner = create_async_runner()?; 123 | let (_, proxy) = runner.block_on(async { 124 | let conn = zbus::Connection::session().await?; 125 | let server = JobViewServerV2Proxy::new(&conn).await?; 126 | let proxy = server 127 | .request_view(app_id, 0, std::collections::HashMap::new()) 128 | .await?; 129 | 130 | Ok::<_, anyhow::Error>((conn, proxy)) 131 | })?; 132 | 133 | Ok(Self { 134 | async_runner: runner, 135 | // dbus_connection: connection, 136 | job_proxy: proxy, 137 | }) 138 | } 139 | } 140 | 141 | impl Drop for KF5Tracker<'_> { 142 | fn drop(&mut self) { 143 | self.terminate("") 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/pk/packagekit.rs: -------------------------------------------------------------------------------- 1 | //! # DBus interface proxies for: `org.freedesktop.PackageKit`, `org.freedesktop.PackageKit.Offline` 2 | //! 3 | //! This code was generated by `zbus-xmlgen` `2.0.1` from DBus introspection data. 4 | //! Source: `Interface '/org/freedesktop/PackageKit' from service 'org.freedesktop.PackageKit' on system bus`. 5 | //! 6 | //! You may prefer to adapt it, instead of using it verbatim. 7 | //! 8 | //! More information can be found in the 9 | //! [Writing a client proxy](https://dbus.pages.freedesktop.org/zbus/client.html) 10 | //! section of the zbus documentation. 11 | //! 12 | //! This DBus object implements 13 | //! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html), 14 | //! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used: 15 | //! 16 | //! * [`zbus::fdo::PropertiesProxy`] 17 | //! * [`zbus::fdo::IntrospectableProxy`] 18 | //! * [`zbus::fdo::PeerProxy`] 19 | //! 20 | //! …consequently `zbus-xmlgen` did not generate code for the above interfaces. 21 | 22 | use zbus::proxy; 23 | 24 | use crate::pk::TransactionProxy; 25 | 26 | #[proxy( 27 | interface = "org.freedesktop.PackageKit", 28 | default_service = "org.freedesktop.PackageKit", 29 | default_path = "/org/freedesktop/PackageKit", 30 | assume_defaults = true 31 | )] 32 | pub trait PackageKit { 33 | /// CanAuthorize method 34 | fn can_authorize(&self, action_id: &str) -> zbus::Result; 35 | 36 | /// CreateTransaction method 37 | #[zbus(object = "Transaction")] 38 | fn create_transaction(&self) -> zbus::Result; 39 | 40 | /// GetDaemonState method 41 | fn get_daemon_state(&self) -> zbus::Result; 42 | 43 | /// GetPackageHistory method 44 | fn get_package_history( 45 | &self, 46 | names: &[&str], 47 | count: u32, 48 | ) -> zbus::Result< 49 | std::collections::HashMap< 50 | String, 51 | Vec>, 52 | >, 53 | >; 54 | 55 | /// GetTimeSinceAction method 56 | fn get_time_since_action(&self, role: u32) -> zbus::Result; 57 | 58 | /// GetTransactionList method 59 | fn get_transaction_list(&self) -> zbus::Result>; 60 | 61 | /// SetProxy method 62 | fn set_proxy( 63 | &self, 64 | proxy_http: &str, 65 | proxy_https: &str, 66 | proxy_ftp: &str, 67 | proxy_socks: &str, 68 | no_proxy: &str, 69 | pac: &str, 70 | ) -> zbus::Result<()>; 71 | 72 | /// StateHasChanged method 73 | fn state_has_changed(&self, reason: &str) -> zbus::Result<()>; 74 | 75 | /// SuggestDaemonQuit method 76 | fn suggest_daemon_quit(&self) -> zbus::Result<()>; 77 | 78 | /// RepoListChanged signal 79 | #[zbus(signal)] 80 | fn repo_list_changed(&self) -> zbus::Result<()>; 81 | 82 | /// RestartSchedule signal 83 | #[zbus(signal)] 84 | fn restart_schedule(&self) -> zbus::Result<()>; 85 | 86 | /// TransactionListChanged signal 87 | #[zbus(signal)] 88 | fn transaction_list_changed(&self, transactions: Vec<&str>) -> zbus::Result<()>; 89 | 90 | /// UpdatesChanged signal 91 | #[zbus(signal)] 92 | fn updates_changed(&self) -> zbus::Result<()>; 93 | 94 | /// BackendAuthor property 95 | #[zbus(property)] 96 | fn backend_author(&self) -> zbus::Result; 97 | 98 | /// BackendDescription property 99 | #[zbus(property)] 100 | fn backend_description(&self) -> zbus::Result; 101 | 102 | /// BackendName property 103 | #[zbus(property)] 104 | fn backend_name(&self) -> zbus::Result; 105 | 106 | /// DistroId property 107 | #[zbus(property)] 108 | fn distro_id(&self) -> zbus::Result; 109 | 110 | /// Filters property 111 | #[zbus(property)] 112 | fn filters(&self) -> zbus::Result; 113 | 114 | /// Groups property 115 | #[zbus(property)] 116 | fn groups(&self) -> zbus::Result; 117 | 118 | /// Locked property 119 | #[zbus(property)] 120 | fn locked(&self) -> zbus::Result; 121 | 122 | /// MimeTypes property 123 | #[zbus(property)] 124 | fn mime_types(&self) -> zbus::Result>; 125 | 126 | /// NetworkState property 127 | #[zbus(property)] 128 | fn network_state(&self) -> zbus::Result; 129 | 130 | /// Roles property 131 | #[zbus(property)] 132 | fn roles(&self) -> zbus::Result; 133 | 134 | /// VersionMajor property 135 | #[zbus(property)] 136 | fn version_major(&self) -> zbus::Result; 137 | 138 | /// VersionMicro property 139 | #[zbus(property)] 140 | fn version_micro(&self) -> zbus::Result; 141 | 142 | /// VersionMinor property 143 | #[zbus(property)] 144 | fn version_minor(&self) -> zbus::Result; 145 | } 146 | -------------------------------------------------------------------------------- /i18n/en-US/atm.ftl: -------------------------------------------------------------------------------- 1 | message = Message 2 | exit = Exit 3 | cancel = Cancel 4 | proceed = Proceed 5 | error = Error 6 | ok = OK 7 | closed = [closed] 8 | name = Name 9 | date = Date 10 | description = Description 11 | topic_selection = Topic Selection 12 | topic-selection-description = Here below is a list of active update topics available for early adoption. 13 | Select one or more topic to enroll in update testing, deselect to withdraw and rollback to stable packages. 14 | Use arrow keys to navigate and use Enter to select/deselect. 15 | topic_selection_closed_topic_warning = Closed/graduated topics detected, ATM will refresh all packages affected by these topics with versions found in the stable repository. 16 | 17 | refresh-manifest = Fetching manifest... 18 | refresh-apt = Downloading packages information... 19 | error-initialize = Failed to initialize the D-Bus connector: {$error}. 20 | error-fetch-manifest = Failed to fetch topics information: {$error}. 21 | nothing = Nothing to do. 22 | dpkg_error = dpkg returned error: {$status} 23 | no_stable_version = {$count -> 24 | [one] Notice: there is one package that does not have a stable version to downgrade to. 25 | *[other] Notice: {$count} packages could not be downgraded to their stable versions. 26 | } 27 | install_count = {$count -> 28 | [one] One additional package will be installed 29 | *[other] {$count} additional packages will be installed 30 | } 31 | erase_count = {$count -> 32 | [one] one package will be uninstalled 33 | *[other] {$count} packages will be uninstalled 34 | } 35 | update_count = {$count -> 36 | [one] one package will be upgraded or downgraded 37 | *[other] {$count} packages will be upgraded or downgraded 38 | } 39 | package_path_error = Package path could not be parsed. 40 | #disk_space_decrease = After this operation, {$size} of additional disk space will be used. 41 | #disk_space_increase = After this operation, {$size} of additional disk space will be freed. 42 | details = Details 43 | tx_title = Transaction Details 44 | tx_body = The following operations will be performed: 45 | tx_hold = Kept Back: {$package} (No stable version) 46 | tx_install = Install: {$package} ({$version}) 47 | tx_upgrade = Upgrade: {$package} (To {$version}) 48 | tx_downgrade = Downgrade: {$package} (To {$version}) 49 | tx_erase = Erase: {$package} ({$version}) 50 | 51 | pk_metered_network = You seem to be on a metered or celluar network. 52 | 53 | ATM may consume a large amount of network data during the transaction. 54 | Do you still wish to continue? 55 | pk_battery = You seem to be on battery power. 56 | 57 | ATM may deplete the battery rather quickly during the transaction. 58 | It is recommended to plug in the power supply to prevent sudden power failure. 59 | Do you still wish to continue? 60 | pk_inhibit_message = ATM transaction is in progress 61 | pk_dbus_error = Failed to connect to D-Bus system bus: {$error} 62 | pk_comm_error_mid_tx = PackageKit daemon unexpectedly disconnected or crashed mid-transaction. 63 | 64 | Your system is likely in an inconsistent state and requires repairing. 65 | Please quit ATM and run `apt install -f` in your terminal to fix the problem. 66 | 67 | Error message: {$error} 68 | pk_comm_error = Unable to communicate with the PackageKit daemon: {$error} 69 | pk_tx_error = PackageKit daemon reported an error: {$error} 70 | pk_comm_no_response = PackageKit daemon did not return a response. 71 | pk_invalid_id = Package identifier "{$name}" is invalid. 72 | 73 | This is a bug, please report this issue to https://github.com/AOSC-Dev/atm/issues/new. 74 | 75 | exe-title = Transaction In-Progress 76 | exe-prepare = Preparing ... 77 | exe-overall = Overall Progress: 78 | exe_download = Downloading {$name}... 79 | exe-install = Installing {$name}... 80 | exe-setup = Configuring {$name}... 81 | info-status = Current status 82 | info-title = ATM is applying topic changes to your system ... 83 | #exe_verify = [{$curr}/{$total}] Verifying {$name}... 84 | exe_download_file_error = Download failed: {$name} 85 | exe_download_error = Unable to download files 86 | #exe_verify_error = Verification failed: {$name} 87 | #exe_path_error = Filename unknown: {$name} 88 | #exe_batch_error = Failed to download packages 89 | 90 | apt_finished = APT configuration updated successfully. 91 | install_error = An error occurred while installing packages: {$error} 92 | 93 | #press_enter_to_return = Press Enter to return to the main menu. 94 | press_enter_to_bail = Press Enter to return to quit. 95 | 96 | ## CLI messages 97 | 98 | needs-root = Please run me as root! 99 | topic-table-hint = Selected or enrolled topics are marked with a `*` character. 100 | fetch-error-fallback = [!] Failed to fetch available topics. Only enrolled topics are shown. 101 | 102 | ## Authentication messages 103 | 104 | await-authentication = Waiting for authentication to finish ... 105 | authentication-failure = Authentication failed: {$reason} 106 | -run-me-as-root-workaround = Your system is not modified. 107 | 108 | Please run ATM as root in your terminal to workaround this issue. 109 | sudo-failure = ATM can not find any privilege escalation facilities in your system. 110 | 111 | { -run-me-as-root-workaround } 112 | headless-sudo-unsupported = ATM does not support headless privilege escalation. 113 | 114 | { -run-me-as-root-workaround } 115 | 116 | file-header = Generated by AOSC Topic Manager. DO NOT EDIT THIS FILE! 117 | -------------------------------------------------------------------------------- /src/network.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashSet, env::consts::ARCH}; 2 | 3 | use anyhow::{anyhow, Result}; 4 | use indexmap::IndexMap; 5 | use reqwest::Client; 6 | use serde::{Deserialize, Serialize}; 7 | use tokio::fs::File; 8 | use tokio::io::AsyncReadExt; 9 | 10 | const USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")); 11 | const PATH_TO_MANIFEST: &str = "debs/manifest/topics.json"; 12 | const APT_GEN_LIST_STATUS: &str = "/var/lib/apt/gen/status.json"; 13 | pub const DEFAULT_REPO_URL: &str = "https://repo.aosc.io"; 14 | 15 | #[derive(Serialize, Deserialize, Debug, Clone)] 16 | pub struct TopicManifest { 17 | #[serde(default)] 18 | pub enabled: bool, 19 | #[serde(default)] 20 | pub closed: bool, 21 | pub name: String, 22 | pub description: Option, 23 | pub date: i64, 24 | pub arch: HashSet, 25 | pub packages: Vec, 26 | } 27 | 28 | #[derive(Deserialize, Debug)] 29 | struct AptGenListStatus { 30 | mirror: IndexMap, 31 | } 32 | 33 | pub(crate) type TopicManifests = Vec; 34 | 35 | #[inline] 36 | pub(crate) fn get_arch_name() -> Option<&'static str> { 37 | match ARCH { 38 | "x86_64" => Some("amd64"), 39 | "x86" => Some("i486"), 40 | "aarch64" => Some("arm64"), 41 | "powerpc64" => Some("ppc64el"), 42 | "mips64" => Some("loongson3"), 43 | "riscv64" => Some("riscv64"), 44 | "loongarch64" => Some("loongarch64"), 45 | _ => None, 46 | } 47 | } 48 | 49 | pub fn create_http_client() -> Result { 50 | Client::builder().user_agent(USER_AGENT).build() 51 | } 52 | 53 | async fn test_mirror<'a>( 54 | client: &Client, 55 | url: reqwest::Url, 56 | mirror: &'a str, 57 | ) -> Result<&'a str, reqwest::Error> { 58 | // HEAD request works better but some mirrors do not support it correctly 59 | client 60 | .get(url) 61 | .send() 62 | .await? 63 | .error_for_status() 64 | .map(|_| mirror) 65 | } 66 | 67 | async fn get_best_mirror_url_inner(client: &Client) -> Result { 68 | let mut file = File::open(APT_GEN_LIST_STATUS).await?; 69 | let mut buffer = Vec::with_capacity(1024); 70 | file.read_to_end(&mut buffer).await?; 71 | let mirrors: AptGenListStatus = serde_json::from_slice(&buffer)?; 72 | if mirrors.mirror.len() < 2 { 73 | // you don't have many choices here 74 | return Err(anyhow!("")); 75 | } 76 | let mut tasks = Vec::with_capacity(mirrors.mirror.len()); 77 | for mirror in mirrors.mirror.iter() { 78 | let test_url = match reqwest::Url::parse(mirror.1) { 79 | Ok(v) => v.join(PATH_TO_MANIFEST).unwrap(), 80 | Err(_) => continue, 81 | }; 82 | tasks.push(Box::pin(test_mirror(client, test_url, mirror.1))); 83 | } 84 | if tasks.is_empty() { 85 | // well, that sad, none of the mirrors have a correct URL 86 | return Err(anyhow!("")); 87 | } 88 | // start the test 89 | let result = futures::future::select_ok(tasks).await?; 90 | 91 | Ok(result.0.to_owned()) 92 | } 93 | 94 | pub async fn get_best_mirror_url(client: &Client) -> String { 95 | get_best_mirror_url_inner(client) 96 | .await 97 | .unwrap_or_else(|_| DEFAULT_REPO_URL.to_owned()) 98 | } 99 | 100 | fn get_sensible_mirror_url_inner() -> Result { 101 | let mirrors: AptGenListStatus = 102 | serde_json::from_reader(std::fs::File::open(APT_GEN_LIST_STATUS)?)?; 103 | mirrors 104 | .mirror 105 | .first() 106 | .map(|v| v.1.to_owned()) 107 | .ok_or_else(|| anyhow!("")) 108 | } 109 | 110 | /// Get a sensible mirror URL (async not needed) 111 | pub fn get_sensible_mirror_url() -> String { 112 | get_sensible_mirror_url_inner().unwrap_or_else(|_| DEFAULT_REPO_URL.to_owned()) 113 | } 114 | 115 | pub async fn fetch_topics(client: &Client, mirror_url: &str) -> Result { 116 | let url = reqwest::Url::parse(mirror_url)?.join(PATH_TO_MANIFEST)?; 117 | let resp = client.get(url).send().await?.error_for_status()?; 118 | let topics: TopicManifests = resp.json().await?; 119 | 120 | Ok(topics) 121 | } 122 | 123 | pub fn filter_topics(topics: TopicManifests) -> Result { 124 | let mut filtered: TopicManifests = Vec::new(); 125 | filtered.reserve(topics.len()); 126 | let arch = get_arch_name().ok_or_else(|| anyhow!("unknown architecture"))?; 127 | 128 | for topic in topics { 129 | if topic.arch.contains("all") || topic.arch.contains(arch) { 130 | filtered.push(topic); 131 | } 132 | } 133 | 134 | Ok(filtered) 135 | } 136 | 137 | #[test] 138 | fn test_filter() { 139 | get_arch_name().unwrap(); 140 | let mut all = HashSet::new(); 141 | all.insert("all".to_owned()); 142 | let mut no = HashSet::new(); 143 | no.insert("not".to_owned()); 144 | let topics = vec![ 145 | TopicManifest { 146 | enabled: false, 147 | closed: false, 148 | name: "test".to_string(), 149 | description: None, 150 | date: 0, 151 | arch: all.clone(), 152 | packages: vec![], 153 | }, 154 | TopicManifest { 155 | enabled: false, 156 | closed: false, 157 | name: "test2".to_string(), 158 | description: None, 159 | date: 0, 160 | arch: no, 161 | packages: vec![], 162 | }, 163 | ]; 164 | assert_eq!(filter_topics(topics).unwrap().len(), 1); 165 | } 166 | -------------------------------------------------------------------------------- /src/pm.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | borrow::Cow, 3 | collections::{HashMap, HashSet}, 4 | fmt::Write as WriteFmt, 5 | fs, 6 | io::Write, 7 | }; 8 | 9 | use crate::network::{TopicManifest, TopicManifests}; 10 | use crate::parser::list_installed; 11 | use crate::pk::{ 12 | create_transaction, find_stable_version_of, get_updated_packages, refresh_cache, 13 | PackageKitProxy, 14 | }; 15 | use anyhow::Result; 16 | use serde::{Deserialize, Serialize}; 17 | use serde_json::{from_reader, to_string}; 18 | 19 | const SOURCE_HEADER: &[u8] = b"# Generated by AOSC Topic Manager. DO NOT EDIT THIS FILE!\n"; 20 | const SOURCE_PATH: &str = "/etc/apt/sources.list.d/atm.list"; 21 | const SOURCE_PATH_NEW: &str = "/etc/apt/sources.list.d/atm.sources"; 22 | const STATE_PATH: &str = "/var/lib/atm/state"; 23 | const STATE_DIR: &str = "/var/lib/atm/"; 24 | const DPKG_STATE: &str = "/var/lib/dpkg/status"; 25 | 26 | #[derive(Serialize, Deserialize, Debug, Clone)] 27 | pub struct PreviousTopic { 28 | pub name: String, 29 | pub description: Option, 30 | #[serde(default)] 31 | pub date: i64, 32 | pub packages: Vec, 33 | } 34 | 35 | type PreviousTopics = Vec; 36 | 37 | /// Returns the packages need to be reinstalled 38 | pub fn close_topics(topics: &[TopicManifest]) -> Result> { 39 | let state_file = fs::read(DPKG_STATE)?; 40 | let state_file_ref = &mut state_file.as_slice(); 41 | let installed = list_installed(state_file_ref)?; 42 | let mut remove = Vec::new(); 43 | 44 | for topic in topics { 45 | for package in topic.packages.iter() { 46 | if installed.contains(package) { 47 | remove.push(package.clone()); 48 | } 49 | } 50 | } 51 | 52 | Ok(remove) 53 | } 54 | 55 | /// Returns the list of enrolled topics 56 | fn get_previous_topics() -> Result { 57 | Ok(from_reader(fs::File::open(STATE_PATH)?)?) 58 | } 59 | 60 | pub fn get_display_listing(current: TopicManifests) -> TopicManifests { 61 | let prev = get_previous_topics().unwrap_or_default(); 62 | let mut lookup: HashMap = HashMap::new(); 63 | let current_len = current.len(); 64 | 65 | for topic in current.into_iter() { 66 | lookup.insert(topic.name.clone(), topic); 67 | } 68 | 69 | let mut concatenated = Vec::new(); 70 | concatenated.reserve(prev.len() + current_len); 71 | for topic in prev { 72 | if let Some(topic) = lookup.get_mut(&topic.name) { 73 | topic.enabled = true; 74 | continue; 75 | } 76 | concatenated.push(TopicManifest { 77 | enabled: false, 78 | closed: true, 79 | name: topic.name.clone(), 80 | description: topic.description.clone(), 81 | date: topic.date, 82 | arch: HashSet::new(), 83 | packages: topic.packages.clone(), 84 | }); 85 | } 86 | // consume the lookup table and append all the elements to the concatenated list 87 | for topic in lookup.into_iter() { 88 | concatenated.push(topic.1); 89 | } 90 | 91 | concatenated 92 | } 93 | 94 | fn save_as_previous_topics(current: &[&TopicManifest]) -> Result { 95 | let mut previous_topics = Vec::new(); 96 | for topic in current { 97 | if !topic.enabled { 98 | continue; 99 | } 100 | previous_topics.push(PreviousTopic { 101 | name: topic.name.clone(), 102 | description: topic.description.clone(), 103 | date: topic.date, 104 | packages: topic.packages.clone(), 105 | }); 106 | } 107 | 108 | Ok(to_string(&previous_topics)?) 109 | } 110 | 111 | fn normalize_url(url: &str) -> Cow { 112 | if url.ends_with('/') { 113 | Cow::Borrowed(url) 114 | } else { 115 | let mut url = Cow::from(url); 116 | url.to_mut().push('/'); 117 | url 118 | } 119 | } 120 | 121 | fn make_topic_list_deb822(topics: &[&TopicManifest], mirror_url: &str) -> String { 122 | let suites = topics 123 | .iter() 124 | .map(|t| &t.name) 125 | .fold(String::new(), |acc, s| acc + " " + &s); 126 | 127 | format!( 128 | "Types: deb\nURIs: {}debs\nSuites: {}\nComponents: main\n\n", 129 | mirror_url, suites 130 | ) 131 | } 132 | 133 | fn make_topic_list(topics: &[&TopicManifest], mirror_url: &str) -> String { 134 | let mut output = String::with_capacity(1024); 135 | 136 | for topic in topics { 137 | writeln!( 138 | &mut output, 139 | "# Topic `{}`\ndeb {}debs {} main", 140 | topic.name, 141 | normalize_url(mirror_url), 142 | topic.name 143 | ) 144 | .unwrap(); 145 | // this will only happen when malloc() fails. 146 | // in which case, it's better to just panic 147 | } 148 | 149 | output 150 | } 151 | 152 | pub fn write_source_list(topics: &[&TopicManifest], mirror_url: &str) -> Result<()> { 153 | let new_f = fs::File::options() 154 | .truncate(true) 155 | .write(true) 156 | .open(SOURCE_PATH_NEW); 157 | let (mut f, is_deb822) = match new_f { 158 | Ok(f) => { 159 | // also remove the old source list if it exists (to avoid conflicts) 160 | fs::remove_file(SOURCE_PATH).ok(); 161 | (f, true) 162 | } 163 | Err(_) => (fs::File::create(SOURCE_PATH)?, false), 164 | }; 165 | f.write_all(SOURCE_HEADER)?; 166 | f.write_all( 167 | if is_deb822 { 168 | make_topic_list_deb822(topics, mirror_url) 169 | } else { 170 | make_topic_list(topics, mirror_url) 171 | } 172 | .as_bytes(), 173 | )?; 174 | 175 | fs::create_dir_all(STATE_DIR)?; 176 | let mut f = fs::File::create(STATE_PATH)?; 177 | f.write_all(save_as_previous_topics(topics)?.as_bytes())?; 178 | 179 | Ok(()) 180 | } 181 | 182 | pub async fn switch_topics( 183 | proxy: &PackageKitProxy<'_>, 184 | closed: &[TopicManifest], 185 | ) -> Result<(Vec, Vec)> { 186 | let tx_proxy = create_transaction(proxy).await?; 187 | refresh_cache(&tx_proxy).await?; 188 | let removed = close_topics(closed)?; 189 | let removed = removed.iter().map(|x| x.as_str()).collect::>(); 190 | let tx_proxy = create_transaction(proxy).await?; 191 | let (not_found, tasks) = find_stable_version_of(&tx_proxy, &removed).await?; 192 | let tx_proxy = create_transaction(proxy).await?; 193 | let updated = get_updated_packages(&tx_proxy).await?; 194 | let mut updated = updated 195 | .into_iter() 196 | .map(|x| x.package_id) 197 | .collect::>(); 198 | updated.extend(tasks); 199 | 200 | Ok((not_found, updated)) 201 | } 202 | -------------------------------------------------------------------------------- /src/frontend/cli.rs: -------------------------------------------------------------------------------- 1 | use std::{fs::File, io::Read, path::Path, process}; 2 | 3 | use anyhow::{anyhow, Result}; 4 | use argh::FromArgs; 5 | use sha2::Digest; 6 | 7 | use super::format_timestamp; 8 | use crate::{fl, network, pm}; 9 | 10 | #[derive(FromArgs, PartialEq, Debug)] 11 | /// enroll into a new topic 12 | #[argh(subcommand, name = "add")] 13 | pub(crate) struct TopicAdd { 14 | /// name of the topic 15 | #[argh(positional)] 16 | pub name: Vec, 17 | } 18 | 19 | #[derive(FromArgs, PartialEq, Debug)] 20 | /// exit from a topic 21 | #[argh(subcommand, name = "remove")] 22 | pub(crate) struct TopicRemove { 23 | /// name of the topic 24 | #[argh(positional)] 25 | pub name: Vec, 26 | } 27 | 28 | #[derive(FromArgs, PartialEq, Debug)] 29 | /// refresh APT configurations 30 | #[argh(subcommand, name = "refresh")] 31 | pub(crate) struct RefreshList { 32 | /// filename of the topic list file (optional) 33 | #[argh(option, short = 'f')] 34 | pub filename: Option, 35 | /// checksum of the topic list file (optional) 36 | #[argh(option, short = 'c')] 37 | pub checksum: Option, 38 | /// mirror URL to use for the topic list file (optional) 39 | #[argh(option, short = 'm')] 40 | pub mirror: Option, 41 | } 42 | 43 | #[derive(FromArgs, PartialEq, Debug)] 44 | /// list current topics and available topics 45 | #[argh(subcommand, name = "list")] 46 | pub(crate) struct TopicList {} 47 | 48 | #[derive(FromArgs, PartialEq, Debug)] 49 | #[argh(subcommand)] 50 | pub(crate) enum ATMCommand { 51 | List(TopicList), 52 | Refresh(RefreshList), 53 | Add(TopicAdd), 54 | Remove(TopicRemove), 55 | } 56 | 57 | #[derive(FromArgs, PartialEq, Debug)] 58 | /// AOSC Topic Manager 59 | pub(crate) struct ATM { 60 | #[argh(subcommand)] 61 | pub command: Option, 62 | } 63 | 64 | // === end of argh constructs 65 | 66 | #[inline] 67 | fn needs_root() -> Result<()> { 68 | use nix::unistd::geteuid; 69 | 70 | if !geteuid().is_root() { 71 | Err(anyhow!(fl!("needs-root"))) 72 | } else { 73 | Ok(()) 74 | } 75 | } 76 | 77 | /// Escalate permissions using Polkit-1 and write configuration file 78 | pub fn privileged_write_source_list( 79 | topics: &[&network::TopicManifest], 80 | mirror_url: &str, 81 | ) -> Result<()> { 82 | use nix::unistd::geteuid; 83 | use std::io::Write; 84 | use std::process::{Command, Stdio}; 85 | use tempfile::NamedTempFile; 86 | 87 | if geteuid().is_root() { 88 | // already root 89 | return pm::write_source_list(topics, mirror_url); 90 | } 91 | if std::env::var("DISPLAY").is_err() { 92 | return Err(anyhow!(fl!("headless-sudo-unsupported"))); 93 | } 94 | let my_name = std::env::current_exe()?; 95 | let xfer_content = serde_json::to_vec(topics)?; 96 | // calculate hash and pass the hash to the privileged process prevent hijack attacks 97 | let mut chksum = sha2::Sha256::new(); 98 | chksum.update(&xfer_content); 99 | let chksum = format!("{:02x}", chksum.finalize()); 100 | // create a temporary file to transfer the states 101 | let mut f = NamedTempFile::new()?; 102 | f.write_all(&xfer_content)?; 103 | // pass the temporary file to the privileged process 104 | let cmd = Command::new("pkexec") 105 | .arg(my_name) 106 | .args(&["refresh", "-c", chksum.as_str(), "-m", mirror_url, "-f"]) 107 | .arg(f.path()) 108 | .stderr(Stdio::piped()) 109 | .stdout(Stdio::null()) 110 | .spawn() 111 | .map_err(|_| anyhow!(fl!("sudo-failure")))? 112 | .wait_with_output()?; 113 | if !cmd.status.success() { 114 | let error_message = std::str::from_utf8(&cmd.stderr).unwrap_or_default(); 115 | return Err(anyhow!(fl!( 116 | "authentication-failure", 117 | reason = error_message 118 | ))); 119 | } 120 | 121 | Ok(()) 122 | } 123 | 124 | async fn fetch_available_topics() -> Result { 125 | let client = network::create_http_client()?; 126 | let mirror_url = network::get_best_mirror_url(&client).await; 127 | let topics = network::fetch_topics(&client, &mirror_url).await?; 128 | 129 | network::filter_topics(topics) 130 | } 131 | 132 | fn format_manifests(topics: network::TopicManifests) { 133 | use std::io::Write; 134 | 135 | let mut formatter = tabwriter::TabWriter::new(std::io::stderr()); 136 | writeln!( 137 | &mut formatter, 138 | " {}\t{}\t{}", 139 | fl!("name"), 140 | fl!("date"), 141 | fl!("description") 142 | ) 143 | .unwrap(); 144 | for topic in topics { 145 | writeln!( 146 | &mut formatter, 147 | "{} {}\t{}\t{}", 148 | if topic.enabled { '*' } else { ' ' }, 149 | topic.name, 150 | format_timestamp(topic.date).unwrap_or_else(|_| "?".to_string()), 151 | topic.description.unwrap_or_default() 152 | ) 153 | .unwrap(); 154 | } 155 | formatter.flush().unwrap(); 156 | } 157 | 158 | async fn list_topics() { 159 | let mut fallback = false; 160 | eprint!("{}", fl!("refresh-manifest")); 161 | let available = fetch_available_topics().await.unwrap_or_else(|_| { 162 | fallback = true; 163 | Vec::new() 164 | }); 165 | let mut topics = pm::get_display_listing(available); 166 | topics.sort_unstable_by_key(|t| t.date + if t.enabled { 1_000_000_000 } else { 0 }); 167 | eprint!("\r\t\t\r"); // clear display 168 | format_manifests(topics); 169 | if fallback { 170 | eprintln!("{}", fl!("fetch-error-fallback")); 171 | } else { 172 | eprintln!("\n{}", fl!("topic-table-hint")); 173 | } 174 | } 175 | 176 | fn refresh_topics>( 177 | filename: Option

, 178 | chksum: &Option, 179 | mirror_url: Option, 180 | ) -> Result<()> { 181 | needs_root()?; 182 | let topics = match filename { 183 | Some(filename) => { 184 | let mut f = File::open(filename)?; 185 | let mut buffer = Vec::new(); 186 | buffer.reserve(1024); 187 | f.read_to_end(&mut buffer)?; 188 | if let Some(chksum) = chksum { 189 | let mut hasher = sha2::Sha256::new(); 190 | hasher.update(&buffer); 191 | if &format!("{:02x}", hasher.finalize()) != chksum { 192 | return Err(anyhow!("Hash mismatch.")); 193 | } 194 | } 195 | 196 | serde_json::from_slice(&buffer)? 197 | } 198 | None => { 199 | let mut topics = pm::get_display_listing(Vec::new()); 200 | topics.iter_mut().for_each(|t| t.enabled = true); 201 | 202 | topics 203 | } 204 | }; 205 | let topics_ref = topics.iter().collect::>(); 206 | let mirror_url = mirror_url.unwrap_or_else(network::get_sensible_mirror_url); 207 | pm::write_source_list(&topics_ref, &mirror_url)?; 208 | println!("{}", fl!("apt_finished")); 209 | 210 | Ok(()) 211 | } 212 | 213 | async fn add_topics(topics_to_add: &[String]) -> Result<()> { 214 | needs_root()?; 215 | eprintln!("{}", fl!("refresh-manifest")); 216 | let client = network::create_http_client()?; 217 | let mirror_url = network::get_best_mirror_url(&client).await; 218 | let available = fetch_available_topics().await?; 219 | let mut topics = pm::get_display_listing(available); 220 | for topic in topics.iter_mut() { 221 | topic.enabled |= topics_to_add.contains(&topic.name); 222 | } 223 | let topics_ref = topics.iter().filter(|t| t.enabled).collect::>(); 224 | pm::write_source_list(&topics_ref, &mirror_url)?; 225 | println!("{}", fl!("apt_finished")); 226 | 227 | Ok(()) 228 | } 229 | 230 | fn remove_topics(topics_to_remove: &[String]) -> Result<()> { 231 | needs_root()?; 232 | let mut topics = pm::get_display_listing(Vec::new()); 233 | topics 234 | .iter_mut() 235 | .for_each(|t| t.enabled = !topics_to_remove.contains(&t.name)); 236 | let topics_ref = topics.iter().collect::>(); 237 | pm::write_source_list(&topics_ref, &network::get_sensible_mirror_url())?; 238 | println!("{}", fl!("apt_finished")); 239 | 240 | Ok(()) 241 | } 242 | 243 | /// CLI parser and main function. 244 | /// Returns `false` if no command-line argument is provided. 245 | pub fn cli_main() -> bool { 246 | let args: ATM = argh::from_env(); 247 | if args.command.is_none() { 248 | return false; 249 | } 250 | let commands = args.command.unwrap(); 251 | let runner = tokio::runtime::Builder::new_current_thread() 252 | .enable_all() 253 | .build() 254 | .expect("failed to initialize async runtime"); 255 | match commands { 256 | ATMCommand::List(_) => runner.block_on(list_topics()), 257 | ATMCommand::Refresh(args) => { 258 | if let Err(e) = refresh_topics(args.filename, &args.checksum, args.mirror) { 259 | eprintln!("{}", e); 260 | process::exit(1); 261 | } 262 | } 263 | ATMCommand::Add(topics) => { 264 | if let Err(e) = runner.block_on(add_topics(&topics.name)) { 265 | eprintln!("{}", e); 266 | process::exit(1); 267 | } 268 | } 269 | ATMCommand::Remove(topics) => { 270 | if let Err(e) = remove_topics(&topics.name) { 271 | eprintln!("{}", e); 272 | process::exit(1); 273 | } 274 | } 275 | } 276 | 277 | true 278 | } 279 | -------------------------------------------------------------------------------- /src/pk/packagekit_tx.rs: -------------------------------------------------------------------------------- 1 | //! # DBus interface proxy for: `org.freedesktop.PackageKit.Transaction` 2 | //! 3 | //! This code was generated by `zbus-xmlgen` `2.0.1` from DBus introspection data. 4 | //! Source: `org.freedesktop.PackageKit.Transaction.xml`. 5 | //! 6 | //! You may prefer to adapt it, instead of using it verbatim. 7 | //! 8 | //! More information can be found in the 9 | //! [Writing a client proxy](https://dbus.pages.freedesktop.org/zbus/client.html) 10 | //! section of the zbus documentation. 11 | //! 12 | 13 | use zbus::proxy; 14 | 15 | #[proxy( 16 | interface = "org.freedesktop.PackageKit.Transaction", 17 | default_service = "org.freedesktop.PackageKit" 18 | )] 19 | pub trait Transaction { 20 | /// AcceptEula method 21 | fn accept_eula(&self, eula_id: &str) -> zbus::Result<()>; 22 | 23 | /// Cancel method 24 | fn cancel(&self) -> zbus::Result<()>; 25 | 26 | /// DependsOn method 27 | fn depends_on(&self, filter: u64, package_ids: &[&str], recursive: bool) -> zbus::Result<()>; 28 | 29 | /// DownloadPackages method 30 | fn download_packages(&self, store_in_cache: bool, package_ids: &[&str]) -> zbus::Result<()>; 31 | 32 | /// GetCategories method 33 | fn get_categories(&self) -> zbus::Result<()>; 34 | 35 | /// GetDetails method 36 | fn get_details(&self, package_ids: &[&str]) -> zbus::Result<()>; 37 | 38 | /// GetDetailsLocal method 39 | fn get_details_local(&self, files: &[&str]) -> zbus::Result<()>; 40 | 41 | /// GetDistroUpgrades method 42 | fn get_distro_upgrades(&self) -> zbus::Result<()>; 43 | 44 | /// GetFiles method 45 | fn get_files(&self, package_ids: &[&str]) -> zbus::Result<()>; 46 | 47 | /// GetFilesLocal method 48 | fn get_files_local(&self, files: &[&str]) -> zbus::Result<()>; 49 | 50 | /// GetOldTransactions method 51 | fn get_old_transactions(&self, number: u32) -> zbus::Result<()>; 52 | 53 | /// GetPackages method 54 | fn get_packages(&self, filter: u64) -> zbus::Result<()>; 55 | 56 | /// GetRepoList method 57 | fn get_repo_list(&self, filter: u64) -> zbus::Result<()>; 58 | 59 | /// GetUpdateDetail method 60 | fn get_update_detail(&self, package_ids: &[&str]) -> zbus::Result<()>; 61 | 62 | /// GetUpdates method 63 | fn get_updates(&self, filter: u64) -> zbus::Result<()>; 64 | 65 | /// InstallFiles method 66 | fn install_files(&self, transaction_flags: u64, full_paths: &[&str]) -> zbus::Result<()>; 67 | 68 | /// InstallPackages method 69 | fn install_packages(&self, transaction_flags: u64, package_ids: &[&str]) -> zbus::Result<()>; 70 | 71 | /// InstallSignature method 72 | fn install_signature(&self, sig_type: u32, key_id: &str, package_id: &str) -> zbus::Result<()>; 73 | 74 | /// RefreshCache method 75 | fn refresh_cache(&self, force: bool) -> zbus::Result<()>; 76 | 77 | /// RemovePackages method 78 | fn remove_packages( 79 | &self, 80 | transaction_flags: u64, 81 | package_ids: &[&str], 82 | allow_deps: bool, 83 | autoremove: bool, 84 | ) -> zbus::Result<()>; 85 | 86 | /// RepairSystem method 87 | fn repair_system(&self, transaction_flags: u64) -> zbus::Result<()>; 88 | 89 | /// RepoEnable method 90 | fn repo_enable(&self, repo_id: &str, enabled: bool) -> zbus::Result<()>; 91 | 92 | /// RepoRemove method 93 | fn repo_remove( 94 | &self, 95 | transaction_flags: u64, 96 | repo_id: &str, 97 | autoremove: bool, 98 | ) -> zbus::Result<()>; 99 | 100 | /// RepoSetData method 101 | fn repo_set_data(&self, repo_id: &str, parameter: &str, value: &str) -> zbus::Result<()>; 102 | 103 | /// RequiredBy method 104 | fn required_by(&self, filter: u64, package_ids: &[&str], recursive: bool) -> zbus::Result<()>; 105 | 106 | /// Resolve method 107 | fn resolve(&self, filter: u64, packages: &[&str]) -> zbus::Result<()>; 108 | 109 | /// SearchDetails method 110 | fn search_details(&self, filter: u64, values: &[&str]) -> zbus::Result<()>; 111 | 112 | /// SearchFiles method 113 | fn search_files(&self, filter: u64, values: &[&str]) -> zbus::Result<()>; 114 | 115 | /// SearchGroups method 116 | fn search_groups(&self, filter: u64, values: &[&str]) -> zbus::Result<()>; 117 | 118 | /// SearchNames method 119 | fn search_names(&self, filter: u64, values: &[&str]) -> zbus::Result<()>; 120 | 121 | /// SetHints method 122 | fn set_hints(&self, hints: &[&str]) -> zbus::Result<()>; 123 | 124 | /// UpdatePackages method 125 | fn update_packages(&self, transaction_flags: u64, package_ids: &[&str]) -> zbus::Result<()>; 126 | 127 | /// UpgradeSystem method 128 | fn upgrade_system( 129 | &self, 130 | transaction_flags: u64, 131 | distro_id: &str, 132 | upgrade_kind: u32, 133 | ) -> zbus::Result<()>; 134 | 135 | /// WhatProvides method 136 | fn what_provides(&self, filter: u64, values: &[&str]) -> zbus::Result<()>; 137 | 138 | /// Category signal 139 | #[zbus(signal)] 140 | fn category( 141 | &self, 142 | parent_id: &str, 143 | cat_id: &str, 144 | name: &str, 145 | summary: &str, 146 | icon: &str, 147 | ) -> zbus::Result<()>; 148 | 149 | /// Destroy signal 150 | #[zbus(signal)] 151 | fn destroy(&self) -> zbus::Result<()>; 152 | 153 | /// Details signal 154 | #[zbus(signal)] 155 | fn details( 156 | &self, 157 | data: std::collections::HashMap<&str, zbus::zvariant::Value<'_>>, 158 | ) -> zbus::Result<()>; 159 | 160 | /// DistroUpgrade signal 161 | #[zbus(signal)] 162 | fn distro_upgrade(&self, type_: u32, name: &str, summary: &str) -> zbus::Result<()>; 163 | 164 | /// ErrorCode signal 165 | #[zbus(signal)] 166 | fn error_code(&self, code: u32, details: &str) -> zbus::Result<()>; 167 | 168 | /// EulaRequired signal 169 | #[zbus(signal)] 170 | fn eula_required( 171 | &self, 172 | eula_id: &str, 173 | package_id: &str, 174 | vendor_name: &str, 175 | license_agreement: &str, 176 | ) -> zbus::Result<()>; 177 | 178 | /// Files signal 179 | #[zbus(signal)] 180 | fn files(&self, package_id: &str, file_list: Vec<&str>) -> zbus::Result<()>; 181 | 182 | /// Finished signal 183 | #[zbus(signal)] 184 | fn finished(&self, exit: u32, runtime: u32) -> zbus::Result<()>; 185 | 186 | /// ItemProgress signal 187 | #[zbus(signal)] 188 | fn item_progress(&self, id: &str, status: u32, percentage: u32) -> zbus::Result<()>; 189 | 190 | /// MediaChangeRequired signal 191 | #[zbus(signal)] 192 | fn media_change_required( 193 | &self, 194 | media_type: u32, 195 | media_id: &str, 196 | media_text: &str, 197 | ) -> zbus::Result<()>; 198 | 199 | /// Package signal 200 | #[zbus(signal)] 201 | fn package(&self, info: u32, package_id: &str, summary: &str) -> zbus::Result<()>; 202 | 203 | /// RepoDetail signal 204 | #[zbus(signal)] 205 | fn repo_detail(&self, repo_id: &str, description: &str, enabled: bool) -> zbus::Result<()>; 206 | 207 | /// RepoSignatureRequired signal 208 | #[zbus(signal)] 209 | fn repo_signature_required( 210 | &self, 211 | package_id: &str, 212 | repository_name: &str, 213 | key_url: &str, 214 | key_userid: &str, 215 | key_id: &str, 216 | key_fingerprint: &str, 217 | key_timestamp: &str, 218 | type_: u32, 219 | ) -> zbus::Result<()>; 220 | 221 | /// RequireRestart signal 222 | #[zbus(signal)] 223 | fn require_restart(&self, type_: u32, package_id: &str) -> zbus::Result<()>; 224 | 225 | /// Transaction signal 226 | #[zbus(signal)] 227 | fn transaction( 228 | &self, 229 | object_path: zbus::zvariant::ObjectPath<'_>, 230 | timespec: &str, 231 | succeeded: bool, 232 | role: u32, 233 | duration: u32, 234 | data: &str, 235 | uid: u32, 236 | cmdline: &str, 237 | ) -> zbus::Result<()>; 238 | 239 | /// UpdateDetail signal 240 | #[zbus(signal)] 241 | fn update_detail( 242 | &self, 243 | package_id: &str, 244 | updates: Vec<&str>, 245 | obsoletes: Vec<&str>, 246 | vendor_urls: Vec<&str>, 247 | bugzilla_urls: Vec<&str>, 248 | cve_urls: Vec<&str>, 249 | restart: u32, 250 | update_text: &str, 251 | changelog: &str, 252 | state: u32, 253 | issued: &str, 254 | updated: &str, 255 | ) -> zbus::Result<()>; 256 | 257 | /// AllowCancel property 258 | #[zbus(property)] 259 | fn allow_cancel(&self) -> zbus::Result; 260 | 261 | /// CallerActive property 262 | #[zbus(property)] 263 | fn caller_active(&self) -> zbus::Result; 264 | 265 | /// DownloadSizeRemaining property 266 | #[zbus(property)] 267 | fn download_size_remaining(&self) -> zbus::Result; 268 | 269 | /// ElapsedTime property 270 | #[zbus(property)] 271 | fn elapsed_time(&self) -> zbus::Result; 272 | 273 | /// LastPackage property 274 | #[zbus(property)] 275 | fn last_package(&self) -> zbus::Result; 276 | 277 | /// Percentage property 278 | #[zbus(property)] 279 | fn percentage(&self) -> zbus::Result; 280 | 281 | /// RemainingTime property 282 | #[zbus(property)] 283 | fn remaining_time(&self) -> zbus::Result; 284 | 285 | /// Role property 286 | #[zbus(property)] 287 | fn role(&self) -> zbus::Result; 288 | 289 | /// Speed property 290 | #[zbus(property)] 291 | fn speed(&self) -> zbus::Result; 292 | 293 | /// Status property 294 | #[zbus(property)] 295 | fn status(&self) -> zbus::Result; 296 | 297 | /// TransactionFlags property 298 | #[zbus(property)] 299 | fn transaction_flags(&self) -> zbus::Result; 300 | 301 | /// Uid property 302 | #[zbus(property)] 303 | fn uid(&self) -> zbus::Result; 304 | } 305 | -------------------------------------------------------------------------------- /src/pk/mod.rs: -------------------------------------------------------------------------------- 1 | //! Packagekit related functions 2 | 3 | mod packagekit; 4 | mod packagekit_tx; 5 | 6 | use std::{collections::HashMap, future::Future, sync::mpsc::Sender, time::Duration}; 7 | 8 | use anyhow::{anyhow, Result}; 9 | use futures::StreamExt; 10 | pub use packagekit::PackageKitProxy; 11 | use packagekit_tx::TransactionProxy; 12 | use serde::Deserialize; 13 | use zbus::{export::ordered_stream::OrderedStreamExt, proxy, Connection, Result as zResult}; 14 | 15 | #[derive(Deserialize, Debug)] 16 | pub struct PkPackage { 17 | pub info: u32, 18 | pub package_id: String, 19 | pub summary: String, 20 | } 21 | 22 | #[derive(Debug, Copy, Clone)] 23 | pub struct PkPackgeId<'a> { 24 | pub name: &'a str, 25 | pub version: &'a str, 26 | arch: &'a str, 27 | data: &'a str, 28 | } 29 | 30 | #[derive(Clone, Debug)] 31 | pub struct PkTaskList<'a> { 32 | pub hold: Vec>, 33 | pub upgrade: Vec>, 34 | pub install: Vec>, 35 | pub downgrade: Vec>, 36 | pub erase: Vec>, 37 | } 38 | 39 | #[proxy( 40 | interface = "org.freedesktop.UPower", 41 | default_service = "org.freedesktop.UPower", 42 | default_path = "/org/freedesktop/UPower" 43 | )] 44 | trait UPower { 45 | /// OnBattery property 46 | #[zbus(property)] 47 | fn on_battery(&self) -> zResult; 48 | } 49 | 50 | #[proxy( 51 | interface = "org.freedesktop.login1.Manager", 52 | default_service = "org.freedesktop.login1", 53 | default_path = "/org/freedesktop/login1" 54 | )] 55 | trait Login1 { 56 | /// Inhibit method 57 | fn inhibit( 58 | &self, 59 | what: &str, 60 | who: &str, 61 | why: &str, 62 | mode: &str, 63 | ) -> zResult; 64 | } 65 | 66 | // PackageKit enumeration constants (could be OR'ed) 67 | const PK_FILTER_ENUM_NEWEST: u32 = 1 << 16; 68 | const PK_FILTER_ENUM_ARCH: u32 = 1 << 18; 69 | const PK_FILTER_ENUM_NOT_SOURCE: u32 = 1 << 21; 70 | const PK_TRANSACTION_FLAG_ENUM_ONLY_TRUSTED: u32 = 1 << 1; 71 | const PK_TRANSACTION_FLAG_ENUM_SIMULATE: u32 = 1 << 2; 72 | const PK_TRANSACTION_FLAG_ENUM_ALLOW_REINSTALL: u32 = 1 << 4; 73 | const PK_TRANSACTION_FLAG_ENUM_ALLOW_DOWNGRADE: u32 = 1 << 6; 74 | // PackageKit informational constants (literal values) 75 | const PK_NETWORK_ENUM_MOBILE: u8 = 5; 76 | // PackageKit status constants 77 | // pub const PK_STATUS_ENUM_WAIT: u8 = 1; 78 | pub const PK_STATUS_ENUM_SETUP: u8 = 2; 79 | pub const PK_STATUS_ENUM_DOWNLOAD: u8 = 8; 80 | pub const PK_STATUS_ENUM_INSTALL: u8 = 9; 81 | const PK_INFO_ENUM_INSTALLED: u8 = 1; 82 | // const PK_INFO_ENUM_AVAILABLE: u8 = 2; 83 | const PK_INFO_ENUM_UPDATING: u8 = 11; 84 | const PK_INFO_ENUM_INSTALLING: u8 = 12; 85 | const PK_INFO_ENUM_REMOVING: u8 = 13; 86 | // const PK_INFO_ENUM_OBSOLETING: u8 = 15; 87 | const PK_INFO_ENUM_REINSTALLING: u8 = 19; 88 | const PK_INFO_ENUM_DOWNGRADING: u8 = 20; 89 | 90 | #[derive(Debug)] 91 | pub enum PkDisplayProgress { 92 | /// Individual package progress (package_id, PK_STATUS, progress %) 93 | Package(String, u8, u32), 94 | /// Overall transaction progress (progress %) 95 | Overall(u32), 96 | /// Sentinel for transaction 97 | Done, 98 | } 99 | 100 | #[inline] 101 | pub fn humanize_package_id(package_id: &str) -> String { 102 | let result = parse_package_id(package_id); 103 | if let Some(result) = result { 104 | format!("{} ({}) [{}]", result.name, result.version, result.arch) 105 | } else { 106 | "? (?)".to_string() 107 | } 108 | } 109 | 110 | fn parse_package_id(package_id: &str) -> Option> { 111 | let mut splitted = package_id.splitn(4, ';'); 112 | 113 | Some(PkPackgeId { 114 | name: splitted.next()?, 115 | version: splitted.next()?, 116 | arch: splitted.next()?, 117 | data: splitted.next()?, 118 | }) 119 | } 120 | 121 | async fn wait_for_exit_signal>>( 122 | proxy: &TransactionProxy<'_>, 123 | func: Fut, 124 | ) -> Result<()> { 125 | // let mut signal_stream = proxy.receive_all_signals().await?; 126 | let mut error_signal_stream = proxy.receive_error_code().await?; 127 | let mut finish_signal_stream = proxy.receive_finished().await?; 128 | let mut destroy_signal_stream = proxy.receive_destroy().await?; 129 | // poll the future to start the transaction 130 | func.await?; 131 | tokio::select!{ 132 | v = async { 133 | while let Some(e) = OrderedStreamExt::next(&mut error_signal_stream).await { 134 | let args = e.args()?; 135 | return Err(anyhow!("({}) {}", args.code, args.details)); 136 | } 137 | Ok(()) 138 | } => v, 139 | v = async { 140 | if let Some(_) = OrderedStreamExt::next(&mut finish_signal_stream).await { 141 | return Ok(()); 142 | } 143 | Ok(()) 144 | } => v, 145 | v = async { 146 | if let Some(_) = OrderedStreamExt::next(&mut destroy_signal_stream).await { 147 | return Ok(()); 148 | } 149 | Ok(()) 150 | } => v 151 | }?; 152 | 153 | Ok(()) 154 | } 155 | 156 | async fn collect_packages>>( 157 | proxy: &TransactionProxy<'_>, 158 | func: Fut, 159 | ) -> Result> { 160 | let mut packages: Vec = Vec::new(); 161 | let mut error_signal_stream = proxy.receive_error_code().await?; 162 | let mut finish_signal_stream = proxy.receive_finished().await?; 163 | let mut destroy_signal_stream = proxy.receive_destroy().await?; 164 | let mut package_signal_stream = proxy.receive_package().await?; 165 | 166 | // poll the future to start the transaction 167 | func.await?; 168 | tokio::select!{ 169 | v = async { 170 | while let Some(package) = OrderedStreamExt::next(&mut package_signal_stream).await { 171 | let args = package.args()?; 172 | packages.push(PkPackage { 173 | info: args.info, 174 | package_id: args.package_id.to_string(), 175 | summary: args.summary.to_string(), 176 | }); 177 | } 178 | Ok(()) 179 | } => v, 180 | v = async { 181 | while let Some(e) = OrderedStreamExt::next(&mut error_signal_stream).await { 182 | let args = e.args()?; 183 | return Err(anyhow!("({}) {}", args.code, args.details)); 184 | } 185 | Ok(()) 186 | } => v, 187 | v = async { 188 | if let Some(_) = OrderedStreamExt::next(&mut finish_signal_stream).await { 189 | return Ok(()); 190 | } 191 | Ok(()) 192 | } => v, 193 | v = async { 194 | if let Some(_) = OrderedStreamExt::next(&mut destroy_signal_stream).await { 195 | return Ok(()); 196 | } 197 | Ok(()) 198 | } => v 199 | }?; 200 | 201 | Ok(packages) 202 | } 203 | 204 | /// Connect to the D-Bus system bus 205 | pub async fn create_dbus_connection() -> zResult { 206 | Connection::system().await 207 | } 208 | 209 | /// Connect to the packagekit backend 210 | pub async fn connect_packagekit(conn: &Connection) -> zResult> { 211 | PackageKitProxy::new(conn).await 212 | } 213 | 214 | /// A convient function to create a new PackageKit transaction session 215 | pub async fn create_transaction<'a>( 216 | proxy: &'a PackageKitProxy<'a>, 217 | ) -> zResult> { 218 | proxy.create_transaction().await 219 | } 220 | 221 | /// Refresh repository cache (forcibly refreshes the caches) 222 | pub async fn refresh_cache(proxy: &TransactionProxy<'_>) -> Result<()> { 223 | wait_for_exit_signal(proxy, async move { proxy.refresh_cache(true).await }).await 224 | } 225 | 226 | /// Fetch all the updatable packages (requires transaction proxy) 227 | pub async fn get_updated_packages(proxy: &TransactionProxy<'_>) -> Result> { 228 | collect_packages(proxy, async move { 229 | proxy.get_updates(PK_FILTER_ENUM_NEWEST as u64).await 230 | }) 231 | .await 232 | } 233 | 234 | /// Find the package ID of the stable version of the given packages, returns (not found, found) (requires transaction proxy) 235 | pub async fn find_stable_version_of( 236 | proxy: &TransactionProxy<'_>, 237 | packages: &[&str], 238 | ) -> Result<(Vec, Vec)> { 239 | if packages.is_empty() { 240 | return Ok((vec![], vec![])); 241 | } 242 | 243 | let candidates = collect_packages(proxy, async move { 244 | proxy 245 | .resolve( 246 | (PK_FILTER_ENUM_ARCH | PK_FILTER_ENUM_NOT_SOURCE) as u64, 247 | packages, 248 | ) 249 | .await 250 | }) 251 | .await?; 252 | 253 | let mut candidates_map: HashMap = HashMap::new(); 254 | candidates_map.reserve(candidates.len()); 255 | 256 | for candidate in candidates { 257 | let candidate_parsed = 258 | parse_package_id(&candidate.package_id).ok_or_else(|| anyhow!("Invalid package id"))?; 259 | // skip packages that are not in the stable branch 260 | if !candidate_parsed.data.starts_with("aosc-stable-") 261 | && !candidate_parsed.data.starts_with("installed:aosc-stable-") 262 | { 263 | continue; 264 | } 265 | 266 | if candidates_map.contains_key(candidate_parsed.name) { 267 | continue; 268 | } 269 | candidates_map.insert(candidate_parsed.name.to_string(), candidate); 270 | } 271 | 272 | let mut result = Vec::new(); 273 | let mut not_found = Vec::new(); 274 | for package in packages { 275 | if let Some(candidate) = candidates_map.get(*package) { 276 | if candidate.info == PK_INFO_ENUM_INSTALLED as u32 { 277 | // if the package is already installed and is at the latest stable version, 278 | // then just skip it 279 | continue; 280 | } 281 | result.push(candidate.package_id.clone()); 282 | continue; 283 | } 284 | // else: 285 | not_found.push(package.to_string()); 286 | } 287 | 288 | Ok((not_found, result)) 289 | } 290 | 291 | /// Get the list of transaction steps (what need to be done) 292 | pub async fn get_transaction_steps( 293 | proxy: &TransactionProxy<'_>, 294 | package_ids: &[&str], 295 | ) -> Result> { 296 | if package_ids.is_empty() { 297 | return Ok(vec![]); 298 | } 299 | 300 | collect_packages(proxy, async move { 301 | proxy 302 | .install_packages( 303 | (PK_TRANSACTION_FLAG_ENUM_SIMULATE 304 | | PK_TRANSACTION_FLAG_ENUM_ALLOW_REINSTALL 305 | | PK_TRANSACTION_FLAG_ENUM_ALLOW_DOWNGRADE) as u64, 306 | package_ids, 307 | ) 308 | .await 309 | }) 310 | .await 311 | } 312 | 313 | async fn send_packagekit_hints(proxy: &TransactionProxy<'_>) -> zResult<()> { 314 | proxy 315 | .set_hints(&["background=false", "interactive=true"]) 316 | .await 317 | } 318 | 319 | /// Execute a transaction with progress monitoring 320 | pub async fn execute_transaction( 321 | proxy: &TransactionProxy<'_>, 322 | package_ids: &[&str], 323 | progress_tx: Sender, 324 | ) -> Result<()> { 325 | // safety guard 326 | if package_ids.is_empty() { 327 | return Ok(()); 328 | } 329 | // start transaction 330 | let fut = async { 331 | send_packagekit_hints(proxy).await?; 332 | proxy 333 | .update_packages( 334 | (PK_TRANSACTION_FLAG_ENUM_ONLY_TRUSTED 335 | | PK_TRANSACTION_FLAG_ENUM_ALLOW_REINSTALL 336 | | PK_TRANSACTION_FLAG_ENUM_ALLOW_DOWNGRADE) as u64, 337 | package_ids, 338 | ) 339 | .await 340 | }; 341 | 342 | // start all the monitoring facilities 343 | tokio::select! { 344 | v = monitor_item_progress(proxy, &progress_tx, fut) => v, 345 | v = async { 346 | // handle overall transaction progress 347 | let mut stream = proxy.receive_percentage_changed().await; 348 | // get the "Percentage" properties from the change signal 349 | // if the changed_properties does not contain our interest, just ignore it 350 | while let Some(event) = stream.next().await { 351 | let progress = event.get().await?; 352 | progress_tx.send(PkDisplayProgress::Overall(progress as u32))?; 353 | } 354 | Ok(()) 355 | } => v, 356 | v = async { 357 | // periodically check if PackageKit is still alive 358 | let mut timer = tokio::time::interval(Duration::from_secs(3)); 359 | loop { 360 | proxy.status().await?; 361 | timer.tick().await; 362 | } 363 | } => v 364 | } 365 | } 366 | 367 | async fn monitor_item_progress>>( 368 | proxy: &TransactionProxy<'_>, 369 | progress_tx: &Sender, 370 | fut: Fut, 371 | ) -> Result<()> { 372 | let mut error_signal_stream = proxy.receive_error_code().await?; 373 | let mut finish_signal_stream = proxy.receive_finished().await?; 374 | let mut destroy_signal_stream = proxy.receive_destroy().await?; 375 | let mut progress_signal_stream = proxy.receive_item_progress().await?; 376 | 377 | fut.await?; 378 | tokio::select! { 379 | v = async { 380 | while let Some(p) = OrderedStreamExt::next(&mut progress_signal_stream).await { 381 | let item = p.args()?; 382 | progress_tx.send(PkDisplayProgress::Package( 383 | item.id.to_string(), 384 | item.status as u8, 385 | item.percentage, 386 | ))?; 387 | } 388 | Ok(()) 389 | } => v, 390 | v = async { 391 | while let Some(e) = OrderedStreamExt::next(&mut error_signal_stream).await { 392 | let args = e.args()?; 393 | return Err(anyhow!("({}) {}", args.code, args.details)); 394 | } 395 | Ok(()) 396 | } => v, 397 | v = async { 398 | if let Some(_) = OrderedStreamExt::next(&mut finish_signal_stream).await { 399 | progress_tx.send(PkDisplayProgress::Done)?; 400 | return Ok(()); 401 | } 402 | Ok(()) 403 | } => v, 404 | v = async { 405 | if let Some(_) = OrderedStreamExt::next(&mut destroy_signal_stream).await { 406 | progress_tx.send(PkDisplayProgress::Done)?; 407 | return Ok(()); 408 | } 409 | Ok(()) 410 | } => v 411 | }?; 412 | 413 | Ok(()) 414 | } 415 | 416 | pub fn get_task_details<'a>( 417 | not_found: &'a [String], 418 | meta: &'a [PkPackage], 419 | ) -> Result> { 420 | let mut output = PkTaskList { 421 | upgrade: Vec::with_capacity(meta.len() / 4), 422 | install: Vec::new(), 423 | downgrade: Vec::new(), 424 | erase: Vec::new(), 425 | hold: not_found 426 | .iter() 427 | .map(|name| PkPackgeId { 428 | name, 429 | version: "", 430 | arch: "", 431 | data: "", 432 | }) 433 | .collect(), 434 | }; 435 | 436 | for m in meta { 437 | let parsed = 438 | parse_package_id(&m.package_id).ok_or_else(|| anyhow!("({})", m.package_id))?; 439 | match m.info as u8 { 440 | PK_INFO_ENUM_INSTALLING | PK_INFO_ENUM_REINSTALLING => output.install.push(parsed), 441 | PK_INFO_ENUM_UPDATING => output.upgrade.push(parsed), 442 | PK_INFO_ENUM_DOWNGRADING => output.downgrade.push(parsed), 443 | PK_INFO_ENUM_REMOVING => output.erase.push(parsed), 444 | _ => continue, 445 | } 446 | } 447 | 448 | Ok(output) 449 | } 450 | 451 | /// Take the wake lock and prevent the system from sleeping. Drop the returned file handle to release the lock. 452 | pub async fn take_wake_lock(conn: &Connection, why: &str) -> zResult { 453 | let proxy = Login1Proxy::new(conn).await?; 454 | 455 | proxy.inhibit("shutdown:sleep", "atm", why, "block").await 456 | } 457 | 458 | pub async fn is_using_battery(conn: &Connection) -> zResult { 459 | let proxy = UPowerProxy::new(conn).await?; 460 | 461 | proxy.on_battery().await 462 | } 463 | 464 | pub async fn is_metered_network(conn: &Connection) -> zResult { 465 | let proxy = connect_packagekit(conn).await?; 466 | 467 | Ok(proxy.network_state().await? == PK_NETWORK_ENUM_MOBILE as u32) 468 | } 469 | -------------------------------------------------------------------------------- /src/frontend/tui.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use std::thread; 3 | 4 | use cursive::utils::Counter; 5 | use cursive::{align::HAlign, traits::*, views::*}; 6 | use cursive::{views::Dialog, Cursive, CursiveRunnable}; 7 | 8 | use anyhow::Result; 9 | use cursive_async_view::AsyncView; 10 | use cursive_table_view::{TableView, TableViewItem}; 11 | use dashmap::DashMap; 12 | 13 | use super::cli::privileged_write_source_list; 14 | use super::format_timestamp; 15 | use crate::network::{TopicManifest, TopicManifests}; 16 | use crate::pk::{self, PkPackage, PkTaskList}; 17 | use crate::{fl, network, pm}; 18 | 19 | type MarksMap = DashMap; 20 | 21 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 22 | enum TopicColumn { 23 | Enabled, 24 | Name, 25 | Date, 26 | Description, 27 | } 28 | 29 | impl TableViewItem for network::TopicManifest { 30 | fn to_column(&self, column: TopicColumn) -> String { 31 | match column { 32 | TopicColumn::Enabled => { 33 | if self.enabled { 34 | " ✓".to_string() 35 | } else { 36 | " ".to_string() 37 | } 38 | } 39 | TopicColumn::Name => { 40 | let mut name = self.name.clone(); 41 | if self.closed { 42 | name.push(' '); 43 | name.push_str(&fl!("closed")); 44 | } 45 | name 46 | } 47 | TopicColumn::Date => format_timestamp(self.date).unwrap_or_else(|_| "?".to_string()), 48 | TopicColumn::Description => self.description.clone().unwrap_or_default(), 49 | } 50 | } 51 | fn cmp(&self, other: &Self, column: TopicColumn) -> std::cmp::Ordering 52 | where 53 | Self: Sized, 54 | { 55 | match column { 56 | TopicColumn::Enabled => self.enabled.cmp(&other.enabled), 57 | TopicColumn::Name => self.name.cmp(&other.name), 58 | TopicColumn::Date => self.date.cmp(&other.date), 59 | TopicColumn::Description => self.description.cmp(&other.description), 60 | } 61 | } 62 | } 63 | 64 | struct TUIContext { 65 | async_runner: tokio::runtime::Runtime, 66 | dbus_connection: zbus::Connection, 67 | mirror_url: String, 68 | client: reqwest::Client, 69 | } 70 | 71 | fn create_async_runner() -> Result { 72 | tokio::runtime::Builder::new_current_thread() 73 | .enable_all() 74 | .build() 75 | } 76 | 77 | impl TUIContext { 78 | fn new() -> Result { 79 | let async_runner = create_async_runner()?; 80 | let dbus_connection = async_runner.block_on(pk::create_dbus_connection())?; 81 | let client = network::create_http_client()?; 82 | let mirror_url = async_runner.block_on(network::get_best_mirror_url(&client)); 83 | 84 | Ok(TUIContext { 85 | async_runner, 86 | dbus_connection, 87 | mirror_url, 88 | client, 89 | }) 90 | } 91 | } 92 | 93 | fn show_blocking_message(siv: &mut Cursive, msg: &str) { 94 | siv.add_layer( 95 | Dialog::around(TextView::new(msg)) 96 | .title(fl!("message")) 97 | .padding_lrtb(2, 2, 1, 1), 98 | ); 99 | } 100 | 101 | fn show_error(siv: &mut Cursive, msg: &str) { 102 | siv.add_layer( 103 | Dialog::around(TextView::new(msg)) 104 | .title(fl!("error")) 105 | .button(fl!("exit"), |s| s.quit()) 106 | .padding_lrtb(2, 2, 1, 1), 107 | ); 108 | } 109 | 110 | fn show_message(siv: &mut Cursive, msg: &str) { 111 | siv.add_layer( 112 | Dialog::around(TextView::new(msg)) 113 | .title(fl!("message")) 114 | .button(fl!("ok"), |s| { 115 | s.pop_layer(); 116 | }) 117 | .padding_lrtb(2, 2, 1, 1), 118 | ); 119 | } 120 | 121 | fn show_finished(siv: &mut Cursive) { 122 | show_message(siv, &fl!("apt_finished")); 123 | } 124 | 125 | fn check_network(siv: &mut Cursive, marks: Arc) { 126 | let ctx = siv.user_data::().unwrap(); 127 | if !ctx.async_runner.block_on(async { 128 | pk::is_metered_network(&ctx.dbus_connection) 129 | .await 130 | .unwrap_or(false) 131 | }) { 132 | return check_battery_level(siv, marks); 133 | } 134 | siv.add_layer( 135 | Dialog::around(TextView::new(fl!("pk_metered_network"))) 136 | .title(fl!("message")) 137 | .button(fl!("proceed"), move |s| { 138 | s.pop_layer(); 139 | check_battery_level(s, marks.clone()); 140 | }) 141 | .button(fl!("cancel"), |s| { 142 | s.pop_layer(); 143 | }) 144 | .padding_lrtb(2, 2, 1, 1), 145 | ); 146 | } 147 | 148 | fn check_battery_level(siv: &mut Cursive, marks: Arc) { 149 | let ctx = siv.user_data::().unwrap(); 150 | if !ctx.async_runner.block_on(async { 151 | pk::is_using_battery(&ctx.dbus_connection) 152 | .await 153 | .unwrap_or(false) 154 | }) { 155 | return check_changes(siv, marks); 156 | } 157 | siv.add_layer( 158 | Dialog::around(TextView::new(fl!("pk_battery"))) 159 | .title(fl!("message")) 160 | .button(fl!("proceed"), move |s| { 161 | s.pop_layer(); 162 | check_changes(s, marks.clone()); 163 | }) 164 | .button(fl!("cancel"), |s| { 165 | s.pop_layer(); 166 | }) 167 | .padding_lrtb(2, 2, 1, 1), 168 | ); 169 | } 170 | 171 | fn show_tx_details(tasks: &PkTaskList) -> String { 172 | let mut listing = String::with_capacity(1024); 173 | listing += &fl!("tx_body"); 174 | listing.push('\n'); 175 | 176 | for t in tasks.hold.iter() { 177 | listing += &fl!("tx_hold", package = t.name); 178 | listing.push('\n'); 179 | } 180 | for t in tasks.erase.iter() { 181 | listing += &fl!("tx_erase", package = t.name, version = t.version); 182 | listing.push('\n'); 183 | } 184 | for t in tasks.downgrade.iter() { 185 | listing += &fl!("tx_downgrade", package = t.name, version = t.version); 186 | listing.push('\n'); 187 | } 188 | for t in tasks.upgrade.iter() { 189 | listing += &fl!("tx_upgrade", package = t.name, version = t.version); 190 | listing.push('\n'); 191 | } 192 | for t in tasks.install.iter() { 193 | listing += &fl!("tx_install", package = t.name, version = t.version); 194 | listing.push('\n'); 195 | } 196 | 197 | listing 198 | } 199 | 200 | fn commit_transactions(siv: &mut Cursive, packages: &[PkPackage]) { 201 | if packages.is_empty() { 202 | return siv.cb_sink().send(Box::new(show_finished)).unwrap(); 203 | } 204 | 205 | let cb_sink = siv.cb_sink().clone(); 206 | let (progress_tx, progress_rx) = std::sync::mpsc::channel(); 207 | let package_ids = packages 208 | .iter() 209 | .map(|m| m.package_id.to_string()) 210 | .collect::>(); 211 | // UI components 212 | let item_counter = Counter::new(0); 213 | let overall_counter = Counter::new(0); 214 | let mut status_message = TextView::new(&fl!("exe-prepare")); 215 | let status_text = Arc::new(status_message.get_shared_content()); 216 | siv.add_layer( 217 | Dialog::around( 218 | LinearLayout::vertical() 219 | .child(status_message) 220 | .child(ProgressBar::new().max(100).with_value(item_counter.clone())) 221 | .child(TextView::new(fl!("exe-overall"))) 222 | .child( 223 | ProgressBar::new() 224 | .max(100) 225 | .with_value(overall_counter.clone()), 226 | ), 227 | ) 228 | .title(fl!("exe-title")), 229 | ); 230 | siv.set_autorefresh(true); 231 | // actual execution 232 | let ctx = siv.user_data::().unwrap(); 233 | let dbus_connection = ctx.dbus_connection.clone(); 234 | let transaction_thread = thread::spawn(move || -> Result<()> { 235 | let runner = create_async_runner()?; 236 | runner.block_on(async { 237 | let cookie = pk::take_wake_lock(&dbus_connection, &fl!("pk_inhibit_message")) 238 | .await 239 | .ok(); 240 | let proxy = pk::connect_packagekit(&dbus_connection).await?; 241 | let transaction = pk::create_transaction(&proxy).await?; 242 | let package_ids = package_ids.iter().map(|m| m.as_str()).collect::>(); 243 | pk::execute_transaction(&transaction, &package_ids, progress_tx).await?; 244 | drop(cookie); 245 | 246 | Ok(()) 247 | }) 248 | }); 249 | thread::spawn(move || { 250 | // tracker 251 | let mut tracker = crate::desktop::select_best_tracker(); 252 | tracker.set_general_description(&fl!("info-title")); 253 | loop { 254 | if let Ok(progress) = progress_rx.recv() { 255 | match progress { 256 | pk::PkDisplayProgress::Package(id, status, pct) => { 257 | let name = pk::humanize_package_id(&id); 258 | let status_message = match status { 259 | pk::PK_STATUS_ENUM_DOWNLOAD => fl!("exe_download", name = name), 260 | pk::PK_STATUS_ENUM_INSTALL => fl!("exe-install", name = name), 261 | pk::PK_STATUS_ENUM_SETUP => fl!("exe-setup", name = name), 262 | _ => fl!("exe-install", name = name), 263 | }; 264 | item_counter.set(pct as usize); 265 | tracker.set_message(&fl!("info-status"), &status_message); 266 | status_text.set_content(status_message); 267 | } 268 | pk::PkDisplayProgress::Overall(pct) => { 269 | if pct < 101 { 270 | tracker.set_percent(pct); 271 | overall_counter.set(pct as usize); 272 | } 273 | } 274 | pk::PkDisplayProgress::Done => break, 275 | } 276 | } else { 277 | tracker.terminate(""); 278 | break; 279 | } 280 | } 281 | 282 | let result = transaction_thread.join().unwrap(); 283 | match result { 284 | Ok(()) => cb_sink 285 | .send(Box::new(|s| { 286 | s.set_autorefresh(false); 287 | s.pop_layer(); 288 | show_finished(s); 289 | })) 290 | .unwrap(), 291 | Err(e) => cb_sink 292 | .send(Box::new(move |s| { 293 | s.set_autorefresh(false); 294 | show_error(s, &fl!("pk_comm_error_mid_tx", error = e.to_string())) 295 | })) 296 | .unwrap(), 297 | } 298 | }); 299 | } 300 | 301 | fn show_summary(tasks: PkTaskList, packages: Arc>) -> Dialog { 302 | let mut summary = String::with_capacity(128); 303 | let details = show_tx_details(&tasks); 304 | let updates = tasks.upgrade.len(); 305 | if updates > 0 { 306 | summary += &fl!("update_count", count = updates); 307 | summary.push('\n'); 308 | } 309 | let erase = tasks.erase.len(); 310 | if erase > 0 { 311 | summary += &fl!("erase_count", count = erase); 312 | summary.push('\n'); 313 | } 314 | let install = tasks.install.len(); 315 | if install > 0 { 316 | summary += &fl!("install_count", count = install); 317 | summary.push('\n'); 318 | } 319 | let hold = tasks.hold.len(); 320 | if hold > 0 { 321 | summary += &fl!("no_stable_version", count = hold); 322 | summary.push('\n'); 323 | } 324 | 325 | if summary.is_empty() { 326 | return Dialog::around(TextView::new(fl!("nothing"))).button(fl!("ok"), |s| { 327 | s.pop_layer(); 328 | }); 329 | } 330 | 331 | Dialog::around(TextView::new(summary)) 332 | .title(fl!("message")) 333 | .button(fl!("exit"), |s| { 334 | s.pop_layer(); 335 | }) 336 | .button(fl!("details"), move |s| { 337 | s.add_layer( 338 | Dialog::around(TextView::new(details.clone()).scrollable().scroll_y(true)) 339 | .title(fl!("tx_title")) 340 | .button(fl!("ok"), |s| { 341 | s.pop_layer(); 342 | }) 343 | .padding_lrtb(2, 2, 1, 1), 344 | ); 345 | }) 346 | .button(fl!("proceed"), move |s| { 347 | let p = packages.clone(); 348 | s.pop_layer(); 349 | commit_transactions(s, &p); 350 | }) 351 | .padding_lrtb(2, 2, 1, 1) 352 | } 353 | 354 | fn calculate_changes(siv: &mut Cursive, reinstall: TopicManifests) { 355 | let ctx = siv.user_data::().unwrap(); 356 | let dbus_connection = ctx.dbus_connection.clone(); 357 | let loader = AsyncView::new_with_bg_creator( 358 | siv, 359 | move || { 360 | let runner = create_async_runner().map_err(|e| e.to_string())?; 361 | let mut tracker = crate::desktop::select_best_tracker(); 362 | tracker.set_general_description(&fl!("refresh-apt")); 363 | 364 | runner.block_on(async { 365 | let proxy = pk::connect_packagekit(&dbus_connection) 366 | .await 367 | .map_err(|e| fl!("pk_comm_error", error = e.to_string()))?; 368 | let (not_found, tasks) = pm::switch_topics(&proxy, &reinstall) 369 | .await 370 | .map_err(|e| fl!("pk_tx_error", error = e.to_string()))?; 371 | let tx = pk::create_transaction(&proxy) 372 | .await 373 | .map_err(|e| fl!("pk_comm_error", error = e.to_string()))?; 374 | let tasks = tasks.iter().map(|t| t.as_str()).collect::>(); 375 | let transaction = pk::get_transaction_steps(&tx, &tasks) 376 | .await 377 | .map_err(|e| fl!("pk_tx_error", error = e.to_string()))?; 378 | 379 | Ok((not_found, transaction)) 380 | }) 381 | }, 382 | |(nf, tx)| { 383 | let tx = Arc::new(tx); 384 | let details = pk::get_task_details(&nf, &tx); 385 | match details { 386 | Ok(details) => show_summary(details, Arc::clone(&tx)), 387 | Err(e) => Dialog::around(TextView::new(fl!("pk_invalid_id", name = e.to_string()))) 388 | .title(fl!("error")) 389 | .button(fl!("exit"), |s| s.quit()) 390 | .padding_lrtb(2, 2, 1, 1), 391 | } 392 | }, 393 | ); 394 | siv.add_layer(loader); 395 | } 396 | 397 | fn check_changes(siv: &mut Cursive, marks: Arc) { 398 | let cb_sink = siv.cb_sink().clone(); 399 | let ctx = siv.user_data::().unwrap(); 400 | let mirror_url = ctx.mirror_url.clone(); 401 | 402 | siv.call_on_name( 403 | "topic", 404 | |v: &mut TableView| { 405 | let items = v.borrow_items(); 406 | let marks_ref = &marks; 407 | let mut enabled = Vec::with_capacity(marks_ref.len()); 408 | let mut reinstall = Vec::with_capacity(marks_ref.len()); 409 | 410 | for item in items.iter() { 411 | if item.enabled { 412 | enabled.push(item); 413 | continue; 414 | } 415 | if let Some(enable) = marks_ref.get(&item.name) { 416 | if !*enable { 417 | reinstall.push(item.clone()); 418 | } 419 | } 420 | } 421 | 422 | if let Err(e) = privileged_write_source_list(&enabled, &mirror_url) { 423 | let message = e.to_string(); 424 | cb_sink 425 | .send(Box::new(move |s| show_error(s, &message))) 426 | .unwrap(); 427 | } else { 428 | marks.clear(); 429 | cb_sink 430 | .send(Box::new(|s| { 431 | calculate_changes(s, reinstall); 432 | })) 433 | .unwrap(); 434 | } 435 | }, 436 | ); 437 | } 438 | 439 | fn build_topic_list_view(siv: &mut Cursive, manifest: Vec) { 440 | let map = DashMap::::with_capacity(std::cmp::min(manifest.len(), 10)); 441 | let marks = Arc::new(map); 442 | let marks_table = Arc::clone(&marks); 443 | let has_closed = manifest.iter().any(|x| x.closed); 444 | let table_height = siv.screen_size().y.checked_sub(14).unwrap_or(4); 445 | 446 | let view = TableView::::new() 447 | .column(TopicColumn::Enabled, "", |c| { 448 | c.align(HAlign::Center) 449 | .width(4) 450 | .ordering(std::cmp::Ordering::Greater) 451 | }) 452 | .column(TopicColumn::Name, fl!("name"), |c| { 453 | c.ordering(std::cmp::Ordering::Greater) 454 | }) 455 | .column(TopicColumn::Date, fl!("date"), |c| c.width(12)) 456 | .column(TopicColumn::Description, fl!("description"), |c| c) 457 | .items(manifest) 458 | .on_submit(move |siv, _, index| { 459 | siv.call_on_name( 460 | "topic", 461 | |v: &mut TableView| { 462 | if let Some(item) = v.borrow_item_mut(index) { 463 | item.enabled = !item.enabled; 464 | // update tracking information 465 | if marks_table.contains_key(&item.name) { 466 | marks_table.remove(&item.name); 467 | } else { 468 | marks_table.insert(item.name.clone(), item.enabled); 469 | } 470 | v.needs_relayout(); 471 | } 472 | }, 473 | ); 474 | }) 475 | .with_name("topic") 476 | .min_width(106) 477 | .min_height(table_height) 478 | .scrollable(); 479 | 480 | let mut top_view = LinearLayout::vertical(); 481 | top_view.add_child(TextView::new(fl!("topic-selection-description"))); 482 | top_view.add_child(DummyView {}); 483 | if has_closed { 484 | top_view.add_child(TextView::new(fl!("topic_selection_closed_topic_warning"))); 485 | } 486 | top_view.add_child(view.scroll_x(true)); 487 | siv.pop_layer(); 488 | siv.add_layer( 489 | Dialog::around(top_view) 490 | .title(fl!("topic_selection")) 491 | .button(fl!("exit"), |siv| siv.quit()) 492 | .button(fl!("proceed"), move |siv| check_network(siv, marks.clone())) 493 | .padding_lrtb(2, 2, 1, 1), 494 | ); 495 | } 496 | 497 | fn fetch_manifest(siv: &mut Cursive) { 498 | let ctx = siv.user_data::().unwrap(); 499 | let fetch_result = ctx 500 | .async_runner 501 | .block_on(network::fetch_topics(&ctx.client, &ctx.mirror_url)); 502 | let filtered_list = fetch_result 503 | .and_then(network::filter_topics) 504 | .map(pm::get_display_listing); 505 | match filtered_list { 506 | Ok(filtered_list) => build_topic_list_view(siv, filtered_list), 507 | Err(e) => show_error(siv, &fl!("error-fetch-manifest", error = e.to_string())), 508 | } 509 | } 510 | 511 | fn initialize_context(siv: &mut CursiveRunnable) { 512 | show_blocking_message(siv, &fl!("refresh-manifest")); 513 | let cb_sink = siv.cb_sink().clone(); 514 | thread::spawn(move || { 515 | // time-consuming and blocking operations 516 | let ctx = TUIContext::new(); 517 | match ctx { 518 | Ok(ctx) => { 519 | cb_sink 520 | .send(Box::new(move |s| { 521 | s.set_user_data(ctx); 522 | fetch_manifest(s); 523 | })) 524 | .unwrap(); 525 | } 526 | Err(e) => { 527 | cb_sink 528 | .send(Box::new(move |s| { 529 | s.pop_layer(); 530 | show_error(s, &fl!("error-initialize", error = e.to_string())); 531 | })) 532 | .unwrap(); 533 | } 534 | } 535 | }); 536 | } 537 | 538 | pub fn tui_main() { 539 | let mut siv = cursive::default(); 540 | initialize_context(&mut siv); 541 | siv.run(); 542 | } 543 | -------------------------------------------------------------------------------- /dbus-xml/org.freedesktop.PackageKit.xml: -------------------------------------------------------------------------------- 1 | 5 | ]> 6 | 7 | 8 | 9 | 10 | 11 | The root interface is used for interacting with the daemon. 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | The major version number. 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | The minor version number. 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | The micro version number. 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | The backend name, e.g. "dnf". 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | The backend description, e.g. "Yellow Dog Update Modifier". 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | The backend author, e.g. "Joe Bloggs <joe&blogs.com>". 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | The roles the backend supports, e.g. search-name|refresh-cache. 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | The groups the backend supports, e.g. accessories|games. 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | The filters the backend supports, e.g. installed|newest. 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | The mime-types the backend supports, e.g. 117 | ['application/x-rpm;', 'application/x-deb']. 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | Set when the backend is locked and native tools would fail. 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | Gets the network state from the daemon. This is provided as some clients may not want 140 | to use NetworkManager if the system daemon is configured to use something else. 141 | 142 | 143 | If the system is managed using NetworkManager then the following 144 | states are supported: 145 | unknown, offline, online, 146 | wifi, mobile or wired. 147 | If the system is configured for legacy UNIX network fallback, or NetworkManager 148 | is not running then the folowing states are supported: 149 | unknown, offline or online. 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | The distribution identification, in the 161 | distro;version;arch form e.g. 162 | "debian;squeeze/sid;x86_64". 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | Allows a client to find out if it would be allowed to authorize an action. 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | The action ID, e.g. org.freedesktop.packagekit.system-network-proxy-configure 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | The result, either yes, no or interactive. 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | Creates a new transaction that can have operations done on 205 | it. 206 | Note: The dameon will automatically destroy this transaction 207 | if it is not used after a few minutes. 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | The object_path, e.g. /45_dafeca 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | This method allows us to query how long since an action has successfully completed. 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | The role enum, e.g. update-system 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | The amount of time in seconds 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | Gets the transaction list of any transactions that are in progress 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | A list of transaction ID's 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | This method suggests to PackageKit that the package backend state may have changed. 277 | This allows plugins to the native package manager to suggest that PackageKit drops 278 | it's caches. 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | The reason of the state change. Valid reasons are resume or 287 | posttrans. 288 | Resume is given a lower priority than posttrans. 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | Suggests to the daemon that it should quit as soon as possible, for instance if a native 301 | package management tool is waiting to be used. 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | Gets the history for a given package name. 314 | This uses the internal PackageKit history database and will not 315 | return transactions done outside of PackageKit using a distribution 316 | native tool. 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | The package names to return history for, e.g. [ colord ]. 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | The maximum number of past transactions to return, or 0 for no limit. 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | The list of actions performed on this package. The array may contain 343 | the following keys of types: 344 | info[uint], 345 | user-id[uint], 346 | version[string], 347 | source[string], 348 | timestamp[uint64]. 349 | Other keys and values may be added in the future. 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | Gets the debugging state from the daemon. 362 | No secure state will be shown, and all information is for reference only. 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | The state of the dameon at this specific moment. 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | Sets the proxy used by the dameon. 384 | 385 | 386 | Callers need the org.freedesktop.packagekit.set-proxy 387 | 388 | 389 | 390 | 391 | 392 | The HTTP proxy, e.g. username:password@server:port. 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | The HTTPS proxy, e.g. username:password@server:port. 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | The FTP proxy, e.g. username:password@server:port. 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | The SOCKS proxy, e.g. username:password@server:port. 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | The comma seporated list of sites to not use the proxy for, e.g. 429 | 127.0.0.1,localmirror.org. 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | The PAC file for the proxy, e.g. 439 | /etc/network/school.pac. 440 | Note: Most backends will not be able to use a PAC file. 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | The transaction list has changed, because either a transaction has finished or a new 453 | transaction created. 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | A list of transaction ID's. 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | A system restart has been sceduled 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | This signal is emitted when the repository list has changed 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | This signal is emitted when the number of updates has changed 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | The interface used for interacting with offline actions. 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | If an update has been prepared and is ready to be triggered. 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | If an update has been triggered. 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | If a system upgrade has been prepared and is ready to be triggered. 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | If a system upgrade has been triggered. 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | Details about a prepared system upgrade. Currently recognized keys 564 | are "name" and "version". 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | The action to take when finished applying updates, known values 576 | are power-off, reboot or 577 | unset if no offline update is scheduled. 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | Clears the offline update results store. 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | Triggers the offline update for next boot. 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | The action to take when finished applying updates, known values 608 | are power-off and reboot. 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | Triggers the offline system upgrade for next boot. 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | The action to take when finished installing the system upgrade, known values 629 | are power-off and reboot. 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | Cancels the offline update so the next boot procceeds as normal. 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | Returns the list of prepared updates. 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | An array of package IDs. 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 | 20 | [[package]] 21 | name = "ahash" 22 | version = "0.8.11" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 25 | dependencies = [ 26 | "cfg-if", 27 | "getrandom 0.2.16", 28 | "once_cell", 29 | "version_check", 30 | "zerocopy", 31 | ] 32 | 33 | [[package]] 34 | name = "aho-corasick" 35 | version = "1.1.3" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 38 | dependencies = [ 39 | "memchr", 40 | ] 41 | 42 | [[package]] 43 | name = "anyhow" 44 | version = "1.0.98" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" 47 | 48 | [[package]] 49 | name = "arc-swap" 50 | version = "1.7.1" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" 53 | 54 | [[package]] 55 | name = "argh" 56 | version = "0.1.13" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "34ff18325c8a36b82f992e533ece1ec9f9a9db446bd1c14d4f936bac88fcd240" 59 | dependencies = [ 60 | "argh_derive", 61 | "argh_shared", 62 | "rust-fuzzy-search", 63 | ] 64 | 65 | [[package]] 66 | name = "argh_derive" 67 | version = "0.1.13" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "adb7b2b83a50d329d5d8ccc620f5c7064028828538bdf5646acd60dc1f767803" 70 | dependencies = [ 71 | "argh_shared", 72 | "proc-macro2", 73 | "quote", 74 | "syn", 75 | ] 76 | 77 | [[package]] 78 | name = "argh_shared" 79 | version = "0.1.13" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "a464143cc82dedcdc3928737445362466b7674b5db4e2eb8e869846d6d84f4f6" 82 | dependencies = [ 83 | "serde", 84 | ] 85 | 86 | [[package]] 87 | name = "async-broadcast" 88 | version = "0.7.2" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" 91 | dependencies = [ 92 | "event-listener", 93 | "event-listener-strategy", 94 | "futures-core", 95 | "pin-project-lite", 96 | ] 97 | 98 | [[package]] 99 | name = "async-recursion" 100 | version = "1.1.1" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" 103 | dependencies = [ 104 | "proc-macro2", 105 | "quote", 106 | "syn", 107 | ] 108 | 109 | [[package]] 110 | name = "async-trait" 111 | version = "0.1.88" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" 114 | dependencies = [ 115 | "proc-macro2", 116 | "quote", 117 | "syn", 118 | ] 119 | 120 | [[package]] 121 | name = "atm" 122 | version = "0.6.2" 123 | dependencies = [ 124 | "anyhow", 125 | "argh", 126 | "cursive", 127 | "cursive-async-view", 128 | "cursive_table_view", 129 | "dashmap", 130 | "futures", 131 | "i18n-embed", 132 | "i18n-embed-fl", 133 | "indexmap", 134 | "lazy_static", 135 | "nix", 136 | "reqwest", 137 | "rust-embed", 138 | "serde", 139 | "serde_json", 140 | "sha2", 141 | "tabwriter", 142 | "tempfile", 143 | "time", 144 | "tokio", 145 | "unic-langid", 146 | "winnow", 147 | "zbus", 148 | ] 149 | 150 | [[package]] 151 | name = "atomic-waker" 152 | version = "1.1.2" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 155 | 156 | [[package]] 157 | name = "autocfg" 158 | version = "1.4.0" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 161 | 162 | [[package]] 163 | name = "backtrace" 164 | version = "0.3.74" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 167 | dependencies = [ 168 | "addr2line", 169 | "cfg-if", 170 | "libc", 171 | "miniz_oxide", 172 | "object", 173 | "rustc-demangle", 174 | "windows-targets 0.52.6", 175 | ] 176 | 177 | [[package]] 178 | name = "base64" 179 | version = "0.22.1" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 182 | 183 | [[package]] 184 | name = "basic-toml" 185 | version = "0.1.10" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" 188 | dependencies = [ 189 | "serde", 190 | ] 191 | 192 | [[package]] 193 | name = "bitflags" 194 | version = "2.9.0" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" 197 | 198 | [[package]] 199 | name = "block" 200 | version = "0.1.6" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" 203 | 204 | [[package]] 205 | name = "block-buffer" 206 | version = "0.10.4" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 209 | dependencies = [ 210 | "generic-array", 211 | ] 212 | 213 | [[package]] 214 | name = "bumpalo" 215 | version = "3.17.0" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" 218 | 219 | [[package]] 220 | name = "bytes" 221 | version = "1.10.1" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" 224 | 225 | [[package]] 226 | name = "castaway" 227 | version = "0.2.3" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5" 230 | dependencies = [ 231 | "rustversion", 232 | ] 233 | 234 | [[package]] 235 | name = "cc" 236 | version = "1.2.20" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" 239 | dependencies = [ 240 | "shlex", 241 | ] 242 | 243 | [[package]] 244 | name = "cfg-if" 245 | version = "1.0.0" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 248 | 249 | [[package]] 250 | name = "cfg_aliases" 251 | version = "0.2.1" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 254 | 255 | [[package]] 256 | name = "compact_str" 257 | version = "0.8.1" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32" 260 | dependencies = [ 261 | "castaway", 262 | "cfg-if", 263 | "itoa", 264 | "rustversion", 265 | "ryu", 266 | "static_assertions", 267 | ] 268 | 269 | [[package]] 270 | name = "concurrent-queue" 271 | version = "2.5.0" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" 274 | dependencies = [ 275 | "crossbeam-utils", 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 = "cpufeatures" 296 | version = "0.2.17" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" 299 | dependencies = [ 300 | "libc", 301 | ] 302 | 303 | [[package]] 304 | name = "crossbeam" 305 | version = "0.8.4" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" 308 | dependencies = [ 309 | "crossbeam-channel", 310 | "crossbeam-deque", 311 | "crossbeam-epoch", 312 | "crossbeam-queue", 313 | "crossbeam-utils", 314 | ] 315 | 316 | [[package]] 317 | name = "crossbeam-channel" 318 | version = "0.5.15" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" 321 | dependencies = [ 322 | "crossbeam-utils", 323 | ] 324 | 325 | [[package]] 326 | name = "crossbeam-deque" 327 | version = "0.8.6" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" 330 | dependencies = [ 331 | "crossbeam-epoch", 332 | "crossbeam-utils", 333 | ] 334 | 335 | [[package]] 336 | name = "crossbeam-epoch" 337 | version = "0.9.18" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" 340 | dependencies = [ 341 | "crossbeam-utils", 342 | ] 343 | 344 | [[package]] 345 | name = "crossbeam-queue" 346 | version = "0.3.12" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" 349 | dependencies = [ 350 | "crossbeam-utils", 351 | ] 352 | 353 | [[package]] 354 | name = "crossbeam-utils" 355 | version = "0.8.21" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" 358 | 359 | [[package]] 360 | name = "crossterm" 361 | version = "0.28.1" 362 | source = "registry+https://github.com/rust-lang/crates.io-index" 363 | checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" 364 | dependencies = [ 365 | "bitflags", 366 | "crossterm_winapi", 367 | "mio", 368 | "parking_lot", 369 | "rustix 0.38.44", 370 | "signal-hook", 371 | "signal-hook-mio", 372 | "winapi", 373 | ] 374 | 375 | [[package]] 376 | name = "crossterm_winapi" 377 | version = "0.9.1" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" 380 | dependencies = [ 381 | "winapi", 382 | ] 383 | 384 | [[package]] 385 | name = "crypto-common" 386 | version = "0.1.6" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 389 | dependencies = [ 390 | "generic-array", 391 | "typenum", 392 | ] 393 | 394 | [[package]] 395 | name = "cursive" 396 | version = "0.21.1" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "386d5a36020bb856e9a34ecb8a4e6c9bd6b0262d1857bae4db7bc7e2fdaa532e" 399 | dependencies = [ 400 | "ahash", 401 | "cfg-if", 402 | "crossbeam-channel", 403 | "crossterm", 404 | "cursive_core", 405 | "lazy_static", 406 | "libc", 407 | "log", 408 | "signal-hook", 409 | "unicode-segmentation", 410 | "unicode-width 0.1.14", 411 | ] 412 | 413 | [[package]] 414 | name = "cursive-async-view" 415 | version = "0.8.0" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "240119a1821439b02b9710b22d02b9d0044418452811b0b05230d2c240cfc634" 418 | dependencies = [ 419 | "crossbeam", 420 | "cursive_core", 421 | "doc-comment", 422 | "interpolation", 423 | "lazy_static", 424 | "log", 425 | "num", 426 | "send_wrapper", 427 | ] 428 | 429 | [[package]] 430 | name = "cursive-macros" 431 | version = "0.1.0" 432 | source = "registry+https://github.com/rust-lang/crates.io-index" 433 | checksum = "ac7ac0eb0cede3dfdfebf4d5f22354e05a730b79c25fd03481fc69fcfba0a73e" 434 | dependencies = [ 435 | "proc-macro2", 436 | ] 437 | 438 | [[package]] 439 | name = "cursive_core" 440 | version = "0.4.6" 441 | source = "registry+https://github.com/rust-lang/crates.io-index" 442 | checksum = "321ec774d27fafc66e812034d0025f8858bd7d9095304ff8fc200e0b9f9cc257" 443 | dependencies = [ 444 | "ahash", 445 | "compact_str", 446 | "crossbeam-channel", 447 | "cursive-macros", 448 | "enum-map", 449 | "enumset", 450 | "lazy_static", 451 | "log", 452 | "num", 453 | "parking_lot", 454 | "serde_json", 455 | "time", 456 | "unicode-segmentation", 457 | "unicode-width 0.1.14", 458 | "xi-unicode", 459 | ] 460 | 461 | [[package]] 462 | name = "cursive_table_view" 463 | version = "0.15.0" 464 | source = "registry+https://github.com/rust-lang/crates.io-index" 465 | checksum = "86a6cca21da26bb588502349d09b68574a3e55689ddeaeeb086af373e0ef6766" 466 | dependencies = [ 467 | "cursive_core", 468 | ] 469 | 470 | [[package]] 471 | name = "darling" 472 | version = "0.20.11" 473 | source = "registry+https://github.com/rust-lang/crates.io-index" 474 | checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" 475 | dependencies = [ 476 | "darling_core", 477 | "darling_macro", 478 | ] 479 | 480 | [[package]] 481 | name = "darling_core" 482 | version = "0.20.11" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" 485 | dependencies = [ 486 | "fnv", 487 | "ident_case", 488 | "proc-macro2", 489 | "quote", 490 | "syn", 491 | ] 492 | 493 | [[package]] 494 | name = "darling_macro" 495 | version = "0.20.11" 496 | source = "registry+https://github.com/rust-lang/crates.io-index" 497 | checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" 498 | dependencies = [ 499 | "darling_core", 500 | "quote", 501 | "syn", 502 | ] 503 | 504 | [[package]] 505 | name = "dashmap" 506 | version = "6.1.0" 507 | source = "registry+https://github.com/rust-lang/crates.io-index" 508 | checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" 509 | dependencies = [ 510 | "cfg-if", 511 | "crossbeam-utils", 512 | "hashbrown 0.14.5", 513 | "lock_api", 514 | "once_cell", 515 | "parking_lot_core", 516 | ] 517 | 518 | [[package]] 519 | name = "deranged" 520 | version = "0.4.0" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" 523 | dependencies = [ 524 | "powerfmt", 525 | ] 526 | 527 | [[package]] 528 | name = "digest" 529 | version = "0.10.7" 530 | source = "registry+https://github.com/rust-lang/crates.io-index" 531 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 532 | dependencies = [ 533 | "block-buffer", 534 | "crypto-common", 535 | ] 536 | 537 | [[package]] 538 | name = "displaydoc" 539 | version = "0.2.5" 540 | source = "registry+https://github.com/rust-lang/crates.io-index" 541 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 542 | dependencies = [ 543 | "proc-macro2", 544 | "quote", 545 | "syn", 546 | ] 547 | 548 | [[package]] 549 | name = "doc-comment" 550 | version = "0.3.3" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" 553 | 554 | [[package]] 555 | name = "encoding_rs" 556 | version = "0.8.35" 557 | source = "registry+https://github.com/rust-lang/crates.io-index" 558 | checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" 559 | dependencies = [ 560 | "cfg-if", 561 | ] 562 | 563 | [[package]] 564 | name = "endi" 565 | version = "1.1.0" 566 | source = "registry+https://github.com/rust-lang/crates.io-index" 567 | checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" 568 | 569 | [[package]] 570 | name = "enum-map" 571 | version = "2.7.3" 572 | source = "registry+https://github.com/rust-lang/crates.io-index" 573 | checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" 574 | dependencies = [ 575 | "enum-map-derive", 576 | ] 577 | 578 | [[package]] 579 | name = "enum-map-derive" 580 | version = "0.17.0" 581 | source = "registry+https://github.com/rust-lang/crates.io-index" 582 | checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" 583 | dependencies = [ 584 | "proc-macro2", 585 | "quote", 586 | "syn", 587 | ] 588 | 589 | [[package]] 590 | name = "enumflags2" 591 | version = "0.7.11" 592 | source = "registry+https://github.com/rust-lang/crates.io-index" 593 | checksum = "ba2f4b465f5318854c6f8dd686ede6c0a9dc67d4b1ac241cf0eb51521a309147" 594 | dependencies = [ 595 | "enumflags2_derive", 596 | "serde", 597 | ] 598 | 599 | [[package]] 600 | name = "enumflags2_derive" 601 | version = "0.7.11" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | checksum = "fc4caf64a58d7a6d65ab00639b046ff54399a39f5f2554728895ace4b297cd79" 604 | dependencies = [ 605 | "proc-macro2", 606 | "quote", 607 | "syn", 608 | ] 609 | 610 | [[package]] 611 | name = "enumset" 612 | version = "1.1.5" 613 | source = "registry+https://github.com/rust-lang/crates.io-index" 614 | checksum = "d07a4b049558765cef5f0c1a273c3fc57084d768b44d2f98127aef4cceb17293" 615 | dependencies = [ 616 | "enumset_derive", 617 | ] 618 | 619 | [[package]] 620 | name = "enumset_derive" 621 | version = "0.10.0" 622 | source = "registry+https://github.com/rust-lang/crates.io-index" 623 | checksum = "59c3b24c345d8c314966bdc1832f6c2635bfcce8e7cf363bd115987bba2ee242" 624 | dependencies = [ 625 | "darling", 626 | "proc-macro2", 627 | "quote", 628 | "syn", 629 | ] 630 | 631 | [[package]] 632 | name = "equivalent" 633 | version = "1.0.2" 634 | source = "registry+https://github.com/rust-lang/crates.io-index" 635 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 636 | 637 | [[package]] 638 | name = "errno" 639 | version = "0.3.11" 640 | source = "registry+https://github.com/rust-lang/crates.io-index" 641 | checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" 642 | dependencies = [ 643 | "libc", 644 | "windows-sys 0.59.0", 645 | ] 646 | 647 | [[package]] 648 | name = "event-listener" 649 | version = "5.4.0" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" 652 | dependencies = [ 653 | "concurrent-queue", 654 | "parking", 655 | "pin-project-lite", 656 | ] 657 | 658 | [[package]] 659 | name = "event-listener-strategy" 660 | version = "0.5.4" 661 | source = "registry+https://github.com/rust-lang/crates.io-index" 662 | checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" 663 | dependencies = [ 664 | "event-listener", 665 | "pin-project-lite", 666 | ] 667 | 668 | [[package]] 669 | name = "fastrand" 670 | version = "2.3.0" 671 | source = "registry+https://github.com/rust-lang/crates.io-index" 672 | checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 673 | 674 | [[package]] 675 | name = "find-crate" 676 | version = "0.6.3" 677 | source = "registry+https://github.com/rust-lang/crates.io-index" 678 | checksum = "59a98bbaacea1c0eb6a0876280051b892eb73594fd90cf3b20e9c817029c57d2" 679 | dependencies = [ 680 | "toml", 681 | ] 682 | 683 | [[package]] 684 | name = "fluent" 685 | version = "0.16.1" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "bb74634707bebd0ce645a981148e8fb8c7bccd4c33c652aeffd28bf2f96d555a" 688 | dependencies = [ 689 | "fluent-bundle", 690 | "unic-langid", 691 | ] 692 | 693 | [[package]] 694 | name = "fluent-bundle" 695 | version = "0.15.3" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "7fe0a21ee80050c678013f82edf4b705fe2f26f1f9877593d13198612503f493" 698 | dependencies = [ 699 | "fluent-langneg", 700 | "fluent-syntax", 701 | "intl-memoizer", 702 | "intl_pluralrules", 703 | "rustc-hash", 704 | "self_cell 0.10.3", 705 | "smallvec", 706 | "unic-langid", 707 | ] 708 | 709 | [[package]] 710 | name = "fluent-langneg" 711 | version = "0.13.0" 712 | source = "registry+https://github.com/rust-lang/crates.io-index" 713 | checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94" 714 | dependencies = [ 715 | "unic-langid", 716 | ] 717 | 718 | [[package]] 719 | name = "fluent-syntax" 720 | version = "0.11.1" 721 | source = "registry+https://github.com/rust-lang/crates.io-index" 722 | checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d" 723 | dependencies = [ 724 | "thiserror", 725 | ] 726 | 727 | [[package]] 728 | name = "fnv" 729 | version = "1.0.7" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 732 | 733 | [[package]] 734 | name = "foreign-types" 735 | version = "0.3.2" 736 | source = "registry+https://github.com/rust-lang/crates.io-index" 737 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 738 | dependencies = [ 739 | "foreign-types-shared", 740 | ] 741 | 742 | [[package]] 743 | name = "foreign-types-shared" 744 | version = "0.1.1" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 747 | 748 | [[package]] 749 | name = "form_urlencoded" 750 | version = "1.2.1" 751 | source = "registry+https://github.com/rust-lang/crates.io-index" 752 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 753 | dependencies = [ 754 | "percent-encoding", 755 | ] 756 | 757 | [[package]] 758 | name = "futures" 759 | version = "0.3.31" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" 762 | dependencies = [ 763 | "futures-channel", 764 | "futures-core", 765 | "futures-executor", 766 | "futures-io", 767 | "futures-sink", 768 | "futures-task", 769 | "futures-util", 770 | ] 771 | 772 | [[package]] 773 | name = "futures-channel" 774 | version = "0.3.31" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 777 | dependencies = [ 778 | "futures-core", 779 | "futures-sink", 780 | ] 781 | 782 | [[package]] 783 | name = "futures-core" 784 | version = "0.3.31" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 787 | 788 | [[package]] 789 | name = "futures-executor" 790 | version = "0.3.31" 791 | source = "registry+https://github.com/rust-lang/crates.io-index" 792 | checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" 793 | dependencies = [ 794 | "futures-core", 795 | "futures-task", 796 | "futures-util", 797 | ] 798 | 799 | [[package]] 800 | name = "futures-io" 801 | version = "0.3.31" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 804 | 805 | [[package]] 806 | name = "futures-lite" 807 | version = "2.6.0" 808 | source = "registry+https://github.com/rust-lang/crates.io-index" 809 | checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" 810 | dependencies = [ 811 | "fastrand", 812 | "futures-core", 813 | "futures-io", 814 | "parking", 815 | "pin-project-lite", 816 | ] 817 | 818 | [[package]] 819 | name = "futures-macro" 820 | version = "0.3.31" 821 | source = "registry+https://github.com/rust-lang/crates.io-index" 822 | checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 823 | dependencies = [ 824 | "proc-macro2", 825 | "quote", 826 | "syn", 827 | ] 828 | 829 | [[package]] 830 | name = "futures-sink" 831 | version = "0.3.31" 832 | source = "registry+https://github.com/rust-lang/crates.io-index" 833 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 834 | 835 | [[package]] 836 | name = "futures-task" 837 | version = "0.3.31" 838 | source = "registry+https://github.com/rust-lang/crates.io-index" 839 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 840 | 841 | [[package]] 842 | name = "futures-util" 843 | version = "0.3.31" 844 | source = "registry+https://github.com/rust-lang/crates.io-index" 845 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 846 | dependencies = [ 847 | "futures-channel", 848 | "futures-core", 849 | "futures-io", 850 | "futures-macro", 851 | "futures-sink", 852 | "futures-task", 853 | "memchr", 854 | "pin-project-lite", 855 | "pin-utils", 856 | "slab", 857 | ] 858 | 859 | [[package]] 860 | name = "generic-array" 861 | version = "0.14.7" 862 | source = "registry+https://github.com/rust-lang/crates.io-index" 863 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 864 | dependencies = [ 865 | "typenum", 866 | "version_check", 867 | ] 868 | 869 | [[package]] 870 | name = "getrandom" 871 | version = "0.2.16" 872 | source = "registry+https://github.com/rust-lang/crates.io-index" 873 | checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" 874 | dependencies = [ 875 | "cfg-if", 876 | "libc", 877 | "wasi 0.11.0+wasi-snapshot-preview1", 878 | ] 879 | 880 | [[package]] 881 | name = "getrandom" 882 | version = "0.3.2" 883 | source = "registry+https://github.com/rust-lang/crates.io-index" 884 | checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" 885 | dependencies = [ 886 | "cfg-if", 887 | "libc", 888 | "r-efi", 889 | "wasi 0.14.2+wasi-0.2.4", 890 | ] 891 | 892 | [[package]] 893 | name = "gimli" 894 | version = "0.31.1" 895 | source = "registry+https://github.com/rust-lang/crates.io-index" 896 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 897 | 898 | [[package]] 899 | name = "h2" 900 | version = "0.4.9" 901 | source = "registry+https://github.com/rust-lang/crates.io-index" 902 | checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633" 903 | dependencies = [ 904 | "atomic-waker", 905 | "bytes", 906 | "fnv", 907 | "futures-core", 908 | "futures-sink", 909 | "http", 910 | "indexmap", 911 | "slab", 912 | "tokio", 913 | "tokio-util", 914 | "tracing", 915 | ] 916 | 917 | [[package]] 918 | name = "hashbrown" 919 | version = "0.14.5" 920 | source = "registry+https://github.com/rust-lang/crates.io-index" 921 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 922 | 923 | [[package]] 924 | name = "hashbrown" 925 | version = "0.15.2" 926 | source = "registry+https://github.com/rust-lang/crates.io-index" 927 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 928 | 929 | [[package]] 930 | name = "hex" 931 | version = "0.4.3" 932 | source = "registry+https://github.com/rust-lang/crates.io-index" 933 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 934 | 935 | [[package]] 936 | name = "http" 937 | version = "1.3.1" 938 | source = "registry+https://github.com/rust-lang/crates.io-index" 939 | checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" 940 | dependencies = [ 941 | "bytes", 942 | "fnv", 943 | "itoa", 944 | ] 945 | 946 | [[package]] 947 | name = "http-body" 948 | version = "1.0.1" 949 | source = "registry+https://github.com/rust-lang/crates.io-index" 950 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 951 | dependencies = [ 952 | "bytes", 953 | "http", 954 | ] 955 | 956 | [[package]] 957 | name = "http-body-util" 958 | version = "0.1.3" 959 | source = "registry+https://github.com/rust-lang/crates.io-index" 960 | checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" 961 | dependencies = [ 962 | "bytes", 963 | "futures-core", 964 | "http", 965 | "http-body", 966 | "pin-project-lite", 967 | ] 968 | 969 | [[package]] 970 | name = "httparse" 971 | version = "1.10.1" 972 | source = "registry+https://github.com/rust-lang/crates.io-index" 973 | checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" 974 | 975 | [[package]] 976 | name = "hyper" 977 | version = "1.6.0" 978 | source = "registry+https://github.com/rust-lang/crates.io-index" 979 | checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" 980 | dependencies = [ 981 | "bytes", 982 | "futures-channel", 983 | "futures-util", 984 | "h2", 985 | "http", 986 | "http-body", 987 | "httparse", 988 | "itoa", 989 | "pin-project-lite", 990 | "smallvec", 991 | "tokio", 992 | "want", 993 | ] 994 | 995 | [[package]] 996 | name = "hyper-rustls" 997 | version = "0.27.5" 998 | source = "registry+https://github.com/rust-lang/crates.io-index" 999 | checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" 1000 | dependencies = [ 1001 | "futures-util", 1002 | "http", 1003 | "hyper", 1004 | "hyper-util", 1005 | "rustls", 1006 | "rustls-pki-types", 1007 | "tokio", 1008 | "tokio-rustls", 1009 | "tower-service", 1010 | ] 1011 | 1012 | [[package]] 1013 | name = "hyper-tls" 1014 | version = "0.6.0" 1015 | source = "registry+https://github.com/rust-lang/crates.io-index" 1016 | checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 1017 | dependencies = [ 1018 | "bytes", 1019 | "http-body-util", 1020 | "hyper", 1021 | "hyper-util", 1022 | "native-tls", 1023 | "tokio", 1024 | "tokio-native-tls", 1025 | "tower-service", 1026 | ] 1027 | 1028 | [[package]] 1029 | name = "hyper-util" 1030 | version = "0.1.11" 1031 | source = "registry+https://github.com/rust-lang/crates.io-index" 1032 | checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" 1033 | dependencies = [ 1034 | "bytes", 1035 | "futures-channel", 1036 | "futures-util", 1037 | "http", 1038 | "http-body", 1039 | "hyper", 1040 | "libc", 1041 | "pin-project-lite", 1042 | "socket2", 1043 | "tokio", 1044 | "tower-service", 1045 | "tracing", 1046 | ] 1047 | 1048 | [[package]] 1049 | name = "i18n-config" 1050 | version = "0.4.7" 1051 | source = "registry+https://github.com/rust-lang/crates.io-index" 1052 | checksum = "8e88074831c0be5b89181b05e6748c4915f77769ecc9a4c372f88b169a8509c9" 1053 | dependencies = [ 1054 | "basic-toml", 1055 | "log", 1056 | "serde", 1057 | "serde_derive", 1058 | "thiserror", 1059 | "unic-langid", 1060 | ] 1061 | 1062 | [[package]] 1063 | name = "i18n-embed" 1064 | version = "0.15.4" 1065 | source = "registry+https://github.com/rust-lang/crates.io-index" 1066 | checksum = "669ffc2c93f97e6ddf06ddbe999fcd6782e3342978bb85f7d3c087c7978404c4" 1067 | dependencies = [ 1068 | "arc-swap", 1069 | "fluent", 1070 | "fluent-langneg", 1071 | "fluent-syntax", 1072 | "i18n-embed-impl", 1073 | "intl-memoizer", 1074 | "locale_config", 1075 | "log", 1076 | "parking_lot", 1077 | "rust-embed", 1078 | "thiserror", 1079 | "unic-langid", 1080 | "walkdir", 1081 | ] 1082 | 1083 | [[package]] 1084 | name = "i18n-embed-fl" 1085 | version = "0.9.4" 1086 | source = "registry+https://github.com/rust-lang/crates.io-index" 1087 | checksum = "04b2969d0b3fc6143776c535184c19722032b43e6a642d710fa3f88faec53c2d" 1088 | dependencies = [ 1089 | "find-crate", 1090 | "fluent", 1091 | "fluent-syntax", 1092 | "i18n-config", 1093 | "i18n-embed", 1094 | "proc-macro-error2", 1095 | "proc-macro2", 1096 | "quote", 1097 | "strsim", 1098 | "syn", 1099 | "unic-langid", 1100 | ] 1101 | 1102 | [[package]] 1103 | name = "i18n-embed-impl" 1104 | version = "0.8.4" 1105 | source = "registry+https://github.com/rust-lang/crates.io-index" 1106 | checksum = "0f2cc0e0523d1fe6fc2c6f66e5038624ea8091b3e7748b5e8e0c84b1698db6c2" 1107 | dependencies = [ 1108 | "find-crate", 1109 | "i18n-config", 1110 | "proc-macro2", 1111 | "quote", 1112 | "syn", 1113 | ] 1114 | 1115 | [[package]] 1116 | name = "icu_collections" 1117 | version = "1.5.0" 1118 | source = "registry+https://github.com/rust-lang/crates.io-index" 1119 | checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" 1120 | dependencies = [ 1121 | "displaydoc", 1122 | "yoke", 1123 | "zerofrom", 1124 | "zerovec", 1125 | ] 1126 | 1127 | [[package]] 1128 | name = "icu_locid" 1129 | version = "1.5.0" 1130 | source = "registry+https://github.com/rust-lang/crates.io-index" 1131 | checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" 1132 | dependencies = [ 1133 | "displaydoc", 1134 | "litemap", 1135 | "tinystr", 1136 | "writeable", 1137 | "zerovec", 1138 | ] 1139 | 1140 | [[package]] 1141 | name = "icu_locid_transform" 1142 | version = "1.5.0" 1143 | source = "registry+https://github.com/rust-lang/crates.io-index" 1144 | checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" 1145 | dependencies = [ 1146 | "displaydoc", 1147 | "icu_locid", 1148 | "icu_locid_transform_data", 1149 | "icu_provider", 1150 | "tinystr", 1151 | "zerovec", 1152 | ] 1153 | 1154 | [[package]] 1155 | name = "icu_locid_transform_data" 1156 | version = "1.5.1" 1157 | source = "registry+https://github.com/rust-lang/crates.io-index" 1158 | checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" 1159 | 1160 | [[package]] 1161 | name = "icu_normalizer" 1162 | version = "1.5.0" 1163 | source = "registry+https://github.com/rust-lang/crates.io-index" 1164 | checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" 1165 | dependencies = [ 1166 | "displaydoc", 1167 | "icu_collections", 1168 | "icu_normalizer_data", 1169 | "icu_properties", 1170 | "icu_provider", 1171 | "smallvec", 1172 | "utf16_iter", 1173 | "utf8_iter", 1174 | "write16", 1175 | "zerovec", 1176 | ] 1177 | 1178 | [[package]] 1179 | name = "icu_normalizer_data" 1180 | version = "1.5.1" 1181 | source = "registry+https://github.com/rust-lang/crates.io-index" 1182 | checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" 1183 | 1184 | [[package]] 1185 | name = "icu_properties" 1186 | version = "1.5.1" 1187 | source = "registry+https://github.com/rust-lang/crates.io-index" 1188 | checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" 1189 | dependencies = [ 1190 | "displaydoc", 1191 | "icu_collections", 1192 | "icu_locid_transform", 1193 | "icu_properties_data", 1194 | "icu_provider", 1195 | "tinystr", 1196 | "zerovec", 1197 | ] 1198 | 1199 | [[package]] 1200 | name = "icu_properties_data" 1201 | version = "1.5.1" 1202 | source = "registry+https://github.com/rust-lang/crates.io-index" 1203 | checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" 1204 | 1205 | [[package]] 1206 | name = "icu_provider" 1207 | version = "1.5.0" 1208 | source = "registry+https://github.com/rust-lang/crates.io-index" 1209 | checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" 1210 | dependencies = [ 1211 | "displaydoc", 1212 | "icu_locid", 1213 | "icu_provider_macros", 1214 | "stable_deref_trait", 1215 | "tinystr", 1216 | "writeable", 1217 | "yoke", 1218 | "zerofrom", 1219 | "zerovec", 1220 | ] 1221 | 1222 | [[package]] 1223 | name = "icu_provider_macros" 1224 | version = "1.5.0" 1225 | source = "registry+https://github.com/rust-lang/crates.io-index" 1226 | checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" 1227 | dependencies = [ 1228 | "proc-macro2", 1229 | "quote", 1230 | "syn", 1231 | ] 1232 | 1233 | [[package]] 1234 | name = "ident_case" 1235 | version = "1.0.1" 1236 | source = "registry+https://github.com/rust-lang/crates.io-index" 1237 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 1238 | 1239 | [[package]] 1240 | name = "idna" 1241 | version = "1.0.3" 1242 | source = "registry+https://github.com/rust-lang/crates.io-index" 1243 | checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 1244 | dependencies = [ 1245 | "idna_adapter", 1246 | "smallvec", 1247 | "utf8_iter", 1248 | ] 1249 | 1250 | [[package]] 1251 | name = "idna_adapter" 1252 | version = "1.2.0" 1253 | source = "registry+https://github.com/rust-lang/crates.io-index" 1254 | checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" 1255 | dependencies = [ 1256 | "icu_normalizer", 1257 | "icu_properties", 1258 | ] 1259 | 1260 | [[package]] 1261 | name = "indexmap" 1262 | version = "2.9.0" 1263 | source = "registry+https://github.com/rust-lang/crates.io-index" 1264 | checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" 1265 | dependencies = [ 1266 | "equivalent", 1267 | "hashbrown 0.15.2", 1268 | "serde", 1269 | ] 1270 | 1271 | [[package]] 1272 | name = "interpolation" 1273 | version = "0.2.0" 1274 | source = "registry+https://github.com/rust-lang/crates.io-index" 1275 | checksum = "d3b7357d2bbc5ee92f8e899ab645233e43d21407573cceb37fed8bc3dede2c02" 1276 | 1277 | [[package]] 1278 | name = "intl-memoizer" 1279 | version = "0.5.2" 1280 | source = "registry+https://github.com/rust-lang/crates.io-index" 1281 | checksum = "fe22e020fce238ae18a6d5d8c502ee76a52a6e880d99477657e6acc30ec57bda" 1282 | dependencies = [ 1283 | "type-map", 1284 | "unic-langid", 1285 | ] 1286 | 1287 | [[package]] 1288 | name = "intl_pluralrules" 1289 | version = "7.0.2" 1290 | source = "registry+https://github.com/rust-lang/crates.io-index" 1291 | checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972" 1292 | dependencies = [ 1293 | "unic-langid", 1294 | ] 1295 | 1296 | [[package]] 1297 | name = "ipnet" 1298 | version = "2.11.0" 1299 | source = "registry+https://github.com/rust-lang/crates.io-index" 1300 | checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" 1301 | 1302 | [[package]] 1303 | name = "itoa" 1304 | version = "1.0.15" 1305 | source = "registry+https://github.com/rust-lang/crates.io-index" 1306 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 1307 | 1308 | [[package]] 1309 | name = "js-sys" 1310 | version = "0.3.77" 1311 | source = "registry+https://github.com/rust-lang/crates.io-index" 1312 | checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" 1313 | dependencies = [ 1314 | "once_cell", 1315 | "wasm-bindgen", 1316 | ] 1317 | 1318 | [[package]] 1319 | name = "lazy_static" 1320 | version = "1.5.0" 1321 | source = "registry+https://github.com/rust-lang/crates.io-index" 1322 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 1323 | 1324 | [[package]] 1325 | name = "libc" 1326 | version = "0.2.172" 1327 | source = "registry+https://github.com/rust-lang/crates.io-index" 1328 | checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" 1329 | 1330 | [[package]] 1331 | name = "linux-raw-sys" 1332 | version = "0.4.15" 1333 | source = "registry+https://github.com/rust-lang/crates.io-index" 1334 | checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" 1335 | 1336 | [[package]] 1337 | name = "linux-raw-sys" 1338 | version = "0.9.4" 1339 | source = "registry+https://github.com/rust-lang/crates.io-index" 1340 | checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" 1341 | 1342 | [[package]] 1343 | name = "litemap" 1344 | version = "0.7.5" 1345 | source = "registry+https://github.com/rust-lang/crates.io-index" 1346 | checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" 1347 | 1348 | [[package]] 1349 | name = "locale_config" 1350 | version = "0.3.0" 1351 | source = "registry+https://github.com/rust-lang/crates.io-index" 1352 | checksum = "08d2c35b16f4483f6c26f0e4e9550717a2f6575bcd6f12a53ff0c490a94a6934" 1353 | dependencies = [ 1354 | "lazy_static", 1355 | "objc", 1356 | "objc-foundation", 1357 | "regex", 1358 | "winapi", 1359 | ] 1360 | 1361 | [[package]] 1362 | name = "lock_api" 1363 | version = "0.4.12" 1364 | source = "registry+https://github.com/rust-lang/crates.io-index" 1365 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 1366 | dependencies = [ 1367 | "autocfg", 1368 | "scopeguard", 1369 | ] 1370 | 1371 | [[package]] 1372 | name = "log" 1373 | version = "0.4.27" 1374 | source = "registry+https://github.com/rust-lang/crates.io-index" 1375 | checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" 1376 | 1377 | [[package]] 1378 | name = "malloc_buf" 1379 | version = "0.0.6" 1380 | source = "registry+https://github.com/rust-lang/crates.io-index" 1381 | checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" 1382 | dependencies = [ 1383 | "libc", 1384 | ] 1385 | 1386 | [[package]] 1387 | name = "memchr" 1388 | version = "2.7.4" 1389 | source = "registry+https://github.com/rust-lang/crates.io-index" 1390 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 1391 | 1392 | [[package]] 1393 | name = "memoffset" 1394 | version = "0.9.1" 1395 | source = "registry+https://github.com/rust-lang/crates.io-index" 1396 | checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" 1397 | dependencies = [ 1398 | "autocfg", 1399 | ] 1400 | 1401 | [[package]] 1402 | name = "mime" 1403 | version = "0.3.17" 1404 | source = "registry+https://github.com/rust-lang/crates.io-index" 1405 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 1406 | 1407 | [[package]] 1408 | name = "miniz_oxide" 1409 | version = "0.8.8" 1410 | source = "registry+https://github.com/rust-lang/crates.io-index" 1411 | checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" 1412 | dependencies = [ 1413 | "adler2", 1414 | ] 1415 | 1416 | [[package]] 1417 | name = "mio" 1418 | version = "1.0.3" 1419 | source = "registry+https://github.com/rust-lang/crates.io-index" 1420 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 1421 | dependencies = [ 1422 | "libc", 1423 | "log", 1424 | "wasi 0.11.0+wasi-snapshot-preview1", 1425 | "windows-sys 0.52.0", 1426 | ] 1427 | 1428 | [[package]] 1429 | name = "native-tls" 1430 | version = "0.2.14" 1431 | source = "registry+https://github.com/rust-lang/crates.io-index" 1432 | checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" 1433 | dependencies = [ 1434 | "libc", 1435 | "log", 1436 | "openssl", 1437 | "openssl-probe", 1438 | "openssl-sys", 1439 | "schannel", 1440 | "security-framework", 1441 | "security-framework-sys", 1442 | "tempfile", 1443 | ] 1444 | 1445 | [[package]] 1446 | name = "nix" 1447 | version = "0.29.0" 1448 | source = "registry+https://github.com/rust-lang/crates.io-index" 1449 | checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" 1450 | dependencies = [ 1451 | "bitflags", 1452 | "cfg-if", 1453 | "cfg_aliases", 1454 | "libc", 1455 | "memoffset", 1456 | ] 1457 | 1458 | [[package]] 1459 | name = "num" 1460 | version = "0.4.3" 1461 | source = "registry+https://github.com/rust-lang/crates.io-index" 1462 | checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" 1463 | dependencies = [ 1464 | "num-bigint", 1465 | "num-complex", 1466 | "num-integer", 1467 | "num-iter", 1468 | "num-rational", 1469 | "num-traits", 1470 | ] 1471 | 1472 | [[package]] 1473 | name = "num-bigint" 1474 | version = "0.4.6" 1475 | source = "registry+https://github.com/rust-lang/crates.io-index" 1476 | checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" 1477 | dependencies = [ 1478 | "num-integer", 1479 | "num-traits", 1480 | ] 1481 | 1482 | [[package]] 1483 | name = "num-complex" 1484 | version = "0.4.6" 1485 | source = "registry+https://github.com/rust-lang/crates.io-index" 1486 | checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" 1487 | dependencies = [ 1488 | "num-traits", 1489 | ] 1490 | 1491 | [[package]] 1492 | name = "num-conv" 1493 | version = "0.1.0" 1494 | source = "registry+https://github.com/rust-lang/crates.io-index" 1495 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 1496 | 1497 | [[package]] 1498 | name = "num-integer" 1499 | version = "0.1.46" 1500 | source = "registry+https://github.com/rust-lang/crates.io-index" 1501 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 1502 | dependencies = [ 1503 | "num-traits", 1504 | ] 1505 | 1506 | [[package]] 1507 | name = "num-iter" 1508 | version = "0.1.45" 1509 | source = "registry+https://github.com/rust-lang/crates.io-index" 1510 | checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" 1511 | dependencies = [ 1512 | "autocfg", 1513 | "num-integer", 1514 | "num-traits", 1515 | ] 1516 | 1517 | [[package]] 1518 | name = "num-rational" 1519 | version = "0.4.2" 1520 | source = "registry+https://github.com/rust-lang/crates.io-index" 1521 | checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" 1522 | dependencies = [ 1523 | "num-bigint", 1524 | "num-integer", 1525 | "num-traits", 1526 | ] 1527 | 1528 | [[package]] 1529 | name = "num-traits" 1530 | version = "0.2.19" 1531 | source = "registry+https://github.com/rust-lang/crates.io-index" 1532 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 1533 | dependencies = [ 1534 | "autocfg", 1535 | ] 1536 | 1537 | [[package]] 1538 | name = "num_threads" 1539 | version = "0.1.7" 1540 | source = "registry+https://github.com/rust-lang/crates.io-index" 1541 | checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" 1542 | dependencies = [ 1543 | "libc", 1544 | ] 1545 | 1546 | [[package]] 1547 | name = "objc" 1548 | version = "0.2.7" 1549 | source = "registry+https://github.com/rust-lang/crates.io-index" 1550 | checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" 1551 | dependencies = [ 1552 | "malloc_buf", 1553 | ] 1554 | 1555 | [[package]] 1556 | name = "objc-foundation" 1557 | version = "0.1.1" 1558 | source = "registry+https://github.com/rust-lang/crates.io-index" 1559 | checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" 1560 | dependencies = [ 1561 | "block", 1562 | "objc", 1563 | "objc_id", 1564 | ] 1565 | 1566 | [[package]] 1567 | name = "objc_id" 1568 | version = "0.1.1" 1569 | source = "registry+https://github.com/rust-lang/crates.io-index" 1570 | checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" 1571 | dependencies = [ 1572 | "objc", 1573 | ] 1574 | 1575 | [[package]] 1576 | name = "object" 1577 | version = "0.36.7" 1578 | source = "registry+https://github.com/rust-lang/crates.io-index" 1579 | checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 1580 | dependencies = [ 1581 | "memchr", 1582 | ] 1583 | 1584 | [[package]] 1585 | name = "once_cell" 1586 | version = "1.21.3" 1587 | source = "registry+https://github.com/rust-lang/crates.io-index" 1588 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 1589 | 1590 | [[package]] 1591 | name = "openssl" 1592 | version = "0.10.72" 1593 | source = "registry+https://github.com/rust-lang/crates.io-index" 1594 | checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" 1595 | dependencies = [ 1596 | "bitflags", 1597 | "cfg-if", 1598 | "foreign-types", 1599 | "libc", 1600 | "once_cell", 1601 | "openssl-macros", 1602 | "openssl-sys", 1603 | ] 1604 | 1605 | [[package]] 1606 | name = "openssl-macros" 1607 | version = "0.1.1" 1608 | source = "registry+https://github.com/rust-lang/crates.io-index" 1609 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 1610 | dependencies = [ 1611 | "proc-macro2", 1612 | "quote", 1613 | "syn", 1614 | ] 1615 | 1616 | [[package]] 1617 | name = "openssl-probe" 1618 | version = "0.1.6" 1619 | source = "registry+https://github.com/rust-lang/crates.io-index" 1620 | checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" 1621 | 1622 | [[package]] 1623 | name = "openssl-sys" 1624 | version = "0.9.107" 1625 | source = "registry+https://github.com/rust-lang/crates.io-index" 1626 | checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" 1627 | dependencies = [ 1628 | "cc", 1629 | "libc", 1630 | "pkg-config", 1631 | "vcpkg", 1632 | ] 1633 | 1634 | [[package]] 1635 | name = "ordered-stream" 1636 | version = "0.2.0" 1637 | source = "registry+https://github.com/rust-lang/crates.io-index" 1638 | checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" 1639 | dependencies = [ 1640 | "futures-core", 1641 | "pin-project-lite", 1642 | ] 1643 | 1644 | [[package]] 1645 | name = "parking" 1646 | version = "2.2.1" 1647 | source = "registry+https://github.com/rust-lang/crates.io-index" 1648 | checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" 1649 | 1650 | [[package]] 1651 | name = "parking_lot" 1652 | version = "0.12.3" 1653 | source = "registry+https://github.com/rust-lang/crates.io-index" 1654 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 1655 | dependencies = [ 1656 | "lock_api", 1657 | "parking_lot_core", 1658 | ] 1659 | 1660 | [[package]] 1661 | name = "parking_lot_core" 1662 | version = "0.9.10" 1663 | source = "registry+https://github.com/rust-lang/crates.io-index" 1664 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 1665 | dependencies = [ 1666 | "cfg-if", 1667 | "libc", 1668 | "redox_syscall", 1669 | "smallvec", 1670 | "windows-targets 0.52.6", 1671 | ] 1672 | 1673 | [[package]] 1674 | name = "percent-encoding" 1675 | version = "2.3.1" 1676 | source = "registry+https://github.com/rust-lang/crates.io-index" 1677 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1678 | 1679 | [[package]] 1680 | name = "pin-project-lite" 1681 | version = "0.2.16" 1682 | source = "registry+https://github.com/rust-lang/crates.io-index" 1683 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 1684 | 1685 | [[package]] 1686 | name = "pin-utils" 1687 | version = "0.1.0" 1688 | source = "registry+https://github.com/rust-lang/crates.io-index" 1689 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1690 | 1691 | [[package]] 1692 | name = "pkg-config" 1693 | version = "0.3.32" 1694 | source = "registry+https://github.com/rust-lang/crates.io-index" 1695 | checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" 1696 | 1697 | [[package]] 1698 | name = "powerfmt" 1699 | version = "0.2.0" 1700 | source = "registry+https://github.com/rust-lang/crates.io-index" 1701 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 1702 | 1703 | [[package]] 1704 | name = "proc-macro-crate" 1705 | version = "3.3.0" 1706 | source = "registry+https://github.com/rust-lang/crates.io-index" 1707 | checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" 1708 | dependencies = [ 1709 | "toml_edit", 1710 | ] 1711 | 1712 | [[package]] 1713 | name = "proc-macro-error-attr2" 1714 | version = "2.0.0" 1715 | source = "registry+https://github.com/rust-lang/crates.io-index" 1716 | checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" 1717 | dependencies = [ 1718 | "proc-macro2", 1719 | "quote", 1720 | ] 1721 | 1722 | [[package]] 1723 | name = "proc-macro-error2" 1724 | version = "2.0.1" 1725 | source = "registry+https://github.com/rust-lang/crates.io-index" 1726 | checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" 1727 | dependencies = [ 1728 | "proc-macro-error-attr2", 1729 | "proc-macro2", 1730 | "quote", 1731 | "syn", 1732 | ] 1733 | 1734 | [[package]] 1735 | name = "proc-macro2" 1736 | version = "1.0.95" 1737 | source = "registry+https://github.com/rust-lang/crates.io-index" 1738 | checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" 1739 | dependencies = [ 1740 | "unicode-ident", 1741 | ] 1742 | 1743 | [[package]] 1744 | name = "quote" 1745 | version = "1.0.40" 1746 | source = "registry+https://github.com/rust-lang/crates.io-index" 1747 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 1748 | dependencies = [ 1749 | "proc-macro2", 1750 | ] 1751 | 1752 | [[package]] 1753 | name = "r-efi" 1754 | version = "5.2.0" 1755 | source = "registry+https://github.com/rust-lang/crates.io-index" 1756 | checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" 1757 | 1758 | [[package]] 1759 | name = "redox_syscall" 1760 | version = "0.5.11" 1761 | source = "registry+https://github.com/rust-lang/crates.io-index" 1762 | checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" 1763 | dependencies = [ 1764 | "bitflags", 1765 | ] 1766 | 1767 | [[package]] 1768 | name = "regex" 1769 | version = "1.11.1" 1770 | source = "registry+https://github.com/rust-lang/crates.io-index" 1771 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 1772 | dependencies = [ 1773 | "aho-corasick", 1774 | "memchr", 1775 | "regex-automata", 1776 | "regex-syntax", 1777 | ] 1778 | 1779 | [[package]] 1780 | name = "regex-automata" 1781 | version = "0.4.9" 1782 | source = "registry+https://github.com/rust-lang/crates.io-index" 1783 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 1784 | dependencies = [ 1785 | "aho-corasick", 1786 | "memchr", 1787 | "regex-syntax", 1788 | ] 1789 | 1790 | [[package]] 1791 | name = "regex-syntax" 1792 | version = "0.8.5" 1793 | source = "registry+https://github.com/rust-lang/crates.io-index" 1794 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 1795 | 1796 | [[package]] 1797 | name = "reqwest" 1798 | version = "0.12.15" 1799 | source = "registry+https://github.com/rust-lang/crates.io-index" 1800 | checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" 1801 | dependencies = [ 1802 | "base64", 1803 | "bytes", 1804 | "encoding_rs", 1805 | "futures-core", 1806 | "futures-util", 1807 | "h2", 1808 | "http", 1809 | "http-body", 1810 | "http-body-util", 1811 | "hyper", 1812 | "hyper-rustls", 1813 | "hyper-tls", 1814 | "hyper-util", 1815 | "ipnet", 1816 | "js-sys", 1817 | "log", 1818 | "mime", 1819 | "native-tls", 1820 | "once_cell", 1821 | "percent-encoding", 1822 | "pin-project-lite", 1823 | "rustls-pemfile", 1824 | "serde", 1825 | "serde_json", 1826 | "serde_urlencoded", 1827 | "sync_wrapper", 1828 | "system-configuration", 1829 | "tokio", 1830 | "tokio-native-tls", 1831 | "tower", 1832 | "tower-service", 1833 | "url", 1834 | "wasm-bindgen", 1835 | "wasm-bindgen-futures", 1836 | "web-sys", 1837 | "windows-registry", 1838 | ] 1839 | 1840 | [[package]] 1841 | name = "ring" 1842 | version = "0.17.14" 1843 | source = "registry+https://github.com/rust-lang/crates.io-index" 1844 | checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" 1845 | dependencies = [ 1846 | "cc", 1847 | "cfg-if", 1848 | "getrandom 0.2.16", 1849 | "libc", 1850 | "untrusted", 1851 | "windows-sys 0.52.0", 1852 | ] 1853 | 1854 | [[package]] 1855 | name = "rust-embed" 1856 | version = "8.7.0" 1857 | source = "registry+https://github.com/rust-lang/crates.io-index" 1858 | checksum = "e5fbc0ee50fcb99af7cebb442e5df7b5b45e9460ffa3f8f549cd26b862bec49d" 1859 | dependencies = [ 1860 | "rust-embed-impl", 1861 | "rust-embed-utils", 1862 | "walkdir", 1863 | ] 1864 | 1865 | [[package]] 1866 | name = "rust-embed-impl" 1867 | version = "8.7.0" 1868 | source = "registry+https://github.com/rust-lang/crates.io-index" 1869 | checksum = "6bf418c9a2e3f6663ca38b8a7134cc2c2167c9d69688860e8961e3faa731702e" 1870 | dependencies = [ 1871 | "proc-macro2", 1872 | "quote", 1873 | "rust-embed-utils", 1874 | "syn", 1875 | "walkdir", 1876 | ] 1877 | 1878 | [[package]] 1879 | name = "rust-embed-utils" 1880 | version = "8.7.0" 1881 | source = "registry+https://github.com/rust-lang/crates.io-index" 1882 | checksum = "08d55b95147fe01265d06b3955db798bdaed52e60e2211c41137701b3aba8e21" 1883 | dependencies = [ 1884 | "sha2", 1885 | "walkdir", 1886 | ] 1887 | 1888 | [[package]] 1889 | name = "rust-fuzzy-search" 1890 | version = "0.1.1" 1891 | source = "registry+https://github.com/rust-lang/crates.io-index" 1892 | checksum = "a157657054ffe556d8858504af8a672a054a6e0bd9e8ee531059100c0fa11bb2" 1893 | 1894 | [[package]] 1895 | name = "rustc-demangle" 1896 | version = "0.1.24" 1897 | source = "registry+https://github.com/rust-lang/crates.io-index" 1898 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1899 | 1900 | [[package]] 1901 | name = "rustc-hash" 1902 | version = "1.1.0" 1903 | source = "registry+https://github.com/rust-lang/crates.io-index" 1904 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 1905 | 1906 | [[package]] 1907 | name = "rustix" 1908 | version = "0.38.44" 1909 | source = "registry+https://github.com/rust-lang/crates.io-index" 1910 | checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" 1911 | dependencies = [ 1912 | "bitflags", 1913 | "errno", 1914 | "libc", 1915 | "linux-raw-sys 0.4.15", 1916 | "windows-sys 0.59.0", 1917 | ] 1918 | 1919 | [[package]] 1920 | name = "rustix" 1921 | version = "1.0.5" 1922 | source = "registry+https://github.com/rust-lang/crates.io-index" 1923 | checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" 1924 | dependencies = [ 1925 | "bitflags", 1926 | "errno", 1927 | "libc", 1928 | "linux-raw-sys 0.9.4", 1929 | "windows-sys 0.59.0", 1930 | ] 1931 | 1932 | [[package]] 1933 | name = "rustls" 1934 | version = "0.23.26" 1935 | source = "registry+https://github.com/rust-lang/crates.io-index" 1936 | checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" 1937 | dependencies = [ 1938 | "once_cell", 1939 | "rustls-pki-types", 1940 | "rustls-webpki", 1941 | "subtle", 1942 | "zeroize", 1943 | ] 1944 | 1945 | [[package]] 1946 | name = "rustls-pemfile" 1947 | version = "2.2.0" 1948 | source = "registry+https://github.com/rust-lang/crates.io-index" 1949 | checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" 1950 | dependencies = [ 1951 | "rustls-pki-types", 1952 | ] 1953 | 1954 | [[package]] 1955 | name = "rustls-pki-types" 1956 | version = "1.11.0" 1957 | source = "registry+https://github.com/rust-lang/crates.io-index" 1958 | checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" 1959 | 1960 | [[package]] 1961 | name = "rustls-webpki" 1962 | version = "0.103.1" 1963 | source = "registry+https://github.com/rust-lang/crates.io-index" 1964 | checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" 1965 | dependencies = [ 1966 | "ring", 1967 | "rustls-pki-types", 1968 | "untrusted", 1969 | ] 1970 | 1971 | [[package]] 1972 | name = "rustversion" 1973 | version = "1.0.20" 1974 | source = "registry+https://github.com/rust-lang/crates.io-index" 1975 | checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" 1976 | 1977 | [[package]] 1978 | name = "ryu" 1979 | version = "1.0.20" 1980 | source = "registry+https://github.com/rust-lang/crates.io-index" 1981 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 1982 | 1983 | [[package]] 1984 | name = "same-file" 1985 | version = "1.0.6" 1986 | source = "registry+https://github.com/rust-lang/crates.io-index" 1987 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 1988 | dependencies = [ 1989 | "winapi-util", 1990 | ] 1991 | 1992 | [[package]] 1993 | name = "schannel" 1994 | version = "0.1.27" 1995 | source = "registry+https://github.com/rust-lang/crates.io-index" 1996 | checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" 1997 | dependencies = [ 1998 | "windows-sys 0.59.0", 1999 | ] 2000 | 2001 | [[package]] 2002 | name = "scopeguard" 2003 | version = "1.2.0" 2004 | source = "registry+https://github.com/rust-lang/crates.io-index" 2005 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 2006 | 2007 | [[package]] 2008 | name = "security-framework" 2009 | version = "2.11.1" 2010 | source = "registry+https://github.com/rust-lang/crates.io-index" 2011 | checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 2012 | dependencies = [ 2013 | "bitflags", 2014 | "core-foundation", 2015 | "core-foundation-sys", 2016 | "libc", 2017 | "security-framework-sys", 2018 | ] 2019 | 2020 | [[package]] 2021 | name = "security-framework-sys" 2022 | version = "2.14.0" 2023 | source = "registry+https://github.com/rust-lang/crates.io-index" 2024 | checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" 2025 | dependencies = [ 2026 | "core-foundation-sys", 2027 | "libc", 2028 | ] 2029 | 2030 | [[package]] 2031 | name = "self_cell" 2032 | version = "0.10.3" 2033 | source = "registry+https://github.com/rust-lang/crates.io-index" 2034 | checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d" 2035 | dependencies = [ 2036 | "self_cell 1.2.0", 2037 | ] 2038 | 2039 | [[package]] 2040 | name = "self_cell" 2041 | version = "1.2.0" 2042 | source = "registry+https://github.com/rust-lang/crates.io-index" 2043 | checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" 2044 | 2045 | [[package]] 2046 | name = "send_wrapper" 2047 | version = "0.5.0" 2048 | source = "registry+https://github.com/rust-lang/crates.io-index" 2049 | checksum = "930c0acf610d3fdb5e2ab6213019aaa04e227ebe9547b0649ba599b16d788bd7" 2050 | 2051 | [[package]] 2052 | name = "serde" 2053 | version = "1.0.219" 2054 | source = "registry+https://github.com/rust-lang/crates.io-index" 2055 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 2056 | dependencies = [ 2057 | "serde_derive", 2058 | ] 2059 | 2060 | [[package]] 2061 | name = "serde_derive" 2062 | version = "1.0.219" 2063 | source = "registry+https://github.com/rust-lang/crates.io-index" 2064 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 2065 | dependencies = [ 2066 | "proc-macro2", 2067 | "quote", 2068 | "syn", 2069 | ] 2070 | 2071 | [[package]] 2072 | name = "serde_json" 2073 | version = "1.0.140" 2074 | source = "registry+https://github.com/rust-lang/crates.io-index" 2075 | checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" 2076 | dependencies = [ 2077 | "itoa", 2078 | "memchr", 2079 | "ryu", 2080 | "serde", 2081 | ] 2082 | 2083 | [[package]] 2084 | name = "serde_repr" 2085 | version = "0.1.20" 2086 | source = "registry+https://github.com/rust-lang/crates.io-index" 2087 | checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" 2088 | dependencies = [ 2089 | "proc-macro2", 2090 | "quote", 2091 | "syn", 2092 | ] 2093 | 2094 | [[package]] 2095 | name = "serde_urlencoded" 2096 | version = "0.7.1" 2097 | source = "registry+https://github.com/rust-lang/crates.io-index" 2098 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 2099 | dependencies = [ 2100 | "form_urlencoded", 2101 | "itoa", 2102 | "ryu", 2103 | "serde", 2104 | ] 2105 | 2106 | [[package]] 2107 | name = "sha2" 2108 | version = "0.10.8" 2109 | source = "registry+https://github.com/rust-lang/crates.io-index" 2110 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 2111 | dependencies = [ 2112 | "cfg-if", 2113 | "cpufeatures", 2114 | "digest", 2115 | ] 2116 | 2117 | [[package]] 2118 | name = "shlex" 2119 | version = "1.3.0" 2120 | source = "registry+https://github.com/rust-lang/crates.io-index" 2121 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 2122 | 2123 | [[package]] 2124 | name = "signal-hook" 2125 | version = "0.3.17" 2126 | source = "registry+https://github.com/rust-lang/crates.io-index" 2127 | checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" 2128 | dependencies = [ 2129 | "libc", 2130 | "signal-hook-registry", 2131 | ] 2132 | 2133 | [[package]] 2134 | name = "signal-hook-mio" 2135 | version = "0.2.4" 2136 | source = "registry+https://github.com/rust-lang/crates.io-index" 2137 | checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" 2138 | dependencies = [ 2139 | "libc", 2140 | "mio", 2141 | "signal-hook", 2142 | ] 2143 | 2144 | [[package]] 2145 | name = "signal-hook-registry" 2146 | version = "1.4.5" 2147 | source = "registry+https://github.com/rust-lang/crates.io-index" 2148 | checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" 2149 | dependencies = [ 2150 | "libc", 2151 | ] 2152 | 2153 | [[package]] 2154 | name = "slab" 2155 | version = "0.4.9" 2156 | source = "registry+https://github.com/rust-lang/crates.io-index" 2157 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 2158 | dependencies = [ 2159 | "autocfg", 2160 | ] 2161 | 2162 | [[package]] 2163 | name = "smallvec" 2164 | version = "1.15.0" 2165 | source = "registry+https://github.com/rust-lang/crates.io-index" 2166 | checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" 2167 | 2168 | [[package]] 2169 | name = "socket2" 2170 | version = "0.5.9" 2171 | source = "registry+https://github.com/rust-lang/crates.io-index" 2172 | checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" 2173 | dependencies = [ 2174 | "libc", 2175 | "windows-sys 0.52.0", 2176 | ] 2177 | 2178 | [[package]] 2179 | name = "stable_deref_trait" 2180 | version = "1.2.0" 2181 | source = "registry+https://github.com/rust-lang/crates.io-index" 2182 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 2183 | 2184 | [[package]] 2185 | name = "static_assertions" 2186 | version = "1.1.0" 2187 | source = "registry+https://github.com/rust-lang/crates.io-index" 2188 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 2189 | 2190 | [[package]] 2191 | name = "strsim" 2192 | version = "0.11.1" 2193 | source = "registry+https://github.com/rust-lang/crates.io-index" 2194 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 2195 | 2196 | [[package]] 2197 | name = "subtle" 2198 | version = "2.6.1" 2199 | source = "registry+https://github.com/rust-lang/crates.io-index" 2200 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 2201 | 2202 | [[package]] 2203 | name = "syn" 2204 | version = "2.0.100" 2205 | source = "registry+https://github.com/rust-lang/crates.io-index" 2206 | checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" 2207 | dependencies = [ 2208 | "proc-macro2", 2209 | "quote", 2210 | "unicode-ident", 2211 | ] 2212 | 2213 | [[package]] 2214 | name = "sync_wrapper" 2215 | version = "1.0.2" 2216 | source = "registry+https://github.com/rust-lang/crates.io-index" 2217 | checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 2218 | dependencies = [ 2219 | "futures-core", 2220 | ] 2221 | 2222 | [[package]] 2223 | name = "synstructure" 2224 | version = "0.13.1" 2225 | source = "registry+https://github.com/rust-lang/crates.io-index" 2226 | checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" 2227 | dependencies = [ 2228 | "proc-macro2", 2229 | "quote", 2230 | "syn", 2231 | ] 2232 | 2233 | [[package]] 2234 | name = "system-configuration" 2235 | version = "0.6.1" 2236 | source = "registry+https://github.com/rust-lang/crates.io-index" 2237 | checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" 2238 | dependencies = [ 2239 | "bitflags", 2240 | "core-foundation", 2241 | "system-configuration-sys", 2242 | ] 2243 | 2244 | [[package]] 2245 | name = "system-configuration-sys" 2246 | version = "0.6.0" 2247 | source = "registry+https://github.com/rust-lang/crates.io-index" 2248 | checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" 2249 | dependencies = [ 2250 | "core-foundation-sys", 2251 | "libc", 2252 | ] 2253 | 2254 | [[package]] 2255 | name = "tabwriter" 2256 | version = "1.4.1" 2257 | source = "registry+https://github.com/rust-lang/crates.io-index" 2258 | checksum = "fce91f2f0ec87dff7e6bcbbeb267439aa1188703003c6055193c821487400432" 2259 | dependencies = [ 2260 | "unicode-width 0.2.0", 2261 | ] 2262 | 2263 | [[package]] 2264 | name = "tempfile" 2265 | version = "3.19.1" 2266 | source = "registry+https://github.com/rust-lang/crates.io-index" 2267 | checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" 2268 | dependencies = [ 2269 | "fastrand", 2270 | "getrandom 0.3.2", 2271 | "once_cell", 2272 | "rustix 1.0.5", 2273 | "windows-sys 0.59.0", 2274 | ] 2275 | 2276 | [[package]] 2277 | name = "thiserror" 2278 | version = "1.0.69" 2279 | source = "registry+https://github.com/rust-lang/crates.io-index" 2280 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 2281 | dependencies = [ 2282 | "thiserror-impl", 2283 | ] 2284 | 2285 | [[package]] 2286 | name = "thiserror-impl" 2287 | version = "1.0.69" 2288 | source = "registry+https://github.com/rust-lang/crates.io-index" 2289 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 2290 | dependencies = [ 2291 | "proc-macro2", 2292 | "quote", 2293 | "syn", 2294 | ] 2295 | 2296 | [[package]] 2297 | name = "time" 2298 | version = "0.3.41" 2299 | source = "registry+https://github.com/rust-lang/crates.io-index" 2300 | checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" 2301 | dependencies = [ 2302 | "deranged", 2303 | "itoa", 2304 | "libc", 2305 | "num-conv", 2306 | "num_threads", 2307 | "powerfmt", 2308 | "serde", 2309 | "time-core", 2310 | "time-macros", 2311 | ] 2312 | 2313 | [[package]] 2314 | name = "time-core" 2315 | version = "0.1.4" 2316 | source = "registry+https://github.com/rust-lang/crates.io-index" 2317 | checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" 2318 | 2319 | [[package]] 2320 | name = "time-macros" 2321 | version = "0.2.22" 2322 | source = "registry+https://github.com/rust-lang/crates.io-index" 2323 | checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" 2324 | dependencies = [ 2325 | "num-conv", 2326 | "time-core", 2327 | ] 2328 | 2329 | [[package]] 2330 | name = "tinystr" 2331 | version = "0.7.6" 2332 | source = "registry+https://github.com/rust-lang/crates.io-index" 2333 | checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" 2334 | dependencies = [ 2335 | "displaydoc", 2336 | "zerovec", 2337 | ] 2338 | 2339 | [[package]] 2340 | name = "tokio" 2341 | version = "1.44.2" 2342 | source = "registry+https://github.com/rust-lang/crates.io-index" 2343 | checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" 2344 | dependencies = [ 2345 | "backtrace", 2346 | "bytes", 2347 | "libc", 2348 | "mio", 2349 | "pin-project-lite", 2350 | "signal-hook-registry", 2351 | "socket2", 2352 | "tokio-macros", 2353 | "tracing", 2354 | "windows-sys 0.52.0", 2355 | ] 2356 | 2357 | [[package]] 2358 | name = "tokio-macros" 2359 | version = "2.5.0" 2360 | source = "registry+https://github.com/rust-lang/crates.io-index" 2361 | checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 2362 | dependencies = [ 2363 | "proc-macro2", 2364 | "quote", 2365 | "syn", 2366 | ] 2367 | 2368 | [[package]] 2369 | name = "tokio-native-tls" 2370 | version = "0.3.1" 2371 | source = "registry+https://github.com/rust-lang/crates.io-index" 2372 | checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 2373 | dependencies = [ 2374 | "native-tls", 2375 | "tokio", 2376 | ] 2377 | 2378 | [[package]] 2379 | name = "tokio-rustls" 2380 | version = "0.26.2" 2381 | source = "registry+https://github.com/rust-lang/crates.io-index" 2382 | checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" 2383 | dependencies = [ 2384 | "rustls", 2385 | "tokio", 2386 | ] 2387 | 2388 | [[package]] 2389 | name = "tokio-util" 2390 | version = "0.7.15" 2391 | source = "registry+https://github.com/rust-lang/crates.io-index" 2392 | checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" 2393 | dependencies = [ 2394 | "bytes", 2395 | "futures-core", 2396 | "futures-sink", 2397 | "pin-project-lite", 2398 | "tokio", 2399 | ] 2400 | 2401 | [[package]] 2402 | name = "toml" 2403 | version = "0.5.11" 2404 | source = "registry+https://github.com/rust-lang/crates.io-index" 2405 | checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" 2406 | dependencies = [ 2407 | "serde", 2408 | ] 2409 | 2410 | [[package]] 2411 | name = "toml_datetime" 2412 | version = "0.6.9" 2413 | source = "registry+https://github.com/rust-lang/crates.io-index" 2414 | checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" 2415 | 2416 | [[package]] 2417 | name = "toml_edit" 2418 | version = "0.22.25" 2419 | source = "registry+https://github.com/rust-lang/crates.io-index" 2420 | checksum = "10558ed0bd2a1562e630926a2d1f0b98c827da99fabd3fe20920a59642504485" 2421 | dependencies = [ 2422 | "indexmap", 2423 | "toml_datetime", 2424 | "winnow", 2425 | ] 2426 | 2427 | [[package]] 2428 | name = "tower" 2429 | version = "0.5.2" 2430 | source = "registry+https://github.com/rust-lang/crates.io-index" 2431 | checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" 2432 | dependencies = [ 2433 | "futures-core", 2434 | "futures-util", 2435 | "pin-project-lite", 2436 | "sync_wrapper", 2437 | "tokio", 2438 | "tower-layer", 2439 | "tower-service", 2440 | ] 2441 | 2442 | [[package]] 2443 | name = "tower-layer" 2444 | version = "0.3.3" 2445 | source = "registry+https://github.com/rust-lang/crates.io-index" 2446 | checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" 2447 | 2448 | [[package]] 2449 | name = "tower-service" 2450 | version = "0.3.3" 2451 | source = "registry+https://github.com/rust-lang/crates.io-index" 2452 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 2453 | 2454 | [[package]] 2455 | name = "tracing" 2456 | version = "0.1.41" 2457 | source = "registry+https://github.com/rust-lang/crates.io-index" 2458 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 2459 | dependencies = [ 2460 | "pin-project-lite", 2461 | "tracing-attributes", 2462 | "tracing-core", 2463 | ] 2464 | 2465 | [[package]] 2466 | name = "tracing-attributes" 2467 | version = "0.1.28" 2468 | source = "registry+https://github.com/rust-lang/crates.io-index" 2469 | checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" 2470 | dependencies = [ 2471 | "proc-macro2", 2472 | "quote", 2473 | "syn", 2474 | ] 2475 | 2476 | [[package]] 2477 | name = "tracing-core" 2478 | version = "0.1.33" 2479 | source = "registry+https://github.com/rust-lang/crates.io-index" 2480 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 2481 | dependencies = [ 2482 | "once_cell", 2483 | ] 2484 | 2485 | [[package]] 2486 | name = "try-lock" 2487 | version = "0.2.5" 2488 | source = "registry+https://github.com/rust-lang/crates.io-index" 2489 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 2490 | 2491 | [[package]] 2492 | name = "type-map" 2493 | version = "0.5.0" 2494 | source = "registry+https://github.com/rust-lang/crates.io-index" 2495 | checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f" 2496 | dependencies = [ 2497 | "rustc-hash", 2498 | ] 2499 | 2500 | [[package]] 2501 | name = "typenum" 2502 | version = "1.18.0" 2503 | source = "registry+https://github.com/rust-lang/crates.io-index" 2504 | checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" 2505 | 2506 | [[package]] 2507 | name = "uds_windows" 2508 | version = "1.1.0" 2509 | source = "registry+https://github.com/rust-lang/crates.io-index" 2510 | checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" 2511 | dependencies = [ 2512 | "memoffset", 2513 | "tempfile", 2514 | "winapi", 2515 | ] 2516 | 2517 | [[package]] 2518 | name = "unic-langid" 2519 | version = "0.9.5" 2520 | source = "registry+https://github.com/rust-lang/crates.io-index" 2521 | checksum = "23dd9d1e72a73b25e07123a80776aae3e7b0ec461ef94f9151eed6ec88005a44" 2522 | dependencies = [ 2523 | "unic-langid-impl", 2524 | ] 2525 | 2526 | [[package]] 2527 | name = "unic-langid-impl" 2528 | version = "0.9.5" 2529 | source = "registry+https://github.com/rust-lang/crates.io-index" 2530 | checksum = "0a5422c1f65949306c99240b81de9f3f15929f5a8bfe05bb44b034cc8bf593e5" 2531 | dependencies = [ 2532 | "serde", 2533 | "tinystr", 2534 | ] 2535 | 2536 | [[package]] 2537 | name = "unicode-ident" 2538 | version = "1.0.18" 2539 | source = "registry+https://github.com/rust-lang/crates.io-index" 2540 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 2541 | 2542 | [[package]] 2543 | name = "unicode-segmentation" 2544 | version = "1.12.0" 2545 | source = "registry+https://github.com/rust-lang/crates.io-index" 2546 | checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" 2547 | 2548 | [[package]] 2549 | name = "unicode-width" 2550 | version = "0.1.14" 2551 | source = "registry+https://github.com/rust-lang/crates.io-index" 2552 | checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" 2553 | 2554 | [[package]] 2555 | name = "unicode-width" 2556 | version = "0.2.0" 2557 | source = "registry+https://github.com/rust-lang/crates.io-index" 2558 | checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" 2559 | 2560 | [[package]] 2561 | name = "untrusted" 2562 | version = "0.9.0" 2563 | source = "registry+https://github.com/rust-lang/crates.io-index" 2564 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 2565 | 2566 | [[package]] 2567 | name = "url" 2568 | version = "2.5.4" 2569 | source = "registry+https://github.com/rust-lang/crates.io-index" 2570 | checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 2571 | dependencies = [ 2572 | "form_urlencoded", 2573 | "idna", 2574 | "percent-encoding", 2575 | ] 2576 | 2577 | [[package]] 2578 | name = "utf16_iter" 2579 | version = "1.0.5" 2580 | source = "registry+https://github.com/rust-lang/crates.io-index" 2581 | checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" 2582 | 2583 | [[package]] 2584 | name = "utf8_iter" 2585 | version = "1.0.4" 2586 | source = "registry+https://github.com/rust-lang/crates.io-index" 2587 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 2588 | 2589 | [[package]] 2590 | name = "vcpkg" 2591 | version = "0.2.15" 2592 | source = "registry+https://github.com/rust-lang/crates.io-index" 2593 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 2594 | 2595 | [[package]] 2596 | name = "version_check" 2597 | version = "0.9.5" 2598 | source = "registry+https://github.com/rust-lang/crates.io-index" 2599 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 2600 | 2601 | [[package]] 2602 | name = "walkdir" 2603 | version = "2.5.0" 2604 | source = "registry+https://github.com/rust-lang/crates.io-index" 2605 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" 2606 | dependencies = [ 2607 | "same-file", 2608 | "winapi-util", 2609 | ] 2610 | 2611 | [[package]] 2612 | name = "want" 2613 | version = "0.3.1" 2614 | source = "registry+https://github.com/rust-lang/crates.io-index" 2615 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 2616 | dependencies = [ 2617 | "try-lock", 2618 | ] 2619 | 2620 | [[package]] 2621 | name = "wasi" 2622 | version = "0.11.0+wasi-snapshot-preview1" 2623 | source = "registry+https://github.com/rust-lang/crates.io-index" 2624 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 2625 | 2626 | [[package]] 2627 | name = "wasi" 2628 | version = "0.14.2+wasi-0.2.4" 2629 | source = "registry+https://github.com/rust-lang/crates.io-index" 2630 | checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" 2631 | dependencies = [ 2632 | "wit-bindgen-rt", 2633 | ] 2634 | 2635 | [[package]] 2636 | name = "wasm-bindgen" 2637 | version = "0.2.100" 2638 | source = "registry+https://github.com/rust-lang/crates.io-index" 2639 | checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" 2640 | dependencies = [ 2641 | "cfg-if", 2642 | "once_cell", 2643 | "rustversion", 2644 | "wasm-bindgen-macro", 2645 | ] 2646 | 2647 | [[package]] 2648 | name = "wasm-bindgen-backend" 2649 | version = "0.2.100" 2650 | source = "registry+https://github.com/rust-lang/crates.io-index" 2651 | checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" 2652 | dependencies = [ 2653 | "bumpalo", 2654 | "log", 2655 | "proc-macro2", 2656 | "quote", 2657 | "syn", 2658 | "wasm-bindgen-shared", 2659 | ] 2660 | 2661 | [[package]] 2662 | name = "wasm-bindgen-futures" 2663 | version = "0.4.50" 2664 | source = "registry+https://github.com/rust-lang/crates.io-index" 2665 | checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" 2666 | dependencies = [ 2667 | "cfg-if", 2668 | "js-sys", 2669 | "once_cell", 2670 | "wasm-bindgen", 2671 | "web-sys", 2672 | ] 2673 | 2674 | [[package]] 2675 | name = "wasm-bindgen-macro" 2676 | version = "0.2.100" 2677 | source = "registry+https://github.com/rust-lang/crates.io-index" 2678 | checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" 2679 | dependencies = [ 2680 | "quote", 2681 | "wasm-bindgen-macro-support", 2682 | ] 2683 | 2684 | [[package]] 2685 | name = "wasm-bindgen-macro-support" 2686 | version = "0.2.100" 2687 | source = "registry+https://github.com/rust-lang/crates.io-index" 2688 | checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" 2689 | dependencies = [ 2690 | "proc-macro2", 2691 | "quote", 2692 | "syn", 2693 | "wasm-bindgen-backend", 2694 | "wasm-bindgen-shared", 2695 | ] 2696 | 2697 | [[package]] 2698 | name = "wasm-bindgen-shared" 2699 | version = "0.2.100" 2700 | source = "registry+https://github.com/rust-lang/crates.io-index" 2701 | checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" 2702 | dependencies = [ 2703 | "unicode-ident", 2704 | ] 2705 | 2706 | [[package]] 2707 | name = "web-sys" 2708 | version = "0.3.77" 2709 | source = "registry+https://github.com/rust-lang/crates.io-index" 2710 | checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" 2711 | dependencies = [ 2712 | "js-sys", 2713 | "wasm-bindgen", 2714 | ] 2715 | 2716 | [[package]] 2717 | name = "winapi" 2718 | version = "0.3.9" 2719 | source = "registry+https://github.com/rust-lang/crates.io-index" 2720 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2721 | dependencies = [ 2722 | "winapi-i686-pc-windows-gnu", 2723 | "winapi-x86_64-pc-windows-gnu", 2724 | ] 2725 | 2726 | [[package]] 2727 | name = "winapi-i686-pc-windows-gnu" 2728 | version = "0.4.0" 2729 | source = "registry+https://github.com/rust-lang/crates.io-index" 2730 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2731 | 2732 | [[package]] 2733 | name = "winapi-util" 2734 | version = "0.1.9" 2735 | source = "registry+https://github.com/rust-lang/crates.io-index" 2736 | checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 2737 | dependencies = [ 2738 | "windows-sys 0.59.0", 2739 | ] 2740 | 2741 | [[package]] 2742 | name = "winapi-x86_64-pc-windows-gnu" 2743 | version = "0.4.0" 2744 | source = "registry+https://github.com/rust-lang/crates.io-index" 2745 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2746 | 2747 | [[package]] 2748 | name = "windows-link" 2749 | version = "0.1.1" 2750 | source = "registry+https://github.com/rust-lang/crates.io-index" 2751 | checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" 2752 | 2753 | [[package]] 2754 | name = "windows-registry" 2755 | version = "0.4.0" 2756 | source = "registry+https://github.com/rust-lang/crates.io-index" 2757 | checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" 2758 | dependencies = [ 2759 | "windows-result", 2760 | "windows-strings", 2761 | "windows-targets 0.53.0", 2762 | ] 2763 | 2764 | [[package]] 2765 | name = "windows-result" 2766 | version = "0.3.2" 2767 | source = "registry+https://github.com/rust-lang/crates.io-index" 2768 | checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" 2769 | dependencies = [ 2770 | "windows-link", 2771 | ] 2772 | 2773 | [[package]] 2774 | name = "windows-strings" 2775 | version = "0.3.1" 2776 | source = "registry+https://github.com/rust-lang/crates.io-index" 2777 | checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" 2778 | dependencies = [ 2779 | "windows-link", 2780 | ] 2781 | 2782 | [[package]] 2783 | name = "windows-sys" 2784 | version = "0.52.0" 2785 | source = "registry+https://github.com/rust-lang/crates.io-index" 2786 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2787 | dependencies = [ 2788 | "windows-targets 0.52.6", 2789 | ] 2790 | 2791 | [[package]] 2792 | name = "windows-sys" 2793 | version = "0.59.0" 2794 | source = "registry+https://github.com/rust-lang/crates.io-index" 2795 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 2796 | dependencies = [ 2797 | "windows-targets 0.52.6", 2798 | ] 2799 | 2800 | [[package]] 2801 | name = "windows-targets" 2802 | version = "0.52.6" 2803 | source = "registry+https://github.com/rust-lang/crates.io-index" 2804 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 2805 | dependencies = [ 2806 | "windows_aarch64_gnullvm 0.52.6", 2807 | "windows_aarch64_msvc 0.52.6", 2808 | "windows_i686_gnu 0.52.6", 2809 | "windows_i686_gnullvm 0.52.6", 2810 | "windows_i686_msvc 0.52.6", 2811 | "windows_x86_64_gnu 0.52.6", 2812 | "windows_x86_64_gnullvm 0.52.6", 2813 | "windows_x86_64_msvc 0.52.6", 2814 | ] 2815 | 2816 | [[package]] 2817 | name = "windows-targets" 2818 | version = "0.53.0" 2819 | source = "registry+https://github.com/rust-lang/crates.io-index" 2820 | checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" 2821 | dependencies = [ 2822 | "windows_aarch64_gnullvm 0.53.0", 2823 | "windows_aarch64_msvc 0.53.0", 2824 | "windows_i686_gnu 0.53.0", 2825 | "windows_i686_gnullvm 0.53.0", 2826 | "windows_i686_msvc 0.53.0", 2827 | "windows_x86_64_gnu 0.53.0", 2828 | "windows_x86_64_gnullvm 0.53.0", 2829 | "windows_x86_64_msvc 0.53.0", 2830 | ] 2831 | 2832 | [[package]] 2833 | name = "windows_aarch64_gnullvm" 2834 | version = "0.52.6" 2835 | source = "registry+https://github.com/rust-lang/crates.io-index" 2836 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 2837 | 2838 | [[package]] 2839 | name = "windows_aarch64_gnullvm" 2840 | version = "0.53.0" 2841 | source = "registry+https://github.com/rust-lang/crates.io-index" 2842 | checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" 2843 | 2844 | [[package]] 2845 | name = "windows_aarch64_msvc" 2846 | version = "0.52.6" 2847 | source = "registry+https://github.com/rust-lang/crates.io-index" 2848 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 2849 | 2850 | [[package]] 2851 | name = "windows_aarch64_msvc" 2852 | version = "0.53.0" 2853 | source = "registry+https://github.com/rust-lang/crates.io-index" 2854 | checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" 2855 | 2856 | [[package]] 2857 | name = "windows_i686_gnu" 2858 | version = "0.52.6" 2859 | source = "registry+https://github.com/rust-lang/crates.io-index" 2860 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 2861 | 2862 | [[package]] 2863 | name = "windows_i686_gnu" 2864 | version = "0.53.0" 2865 | source = "registry+https://github.com/rust-lang/crates.io-index" 2866 | checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" 2867 | 2868 | [[package]] 2869 | name = "windows_i686_gnullvm" 2870 | version = "0.52.6" 2871 | source = "registry+https://github.com/rust-lang/crates.io-index" 2872 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 2873 | 2874 | [[package]] 2875 | name = "windows_i686_gnullvm" 2876 | version = "0.53.0" 2877 | source = "registry+https://github.com/rust-lang/crates.io-index" 2878 | checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" 2879 | 2880 | [[package]] 2881 | name = "windows_i686_msvc" 2882 | version = "0.52.6" 2883 | source = "registry+https://github.com/rust-lang/crates.io-index" 2884 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 2885 | 2886 | [[package]] 2887 | name = "windows_i686_msvc" 2888 | version = "0.53.0" 2889 | source = "registry+https://github.com/rust-lang/crates.io-index" 2890 | checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" 2891 | 2892 | [[package]] 2893 | name = "windows_x86_64_gnu" 2894 | version = "0.52.6" 2895 | source = "registry+https://github.com/rust-lang/crates.io-index" 2896 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 2897 | 2898 | [[package]] 2899 | name = "windows_x86_64_gnu" 2900 | version = "0.53.0" 2901 | source = "registry+https://github.com/rust-lang/crates.io-index" 2902 | checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" 2903 | 2904 | [[package]] 2905 | name = "windows_x86_64_gnullvm" 2906 | version = "0.52.6" 2907 | source = "registry+https://github.com/rust-lang/crates.io-index" 2908 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 2909 | 2910 | [[package]] 2911 | name = "windows_x86_64_gnullvm" 2912 | version = "0.53.0" 2913 | source = "registry+https://github.com/rust-lang/crates.io-index" 2914 | checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" 2915 | 2916 | [[package]] 2917 | name = "windows_x86_64_msvc" 2918 | version = "0.52.6" 2919 | source = "registry+https://github.com/rust-lang/crates.io-index" 2920 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2921 | 2922 | [[package]] 2923 | name = "windows_x86_64_msvc" 2924 | version = "0.53.0" 2925 | source = "registry+https://github.com/rust-lang/crates.io-index" 2926 | checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" 2927 | 2928 | [[package]] 2929 | name = "winnow" 2930 | version = "0.7.7" 2931 | source = "registry+https://github.com/rust-lang/crates.io-index" 2932 | checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5" 2933 | dependencies = [ 2934 | "memchr", 2935 | ] 2936 | 2937 | [[package]] 2938 | name = "wit-bindgen-rt" 2939 | version = "0.39.0" 2940 | source = "registry+https://github.com/rust-lang/crates.io-index" 2941 | checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" 2942 | dependencies = [ 2943 | "bitflags", 2944 | ] 2945 | 2946 | [[package]] 2947 | name = "write16" 2948 | version = "1.0.0" 2949 | source = "registry+https://github.com/rust-lang/crates.io-index" 2950 | checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" 2951 | 2952 | [[package]] 2953 | name = "writeable" 2954 | version = "0.5.5" 2955 | source = "registry+https://github.com/rust-lang/crates.io-index" 2956 | checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" 2957 | 2958 | [[package]] 2959 | name = "xdg-home" 2960 | version = "1.3.0" 2961 | source = "registry+https://github.com/rust-lang/crates.io-index" 2962 | checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" 2963 | dependencies = [ 2964 | "libc", 2965 | "windows-sys 0.59.0", 2966 | ] 2967 | 2968 | [[package]] 2969 | name = "xi-unicode" 2970 | version = "0.3.0" 2971 | source = "registry+https://github.com/rust-lang/crates.io-index" 2972 | checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" 2973 | 2974 | [[package]] 2975 | name = "yoke" 2976 | version = "0.7.5" 2977 | source = "registry+https://github.com/rust-lang/crates.io-index" 2978 | checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" 2979 | dependencies = [ 2980 | "serde", 2981 | "stable_deref_trait", 2982 | "yoke-derive", 2983 | "zerofrom", 2984 | ] 2985 | 2986 | [[package]] 2987 | name = "yoke-derive" 2988 | version = "0.7.5" 2989 | source = "registry+https://github.com/rust-lang/crates.io-index" 2990 | checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" 2991 | dependencies = [ 2992 | "proc-macro2", 2993 | "quote", 2994 | "syn", 2995 | "synstructure", 2996 | ] 2997 | 2998 | [[package]] 2999 | name = "zbus" 3000 | version = "5.5.0" 3001 | source = "registry+https://github.com/rust-lang/crates.io-index" 3002 | checksum = "59c333f648ea1b647bc95dc1d34807c8e25ed7a6feff3394034dc4776054b236" 3003 | dependencies = [ 3004 | "async-broadcast", 3005 | "async-recursion", 3006 | "async-trait", 3007 | "enumflags2", 3008 | "event-listener", 3009 | "futures-core", 3010 | "futures-lite", 3011 | "hex", 3012 | "nix", 3013 | "ordered-stream", 3014 | "serde", 3015 | "serde_repr", 3016 | "static_assertions", 3017 | "tokio", 3018 | "tracing", 3019 | "uds_windows", 3020 | "windows-sys 0.59.0", 3021 | "winnow", 3022 | "xdg-home", 3023 | "zbus_macros", 3024 | "zbus_names", 3025 | "zvariant", 3026 | ] 3027 | 3028 | [[package]] 3029 | name = "zbus_macros" 3030 | version = "5.5.0" 3031 | source = "registry+https://github.com/rust-lang/crates.io-index" 3032 | checksum = "f325ad10eb0d0a3eb060203494c3b7ec3162a01a59db75d2deee100339709fc0" 3033 | dependencies = [ 3034 | "proc-macro-crate", 3035 | "proc-macro2", 3036 | "quote", 3037 | "syn", 3038 | "zbus_names", 3039 | "zvariant", 3040 | "zvariant_utils", 3041 | ] 3042 | 3043 | [[package]] 3044 | name = "zbus_names" 3045 | version = "4.2.0" 3046 | source = "registry+https://github.com/rust-lang/crates.io-index" 3047 | checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" 3048 | dependencies = [ 3049 | "serde", 3050 | "static_assertions", 3051 | "winnow", 3052 | "zvariant", 3053 | ] 3054 | 3055 | [[package]] 3056 | name = "zerocopy" 3057 | version = "0.7.35" 3058 | source = "registry+https://github.com/rust-lang/crates.io-index" 3059 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 3060 | dependencies = [ 3061 | "zerocopy-derive", 3062 | ] 3063 | 3064 | [[package]] 3065 | name = "zerocopy-derive" 3066 | version = "0.7.35" 3067 | source = "registry+https://github.com/rust-lang/crates.io-index" 3068 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 3069 | dependencies = [ 3070 | "proc-macro2", 3071 | "quote", 3072 | "syn", 3073 | ] 3074 | 3075 | [[package]] 3076 | name = "zerofrom" 3077 | version = "0.1.6" 3078 | source = "registry+https://github.com/rust-lang/crates.io-index" 3079 | checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" 3080 | dependencies = [ 3081 | "zerofrom-derive", 3082 | ] 3083 | 3084 | [[package]] 3085 | name = "zerofrom-derive" 3086 | version = "0.1.6" 3087 | source = "registry+https://github.com/rust-lang/crates.io-index" 3088 | checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" 3089 | dependencies = [ 3090 | "proc-macro2", 3091 | "quote", 3092 | "syn", 3093 | "synstructure", 3094 | ] 3095 | 3096 | [[package]] 3097 | name = "zeroize" 3098 | version = "1.8.1" 3099 | source = "registry+https://github.com/rust-lang/crates.io-index" 3100 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 3101 | 3102 | [[package]] 3103 | name = "zerovec" 3104 | version = "0.10.4" 3105 | source = "registry+https://github.com/rust-lang/crates.io-index" 3106 | checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" 3107 | dependencies = [ 3108 | "yoke", 3109 | "zerofrom", 3110 | "zerovec-derive", 3111 | ] 3112 | 3113 | [[package]] 3114 | name = "zerovec-derive" 3115 | version = "0.10.3" 3116 | source = "registry+https://github.com/rust-lang/crates.io-index" 3117 | checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" 3118 | dependencies = [ 3119 | "proc-macro2", 3120 | "quote", 3121 | "syn", 3122 | ] 3123 | 3124 | [[package]] 3125 | name = "zvariant" 3126 | version = "5.4.0" 3127 | source = "registry+https://github.com/rust-lang/crates.io-index" 3128 | checksum = "b2df9ee044893fcffbdc25de30546edef3e32341466811ca18421e3cd6c5a3ac" 3129 | dependencies = [ 3130 | "endi", 3131 | "enumflags2", 3132 | "serde", 3133 | "static_assertions", 3134 | "winnow", 3135 | "zvariant_derive", 3136 | "zvariant_utils", 3137 | ] 3138 | 3139 | [[package]] 3140 | name = "zvariant_derive" 3141 | version = "5.4.0" 3142 | source = "registry+https://github.com/rust-lang/crates.io-index" 3143 | checksum = "74170caa85b8b84cc4935f2d56a57c7a15ea6185ccdd7eadb57e6edd90f94b2f" 3144 | dependencies = [ 3145 | "proc-macro-crate", 3146 | "proc-macro2", 3147 | "quote", 3148 | "syn", 3149 | "zvariant_utils", 3150 | ] 3151 | 3152 | [[package]] 3153 | name = "zvariant_utils" 3154 | version = "3.2.0" 3155 | source = "registry+https://github.com/rust-lang/crates.io-index" 3156 | checksum = "e16edfee43e5d7b553b77872d99bc36afdda75c223ca7ad5e3fbecd82ca5fc34" 3157 | dependencies = [ 3158 | "proc-macro2", 3159 | "quote", 3160 | "serde", 3161 | "static_assertions", 3162 | "syn", 3163 | "winnow", 3164 | ] 3165 | --------------------------------------------------------------------------------