Skip to content

Commit 63c3a5f

Browse files
committed
Extracted file upload into its own method
upload is now named upload_crate, and the new upload method is now only responsible for the upload of a single file.
1 parent e804a86 commit 63c3a5f

File tree

2 files changed

+81
-140
lines changed

2 files changed

+81
-140
lines changed

src/krate.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,8 +1152,13 @@ pub fn new(req: &mut Request) -> CargoResult<Response> {
11521152
// Upload the crate, return way to delete the crate from the server
11531153
// If the git commands fail below, we shouldn't keep the crate on the
11541154
// server.
1155-
let (cksum, mut crate_bomb, mut readme_bomb) =
1156-
app.config.uploader.upload(req, &krate, readme, max, vers)?;
1155+
let (cksum, mut crate_bomb, mut readme_bomb) = app.config.uploader.upload_crate(
1156+
req,
1157+
&krate,
1158+
readme,
1159+
max,
1160+
vers,
1161+
)?;
11571162

11581163
// Register this crate in our local git repo.
11591164
let git_crate = git::Crate {

src/uploaders.rs

Lines changed: 74 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -82,40 +82,34 @@ impl Uploader {
8282
format!("readmes/{}/{}-{}.html", name, name, version)
8383
}
8484

85+
/// Uploads a file using the configured uploader (either S3, Local or NoOp).
86+
/// It returns a a tuple containing the path of the uploaded file
87+
/// and its checksum.
8588
pub fn upload(
8689
&self,
87-
req: &mut Request,
88-
krate: &Crate,
89-
readme: Option<String>,
90-
max: u64,
91-
vers: &semver::Version,
92-
) -> CargoResult<(Vec<u8>, Bomb, Bomb)> {
90+
app: Arc<App>,
91+
path: &str,
92+
body: &mut io::Read,
93+
content_type: &str,
94+
content_length: u64,
95+
) -> CargoResult<(Option<String>, Vec<u8>)> {
9396
match *self {
9497
Uploader::S3 { ref bucket, .. } => {
95-
let mut handle = req.app().handle();
96-
let crate_path =
97-
format!("/{}", Uploader::crate_path(&krate.name, &vers.to_string()));
98+
let mut handle = app.handle();
9899
let (response, cksum) = {
99-
let length = read_le_u32(req.body())?;
100-
let body = LimitErrorReader::new(req.body(), max);
101100
let mut body = HashingReader::new(body);
102101
let mut response = Vec::new();
103102
{
104-
let mut s3req = bucket.put(
105-
&mut handle,
106-
&crate_path,
107-
&mut body,
108-
"application/x-tar",
109-
length as u64,
110-
);
103+
let mut s3req =
104+
bucket.put(&mut handle, &path, &mut body, content_type, content_length);
111105
s3req
112106
.write_function(|data| {
113107
response.extend(data);
114108
Ok(data.len())
115109
})
116110
.unwrap();
117111
s3req.perform().chain_error(|| {
118-
internal(&format_args!("failed to upload to S3: `{}`", crate_path))
112+
internal(&format_args!("failed to upload to S3: `{}`", path))
119113
})?;
120114
}
121115
(response, body.finalize())
@@ -127,134 +121,76 @@ impl Uploader {
127121
response
128122
)));
129123
}
130-
let readme_path = if let Some(rendered) = readme {
131-
let mut handle = req.app().handle();
132-
let readme_path =
133-
format!("/{}", Uploader::readme_path(&krate.name, &vers.to_string()));
134-
let response = {
135-
let mut response = Vec::new();
136-
{
137-
let readme_len = rendered.len();
138-
let mut cursor = io::Cursor::new(rendered.into_bytes());
139-
let mut s3req = bucket.put(
140-
&mut handle,
141-
&readme_path,
142-
&mut cursor,
143-
"text/html",
144-
readme_len as u64,
145-
);
146-
s3req
147-
.write_function(|data| {
148-
response.extend(data);
149-
Ok(data.len())
150-
})
151-
.unwrap();
152-
s3req.perform().chain_error(|| {
153-
internal(&format_args!(
154-
"failed to upload readme to S3: `{}`",
155-
readme_path
156-
))
157-
})?;
158-
}
159-
response
160-
};
161-
if handle.response_code().unwrap() != 200 {
162-
if let Err(e) = self.delete(req.app().clone(), &crate_path) {
163-
println!("failed to delete crate from S3: `{}`, {:?}", crate_path, e);
164-
}
165-
let response = String::from_utf8_lossy(&response);
166-
return Err(internal(&format_args!(
167-
"failed to get a 200 response from S3: {}",
168-
response
169-
)));
170-
}
171-
Some(readme_path)
172-
} else {
173-
None
174-
};
175-
176-
Ok((
177-
cksum,
178-
Bomb {
179-
app: req.app().clone(),
180-
path: Some(crate_path),
181-
},
182-
Bomb {
183-
app: req.app().clone(),
184-
path: readme_path,
185-
},
186-
))
124+
Ok((Some(String::from(path)), cksum))
187125
}
188126
Uploader::Local => {
189-
use std::io::Write;
190-
191-
let crate_path = Uploader::crate_path(&krate.name, &vers.to_string());
192-
let crate_filename = env::current_dir()
127+
let filename = env::current_dir()
193128
.unwrap()
194129
.join("dist")
195130
.join("local_uploads")
196-
.join(crate_path);
197-
198-
let crate_dir = crate_filename.parent().unwrap();
199-
fs::create_dir_all(crate_dir)?;
200-
201-
let mut crate_file = File::create(&crate_filename)?;
202-
203-
let cksum = {
204-
read_le_u32(req.body())?;
205-
let body = LimitErrorReader::new(req.body(), max);
206-
let mut body = HashingReader::new(body);
207-
208-
io::copy(&mut body, &mut crate_file)?;
209-
body.finalize()
210-
};
211-
212-
let readme_filename = if let Some(rendered) = readme {
213-
let readme_path = Uploader::readme_path(&krate.name, &vers.to_string());
214-
let readme_filename = env::current_dir()
215-
.unwrap()
216-
.join("dist")
217-
.join("local_uploads")
218-
.join(readme_path);
219-
220-
let readme_dir = readme_filename.parent().unwrap();
221-
fs::create_dir_all(readme_dir)?;
222-
223-
let mut readme_file = File::create(&readme_filename)?;
224-
readme_file.write_all(rendered.as_ref())?;
225-
readme_filename.to_str().map(String::from)
226-
} else {
227-
None
228-
};
229-
230-
Ok((
231-
cksum,
232-
Bomb {
233-
app: req.app().clone(),
234-
path: crate_filename.to_str().map(String::from),
235-
},
236-
Bomb {
237-
app: req.app().clone(),
238-
path: readme_filename,
239-
},
240-
))
241-
}
242-
Uploader::NoOp => {
243-
Ok((
244-
vec![],
245-
Bomb {
246-
app: req.app().clone(),
247-
path: None,
248-
},
249-
Bomb {
250-
app: req.app().clone(),
251-
path: None,
252-
},
253-
))
131+
.join(path);
132+
let dir = filename.parent().unwrap();
133+
fs::create_dir_all(dir)?;
134+
let mut file = File::create(&filename)?;
135+
let mut body = HashingReader::new(body);
136+
io::copy(&mut body, &mut file)?;
137+
Ok((filename.to_str().map(String::from), body.finalize()))
254138
}
139+
Uploader::NoOp => Ok((None, vec![])),
255140
}
256141
}
257142

