From 3f00eee61e7733041739244f2dc3bd023067bf72 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Mon, 19 May 2025 10:48:39 +0200 Subject: [PATCH 01/11] feat(backup): add delta mutation methods; start union tests --- backup/src/delta.rs | 102 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 99 insertions(+), 3 deletions(-) diff --git a/backup/src/delta.rs b/backup/src/delta.rs index 6bdff88..dde906b 100644 --- a/backup/src/delta.rs +++ b/backup/src/delta.rs @@ -1,11 +1,15 @@ -use std::{borrow::Borrow, fmt}; +use std::{ + borrow::Borrow, + fmt, + path::{Path, PathBuf}, +}; use serde::{Deserialize, Serialize}; use super::State; /// Represents the changes relative to the previous backup -#[derive(Debug, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] pub struct Delta { /// What files were added/modified in each part of the tarball. pub added: State, @@ -19,7 +23,6 @@ pub struct Delta { impl Delta { /// Returns whether the delta is empty by checking whether both its added and removed state /// return true for their `is_empty`. - #[allow(dead_code)] pub fn is_empty(&self) -> bool { self.added.is_empty() && self.removed.is_empty() } @@ -143,6 +146,58 @@ impl Delta { contributions } + + /// Append the given files to the directory's list of added files + pub fn append_added(&mut self, dir: impl Into, files: I) + where + I: IntoIterator, + I::Item: Into, + { + let dir: PathBuf = dir.into(); + let files = files.into_iter().map(Into::into); + + if let Some(dir_files) = self.added.get_mut(&dir) { + dir_files.extend(files); + } else { + self.added.insert(dir, files.collect()); + } + } + + /// Wrapper around the `append_added` method for a builder-style construction of delta's + pub fn with_added(mut self, dir: impl Into, files: I) -> Self + where + I: IntoIterator, + I::Item: Into, + { + self.append_added(dir, files); + self + } + + /// Append the given files to the directory's list of removed files + pub fn append_removed(&mut self, dir: impl Into, files: I) + where + I: IntoIterator, + I::Item: Into, + { + let dir: PathBuf = dir.into(); + let files = files.into_iter().map(Into::into); + + if let Some(dir_files) = self.removed.get_mut(&dir) { + dir_files.extend(files); + } else { + self.removed.insert(dir, files.collect()); + } + } + + /// Wrapper around the `append_removed` method for a builder-style construction of delta's + pub fn with_removed(mut self, dir: impl Into, files: I) -> Self + where + I: IntoIterator, + I::Item: Into, + { + self.append_removed(dir, files); + self + } } impl fmt::Display for Delta { @@ -153,3 +208,44 @@ impl fmt::Display for Delta { write!(f, "+{}-{}", added_count, removed_count) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_union_disjunct_dirs() { + let a = Delta::default() + .with_added("dir_added_1", ["file1", "file2"]) + .with_removed("dir_removed_1", ["file1", "file2"]); + let b = Delta::default() + .with_added("dir_added_3", ["file1", "file2"]) + .with_removed("dir_removed_3", ["file1", "file2"]); + + let expected = Delta::default() + .with_added("dir_added_1", ["file1", "file2"]) + .with_added("dir_added_3", ["file1", "file2"]) + .with_removed("dir_removed_1", ["file1", "file2"]) + .with_removed("dir_removed_3", ["file1", "file2"]); + + assert_eq!(expected, a.union(&b)); + assert_eq!(expected, b.union(&a)); + } + + #[test] + fn test_union_disjunct_files() { + let a = Delta::default() + .with_added("dir_added_1", ["file1", "file2"]) + .with_removed("dir_removed_1", ["file1", "file2"]); + let b = Delta::default() + .with_added("dir_added_1", ["file3", "file4"]) + .with_removed("dir_removed_1", ["file3", "file4"]); + + let expected = Delta::default() + .with_added("dir_added_1", ["file1", "file2", "file3", "file4"]) + .with_removed("dir_removed_1", ["file1", "file2", "file3", "file4"]); + + assert_eq!(expected, a.union(&b)); + assert_eq!(expected, b.union(&a)); + } +} From 22a6e68c7cf2e2e314ba3d0f154452cbf14c6d1c Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Mon, 19 May 2025 11:45:49 +0200 Subject: [PATCH 02/11] feat(backup): implement mutation methods and specialized PartialEq for State --- backup/src/delta.rs | 24 ++------------ backup/src/state.rs | 76 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 22 deletions(-) diff --git a/backup/src/delta.rs b/backup/src/delta.rs index dde906b..85b36a0 100644 --- a/backup/src/delta.rs +++ b/backup/src/delta.rs @@ -1,8 +1,4 @@ -use std::{ - borrow::Borrow, - fmt, - path::{Path, PathBuf}, -}; +use std::{borrow::Borrow, fmt, path::PathBuf}; use serde::{Deserialize, Serialize}; @@ -153,14 +149,7 @@ impl Delta { I: IntoIterator, I::Item: Into, { - let dir: PathBuf = dir.into(); - let files = files.into_iter().map(Into::into); - - if let Some(dir_files) = self.added.get_mut(&dir) { - dir_files.extend(files); - } else { - self.added.insert(dir, files.collect()); - } + self.added.append_dir(dir, files); } /// Wrapper around the `append_added` method for a builder-style construction of delta's @@ -179,14 +168,7 @@ impl Delta { I: IntoIterator, I::Item: Into, { - let dir: PathBuf = dir.into(); - let files = files.into_iter().map(Into::into); - - if let Some(dir_files) = self.removed.get_mut(&dir) { - dir_files.extend(files); - } else { - self.removed.insert(dir, files.collect()); - } + self.removed.append_dir(dir, files); } /// Wrapper around the `append_removed` method for a builder-style construction of delta's diff --git a/backup/src/state.rs b/backup/src/state.rs index c0f66b9..b94370f 100644 --- a/backup/src/state.rs +++ b/backup/src/state.rs @@ -11,7 +11,7 @@ use crate::Delta; /// Struct that represents a current state for a backup. This struct acts as a smart pointer around /// a HashMap. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] +#[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct State(HashMap>); impl State { @@ -49,8 +49,52 @@ impl State { pub fn is_empty(&self) -> bool { self.0.values().all(|s| s.is_empty()) } + + pub fn append_dir(&mut self, dir: impl Into, files: I) + where + I: IntoIterator, + I::Item: Into, + { + let dir = dir.into(); + let files = files.into_iter().map(Into::into); + + if let Some(dir_files) = self.0.get_mut(&dir) { + dir_files.extend(files); + } else { + self.0.insert(dir, files.collect()); + } + } + + pub fn with_dir(mut self, dir: impl Into, files: I) -> Self + where + I: IntoIterator, + I::Item: Into, + { + self.append_dir(dir, files); + self + } } +impl PartialEq for State { + fn eq(&self, other: &Self) -> bool { + let self_non_empty = self.0.values().filter(|files| !files.is_empty()).count(); + let other_non_empty = other.0.values().filter(|files| !files.is_empty()).count(); + + if self_non_empty != other_non_empty { + return false; + } + + // If both states have the same number of non-empty directories, then comparing each + // directory of one with the other will only be true if their list of non-empty directories + // is identical. + self.0 + .iter() + .all(|(dir, files)| files.is_empty() || other.0.get(dir).map_or(false, |v| v == files)) + } +} + +impl Eq for State {} + impl From for State where T: IntoIterator, @@ -86,3 +130,33 @@ impl DerefMut for State { &mut self.0 } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_eq() { + let a = State::default().with_dir("dir1", ["file1", "file2"]); + let b = State::default().with_dir("dir1", ["file1", "file2"]); + + assert_eq!(a, b); + + let b = b.with_dir("dir2", ["file3"]); + + assert_ne!(a, b); + } + + #[test] + fn test_eq_empty_dirs() { + let a = State::default().with_dir("dir1", ["file1", "file2"]); + let b = State::default() + .with_dir("dir1", ["file1", "file2"]) + .with_dir("dir2", Vec::::new()); + + assert_eq!(a, b); + + let b = b.with_dir("dir2", ["file3"]); + assert_ne!(a, b); + } +} From 15c4839a819b9dd6ae92c8cc9aa10654e6b47d77 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Mon, 19 May 2025 11:46:19 +0200 Subject: [PATCH 03/11] test(backup): add delta union test --- backup/src/delta.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/backup/src/delta.rs b/backup/src/delta.rs index 85b36a0..cc831ac 100644 --- a/backup/src/delta.rs +++ b/backup/src/delta.rs @@ -230,4 +230,16 @@ mod tests { assert_eq!(expected, a.union(&b)); assert_eq!(expected, b.union(&a)); } + + #[test] + fn test_union_full_revert() { + let a = Delta::default().with_added("dir_1", ["file1", "file2"]); + let b = Delta::default().with_removed("dir_1", ["file1", "file2"]); + + let expected = Delta::default().with_removed("dir_1", ["file1", "file2"]); + assert_eq!(expected, a.union(&b)); + + let expected = Delta::default().with_added("dir_1", ["file1", "file2"]); + assert_eq!(expected, b.union(&a)); + } } From 5f43d7b8b1d7fae17d1f33f5fed357d0809d38fe Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Sat, 24 May 2025 23:23:46 +0200 Subject: [PATCH 04/11] test(backup): add some more delta tests --- backup/src/delta.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/backup/src/delta.rs b/backup/src/delta.rs index cc831ac..993dd3a 100644 --- a/backup/src/delta.rs +++ b/backup/src/delta.rs @@ -242,4 +242,56 @@ mod tests { let expected = Delta::default().with_added("dir_1", ["file1", "file2"]); assert_eq!(expected, b.union(&a)); } + + #[test] + fn test_difference() { + let a = Delta::default() + .with_added("dir1", ["file1", "file2"]) + .with_removed("dir1", ["file3", "file4"]); + let b = Delta::default() + .with_added("dir1", ["file1"]) + .with_removed("dir1", ["file3"]); + let expected = Delta::default() + .with_added("dir1", ["file2"]) + .with_removed("dir1", ["file4"]); + + assert_eq!(a.difference(&b), expected); + assert_eq!(b.difference(&a), Delta::default()); + } + + #[test] + fn test_strict_difference() { + let a = Delta::default() + .with_added("dir1", ["file1", "file2"]) + .with_removed("dir1", ["file3", "file4"]); + let b = Delta::default() + .with_added("dir1", ["file1", "file4"]) + .with_removed("dir1", ["file3"]); + let expected = Delta::default().with_added("dir1", ["file2"]); + + assert_eq!(a.strict_difference(&b), expected); + assert_eq!(b.strict_difference(&a), Delta::default()); + } + + #[test] + fn test_contributions() { + let deltas = [ + Delta::default().with_added("dir1", ["file4"]), + Delta::default().with_added("dir1", ["file1", "file2"]), + Delta::default() + .with_added("dir1", ["file1"]) + .with_added("dir2", ["file3"]), + Delta::default() + .with_added("dir1", ["file2"]) + .with_removed("dir2", ["file3"]), + ]; + let expected = [ + State::default().with_dir("dir1", ["file2"]), + State::default().with_dir("dir1", ["file1"]), + State::default(), + State::default().with_dir("dir1", ["file4"]), + ]; + + assert_eq!(Delta::contributions(deltas.iter().rev()), expected); + } } From f2a0b6230fe419e61710e6dee2a2b6f9554b560e Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Sat, 24 May 2025 23:39:54 +0200 Subject: [PATCH 05/11] refactor(backup): delta contributions function no longer takes reversed input --- backup/src/delta.rs | 22 ++++++++++------------ backup/src/manager/mod.rs | 6 ++---- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/backup/src/delta.rs b/backup/src/delta.rs index 993dd3a..95ec391 100644 --- a/backup/src/delta.rs +++ b/backup/src/delta.rs @@ -110,20 +110,19 @@ impl Delta { out } - /// Given a chain of deltas, ordered from last to first, calculate the "contribution" for each - /// state. + /// Given a chain of deltas, calculate the "contribution" for each state. /// - /// The contribution of a delta in a given chain is defined as the parts of the state produced - /// by this chain that are actually provided by this delta. This comes down to calculating the - /// strict difference of this delta and all of its successive deltas. + /// For each delta, its contribution is the part of its added and removed files that isn't + /// overwritten by any of its following deltas. pub fn contributions(deltas: I) -> Vec where I: IntoIterator, + I::IntoIter: DoubleEndedIterator, I::Item: Borrow, { let mut contributions: Vec = Vec::new(); - let mut deltas = deltas.into_iter(); + let mut deltas = deltas.into_iter().rev(); if let Some(first_delta) = deltas.next() { // From last to first, we calculate the strict difference of the delta with the union of all its @@ -138,8 +137,7 @@ impl Delta { } } - // contributions.reverse(); - + contributions.reverse(); contributions } @@ -286,12 +284,12 @@ mod tests { .with_removed("dir2", ["file3"]), ]; let expected = [ - State::default().with_dir("dir1", ["file2"]), - State::default().with_dir("dir1", ["file1"]), - State::default(), State::default().with_dir("dir1", ["file4"]), + State::default(), + State::default().with_dir("dir1", ["file1"]), + State::default().with_dir("dir1", ["file2"]), ]; - assert_eq!(Delta::contributions(deltas.iter().rev()), expected); + assert_eq!(Delta::contributions(deltas), expected); } } diff --git a/backup/src/manager/mod.rs b/backup/src/manager/mod.rs index f8bbc73..f13c69f 100644 --- a/backup/src/manager/mod.rs +++ b/backup/src/manager/mod.rs @@ -229,9 +229,8 @@ where .map(|_| ()), // Incremental backups are exported one by one according to their contribution BackupType::Incremental => { - let contributions = Delta::contributions( - chain.iter().take(index + 1).map(|b| &b.delta).rev(), - ); + let contributions = + Delta::contributions(chain.iter().take(index + 1).map(|b| &b.delta)); let tar_gz = OpenOptions::new() .write(true) @@ -245,7 +244,6 @@ where // overwritten by their successors anyways. for (contribution, backup) in contributions .iter() - .rev() .zip(chain.iter().take(index + 1)) .filter(|(contribution, _)| !contribution.is_empty()) { From b4dce4b69acac5a087e2af1f05e8ba2091dc232d Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Tue, 31 Mar 2026 19:14:17 +0200 Subject: [PATCH 06/11] feat(papermc_api): implement wrapper for PaperMC builds API --- Cargo.lock | 615 +++++++++++++++++++++++++++++++-- Cargo.toml | 3 +- papermc-api/Cargo.toml | 10 + papermc-api/examples/routes.rs | 19 + papermc-api/src/error.rs | 22 ++ papermc-api/src/lib.rs | 217 ++++++++++++ papermc-api/src/models.rs | 90 +++++ 7 files changed, 952 insertions(+), 24 deletions(-) create mode 100644 papermc-api/Cargo.toml create mode 100644 papermc-api/examples/routes.rs create mode 100644 papermc-api/src/error.rs create mode 100644 papermc-api/src/lib.rs create mode 100644 papermc-api/src/models.rs diff --git a/Cargo.lock b/Cargo.lock index a46a1ae..6e569bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "adler2" @@ -71,7 +71,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -82,7 +82,7 @@ checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", "once_cell", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -112,10 +112,16 @@ dependencies = [ ] [[package]] -name = "bitflags" -version = "2.9.0" +name = "base64" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "bumpalo" @@ -130,11 +136,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" [[package]] -name = "cc" -version = "1.2.20" +name = "bytes" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cc" +version = "1.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" dependencies = [ + "find-msvc-tools", "shlex", ] @@ -205,6 +218,35 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "cookie_store" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fc4bff745c9b4c7fb1e97b25d13153da2bc7796260141df62378998d070207f" +dependencies = [ + "cookie", + "document-features", + "idna", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "time", + "url", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -220,6 +262,35 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "deranged" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -233,7 +304,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -259,9 +330,15 @@ dependencies = [ "cfg-if", "libc", "libredox", - "windows-sys", + "windows-sys 0.59.0", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + [[package]] name = "flate2" version = "1.1.1" @@ -272,6 +349,26 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "hashbrown" version = "0.15.2" @@ -284,6 +381,22 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + [[package]] name = "iana-time-zone" version = "0.1.63" @@ -308,6 +421,108 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + [[package]] name = "indexmap" version = "2.9.0" @@ -369,6 +584,18 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + [[package]] name = "log" version = "0.4.27" @@ -390,6 +617,12 @@ dependencies = [ "adler2", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-traits" version = "0.2.19" @@ -405,6 +638,16 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "papermc-api" +version = "0.4.2" +dependencies = [ + "chrono", + "serde", + "serde_json", + "ureq", +] + [[package]] name = "pear" version = "0.2.9" @@ -428,6 +671,27 @@ dependencies = [ "syn", ] +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "proc-macro2" version = "1.0.95" @@ -468,6 +732,20 @@ dependencies = [ "bitflags", ] +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rustix" version = "1.0.5" @@ -478,7 +756,42 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls" +version = "0.23.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", ] [[package]] @@ -488,25 +801,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" [[package]] -name = "ryu" -version = "1.0.20" +name = "serde" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] [[package]] -name = "serde" -version = "1.0.219" +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -515,14 +832,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", + "serde_core", + "zmij", ] [[package]] @@ -559,12 +877,30 @@ dependencies = [ "libc", ] +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.101" @@ -576,6 +912,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tar" version = "0.4.44" @@ -587,6 +934,47 @@ dependencies = [ "xattr", ] +[[package]] +name = "time" +version = "0.3.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" + +[[package]] +name = "time-macros" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "toml" version = "0.8.22" @@ -643,6 +1031,68 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea7109cdcd5864d4eeb1b58a1648dc9bf520360d7af16ec26d0a9354bafcfc0" +dependencies = [ + "base64", + "cookie_store", + "flate2", + "log", + "percent-encoding", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "ureq-proto", + "utf8-zero", + "webpki-roots", +] + +[[package]] +name = "ureq-proto" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c" +dependencies = [ + "base64", + "http", + "httparse", + "log", +] + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8-zero" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -655,6 +1105,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -713,6 +1169,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "webpki-roots" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "windows-core" version = "0.61.0" @@ -772,6 +1237,15 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.59.0" @@ -854,6 +1328,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + [[package]] name = "xattr" version = "1.5.0" @@ -869,3 +1349,92 @@ name = "yansi" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index 4f14331..6317a33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,8 @@ resolver = "2" members = [ 'backup', - 'alex' + 'alex', + 'papermc-api' ] [workspace.package] diff --git a/papermc-api/Cargo.toml b/papermc-api/Cargo.toml new file mode 100644 index 0000000..9c8a2a0 --- /dev/null +++ b/papermc-api/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "papermc-api" +version.workspace = true +edition.workspace = true + +[dependencies] +serde.workspace = true +chrono.workspace = true +serde_json = "1.0.149" +ureq = { version = "3.3.0", features = ["json"] } diff --git a/papermc-api/examples/routes.rs b/papermc-api/examples/routes.rs new file mode 100644 index 0000000..5628546 --- /dev/null +++ b/papermc-api/examples/routes.rs @@ -0,0 +1,19 @@ +fn main() { + let client = papermc_api::Client::new(); + let projects = client.projects().unwrap(); + + for project in projects { + println!("project: {:?}", project); + } + + let versions = client.project("paper").versions().unwrap(); + for version in versions { + println!("version: {:?}", version); + } + + let latest = client.project("paper").version("1.21.1").latest().unwrap(); + println!("latest: {:?}", latest); + + let builds = client.project("paper").version("1.21.10").builds().unwrap(); + println!("number of builds: {}", builds.len()); +} diff --git a/papermc-api/src/error.rs b/papermc-api/src/error.rs new file mode 100644 index 0000000..3e9fa21 --- /dev/null +++ b/papermc-api/src/error.rs @@ -0,0 +1,22 @@ +#[derive(Debug)] +pub enum Error { + Ureq(ureq::Error), + BadBody, +} + +impl std::error::Error for Error {} + +impl From for Error { + fn from(value: ureq::Error) -> Self { + Self::Ureq(value) + } +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Ureq(err) => err.fmt(f), + Self::BadBody => f.write_str("bad response body"), + } + } +} diff --git a/papermc-api/src/lib.rs b/papermc-api/src/lib.rs new file mode 100644 index 0000000..dbb0cf9 --- /dev/null +++ b/papermc-api/src/lib.rs @@ -0,0 +1,217 @@ +use serde_json::Value; + +use crate::{ + error::Error, + models::{Build, BuildCommit, BuildDownload, Java, Project, Version}, +}; + +mod error; +mod models; + +pub struct Client { + agent: ureq::Agent, +} + +pub const BASE_URL: &str = "https://fill.papermc.io/v3"; + +impl Client { + pub fn new() -> Self { + Self { + agent: ureq::agent(), + } + } + + pub fn projects(&self) -> Result, Error> { + let mut res = self.agent.get(format!("{}/projects", BASE_URL)).call()?; + let body_json: Value = res.body_mut().read_json()?; + + let projects = body_json["projects"].as_array().ok_or(Error::BadBody)?; + projects + .into_iter() + .map(|p| { + Ok(Project { + id: p["project"]["id"] + .as_str() + .map(|s| s.to_string()) + .ok_or(Error::BadBody)?, + name: p["project"]["name"] + .as_str() + .map(|s| s.to_string()) + .ok_or(Error::BadBody)?, + // Flatten map of versions into one array + versions: p["versions"] + .as_object() + .ok_or(Error::BadBody)? + .into_iter() + .map(|(_, versions)| versions.as_array().ok_or(Error::BadBody)) + // Collect into error to propagate error of any of the versions + .collect::, _>>()? + .into_iter() + .flatten() + .map(|v| v.as_str().ok_or(Error::BadBody).map(|s| s.to_string())) + .collect::>()?, + }) + }) + .collect() + } + + pub fn project<'a>(&'a self, project: &'a str) -> ProjectQuery<'a> { + return ProjectQuery { + agent: &self.agent, + project, + }; + } +} + +pub struct ProjectQuery<'a> { + agent: &'a ureq::Agent, + project: &'a str, +} + +impl<'a> ProjectQuery<'a> { + pub fn versions(&self) -> Result, Error> { + let mut res = self + .agent + .get(format!("{}/projects/{}/versions", BASE_URL, self.project)) + .call()?; + let body_json: Value = res.body_mut().read_json()?; + + let versions = body_json["versions"].as_array().ok_or(Error::BadBody)?; + versions + .into_iter() + .map(|v| { + Ok(Version { + id: v["version"]["id"] + .as_str() + .map(String::from) + .ok_or(Error::BadBody)?, + support_status: v["version"]["support"]["status"] + .as_str() + .ok_or(Error::BadBody)? + .parse() + .map_err(|_| Error::BadBody)?, + java: Java { + minimum_version: v["version"]["java"]["version"]["minimum"] + .as_u64() + .ok_or(Error::BadBody)?, + recommended_flags: v["version"]["java"]["flags"]["recommended"] + .as_array() + .ok_or(Error::BadBody)? + .into_iter() + .map(|v| v.as_str().map(String::from).ok_or(Error::BadBody)) + .collect::>()?, + }, + builds: v["builds"] + .as_array() + .ok_or(Error::BadBody)? + .into_iter() + .map(|v| v.as_u64().ok_or(Error::BadBody)) + .collect::>()?, + }) + }) + .collect() + } + + pub fn version(&self, version: &'a str) -> VersionQuery<'a> { + VersionQuery { + agent: self.agent, + project: self.project, + version, + } + } +} + +pub struct VersionQuery<'a> { + agent: &'a ureq::Agent, + project: &'a str, + version: &'a str, +} + +impl<'a> VersionQuery<'a> { + pub fn latest(&self) -> Result { + let mut res = self + .agent + .get(format!( + "{}/projects/{}/versions/{}/builds/latest", + BASE_URL, self.project, self.version + )) + .call()?; + let body_json: Value = res.body_mut().read_json()?; + + parse_build_json(&body_json) + } + + pub fn builds(&self) -> Result, Error> { + let mut res = self + .agent + .get(format!( + "{}/projects/{}/versions/{}/builds", + BASE_URL, self.project, self.version + )) + .call()?; + let body_json: Value = res.body_mut().read_json()?; + + body_json + .as_array() + .ok_or(Error::BadBody)? + .into_iter() + .map(parse_build_json) + .collect() + } +} + +fn parse_build_json(value: &Value) -> Result { + Ok(Build { + id: value["id"].as_u64().ok_or(Error::BadBody)?, + time: chrono::DateTime::parse_from_rfc3339(value["time"].as_str().ok_or(Error::BadBody)?) + .map_err(|_| Error::BadBody)? + .into(), + channel: value["channel"] + .as_str() + .ok_or(Error::BadBody)? + .parse() + .map_err(|_| Error::BadBody)?, + commits: value["commits"] + .as_array() + .ok_or(Error::BadBody)? + .into_iter() + .map(|build| { + Ok(BuildCommit { + sha: build["sha"].as_str().ok_or(Error::BadBody)?.to_string(), + time: chrono::DateTime::parse_from_rfc3339( + build["time"].as_str().ok_or(Error::BadBody)?, + ) + .map_err(|_| Error::BadBody)? + .into(), + message: build["message"].as_str().ok_or(Error::BadBody)?.to_string(), + }) + }) + .collect::>()?, + downloads: value["downloads"] + .as_object() + .ok_or(Error::BadBody)? + .into_iter() + .map(|(key, build)| { + Ok(( + key.to_string(), + BuildDownload { + name: build["name"].as_str().ok_or(Error::BadBody)?.to_string(), + size: build["size"].as_u64().ok_or(Error::BadBody)?, + url: build["url"].as_str().ok_or(Error::BadBody)?.to_string(), + checksums: build["checksums"] + .as_object() + .ok_or(Error::BadBody)? + .into_iter() + .map(|(key, value)| { + Ok(( + key.to_string(), + value.as_str().ok_or(Error::BadBody)?.to_string(), + )) + }) + .collect::>()?, + }, + )) + }) + .collect::>()?, + }) +} diff --git a/papermc-api/src/models.rs b/papermc-api/src/models.rs new file mode 100644 index 0000000..c73ecf9 --- /dev/null +++ b/papermc-api/src/models.rs @@ -0,0 +1,90 @@ +use std::{collections::HashMap, str::FromStr}; + +use chrono::{DateTime, Utc}; + +#[derive(Debug)] +pub struct Project { + pub id: String, + pub name: String, + pub versions: Vec, +} + +#[derive(Debug)] +pub enum SupportStatus { + Supported, + Unsupported, +} + +pub struct SupportStatusParseError; + +impl FromStr for SupportStatus { + type Err = SupportStatusParseError; + + fn from_str(s: &str) -> Result { + match s { + "SUPPORTED" => Ok(Self::Supported), + "UNSUPPORTED" => Ok(Self::Unsupported), + _ => Err(SupportStatusParseError), + } + } +} + +#[derive(Debug)] +pub struct Java { + pub minimum_version: u64, + pub recommended_flags: Vec, +} + +#[derive(Debug)] +pub struct Version { + pub id: String, + pub support_status: SupportStatus, + pub java: Java, + pub builds: Vec, +} + +#[derive(Debug)] +pub struct Build { + pub id: u64, + pub time: DateTime, + pub channel: BuildChannel, + pub commits: Vec, + pub downloads: HashMap, +} + +#[derive(Debug)] +pub enum BuildChannel { + Alpha, + Beta, + Stable, +} + +pub struct BuildChannelParseError; + +impl FromStr for BuildChannel { + type Err = BuildChannelParseError; + + fn from_str(s: &str) -> Result { + match s { + "STABLE" => Ok(Self::Stable), + "BETA" => Ok(Self::Beta), + "ALPHA" => Ok(Self::Alpha), + _ => Err(BuildChannelParseError), + } + } +} + +#[derive(Debug)] +pub struct BuildCommit { + pub sha: String, + pub time: DateTime, + pub message: String, +} + +#[derive(Debug)] +pub struct BuildDownload { + pub name: String, + pub checksums: HashMap, + pub size: u64, + pub url: String, +} From f2c4b97626a7fb6beba99077fe957142d3b1ef86 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Mon, 13 Apr 2026 22:31:24 +0200 Subject: [PATCH 07/11] feat(papermc_api): add routes for per-version, project and build information --- papermc-api/src/lib.rs | 158 ++++++++++++++++++++++---------------- papermc-api/src/models.rs | 21 ++++- 2 files changed, 111 insertions(+), 68 deletions(-) diff --git a/papermc-api/src/lib.rs b/papermc-api/src/lib.rs index dbb0cf9..d9881c8 100644 --- a/papermc-api/src/lib.rs +++ b/papermc-api/src/lib.rs @@ -1,9 +1,8 @@ use serde_json::Value; -use crate::{ - error::Error, - models::{Build, BuildCommit, BuildDownload, Java, Project, Version}, -}; +pub use error::Error; + +use crate::models::{Build, BuildCommit, BuildDownload, Java, Project, Version}; mod error; mod models; @@ -26,33 +25,7 @@ impl Client { let body_json: Value = res.body_mut().read_json()?; let projects = body_json["projects"].as_array().ok_or(Error::BadBody)?; - projects - .into_iter() - .map(|p| { - Ok(Project { - id: p["project"]["id"] - .as_str() - .map(|s| s.to_string()) - .ok_or(Error::BadBody)?, - name: p["project"]["name"] - .as_str() - .map(|s| s.to_string()) - .ok_or(Error::BadBody)?, - // Flatten map of versions into one array - versions: p["versions"] - .as_object() - .ok_or(Error::BadBody)? - .into_iter() - .map(|(_, versions)| versions.as_array().ok_or(Error::BadBody)) - // Collect into error to propagate error of any of the versions - .collect::, _>>()? - .into_iter() - .flatten() - .map(|v| v.as_str().ok_or(Error::BadBody).map(|s| s.to_string())) - .collect::>()?, - }) - }) - .collect() + projects.into_iter().map(parse_project_json).collect() } pub fn project<'a>(&'a self, project: &'a str) -> ProjectQuery<'a> { @@ -69,6 +42,16 @@ pub struct ProjectQuery<'a> { } impl<'a> ProjectQuery<'a> { + pub fn info(&self) -> Result { + let mut res = self + .agent + .get(format!("{}/projects/{}", BASE_URL, self.project)) + .call()?; + let body_json: Value = res.body_mut().read_json()?; + + parse_project_json(&body_json) + } + pub fn versions(&self) -> Result, Error> { let mut res = self .agent @@ -77,39 +60,7 @@ impl<'a> ProjectQuery<'a> { let body_json: Value = res.body_mut().read_json()?; let versions = body_json["versions"].as_array().ok_or(Error::BadBody)?; - versions - .into_iter() - .map(|v| { - Ok(Version { - id: v["version"]["id"] - .as_str() - .map(String::from) - .ok_or(Error::BadBody)?, - support_status: v["version"]["support"]["status"] - .as_str() - .ok_or(Error::BadBody)? - .parse() - .map_err(|_| Error::BadBody)?, - java: Java { - minimum_version: v["version"]["java"]["version"]["minimum"] - .as_u64() - .ok_or(Error::BadBody)?, - recommended_flags: v["version"]["java"]["flags"]["recommended"] - .as_array() - .ok_or(Error::BadBody)? - .into_iter() - .map(|v| v.as_str().map(String::from).ok_or(Error::BadBody)) - .collect::>()?, - }, - builds: v["builds"] - .as_array() - .ok_or(Error::BadBody)? - .into_iter() - .map(|v| v.as_u64().ok_or(Error::BadBody)) - .collect::>()?, - }) - }) - .collect() + versions.into_iter().map(parse_version_json).collect() } pub fn version(&self, version: &'a str) -> VersionQuery<'a> { @@ -128,17 +79,17 @@ pub struct VersionQuery<'a> { } impl<'a> VersionQuery<'a> { - pub fn latest(&self) -> Result { + pub fn info(&self) -> Result { let mut res = self .agent .get(format!( - "{}/projects/{}/versions/{}/builds/latest", + "{}/projects/{}/versions/{}", BASE_URL, self.project, self.version )) .call()?; let body_json: Value = res.body_mut().read_json()?; - parse_build_json(&body_json) + parse_version_json(&body_json) } pub fn builds(&self) -> Result, Error> { @@ -158,6 +109,79 @@ impl<'a> VersionQuery<'a> { .map(parse_build_json) .collect() } + + pub fn build(&self, build: &str) -> Result { + let mut res = self + .agent + .get(format!( + "{}/projects/{}/versions/{}/builds/{}", + BASE_URL, self.project, self.version, build + )) + .call()?; + let body_json: Value = res.body_mut().read_json()?; + + parse_build_json(&body_json) + } + + pub fn latest(&self) -> Result { + return self.build("latest"); + } +} + +fn parse_project_json(value: &Value) -> Result { + Ok(Project { + id: value["project"]["id"] + .as_str() + .map(|s| s.to_string()) + .ok_or(Error::BadBody)?, + name: value["project"]["name"] + .as_str() + .map(|s| s.to_string()) + .ok_or(Error::BadBody)?, + // Flatten map of versions into one array + versions: value["versions"] + .as_object() + .ok_or(Error::BadBody)? + .into_iter() + .map(|(_, versions)| versions.as_array().ok_or(Error::BadBody)) + // Collect into error to propagate error of any of the versions + .collect::, _>>()? + .into_iter() + .flatten() + .map(|v| v.as_str().ok_or(Error::BadBody).map(|s| s.to_string())) + .collect::>()?, + }) +} + +fn parse_version_json(value: &Value) -> Result { + Ok(Version { + id: value["version"]["id"] + .as_str() + .map(String::from) + .ok_or(Error::BadBody)?, + support_status: value["version"]["support"]["status"] + .as_str() + .ok_or(Error::BadBody)? + .parse() + .map_err(|_| Error::BadBody)?, + java: Java { + minimum_version: value["version"]["java"]["version"]["minimum"] + .as_u64() + .ok_or(Error::BadBody)?, + recommended_flags: value["version"]["java"]["flags"]["recommended"] + .as_array() + .ok_or(Error::BadBody)? + .into_iter() + .map(|v| v.as_str().map(String::from).ok_or(Error::BadBody)) + .collect::>()?, + }, + builds: value["builds"] + .as_array() + .ok_or(Error::BadBody)? + .into_iter() + .map(|v| v.as_u64().ok_or(Error::BadBody)) + .collect::>()?, + }) } fn parse_build_json(value: &Value) -> Result { diff --git a/papermc-api/src/models.rs b/papermc-api/src/models.rs index c73ecf9..c28f7e9 100644 --- a/papermc-api/src/models.rs +++ b/papermc-api/src/models.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, str::FromStr}; +use std::{collections::HashMap, fmt::Display, str::FromStr}; use chrono::{DateTime, Utc}; @@ -29,6 +29,15 @@ impl FromStr for SupportStatus { } } +impl Display for SupportStatus { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Supported => f.write_str("SUPPORTED"), + Self::Unsupported => f.write_str("UNSUPPORTED"), + } + } +} + #[derive(Debug)] pub struct Java { pub minimum_version: u64, @@ -74,6 +83,16 @@ impl FromStr for BuildChannel { } } +impl Display for BuildChannel { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Alpha => f.write_str("ALPHA"), + Self::Beta => f.write_str("BETA"), + Self::Stable => f.write_str("STABLE"), + } + } +} + #[derive(Debug)] pub struct BuildCommit { pub sha: String, From d38cb4ce39f1e532c927fe926e1b1ab36d5ae10c Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Mon, 13 Apr 2026 22:44:17 +0200 Subject: [PATCH 08/11] feat(cli): add commands to list, view and download PaperMC builds --- CHANGELOG.md | 6 ++ Cargo.lock | 2 + alex/Cargo.toml | 2 + alex/src/cli/mod.rs | 5 + alex/src/cli/papermc.rs | 213 ++++++++++++++++++++++++++++++++++++++++ alex/src/error.rs | 2 + 6 files changed, 230 insertions(+) create mode 100644 alex/src/cli/papermc.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b6fa3a..4b9fb7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased](https://git.rustybever.be/Chewing_Bever/alex/src/branch/dev) +### Added + +* CLI commands to interact with the PaperMC API + * list and view available Minecraft versions and builds per version + * Download jars to simplify manual server updating + ## [0.4.2](https://git.rustybever.be/Chewing_Bever/alex/src/tag/0.4.2) ### Fixed diff --git a/Cargo.lock b/Cargo.lock index 6e569bb..c1afa68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,8 +16,10 @@ dependencies = [ "chrono", "clap", "figment", + "papermc-api", "serde", "signal-hook", + "ureq", ] [[package]] diff --git a/alex/Cargo.toml b/alex/Cargo.toml index 7f7cac8..71c1c93 100644 --- a/alex/Cargo.toml +++ b/alex/Cargo.toml @@ -6,6 +6,7 @@ edition.workspace = true [dependencies] backup = { path = "../backup" } +papermc-api = { path = "../papermc-api" } chrono.workspace = true serde.workspace = true @@ -13,3 +14,4 @@ serde.workspace = true clap = { version = "4.5.37", features = ["derive", "env"] } signal-hook = "0.3.15" figment = { version = "0.10.10", features = ["env", "toml"] } +ureq = "3.3.0" diff --git a/alex/src/cli/mod.rs b/alex/src/cli/mod.rs index 47d12f3..92724ea 100644 --- a/alex/src/cli/mod.rs +++ b/alex/src/cli/mod.rs @@ -1,5 +1,6 @@ mod backup; mod config; +mod papermc; mod run; use std::{path::PathBuf, str::FromStr}; @@ -72,6 +73,9 @@ pub enum Commands { Run(RunCli), /// Interact with the backup system without starting a server Backup(BackupArgs), + /// Interact with the PaperMC API and download new JARs + #[command(name = "papermc")] + PaperMC(papermc::Cli), } impl Cli { @@ -81,6 +85,7 @@ impl Cli { match &self.command { Commands::Run(args) => args.run(self, &config), Commands::Backup(args) => Ok(args.run(&config)?), + Commands::PaperMC(cli) => cli.run(), } } diff --git a/alex/src/cli/papermc.rs b/alex/src/cli/papermc.rs new file mode 100644 index 0000000..66fc724 --- /dev/null +++ b/alex/src/cli/papermc.rs @@ -0,0 +1,213 @@ +use std::path::{Path, PathBuf}; + +use chrono::Local; +use clap::{Args, Subcommand}; + +#[derive(Args)] +pub struct Cli { + #[command(subcommand)] + pub command: Commands, +} + +#[derive(Subcommand)] +pub enum Commands { + /// Show information or a specific version or build + Show(ShowArgs), + /// List the available versions, or builds for a specific version + List(ListArgs), + /// Download the jar for a specific build + Download(DownloadBuildArgs), +} + +#[derive(Args)] +pub struct ShowArgs { + /// Version to show information for + version: String, + + /// Build within version to show information for + build: Option, +} + +#[derive(Args)] +pub struct ListArgs { + /// If provided, list the available builds for this version + version: Option, +} + +#[derive(Args)] +pub struct DownloadBuildArgs { + /// Version of build to download + version: String, + /// Build number for build to download + build: String, + + /// Path to store the new JAR file in; stores JAR in the local directory if not specified + #[arg(short, long, value_name = "OUT_PATH")] + out: Option, +} + +impl Cli { + pub fn run(&self) -> crate::Result<()> { + match &self.command { + Commands::Show(ShowArgs { + version, + build: None, + }) => show_version(&version), + Commands::List(ListArgs { version: None }) => list_versions(), + Commands::List(ListArgs { + version: Some(version), + }) => list_builds(version), + Commands::Show(ShowArgs { + version, + build: Some(build), + }) => show_build(&version, &build), + Commands::Download(args) => { + download_build(&args.version, &args.build, args.out.as_deref()) + } + } + + Ok(()) + } +} + +fn show_version(version_str: &str) { + let client = papermc_api::Client::new(); + + let version = match client.project("paper").version(version_str).info() { + Ok(version) => version, + Err(err) => { + println!("failed to query API: {err}"); + return; + } + }; + + println!("id : {}", version.id); + println!("status : {}", version.support_status); + println!("builds : {}", version.builds.len()); + println!("Min. Java : {}", version.java.minimum_version); + println!("Java flags: {}", version.java.recommended_flags.join(" ")) +} + +fn show_build(version_str: &str, build_str: &str) { + let client = papermc_api::Client::new(); + + let build = match client + .project("paper") + .version(version_str) + .build(build_str) + { + Ok(build) => build, + Err(err) => { + println!("failed to query API: {err}"); + return; + } + }; + + println!("id : {}", build.id); + println!("time : {}", build.time.with_timezone(&Local)); + println!("channel: {}", build.channel); + println!("commits:"); + + for commit in build.commits { + println!("- SHA : {}", commit.sha); + println!(" time : {}", commit.time.with_timezone(&Local)); + println!(" message: {}", commit.message); + } + + println!("downloads:"); + + for (name, download) in build.downloads.iter() { + println!(" {name}:"); + println!(" name: {}", download.name); + println!(" size: {}", download.size); + println!(" URL : {}", download.url); + println!(" checksums:"); + + for (name, value) in download.checksums.iter() { + println!(" - {}: {}", name, value); + } + } +} + +fn list_versions() { + let client = papermc_api::Client::new(); + + match client.project("paper").versions() { + Ok(versions) => { + for version in versions { + println!("{} ({})", version.id, version.support_status); + } + } + Err(err) => { + println!("failed to query API: {err}"); + } + } +} + +fn list_builds(version: &str) { + let client = papermc_api::Client::new(); + + match client.project("paper").version(version).builds() { + Ok(builds) => { + for build in builds { + println!("- id : {}", build.id); + println!(" time : {}", build.time.with_timezone(&Local)); + println!(" channel: {}", build.channel); + } + } + Err(err) => { + println!("failed to query API: {err}"); + } + } +} + +fn download_build(version: &str, build: &str, out_path: Option<&Path>) { + let client = papermc_api::Client::new(); + let build = match client.project("paper").version(version).build(build) { + Ok(build) => build, + Err(err) => { + println!("failed to query API: {err}"); + return; + } + }; + + let filename = format!("paper-{}-{}.jar", version, build.id); + let dest_path = match out_path { + Some(path) if path.is_dir() => path.join(filename), + Some(path) => path.to_path_buf(), + None => PathBuf::from(filename), + }; + + let download_url = match build + .downloads + .get("server:default") + .or(build.downloads.values().next()) + { + Some(download) => &download.url, + None => { + println!("no download URLs found for build."); + return; + } + }; + + let mut f = match std::fs::File::create(dest_path) { + Ok(f) => f, + Err(err) => { + println!("failed to create destination file: {err}"); + return; + } + }; + + let mut res = match ureq::get(download_url).call() { + Ok(res) => res, + Err(err) => { + println!("failed to download file: {err}"); + return; + } + }; + + let mut reader = res.body_mut().as_reader(); + if let Err(err) = std::io::copy(&mut reader, &mut f) { + println!("failed to download file: {err}"); + } +} diff --git a/alex/src/error.rs b/alex/src/error.rs index 0ea7532..b46a49e 100644 --- a/alex/src/error.rs +++ b/alex/src/error.rs @@ -6,6 +6,7 @@ pub type Result = std::result::Result; pub enum Error { IO(io::Error), Figment(figment::Error), + Other(Box), } impl fmt::Display for Error { @@ -13,6 +14,7 @@ impl fmt::Display for Error { match self { Error::IO(err) => write!(fmt, "{}", err), Error::Figment(err) => write!(fmt, "{}", err), + Error::Other(err) => write!(fmt, "{}", err), } } } From 7987bef3849e12557a533f69c1bc1f151021d0eb Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Tue, 14 Apr 2026 21:04:57 +0200 Subject: [PATCH 09/11] refactor(papermc_api): fix Clippy diagnostics --- papermc-api/src/lib.rs | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/papermc-api/src/lib.rs b/papermc-api/src/lib.rs index d9881c8..1de90b5 100644 --- a/papermc-api/src/lib.rs +++ b/papermc-api/src/lib.rs @@ -13,6 +13,12 @@ pub struct Client { pub const BASE_URL: &str = "https://fill.papermc.io/v3"; +impl Default for Client { + fn default() -> Self { + Self::new() + } +} + impl Client { pub fn new() -> Self { Self { @@ -25,14 +31,14 @@ impl Client { let body_json: Value = res.body_mut().read_json()?; let projects = body_json["projects"].as_array().ok_or(Error::BadBody)?; - projects.into_iter().map(parse_project_json).collect() + projects.iter().map(parse_project_json).collect() } pub fn project<'a>(&'a self, project: &'a str) -> ProjectQuery<'a> { - return ProjectQuery { + ProjectQuery { agent: &self.agent, project, - }; + } } } @@ -60,7 +66,7 @@ impl<'a> ProjectQuery<'a> { let body_json: Value = res.body_mut().read_json()?; let versions = body_json["versions"].as_array().ok_or(Error::BadBody)?; - versions.into_iter().map(parse_version_json).collect() + versions.iter().map(parse_version_json).collect() } pub fn version(&self, version: &'a str) -> VersionQuery<'a> { @@ -105,7 +111,7 @@ impl<'a> VersionQuery<'a> { body_json .as_array() .ok_or(Error::BadBody)? - .into_iter() + .iter() .map(parse_build_json) .collect() } @@ -124,7 +130,7 @@ impl<'a> VersionQuery<'a> { } pub fn latest(&self) -> Result { - return self.build("latest"); + self.build("latest") } } @@ -142,7 +148,7 @@ fn parse_project_json(value: &Value) -> Result { versions: value["versions"] .as_object() .ok_or(Error::BadBody)? - .into_iter() + .iter() .map(|(_, versions)| versions.as_array().ok_or(Error::BadBody)) // Collect into error to propagate error of any of the versions .collect::, _>>()? @@ -171,14 +177,14 @@ fn parse_version_json(value: &Value) -> Result { recommended_flags: value["version"]["java"]["flags"]["recommended"] .as_array() .ok_or(Error::BadBody)? - .into_iter() + .iter() .map(|v| v.as_str().map(String::from).ok_or(Error::BadBody)) .collect::>()?, }, builds: value["builds"] .as_array() .ok_or(Error::BadBody)? - .into_iter() + .iter() .map(|v| v.as_u64().ok_or(Error::BadBody)) .collect::>()?, }) @@ -198,7 +204,7 @@ fn parse_build_json(value: &Value) -> Result { commits: value["commits"] .as_array() .ok_or(Error::BadBody)? - .into_iter() + .iter() .map(|build| { Ok(BuildCommit { sha: build["sha"].as_str().ok_or(Error::BadBody)?.to_string(), @@ -214,7 +220,7 @@ fn parse_build_json(value: &Value) -> Result { downloads: value["downloads"] .as_object() .ok_or(Error::BadBody)? - .into_iter() + .iter() .map(|(key, build)| { Ok(( key.to_string(), From f0d552266142ba20addff7fb71844d613f8caf57 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Tue, 14 Apr 2026 21:30:27 +0200 Subject: [PATCH 10/11] chore: update dependencies; bump version to 0.5.0 --- CHANGELOG.md | 2 + Cargo.lock | 425 ++++++++++++++++++++++++++------------------------- Cargo.toml | 2 +- Justfile | 3 +- 4 files changed, 218 insertions(+), 214 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b9fb7d..aaec0f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased](https://git.rustybever.be/Chewing_Bever/alex/src/branch/dev) +## [0.5.0](https://git.rustybever.be/Chewing_Bever/alex/src/tag/0.5.0) + ### Added * CLI commands to interact with the PaperMC API diff --git a/Cargo.lock b/Cargo.lock index c1afa68..a71e4e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,13 +4,13 @@ version = 4 [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "alex" -version = "0.4.2" +version = "0.5.0" dependencies = [ "backup", "chrono", @@ -22,12 +22,6 @@ dependencies = [ "ureq", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -39,9 +33,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.18" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", @@ -54,57 +48,57 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", - "once_cell", - "windows-sys 0.59.0", + "once_cell_polyfill", + "windows-sys 0.61.2", ] [[package]] name = "atomic" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" +checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340" dependencies = [ "bytemuck", ] [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backup" -version = "0.4.2" +version = "0.5.0" dependencies = [ "chrono", "flate2", @@ -121,21 +115,21 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "bytemuck" -version = "1.23.0" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" [[package]] name = "bytes" @@ -145,9 +139,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.58" +version = "1.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" dependencies = [ "find-msvc-tools", "shlex", @@ -155,17 +149,16 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" -version = "0.4.41" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ - "android-tzdata", "iana-time-zone", "js-sys", "num-traits", @@ -176,9 +169,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.37" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" dependencies = [ "clap_builder", "clap_derive", @@ -186,9 +179,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.37" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ "anstream", "anstyle", @@ -198,9 +191,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.32" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" dependencies = [ "heck", "proc-macro2", @@ -210,15 +203,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "cookie" @@ -233,9 +226,9 @@ dependencies = [ [[package]] name = "cookie_store" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fc4bff745c9b4c7fb1e97b25d13153da2bc7796260141df62378998d070207f" +checksum = "15b2c103cf610ec6cae3da84a766285b42fd16aad564758459e6ecf128c75206" dependencies = [ "cookie", "document-features", @@ -257,18 +250,18 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] [[package]] name = "deranged" -version = "0.5.5" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ "powerfmt", ] @@ -301,12 +294,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.11" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -325,14 +318,13 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.25" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" dependencies = [ "cfg-if", "libc", "libredox", - "windows-sys 0.59.0", ] [[package]] @@ -343,9 +335,9 @@ checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "flate2" -version = "1.1.1" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", @@ -373,9 +365,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" [[package]] name = "heck" @@ -401,9 +393,9 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "iana-time-zone" -version = "0.1.63" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -425,12 +417,13 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ "displaydoc", "potential_utf", + "utf8_iter", "yoke", "zerofrom", "zerovec", @@ -438,9 +431,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ "displaydoc", "litemap", @@ -451,9 +444,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -465,15 +458,15 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] name = "icu_properties" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ "icu_collections", "icu_locale_core", @@ -485,15 +478,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] name = "icu_provider" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ "displaydoc", "icu_locale_core", @@ -527,9 +520,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.9.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", "hashbrown", @@ -543,21 +536,21 @@ checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca" dependencies = [ "once_cell", "wasm-bindgen", @@ -565,32 +558,33 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.172" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] name = "libredox" -version = "0.1.3" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" dependencies = [ "bitflags", "libc", + "plain", "redox_syscall", ] [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "litrs" @@ -600,30 +594,31 @@ checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] name = "log" -version = "0.4.27" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "memchr" -version = "2.7.4" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" [[package]] name = "num-traits" @@ -636,13 +631,19 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "papermc-api" -version = "0.4.2" +version = "0.5.0" dependencies = [ "chrono", "serde", @@ -680,10 +681,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] -name = "potential_utf" -version = "0.1.4" +name = "plain" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" dependencies = [ "zerovec", ] @@ -696,9 +703,9 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -718,18 +725,18 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.5.11" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +checksum = "f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a" dependencies = [ "bitflags", ] @@ -750,22 +757,22 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.5" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.23.37" +version = "0.23.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +checksum = "69f9466fb2c14ea04357e91413efb882e2a6d4a406e625449bc0a5d360d53a21" dependencies = [ "log", "once_cell", @@ -787,9 +794,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.10" +version = "0.103.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" +checksum = "8279bb85272c9f10811ae6a6c547ff594d6a7f3c6c6b02ee9726d1d0dcfcdd06" dependencies = [ "ring", "rustls-pki-types", @@ -798,9 +805,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "serde" @@ -847,9 +854,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -862,9 +869,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" dependencies = [ "libc", "signal-hook-registry", @@ -872,13 +879,20 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.5" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + [[package]] name = "smallvec" version = "1.15.1" @@ -905,9 +919,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.101" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -927,9 +941,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973" dependencies = [ "filetime", "libc", @@ -938,9 +952,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.45" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", @@ -953,15 +967,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.25" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ "num-conv", "time-core", @@ -969,9 +983,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", "zerovec", @@ -979,9 +993,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", @@ -991,18 +1005,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.9" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.26" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", @@ -1014,9 +1028,9 @@ dependencies = [ [[package]] name = "toml_write" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "uncased" @@ -1029,9 +1043,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "untrusted" @@ -1115,35 +1129,22 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1151,22 +1152,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129" dependencies = [ "unicode-ident", ] @@ -1182,9 +1183,9 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.61.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", @@ -1195,9 +1196,9 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", @@ -1206,9 +1207,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", @@ -1217,24 +1218,24 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-result" -version = "0.3.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ "windows-link", ] @@ -1250,11 +1251,11 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-targets", + "windows-link", ] [[package]] @@ -1323,24 +1324,24 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.7.7" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" dependencies = [ "memchr", ] [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "xattr" -version = "1.5.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" dependencies = [ "libc", "rustix", @@ -1354,9 +1355,9 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -1365,9 +1366,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", @@ -1377,18 +1378,18 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", @@ -1404,9 +1405,9 @@ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ "displaydoc", "yoke", @@ -1415,9 +1416,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ "yoke", "zerofrom", @@ -1426,9 +1427,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 6317a33..66f7b00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members = [ ] [workspace.package] -version = "0.4.2" +version = "0.5.0" authors = ["Jef Roosens"] edition = "2021" diff --git a/Justfile b/Justfile index 54943ad..75af725 100644 --- a/Justfile +++ b/Justfile @@ -43,7 +43,8 @@ run: --java '/usr/lib/jvm/java-21-openjdk/bin/java' \ --layers '2min,2,4,4;3min,3,2,2' -publish-release-binaries tag: (build-release 'x86_64-unknown-linux-musl') (build-release 'aarch64-unknown-linux-musl') +# Publish the binaries and packages for a new release +publish-release tag: (build-release 'x86_64-unknown-linux-musl') (build-release 'aarch64-unknown-linux-musl') # Check the binaries are proper static binaries [ "$(readelf -d target/x86_64-unknown-linux-musl/release/alex | grep NEEDED | wc -l)" = 0 ] [ "$(readelf -d target/aarch64-unknown-linux-musl/release/alex | grep NEEDED | wc -l)" = 0 ] From e1bf2cb4672589865f4391ba8cf480b2594c0ec9 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Sun, 19 Apr 2026 16:03:43 +0200 Subject: [PATCH 11/11] chore: added Debian packaging using cargo-deb --- CHANGELOG.md | 4 ++++ Cargo.toml | 1 + Justfile | 44 ++++++++++++++++++++++++++++++++------------ alex/Cargo.toml | 2 ++ 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aaec0f2..8e1ad49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased](https://git.rustybever.be/Chewing_Bever/alex/src/branch/dev) +### Added + +* Debian packages are now available in the [package registry](https://git.rustybever.be/Chewing_Bever/alex/packages) + ## [0.5.0](https://git.rustybever.be/Chewing_Bever/alex/src/tag/0.5.0) ### Added diff --git a/Cargo.toml b/Cargo.toml index 66f7b00..f834642 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ members = [ version = "0.5.0" authors = ["Jef Roosens"] edition = "2021" +license-file = "LICENSE" [workspace.dependencies] chrono = { version = "0.4.26", features = ["serde"] } diff --git a/Justfile b/Justfile index 75af725..54180ad 100644 --- a/Justfile +++ b/Justfile @@ -1,20 +1,25 @@ +# Build the local development build [group('build')] build: cargo build --frozen --workspace alias b := build +# Build release binaries for the supported architectures [group('build')] -build-release target: +build-release: cargo build \ --release \ --frozen \ --workspace \ - --target '{{ target }}' + --target x86_64-unknown-linux-musl \ + --target aarch64-unknown-linux-musl +# Run all tests in the workspace test: cargo test --frozen --workspace alias t := test +# Run cargofmt and clippy check: cargo fmt --check --all cargo clippy \ @@ -23,6 +28,7 @@ check: --no-deps \ --deny 'clippy::all' alias c := check +alias lint := check fetch: cargo fetch --locked @@ -43,19 +49,33 @@ run: --java '/usr/lib/jvm/java-21-openjdk/bin/java' \ --layers '2min,2,4,4;3min,3,2,2' +# Package the static release binaries as a Debian package +[group('package')] +package-deb: build-release + cargo deb \ + --package alex \ + --frozen \ + --no-build \ + --target x86_64-unknown-linux-musl \ + --target aarch64-unknown-linux-musl + # Publish the binaries and packages for a new release -publish-release tag: (build-release 'x86_64-unknown-linux-musl') (build-release 'aarch64-unknown-linux-musl') +[group('package')] +publish-release tag: build-release package-deb # Check the binaries are proper static binaries [ "$(readelf -d target/x86_64-unknown-linux-musl/release/alex | grep NEEDED | wc -l)" = 0 ] [ "$(readelf -d target/aarch64-unknown-linux-musl/release/alex | grep NEEDED | wc -l)" = 0 ] curl \ - --netrc \ - --fail \ - --upload-file target/x86_64-unknown-linux-musl/release/alex \ - https://git.rustybever.be/api/packages/Chewing_Bever/generic/alex/"{{ tag }}"/alex-linux-amd64 - curl \ - --netrc \ - --fail \ - --upload-file target/aarch64-unknown-linux-musl/release/alex \ - https://git.rustybever.be/api/packages/Chewing_Bever/generic/alex/"{{ tag }}"/alex-linux-arm64 + --parallel --fail-early \ + --netrc --upload-file target/x86_64-unknown-linux-musl/release/alex \ + https://git.rustybever.be/api/packages/Chewing_Bever/generic/alex/"{{ tag }}"/alex-linux-amd64 \ + --next \ + --netrc --upload-file target/aarch64-unknown-linux-musl/release/alex \ + https://git.rustybever.be/api/packages/Chewing_Bever/generic/alex/"{{ tag }}"/alex-linux-arm64 \ + --next \ + --netrc --upload-file target/debian/alex_{{ tag }}-1_amd64.deb \ + https://git.rustybever.be/api/packages/Chewing_Bever/debian/pool/any/main/upload \ + --next \ + --netrc --upload-file target/debian/alex_{{ tag }}-1_arm64.deb \ + https://git.rustybever.be/api/packages/Chewing_Bever/debian/pool/any/main/upload > /dev/null diff --git a/alex/Cargo.toml b/alex/Cargo.toml index 71c1c93..ff5df75 100644 --- a/alex/Cargo.toml +++ b/alex/Cargo.toml @@ -3,6 +3,8 @@ name = "alex" description = "Wrapper around Minecraft server processes, designed to complement Docker image installations." version.workspace = true edition.workspace = true +authors.workspace = true +license-file.workspace = true [dependencies] backup = { path = "../backup" }