diff --git a/Cargo.lock b/Cargo.lock index c288fd463ab..4123ddf516d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -678,6 +678,29 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bon" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97493a391b4b18ee918675fb8663e53646fd09321c58b46afa04e8ce2499c869" +dependencies = [ + "bon-macros", + "rustversion", +] + +[[package]] +name = "bon-macros" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2af3eac944c12cdf4423eab70d310da0a8e5851a18ffb192c0a5e3f7ae1663" +dependencies = [ + "darling", + "ident_case", + "proc-macro2", + "quote", + "syn 2.0.82", +] + [[package]] name = "brotli" version = "7.0.0" @@ -994,6 +1017,7 @@ dependencies = [ "axum-extra", "base64 0.22.1", "bigdecimal", + "bon", "bytes", "cargo-manifest", "chrono", @@ -1012,7 +1036,6 @@ dependencies = [ "crates_io_worker", "csv", "deadpool-diesel", - "derive_builder", "derive_deref", "dialoguer", "diesel", diff --git a/Cargo.toml b/Cargo.toml index 04b88e07c78..1f69db82b58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ axum = { version = "=0.7.7", features = ["macros", "matched-path"] } axum-extra = { version = "=0.9.4", features = ["cookie-signed", "typed-header"] } base64 = "=0.22.1" bigdecimal = { version = "=0.4.5", features = ["serde"] } +bon = "=2.3.0" cargo-manifest = "=0.15.2" crates_io_cdn_logs = { path = "crates/crates_io_cdn_logs" } crates_io_database = { path = "crates/crates_io_database" } @@ -62,7 +63,6 @@ chrono = { version = "=0.4.38", default-features = false, features = ["serde"] } clap = { version = "=4.5.20", features = ["derive", "env", "unicode", "wrap_help"] } cookie = { version = "=0.18.1", features = ["secure"] } deadpool-diesel = { version = "=0.6.1", features = ["postgres", "tracing"] } -derive_builder = "=0.20.2" derive_deref = "=1.1.1" dialoguer = "=0.11.0" diesel = { version = "=2.2.4", features = ["postgres", "serde_json", "chrono", "numeric"] } diff --git a/src/bin/background-worker.rs b/src/bin/background-worker.rs index f320f5c3462..34e17191374 100644 --- a/src/bin/background-worker.rs +++ b/src/bin/background-worker.rs @@ -28,7 +28,6 @@ use crates_io_worker::Runner; use diesel_async::pooled_connection::deadpool::Pool; use diesel_async::pooled_connection::AsyncDieselConnectionManager; use object_store::prefix::PrefixStore; -use object_store::ObjectStore; use reqwest::Client; use secrecy::ExposeSecret; use std::sync::Arc; @@ -74,7 +73,7 @@ fn main() -> anyhow::Result<()> { let storage = Arc::new(Storage::from_config(&config.storage)); let downloads_archive_store = PrefixStore::new(storage.as_inner(), "archive/version-downloads"); - let downloads_archive_store: Box = Box::new(downloads_archive_store); + let downloads_archive_store = Box::new(downloads_archive_store); let client = Client::builder() .timeout(Duration::from_secs(45)) @@ -92,14 +91,14 @@ fn main() -> anyhow::Result<()> { let environment = Environment::builder() .config(Arc::new(config)) .repository_config(repository_config) - .cloudfront(cloudfront) - .fastly(fastly) + .maybe_cloudfront(cloudfront) + .maybe_fastly(fastly) .storage(storage) - .downloads_archive_store(Some(downloads_archive_store)) + .downloads_archive_store(downloads_archive_store) .deadpool(deadpool.clone()) .emails(emails) .team_repo(Box::new(team_repo)) - .build()?; + .build(); let environment = Arc::new(environment); diff --git a/src/controllers/krate/publish.rs b/src/controllers/krate/publish.rs index 6c0e63f0727..ac105c547ec 100644 --- a/src/controllers/krate/publish.rs +++ b/src/controllers/krate/publish.rs @@ -360,19 +360,18 @@ pub async fn publish(app: AppState, req: BytesRequest) -> AppResult { + #[builder(start_fn)] crate_id: i32, + #[builder(start_fn)] num: &'a str, - #[builder(default)] created_at: Option<&'a NaiveDateTime>, - #[builder(default, setter(strip_option))] yanked: Option, - #[builder( - default = "serde_json::Value::Object(Default::default())", - setter(custom) - )] + #[builder(default = serde_json::Value::Object(Default::default()))] features: serde_json::Value, - #[builder(default)] license: Option<&'a str>, - #[builder(default, setter(name = "size"))] + #[builder(default, name = "size")] crate_size: i32, published_by: i32, checksum: &'a str, - #[builder(default)] links: Option<&'a str>, - #[builder(default)] rust_version: Option<&'a str>, - #[builder(default, setter(strip_option))] pub has_lib: Option, - #[builder(default, setter(strip_option))] pub bin_names: Option<&'a [&'a str]>, } -impl NewVersionBuilder<'_> { - pub fn features( - &mut self, - features: &BTreeMap>, - ) -> serde_json::Result<&mut Self> { - self.features = Some(serde_json::to_value(features)?); - Ok(self) - } - - /// Set the `checksum` field to a basic dummy value. - pub fn dummy_checksum(&mut self) -> &mut Self { - const DUMMY_CHECKSUM: &str = - "0000000000000000000000000000000000000000000000000000000000000000"; - - self.checksum(DUMMY_CHECKSUM) - } -} - impl NewVersion<'_> { - pub fn builder(crate_id: i32, version: &str) -> NewVersionBuilder<'_> { - let mut builder = NewVersionBuilder::default(); - builder.crate_id(crate_id).num(version); - builder - } - pub fn save(&self, conn: &mut impl Conn, published_by_email: &str) -> AppResult { use diesel::dsl::exists; use diesel::{insert_into, select}; diff --git a/src/tests/builders/version.rs b/src/tests/builders/version.rs index bb77ce54b45..79274a2837d 100644 --- a/src/tests/builders/version.rs +++ b/src/tests/builders/version.rs @@ -5,7 +5,6 @@ use crate::{ }; use std::collections::BTreeMap; -use crate::util::errors::internal; use chrono::NaiveDateTime; use diesel::prelude::*; @@ -102,17 +101,16 @@ impl VersionBuilder { let version = self.num.to_string(); let new_version = NewVersion::builder(crate_id, &version) - .features(&self.features)? - .license(self.license.as_deref()) + .features(serde_json::to_value(&self.features)?) + .maybe_license(self.license.as_deref()) .size(self.size) .published_by(published_by) .checksum(&self.checksum) - .links(self.links.as_deref()) - .rust_version(self.rust_version.as_deref()) + .maybe_links(self.links.as_deref()) + .maybe_rust_version(self.rust_version.as_deref()) .yanked(self.yanked) - .created_at(self.created_at.as_ref()) - .build() - .map_err(|error| internal(error.to_string()))?; + .maybe_created_at(self.created_at.as_ref()) + .build(); let vers = new_version.save(connection, "someone@example.com")?; diff --git a/src/tests/util/test_app.rs b/src/tests/util/test_app.rs index 179683f7ffb..e5e32c676d9 100644 --- a/src/tests/util/test_app.rs +++ b/src/tests/util/test_app.rs @@ -306,8 +306,7 @@ impl TestAppBuilder { .deadpool(app.primary_database.clone()) .emails(app.emails.clone()) .team_repo(Box::new(self.team_repo)) - .build() - .unwrap(); + .build(); let runner = Runner::new(app.primary_database.clone(), Arc::new(environment)) .shutdown_when_queue_empty() diff --git a/src/typosquat/test_util.rs b/src/typosquat/test_util.rs index c1eb58cf59a..e71721b93f6 100644 --- a/src/typosquat/test_util.rs +++ b/src/typosquat/test_util.rs @@ -53,9 +53,8 @@ pub mod faker { let version = NewVersion::builder(krate.id, "1.0.0") .published_by(user.id) - .dummy_checksum() + .checksum("0000000000000000000000000000000000000000000000000000000000000000") .build() - .unwrap() .save(conn, "someone@example.com") .unwrap(); diff --git a/src/worker/environment.rs b/src/worker/environment.rs index f8c00857846..49247dafd33 100644 --- a/src/worker/environment.rs +++ b/src/worker/environment.rs @@ -5,9 +5,9 @@ use crate::typosquat; use crate::util::diesel::Conn; use crate::Emails; use anyhow::Context; +use bon::Builder; use crates_io_index::{Repository, RepositoryConfig}; use crates_io_team_repo::TeamRepo; -use derive_builder::Builder; use diesel_async::pooled_connection::deadpool::Pool; use diesel_async::AsyncPgConnection; use object_store::ObjectStore; @@ -17,34 +17,26 @@ use std::sync::{Arc, OnceLock}; use std::time::Instant; #[derive(Builder)] -#[builder(pattern = "owned")] pub struct Environment { pub config: Arc, repository_config: RepositoryConfig, - #[builder(default, setter(skip))] + #[builder(skip)] repository: Mutex>, - #[builder(default)] cloudfront: Option, - #[builder(default)] fastly: Option, pub storage: Arc, - #[builder(default)] pub downloads_archive_store: Option>, pub deadpool: Pool, pub emails: Emails, pub team_repo: Box, /// A lazily initialised cache of the most popular crates ready to use in typosquatting checks. - #[builder(default, setter(skip))] + #[builder(skip)] typosquat_cache: OnceLock>, } impl Environment { - pub fn builder() -> EnvironmentBuilder { - EnvironmentBuilder::default() - } - #[instrument(skip_all)] pub fn lock_index(&self) -> anyhow::Result> { let mut repo = self.repository.lock(); diff --git a/src/worker/jobs/downloads/update_metadata.rs b/src/worker/jobs/downloads/update_metadata.rs index 7f8233d0cb2..0000c94cf9d 100644 --- a/src/worker/jobs/downloads/update_metadata.rs +++ b/src/worker/jobs/downloads/update_metadata.rs @@ -126,9 +126,8 @@ mod tests { let version = NewVersion::builder(krate.id, "1.0.0") .published_by(user_id) - .dummy_checksum() - .build() - .unwrap(); + .checksum("0000000000000000000000000000000000000000000000000000000000000000") + .build(); let version = version.save(conn, "someone@example.com").unwrap(); (krate, version)