143+
/// Uploads a crate and its readme. Returns the checksum of the uploaded crate
144+
/// file, and bombs for the uploaded crate and the uploaded readme.
145+
pub fn upload_crate(
146+
&self,
147+
req: &mut Request,
148+
krate: &Crate,
149+
readme: Option<String>,
150+
max: u64,
151+
vers: &semver::Version,
152+
) -> CargoResult<(Vec<u8>, Bomb, Bomb)> {
153+
let app = req.app().clone();
154+
let (crate_path, checksum) = {
155+
let path = format!("/{}", Uploader::crate_path(&krate.name, &vers.to_string()));
156+
let length = read_le_u32(req.body())?;
157+
let mut body = LimitErrorReader::new(req.body(), max);
158+
self.upload(
159+
app.clone(),
160+
&path,
161+
&mut body,
162+
"application/x-tar",
163+
length as u64,
164+
)?
165+
};
166+
let crate_bomb = Bomb {
167+
app: app.clone(),
168+
path: crate_path,
169+
};
170+
let (readme_path, _) = if let Some(rendered) = readme {
171+
let path = format!("/{}", Uploader::readme_path(&krate.name, &vers.to_string()));
172+
let length = rendered.len();
173+
let mut body = io::Cursor::new(rendered.into_bytes());
174+
self.upload(
175+
app.clone(),
176+
&path,
177+
&mut body,
178+
"text/html",
179+
length as u64,
180+
)?
181+
} else {
182+
(None, vec![])
183+
};
184+
Ok((
185+
checksum,
186+
crate_bomb,
187+
Bomb {
188+
app: app.clone(),
189+
path: readme_path,
190+
},
191+
))
192+
}
193+
258194
pub fn delete(&self, app: Arc<App>, path: &str) -> CargoResult<()> {
259195
match *self {
260196
Uploader::S3 { ref bucket, .. } => {

0 commit comments

Comments
 (0)