|
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