|
4 | 4 | use std::collections::BTreeMap; |
5 | 5 | use std::fs::File; |
6 | 6 | use std::io::prelude::*; |
7 | | -use std::io::Cursor; |
| 7 | +use std::io::{Cursor, SeekFrom}; |
8 | 8 | use std::time::Instant; |
9 | 9 |
|
10 | | -use anyhow::{bail, Result}; |
| 10 | +use anyhow::{bail, Context, Result}; |
11 | 11 | use curl::easy::{Easy, List}; |
12 | 12 | use percent_encoding::{percent_encode, NON_ALPHANUMERIC}; |
13 | 13 | use serde::{Deserialize, Serialize}; |
@@ -161,23 +161,34 @@ impl Registry { |
161 | 161 | Ok(serde_json::from_str::<Users>(&body)?.users) |
162 | 162 | } |
163 | 163 |
|
164 | | - pub fn publish(&mut self, krate: &NewCrate, tarball: &File) -> Result<Warnings> { |
| 164 | + pub fn publish(&mut self, krate: &NewCrate, mut tarball: &File) -> Result<Warnings> { |
165 | 165 | let json = serde_json::to_string(krate)?; |
166 | 166 | // Prepare the body. The format of the upload request is: |
167 | 167 | // |
168 | 168 | // <le u32 of json> |
169 | 169 | // <json request> (metadata for the package) |
170 | 170 | // <le u32 of tarball> |
171 | 171 | // <source tarball> |
172 | | - let stat = tarball.metadata()?; |
| 172 | + |
| 173 | + // NOTE: This can be replaced with `stream_len` if it is ever stabilized. |
| 174 | + // |
| 175 | + // This checks the length using seeking instead of metadata, because |
| 176 | + // on some filesystems, getting the metadata will fail because |
| 177 | + // the file was renamed in ops::package. |
| 178 | + let tarball_len = tarball |
| 179 | + .seek(SeekFrom::End(0)) |
| 180 | + .with_context(|| "failed to seek tarball")?; |
| 181 | + tarball |
| 182 | + .seek(SeekFrom::Start(0)) |
| 183 | + .with_context(|| "failed to seek tarball")?; |
173 | 184 | let header = { |
174 | 185 | let mut w = Vec::new(); |
175 | 186 | w.extend(&(json.len() as u32).to_le_bytes()); |
176 | 187 | w.extend(json.as_bytes().iter().cloned()); |
177 | | - w.extend(&(stat.len() as u32).to_le_bytes()); |
| 188 | + w.extend(&(tarball_len as u32).to_le_bytes()); |
178 | 189 | w |
179 | 190 | }; |
180 | | - let size = stat.len() as usize + header.len(); |
| 191 | + let size = tarball_len as usize + header.len(); |
181 | 192 | let mut body = Cursor::new(header).chain(tarball); |
182 | 193 |
|
183 | 194 | let url = format!("{}/api/v1/crates/new", self.host); |
|
0 commit comments