Skip to content

Commit d099117

Browse files
committed
Upload build log to S3
1 parent d72aee6 commit d099117

File tree

5 files changed

+170
-34
lines changed

5 files changed

+170
-34
lines changed

src/db/add_package.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -175,17 +175,14 @@ pub(crate) fn add_build_into_database(
175175
) -> Result<i32> {
176176
debug!("Adding build into database");
177177
let rows = conn.query(
178-
"INSERT INTO builds (rid, rustc_version,
179-
cratesfyi_version,
180-
build_status, output)
181-
VALUES ($1, $2, $3, $4, $5)
182-
RETURNING id",
178+
"INSERT INTO builds (rid, rustc_version, cratesfyi_version, build_status)
179+
VALUES ($1, $2, $3, $4)
180+
RETURNING id",
183181
&[
184182
&release_id,
185183
&res.rustc_version,
186184
&res.docsrs_version,
187185
&res.successful,
188-
&res.build_log,
189186
],
190187
)?;
191188
Ok(rows[0].get(0))

src/docbuilder/rustwide_builder.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ impl RustwideBuilder {
322322

323323
let local_storage = tempfile::Builder::new().prefix("docsrs-docs").tempdir()?;
324324

325-
let res = build_dir
325+
let successful = build_dir
326326
.build(&self.toolchain, &krate, self.prepare_sandbox(&limits))
327327
.run(|build| {
328328
use docsrs_metadata::BuildTargets;
@@ -414,21 +414,23 @@ impl RustwideBuilder {
414414
add_doc_coverage(&mut conn, release_id, doc_coverage)?;
415415
}
416416

417-
add_build_into_database(&mut conn, release_id, &res.result)?;
417+
let build_id = add_build_into_database(&mut conn, release_id, &res.result)?;
418+
let build_log_path = format!("build-logs/{}/{}.txt", build_id, default_target);
419+
self.storage.store_one(build_log_path, res.build_log)?;
418420

419421
// Some crates.io crate data is mutable, so we proactively update it during a release
420422
match self.index.api().get_crate_data(name) {
421423
Ok(crate_data) => update_crate_data_in_database(&mut conn, name, &crate_data)?,
422424
Err(err) => warn!("{:#?}", err),
423425
}
424426

425-
Ok(res)
427+
Ok(res.result.successful)
426428
})?;
427429

428430
build_dir.purge()?;
429431
krate.purge_from_cache(&self.workspace)?;
430432
local_storage.close()?;
431-
Ok(res.result.successful)
433+
Ok(successful)
432434
}
433435

