diff -Nru rust-crates-io-0.31.1/Cargo.toml rust-crates-io-0.33.0/Cargo.toml --- rust-crates-io-0.31.1/Cargo.toml 2020-07-16 19:58:05.000000000 +0000 +++ rust-crates-io-0.33.0/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 @@ -13,7 +13,7 @@ [package] edition = "2018" name = "crates-io" -version = "0.31.1" +version = "0.33.0" authors = ["Alex Crichton "] description = "Helpers for interacting with crates.io\n" license = "MIT OR Apache-2.0" @@ -23,7 +23,7 @@ name = "crates_io" path = "lib.rs" [dependencies.anyhow] -version = "1.0.0" +version = "1.0.34" [dependencies.curl] version = "0.4" @@ -35,9 +35,6 @@ version = "1.0" features = ["derive"] -[dependencies.serde_derive] -version = "1.0" - [dependencies.serde_json] version = "1.0" diff -Nru rust-crates-io-0.31.1/Cargo.toml.orig rust-crates-io-0.33.0/Cargo.toml.orig --- rust-crates-io-0.31.1/Cargo.toml.orig 2020-07-16 13:20:26.000000000 +0000 +++ rust-crates-io-0.33.0/Cargo.toml.orig 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +1,6 @@ [package] name = "crates-io" -version = "0.31.1" +version = "0.33.0" edition = "2018" authors = ["Alex Crichton "] license = "MIT OR Apache-2.0" @@ -15,9 +15,8 @@ [dependencies] curl = "0.4" -anyhow = "1.0.0" +anyhow = "1.0.34" percent-encoding = "2.0" serde = { version = "1.0", features = ['derive'] } -serde_derive = "1.0" serde_json = "1.0" url = "2.0" diff -Nru rust-crates-io-0.31.1/.cargo_vcs_info.json rust-crates-io-0.33.0/.cargo_vcs_info.json --- rust-crates-io-0.31.1/.cargo_vcs_info.json 2020-07-16 19:58:05.000000000 +0000 +++ rust-crates-io-0.33.0/.cargo_vcs_info.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +1,5 @@ { "git": { - "sha1": "744bd1fbb666f33b20b09d5bacc5047957c8ed42" + "sha1": "43b129a20fbf1ede0df411396ccf0c024bf34134" } } diff -Nru rust-crates-io-0.31.1/debian/cargo-checksum.json rust-crates-io-0.33.0/debian/cargo-checksum.json --- rust-crates-io-0.31.1/debian/cargo-checksum.json 2020-10-01 22:25:10.000000000 +0000 +++ rust-crates-io-0.33.0/debian/cargo-checksum.json 2021-10-23 18:03:56.000000000 +0000 @@ -1 +1 @@ -{"package":"09f977948a46e9edf93eb3dc2d7a8dd4ce3105d36de63300befed37cdf051d4a","files":{}} +{"package":"217138863f33507d7a8edef10fc673c4911679ef7aeb9ff53ee7bb82dc7bf590","files":{}} diff -Nru rust-crates-io-0.31.1/debian/changelog rust-crates-io-0.33.0/debian/changelog --- rust-crates-io-0.31.1/debian/changelog 2020-10-01 22:25:10.000000000 +0000 +++ rust-crates-io-0.33.0/debian/changelog 2021-10-23 18:03:56.000000000 +0000 @@ -1,3 +1,9 @@ +rust-crates-io (0.33.0-1) unstable; urgency=medium + + * Package crates-io 0.33.0 from crates.io using debcargo 2.4.4 + + -- Ximin Luo Sat, 23 Oct 2021 19:03:56 +0100 + rust-crates-io (0.31.1-1) unstable; urgency=medium * Package crates-io 0.31.1 from crates.io using debcargo 2.4.3 diff -Nru rust-crates-io-0.31.1/debian/compat rust-crates-io-0.33.0/debian/compat --- rust-crates-io-0.31.1/debian/compat 2020-10-01 22:25:10.000000000 +0000 +++ rust-crates-io-0.33.0/debian/compat 2021-10-23 18:03:56.000000000 +0000 @@ -1 +1 @@ -11 +12 diff -Nru rust-crates-io-0.31.1/debian/control rust-crates-io-0.33.0/debian/control --- rust-crates-io-0.31.1/debian/control 2020-10-01 22:25:10.000000000 +0000 +++ rust-crates-io-0.33.0/debian/control 2021-10-23 18:03:56.000000000 +0000 @@ -1,47 +1,46 @@ Source: rust-crates-io Section: rust Priority: optional -Build-Depends: debhelper (>= 11), - dh-cargo (>= 18), +Build-Depends: debhelper (>= 12), + dh-cargo (>= 24), cargo:native , rustc:native , libstd-rust-dev , - librust-anyhow-1+default-dev , + librust-anyhow-1+default-dev (>= 1.0.34-~~) , librust-curl-0.4+default-dev , librust-percent-encoding-2+default-dev , librust-serde-1+default-dev , librust-serde-1+derive-dev , - librust-serde-derive-1+default-dev , librust-serde-json-1+default-dev , librust-url-2+default-dev Maintainer: Debian Rust Maintainers Uploaders: Ximin Luo -Standards-Version: 4.4.1 +Standards-Version: 4.5.1 Vcs-Git: https://salsa.debian.org/rust-team/debcargo-conf.git [src/crates-io] Vcs-Browser: https://salsa.debian.org/rust-team/debcargo-conf/tree/master/src/crates-io +Rules-Requires-Root: no Package: librust-crates-io-dev Architecture: any Multi-Arch: same Depends: ${misc:Depends}, - librust-anyhow-1+default-dev, + librust-anyhow-1+default-dev (>= 1.0.34-~~), librust-curl-0.4+default-dev, librust-percent-encoding-2+default-dev, librust-serde-1+default-dev, librust-serde-1+derive-dev, - librust-serde-derive-1+default-dev, librust-serde-json-1+default-dev, librust-url-2+default-dev Provides: librust-crates-io+default-dev (= ${binary:Version}), librust-crates-io-0-dev (= ${binary:Version}), librust-crates-io-0+default-dev (= ${binary:Version}), - librust-crates-io-0.31-dev (= ${binary:Version}), - librust-crates-io-0.31+default-dev (= ${binary:Version}), - librust-crates-io-0.31.1-dev (= ${binary:Version}), - librust-crates-io-0.31.1+default-dev (= ${binary:Version}) + librust-crates-io-0.33-dev (= ${binary:Version}), + librust-crates-io-0.33+default-dev (= ${binary:Version}), + librust-crates-io-0.33.0-dev (= ${binary:Version}), + librust-crates-io-0.33.0+default-dev (= ${binary:Version}) Description: Helpers for interacting with crates.io - Rust source code This package contains the source for the Rust crates-io crate, packaged by debcargo for use with cargo and dh-cargo. diff -Nru rust-crates-io-0.31.1/debian/copyright rust-crates-io-0.33.0/debian/copyright --- rust-crates-io-0.31.1/debian/copyright 2020-10-01 22:25:10.000000000 +0000 +++ rust-crates-io-0.33.0/debian/copyright 2021-10-23 18:03:56.000000000 +0000 @@ -9,8 +9,8 @@ Files: debian/* Copyright: - 2018-2020 Debian Rust Maintainers - 2018-2020 Ximin Luo + 2018-2021 Debian Rust Maintainers + 2018-2021 Ximin Luo License: MIT or Apache-2.0 License: Apache-2.0 diff -Nru rust-crates-io-0.31.1/debian/copyright.debcargo.hint rust-crates-io-0.33.0/debian/copyright.debcargo.hint --- rust-crates-io-0.31.1/debian/copyright.debcargo.hint 2020-10-01 22:25:10.000000000 +0000 +++ rust-crates-io-0.33.0/debian/copyright.debcargo.hint 2021-10-23 18:03:56.000000000 +0000 @@ -14,8 +14,8 @@ Files: debian/* Copyright: - 2018-2020 Debian Rust Maintainers - 2018-2020 Ximin Luo + 2018-2021 Debian Rust Maintainers + 2018-2021 Ximin Luo License: MIT or Apache-2.0 License: Apache-2.0 diff -Nru rust-crates-io-0.31.1/debian/tests/control rust-crates-io-0.33.0/debian/tests/control --- rust-crates-io-0.31.1/debian/tests/control 2020-10-01 22:25:10.000000000 +0000 +++ rust-crates-io-0.33.0/debian/tests/control 2021-10-23 18:03:56.000000000 +0000 @@ -1,9 +1,14 @@ -Test-Command: /usr/share/cargo/bin/cargo-auto-test crates-io 0.31.1 --all-targets --all-features -Features: test-name=@ +Test-Command: /usr/share/cargo/bin/cargo-auto-test crates-io 0.33.0 --all-targets --all-features +Features: test-name=rust-crates-io:@ Depends: dh-cargo (>= 18), @ Restrictions: allow-stderr, skip-not-installable -Test-Command: /usr/share/cargo/bin/cargo-auto-test crates-io 0.31.1 --all-targets --no-default-features -Features: test-name=librust-crates-io-dev +Test-Command: /usr/share/cargo/bin/cargo-auto-test crates-io 0.33.0 --all-targets +Features: test-name=librust-crates-io-dev:default +Depends: dh-cargo (>= 18), @ +Restrictions: allow-stderr, skip-not-installable + +Test-Command: /usr/share/cargo/bin/cargo-auto-test crates-io 0.33.0 --all-targets --no-default-features +Features: test-name=librust-crates-io-dev: Depends: dh-cargo (>= 18), @ Restrictions: allow-stderr, skip-not-installable diff -Nru rust-crates-io-0.31.1/lib.rs rust-crates-io-0.33.0/lib.rs --- rust-crates-io-0.31.1/lib.rs 2020-07-16 13:20:26.000000000 +0000 +++ rust-crates-io-0.33.0/lib.rs 1970-01-01 00:00:00.000000000 +0000 @@ -2,12 +2,13 @@ #![allow(clippy::identity_op)] // used for vertical alignment use std::collections::BTreeMap; +use std::fmt; use std::fs::File; use std::io::prelude::*; -use std::io::Cursor; +use std::io::{Cursor, SeekFrom}; use std::time::Instant; -use anyhow::{bail, Result}; +use anyhow::{bail, format_err, Context, Result}; use curl::easy::{Easy, List}; use percent_encoding::{percent_encode, NON_ALPHANUMERIC}; use serde::{Deserialize, Serialize}; @@ -55,6 +56,8 @@ pub repository: Option, pub badges: BTreeMap>, pub links: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub v: Option, } #[derive(Serialize)] @@ -121,11 +124,84 @@ crates: Vec, meta: TotalCrates, } -impl Registry { - pub fn new(host: String, token: Option) -> Registry { - Registry::new_handle(host, token, Easy::new()) + +#[derive(Debug)] +pub enum ResponseError { + Curl(curl::Error), + Api { + code: u32, + errors: Vec, + }, + Code { + code: u32, + headers: Vec, + body: String, + }, + Other(anyhow::Error), +} + +impl std::error::Error for ResponseError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + ResponseError::Curl(..) => None, + ResponseError::Api { .. } => None, + ResponseError::Code { .. } => None, + ResponseError::Other(e) => Some(e.as_ref()), + } } +} +impl fmt::Display for ResponseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ResponseError::Curl(e) => write!(f, "{}", e), + ResponseError::Api { code, errors } => write!( + f, + "api errors (status {} {}): {}", + code, + reason(*code), + errors.join(", ") + ), + ResponseError::Code { + code, + headers, + body, + } => write!( + f, + "failed to get a 200 OK response, got {}\n\ + headers:\n\ + \t{}\n\ + body:\n\ + {}", + code, + headers.join("\n\t"), + body + ), + ResponseError::Other(..) => write!(f, "invalid response from server"), + } + } +} + +impl From for ResponseError { + fn from(error: curl::Error) -> Self { + ResponseError::Curl(error) + } +} + +impl Registry { + /// Creates a new `Registry`. + /// + /// ## Example + /// + /// ```rust + /// use curl::easy::Easy; + /// use crates_io::Registry; + /// + /// let mut handle = Easy::new(); + /// // If connecting to crates.io, a user-agent is required. + /// handle.useragent("my_crawler (example.com/info)"); + /// let mut reg = Registry::new_handle(String::from("https://crates.io"), None, handle); + /// ``` pub fn new_handle(host: String, token: Option, handle: Easy) -> Registry { Registry { host, @@ -161,7 +237,7 @@ Ok(serde_json::from_str::(&body)?.users) } - pub fn publish(&mut self, krate: &NewCrate, tarball: &File) -> Result { + pub fn publish(&mut self, krate: &NewCrate, mut tarball: &File) -> Result { let json = serde_json::to_string(krate)?; // Prepare the body. The format of the upload request is: // @@ -169,33 +245,26 @@ // (metadata for the package) // // - let stat = tarball.metadata()?; + + // NOTE: This can be replaced with `stream_len` if it is ever stabilized. + // + // This checks the length using seeking instead of metadata, because + // on some filesystems, getting the metadata will fail because + // the file was renamed in ops::package. + let tarball_len = tarball + .seek(SeekFrom::End(0)) + .with_context(|| "failed to seek tarball")?; + tarball + .seek(SeekFrom::Start(0)) + .with_context(|| "failed to seek tarball")?; let header = { let mut w = Vec::new(); - w.extend( - [ - (json.len() >> 0) as u8, - (json.len() >> 8) as u8, - (json.len() >> 16) as u8, - (json.len() >> 24) as u8, - ] - .iter() - .cloned(), - ); + w.extend(&(json.len() as u32).to_le_bytes()); w.extend(json.as_bytes().iter().cloned()); - w.extend( - [ - (stat.len() >> 0) as u8, - (stat.len() >> 8) as u8, - (stat.len() >> 16) as u8, - (stat.len() >> 24) as u8, - ] - .iter() - .cloned(), - ); + w.extend(&(tarball_len as u32).to_le_bytes()); w }; - let size = stat.len() as usize + header.len(); + let size = tarball_len as usize + header.len(); let mut body = Cursor::new(header).chain(tarball); let url = format!("{}/api/v1/crates/new", self.host); @@ -212,7 +281,25 @@ headers.append(&format!("Authorization: {}", token))?; self.handle.http_headers(headers)?; - let body = self.handle(&mut |buf| body.read(buf).unwrap_or(0))?; + let started = Instant::now(); + let body = self + .handle(&mut |buf| body.read(buf).unwrap_or(0)) + .map_err(|e| match e { + ResponseError::Code { code, .. } + if code == 503 + && started.elapsed().as_secs() >= 29 + && self.host_is_crates_io() => + { + format_err!( + "Request timed out after 30 seconds. If you're trying to \ + upload a crate it may be too large. If the crate is under \ + 10MB in size, you can email help@crates.io for assistance.\n\ + Total size was {}.", + tarball_len + ) + } + _ => e.into(), + })?; let response = if body.is_empty() { "{}".parse()? @@ -306,15 +393,18 @@ self.handle.upload(true)?; self.handle.in_filesize(body.len() as u64)?; self.handle(&mut |buf| body.read(buf).unwrap_or(0)) + .map_err(|e| e.into()) } - None => self.handle(&mut |_| 0), + None => self.handle(&mut |_| 0).map_err(|e| e.into()), } } - fn handle(&mut self, read: &mut dyn FnMut(&mut [u8]) -> usize) -> Result { + fn handle( + &mut self, + read: &mut dyn FnMut(&mut [u8]) -> usize, + ) -> std::result::Result { let mut headers = Vec::new(); let mut body = Vec::new(); - let started; { let mut handle = self.handle.transfer(); handle.read_function(|buf| Ok(read(buf)))?; @@ -323,50 +413,36 @@ Ok(data.len()) })?; handle.header_function(|data| { - headers.push(String::from_utf8_lossy(data).into_owned()); + // Headers contain trailing \r\n, trim them to make it easier + // to work with. + let s = String::from_utf8_lossy(data).trim().to_string(); + headers.push(s); true })?; - started = Instant::now(); handle.perform()?; } let body = match String::from_utf8(body) { Ok(body) => body, - Err(..) => bail!("response body was not valid utf-8"), + Err(..) => { + return Err(ResponseError::Other(format_err!( + "response body was not valid utf-8" + ))) + } }; let errors = serde_json::from_str::(&body) .ok() .map(|s| s.errors.into_iter().map(|s| s.detail).collect::>()); match (self.handle.response_code()?, errors) { - (0, None) | (200, None) => {} - (503, None) if started.elapsed().as_secs() >= 29 && self.host_is_crates_io() => bail!( - "Request timed out after 30 seconds. If you're trying to \ - upload a crate it may be too large. If the crate is under \ - 10MB in size, you can email help@crates.io for assistance." - ), - (code, Some(errors)) => { - let reason = reason(code); - bail!( - "api errors (status {} {}): {}", - code, - reason, - errors.join(", ") - ) - } - (code, None) => bail!( - "failed to get a 200 OK response, got {}\n\ - headers:\n\ - \t{}\n\ - body:\n\ - {}", + (0, None) | (200, None) => Ok(body), + (code, Some(errors)) => Err(ResponseError::Api { code, errors }), + (code, None) => Err(ResponseError::Code { code, - headers.join("\n\t"), + headers, body, - ), + }), } - - Ok(body) } }