434436
fn build_target(
@@ -556,13 +558,13 @@ impl RustwideBuilder {
556558

557559
Ok(FullBuildResult {
558560
result: BuildResult {
559-
build_log: storage.to_string(),
560561
rustc_version: self.rustc_version.clone(),
561562
docsrs_version: format!("docsrs {}", crate::BUILD_VERSION),
562563
successful,
563564
},
564565
doc_coverage,
565566
cargo_metadata,
567+
build_log: storage.to_string(),
566568
target: target.to_string(),
567569
})
568570
}
@@ -706,6 +708,7 @@ struct FullBuildResult {
706708
target: String,
707709
cargo_metadata: CargoMetadata,
708710
doc_coverage: Option<DocCoverage>,
711+
build_log: String,
709712
}
710713

711714
#[derive(Clone, Copy)]
@@ -725,6 +728,5 @@ pub(crate) struct DocCoverage {
725728
pub(crate) struct BuildResult {
726729
pub(crate) rustc_version: String,
727730
pub(crate) docsrs_version: String,
728-
pub(crate) build_log: String,
729731
pub(crate) successful: bool,
730732
}

src/storage/mod.rs

+30-7
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,6 @@ impl Storage {
149149

150150
// Store all files in `root_dir` into the backend under `prefix`.
151151
//
152-
// If the environment is configured with S3 credentials, this will upload to S3;
153-
// otherwise, this will store files in the database.
154-
//
155152
// This returns (map<filename, mime type>, set<compression algorithms>).
156153
pub(crate) fn store_all(
157154
&self,
@@ -199,10 +196,36 @@ impl Storage {
199196
self.store_inner(blobs.into_iter().map(Ok))
200197
}
201198

199+
// Store file into the backend at the given path (also used to detect mime type), returns the
200+
// chosen compression algorithm
201+
pub(crate) fn store_one(
202+
&self,
203+
path: impl Into<String>,
204+
content: impl Into<Vec<u8>>,
205+
) -> Result<CompressionAlgorithm, Error> {
206+
let path = path.into();
207+
let content = content.into();
208+
let alg = CompressionAlgorithm::default();
209+
let content = compress(&*content, alg)?;
210+
let mime = detect_mime(&path)?.to_owned();
211+
212+
self.store_inner(std::iter::once(Ok(Blob {
213+
path,
214+
mime,
215+
content,
216+
compression: Some(alg),
217+
// this field is ignored by the backend
218+
date_updated: Utc::now(),
219+
})))?;
220+
221+
Ok(alg)
222+
}
223+
202224
fn store_inner(
203225
&self,
204-
mut blobs: impl Iterator<Item = Result<Blob, Error>>,
226+
blobs: impl IntoIterator<Item = Result<Blob, Error>>,
205227
) -> Result<(), Error> {
228+
let mut blobs = blobs.into_iter();
206229
self.transaction(|trans| {
207230
loop {
208231
let batch: Vec<_> = blobs
@@ -249,13 +272,13 @@ trait StorageTransaction {
249272
fn complete(self: Box<Self>) -> Result<(), Error>;
250273
}
251274

252-
fn detect_mime(file_path: &Path) -> Result<&'static str, Error> {
253-
let mime = mime_guess::from_path(file_path)
275+
fn detect_mime(file_path: impl AsRef<Path>) -> Result<&'static str, Error> {
276+
let mime = mime_guess::from_path(file_path.as_ref())
254277
.first_raw()
255278
.unwrap_or("text/plain");
256279
Ok(match mime {
257280
"text/plain" | "text/troff" | "text/x-markdown" | "text/x-rust" | "text/x-toml" => {
258-
match file_path.extension().and_then(OsStr::to_str) {
281+
match file_path.as_ref().extension().and_then(OsStr::to_str) {
259282
Some("md") => "text/markdown",
260283
Some("rs") => "text/rust",
261284
Some("markdown") => "text/markdown",

src/test/fakes.rs

+47-10
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ pub(crate) struct FakeRelease<'a> {
3232
}
3333

3434
pub(crate) struct FakeBuild {
35+
s3_build_log: Option<String>,
36+
db_build_log: Option<String>,
3537
result: BuildResult,
3638
}
3739

@@ -323,12 +325,13 @@ impl<'a> FakeRelease<'a> {
323325
if let Some(markdown) = self.readme {
324326
fs::write(crate_dir.join("README.md"), markdown)?;
325327
}
328+
let default_target = self.default_target.unwrap_or(docsrs_metadata::HOST_TARGET);
326329
let release_id = crate::db::add_package_into_database(
327330
&mut db.conn(),
328331
&package,
329332
crate_dir,
330333
last_build_result,
331-
self.default_target.unwrap_or("x86_64-unknown-linux-gnu"),
334+
default_target,
332335
source_meta,
333336
self.doc_targets,
334337
&self.registry_release_data,
@@ -343,7 +346,7 @@ impl<'a> FakeRelease<'a> {
343346
&self.registry_crate_data,
344347
)?;
345348
for build in &self.builds {
346-
build.create(&mut db.conn(), release_id)?;
349+
build.create(&mut db.conn(), &*storage, release_id, default_target)?;
347350
}
348351
if let Some(coverage) = self.doc_coverage {
349352
crate::db::add_doc_coverage(&mut db.conn(), release_id, coverage)?;
@@ -384,6 +387,7 @@ impl FakeBuild {
384387
rustc_version: rustc_version.into(),
385388
..self.result
386389
},
390+
..self
387391
}
388392
}
389393

@@ -393,15 +397,28 @@ impl FakeBuild {
393397
docsrs_version: docsrs_version.into(),
394398
..self.result
395399
},
400+
..self
396401
}
397402
}
398403

399-
pub(crate) fn build_log(self, build_log: impl Into<String>) -> Self {
404+
pub(crate) fn s3_build_log(self, build_log: impl Into<String>) -> Self {
400405
Self {
401-
result: BuildResult {
402-
build_log: build_log.into(),
403-
..self.result
404-
},
406+
s3_build_log: Some(build_log.into()),
407+
..self
408+
}
409+
}
410+
411+
pub(crate) fn db_build_log(self, build_log: impl Into<String>) -> Self {
412+
Self {
413+
db_build_log: Some(build_log.into()),
414+
..self
415+
}
416+
}
417+
418+
pub(crate) fn no_s3_build_log(self) -> Self {
419+
Self {
420+
s3_build_log: None,
421+
..self
405422
}
406423
}
407424

@@ -411,11 +428,30 @@ impl FakeBuild {
411428
successful,
412429
..self.result
413430
},
431+
..self
414432
}
415433
}
416434

417-
fn create(&self, conn: &mut Client, release_id: i32) -> Result<(), Error> {
418-
crate::db::add_build_into_database(conn, release_id, &self.result)?;
435+
fn create(
436+
&self,
437+
conn: &mut Client,
438+
storage: &Storage,
439+
release_id: i32,
440+
default_target: &str,
441+
) -> Result<(), Error> {
442+
let build_id = crate::db::add_build_into_database(conn, release_id, &self.result)?;
443+
444+
if let Some(db_build_log) = self.db_build_log.as_deref() {
445+
conn.query(
446+
"UPDATE builds SET output = $2 WHERE id = $1",
447+
&[&build_id, &db_build_log],
448+
)?;
449+
}
450+
451+
if let Some(s3_build_log) = self.s3_build_log.as_deref() {
452+
let path = format!("build-logs/{}/{}.txt", build_id, default_target);
453+
storage.store_one(path, s3_build_log)?;
454+
}
419455

420456
Ok(())
421457
}
@@ -424,10 +460,11 @@ impl FakeBuild {
424460
impl Default for FakeBuild {
425461
fn default() -> Self {
426462
Self {
463+
s3_build_log: Some("It works!".into()),
464+
db_build_log: None,
427465
result: BuildResult {
428466
rustc_version: "rustc 2.0.0-nightly (000000000 1970-01-01)".into(),
429467
docsrs_version: "docs.rs 1.0.0 (000000000 1970-01-01)".into(),
430-
build_log: "It works!".into(),
431468
successful: true,
432469
},
433470
}

0 commit comments

Comments
 (0)