From 9776e7005d9c8e9f0b9fe138f16f8a5d8957dcab Mon Sep 17 00:00:00 2001
From: Onur Aslan 
Date: Thu, 22 Aug 2019 02:28:06 +0300
Subject: [PATCH 01/23] WIP rustwide
---
 Cargo.lock                      |  62 ++++++++++++++++++++
 Cargo.toml                      |   1 +
 src/bin/cratesfyi.rs            |  23 +++++++-
 src/lib.rs                      |   1 +
 src/utils/build_doc.rs          |   2 +-
 src/utils/build_doc_rustwide.rs | 101 ++++++++++++++++++++++++++++++++
 src/utils/mod.rs                |   4 +-
 7 files changed, 191 insertions(+), 3 deletions(-)
 create mode 100644 src/utils/build_doc_rustwide.rs
diff --git a/Cargo.lock b/Cargo.lock
index 89e56cff8..9e257463f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -451,6 +451,7 @@ dependencies = [
  "rusoto_credential 0.40.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rusoto_s3 0.40.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustwide 0.1.0 (git+https://github.com/onur/crater.git?rev=6907da8)",
  "sass-rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "schemamama 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "schemamama_postgres 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1425,6 +1426,18 @@ dependencies = [
  "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "nix"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "nodrop"
 version = "0.1.12"
@@ -1615,6 +1628,11 @@ name = "percent-encoding"
 version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "percent-encoding"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "persistent"
 version = "0.3.0"
@@ -2173,6 +2191,31 @@ dependencies = [
  "stb_truetype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "rustwide"
+version = "0.1.0"
+source = "git+https://github.com/onur/crater.git?rev=6907da8#6907da82bfcbcd74a25e24c50a834aae8a552d42"
+dependencies = [
+ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "reqwest 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tar 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-process 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "ryu"
 version = "0.2.6"
@@ -2259,6 +2302,11 @@ name = "scopeguard"
 version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "scopeguard"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "security-framework"
 version = "0.2.1"
@@ -2604,6 +2652,7 @@ dependencies = [
  "filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -3163,6 +3212,14 @@ dependencies = [
  "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "xattr"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "xml-rs"
 version = "0.7.0"
@@ -3322,6 +3379,7 @@ dependencies = [
 "checksum native-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8b0a7bd714e83db15676d31caf968ad7318e9cc35f93c85a90231c8f22867549"
 "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
 "checksum new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0cdc457076c78ab54d5e0d6fa7c47981757f1e34dc39ff92787f217dede586c4"
+"checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17"
 "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
 "checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b"
 "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e"
@@ -3343,6 +3401,7 @@ dependencies = [
 "checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5"
 "checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c"
 "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
+"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
 "checksum persistent 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c9c94f2ef72dc272c6bcc8157ccf2bc7da14f4c58c69059ac2fc48492d6916"
 "checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8"
 "checksum pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0fce5d8b5cc33983fc74f78ad552b5522ab41442c4ca91606e4236eb4b5ceefc"
@@ -3401,6 +3460,7 @@ dependencies = [
 "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
 "checksum rustfix 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "af7c21531a91512a4a51b490be6ba1c8eff34fdda0dc5bf87dc28d86748aac56"
 "checksum rusttype 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b8eb11f5b0a98c8eca2fb1483f42646d8c340e83e46ab416f8a063a0fd0eeb20"
+"checksum rustwide 0.1.0 (git+https://github.com/onur/crater.git?rev=6907da8)" = ""
 "checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7"
 "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f"
 "checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9"
@@ -3413,6 +3473,7 @@ dependencies = [
 "checksum schemamama_postgres 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9a69defe7b625fa5c4bfda0a1525c9729baef68f620e505464b7bf0a4d1697f6"
 "checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
 "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
+"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
 "checksum security-framework 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "697d3f3c23a618272ead9e1fb259c1411102b31c6af8b93f1d64cca9c3b0e8e0"
 "checksum security-framework-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab01dfbe5756785b5b4d46e0289e5a18071dfa9a7c2b24213ea00b9ef9b665bf"
 "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
@@ -3520,4 +3581,5 @@ dependencies = [
 "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 "checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"
 "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
+"checksum xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c"
 "checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2"
diff --git a/Cargo.toml b/Cargo.toml
index fffbc96b4..28aa08da1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -39,6 +39,7 @@ tokio = "0.1"
 systemstat = "0.1.4"
 prometheus = { version = "0.7.0", default-features = false }
 lazy_static = "1.0.0"
+rustwide = { git = "https://github.com/onur/crater.git", rev = "6907da8" }
 
 # iron dependencies
 iron = "0.5"
diff --git a/src/bin/cratesfyi.rs b/src/bin/cratesfyi.rs
index 71e6193b9..e8f3943db 100644
--- a/src/bin/cratesfyi.rs
+++ b/src/bin/cratesfyi.rs
@@ -12,7 +12,7 @@ use std::path::PathBuf;
 
 use clap::{Arg, App, SubCommand};
 use cratesfyi::{DocBuilder, DocBuilderOptions, db};
-use cratesfyi::utils::{build_doc, add_crate_to_queue};
+use cratesfyi::utils::{build_doc, build_doc_rustwide, add_crate_to_queue};
 use cratesfyi::start_web_server;
 use cratesfyi::db::{add_path_into_database, connect_db};
 
@@ -37,6 +37,20 @@ pub fn main() {
                 .index(3)
                 .required(false)
                 .help("The target platform to compile for")))
+        .subcommand(SubCommand::with_name("doc_rustwide")
+            .about("Builds documentation of a crate with rustwide")
+            .arg(Arg::with_name("CRATE_NAME")
+                .index(1)
+                .required(true)
+                .help("Crate name"))
+            .arg(Arg::with_name("CRATE_VERSION")
+                .index(2)
+                .required(true)
+                .help("Crate version"))
+            .arg(Arg::with_name("TARGET")
+                .index(3)
+                .required(false)
+                .help("The target platform to compile for")))
         .subcommand(SubCommand::with_name("build")
             .about("Builds documentation in a chroot environment")
             .arg(Arg::with_name("PREFIX")
@@ -160,6 +174,13 @@ pub fn main() {
         if let Err(e) = build_doc(name, version, target) {
             panic!("{:#?}", e);
         }
+    } else if let Some(matches) = matches.subcommand_matches("doc_rustwide") {
+        let name = matches.value_of("CRATE_NAME").unwrap();
+        let version = matches.value_of("CRATE_VERSION").unwrap();
+        let target = matches.value_of("TARGET");
+        if let Err(e) = build_doc_rustwide(name, version, target) {
+            panic!("{:#?}", e);
+        }
     } else if let Some(matches) = matches.subcommand_matches("build") {
         let docbuilder_opts = {
             let mut docbuilder_opts = if let Some(prefix) = matches.value_of("PREFIX") {
diff --git a/src/lib.rs b/src/lib.rs
index 0da58ca8c..c98890cd9 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -40,6 +40,7 @@ extern crate rusoto_credential;
 extern crate futures;
 extern crate tokio;
 extern crate systemstat;
+extern crate rustwide;
 
 pub use self::docbuilder::DocBuilder;
 pub use self::docbuilder::ChrootBuilderResult;
diff --git a/src/utils/build_doc.rs b/src/utils/build_doc.rs
index 7fb9d69b5..be1f41d9b 100644
--- a/src/utils/build_doc.rs
+++ b/src/utils/build_doc.rs
@@ -127,7 +127,7 @@ pub fn build_doc(name: &str, vers: Option<&str>, target: Option<&str>) -> Result
     Ok(try!(ws.current()).clone())
 }
 
-fn resolve_deps<'cfg>(pkg: &Package, config: &'cfg Config, src: Box)
+pub fn resolve_deps<'cfg>(pkg: &Package, config: &'cfg Config, src: Box)
     -> CargoResult>
 {
     let mut registry = try!(PackageRegistry::new(config));
diff --git a/src/utils/build_doc_rustwide.rs b/src/utils/build_doc_rustwide.rs
new file mode 100644
index 000000000..87c1cb1bc
--- /dev/null
+++ b/src/utils/build_doc_rustwide.rs
@@ -0,0 +1,101 @@
+use cargo::core::{enable_nightly_features, Package, SourceId, Workspace};
+use cargo::sources::SourceConfigMap;
+use cargo::util::{internal, Config};
+use error::Result;
+use rustwide::{cmd::SandboxBuilder, Crate, Toolchain, WorkspaceBuilder};
+use std::collections::HashSet;
+use std::path::Path;
+use utils::{get_current_versions, parse_rustc_version, resolve_deps};
+use Metadata;
+
+pub fn build_doc_rustwide(name: &str, version: &str, target: Option<&str>) -> Result {
+    // TODO: Handle workspace path correctly
+    let rustwide_workspace =
+        WorkspaceBuilder::new(Path::new("/tmp/docs-builder"), "docsrs").init()?;
+
+    // TODO: Instead of using just nightly, we can pin a version.
+    //       Docs.rs can only use nightly (due to unstable docs.rs features in rustdoc)
+    let toolchain = Toolchain::Dist {
+        name: "nightly".into(),
+    };
+    toolchain.install(&rustwide_workspace)?;
+
+    let krate = Crate::crates_io(name, version);
+    krate.fetch(&rustwide_workspace)?;
+
+    // Configure a sandbox with 1GB of RAM and no network access
+    // TODO: 1GB might not be enough
+    let sandbox = SandboxBuilder::new()
+        .memory_limit(Some(1024 * 1024 * 1024))
+        .enable_networking(false);
+
+    let mut build_dir = rustwide_workspace.build_dir(&format!("{}-{}", name, version));
+    let pkg = build_dir.build(&toolchain, &krate, sandbox, |build| {
+        enable_nightly_features();
+        let config = Config::default()?;
+        let source_id = try!(SourceId::crates_io(&config));
+        let source_cfg_map = try!(SourceConfigMap::new(&config));
+        let manifest_path = build.host_source_dir().join("Cargo.toml");
+        let ws = Workspace::new(&manifest_path, &config)?;
+        let pkg = ws.load(&manifest_path)?;
+
+        let metadata = Metadata::from_package(&pkg).map_err(|e| internal(e.to_string()))?;
+
+        let mut rustdoc_flags: Vec = vec![
+            "-Z".to_string(),
+            "unstable-options".to_string(),
+            "--resource-suffix".to_string(),
+            // FIXME: We need to get rustc version inside of container.
+            //        Our get_current_versions gets rustc version from host system not container.
+            format!("-{}", parse_rustc_version(get_current_versions()?.0)?),
+            "--static-root-path".to_string(),
+            "/".to_string(),
+            "--disable-per-crate-search".to_string(),
+        ];
+
+        let source = try!(source_cfg_map.load(source_id, &HashSet::new()));
+        let _lock = try!(config.acquire_package_cache_lock());
+
+        for (name, dep) in try!(resolve_deps(&pkg, &config, source)) {
+            rustdoc_flags.push("--extern-html-root-url".to_string());
+            rustdoc_flags.push(format!(
+                "{}=https://docs.rs/{}/{}",
+                name.replace("-", "_"),
+                dep.name(),
+                dep.version()
+            ));
+        }
+
+        let mut cargo_args = vec!["doc".to_owned(), "--lib".to_owned(), "--no-deps".to_owned()];
+        if let Some(features) = &metadata.features {
+            cargo_args.push("--features".to_owned());
+            cargo_args.push(features.join(" "));
+        }
+        if metadata.all_features {
+            cargo_args.push("--all-features".to_owned());
+        }
+        if metadata.no_default_features {
+            cargo_args.push("--no-default-features".to_owned());
+        }
+
+        // TODO: We need to use build result here
+        // FIXME: We also need build log (basically stderr message)
+        let result = build
+            .cargo()
+            .env(
+                "RUSTFLAGS",
+                metadata
+                    .rustc_args
+                    .map(|args| args.join(""))
+                    .unwrap_or("".to_owned()),
+            )
+            .env("RUSTDOCFLAGS", rustdoc_flags.join(" "))
+            .args(&cargo_args)
+            .run();
+
+        // TODO: We need to return build result as well
+        Ok(pkg)
+    })?;
+
+    Ok(pkg)
+}
diff --git a/src/utils/mod.rs b/src/utils/mod.rs
index 6f03bc9ac..f3b24d708 100644
--- a/src/utils/mod.rs
+++ b/src/utils/mod.rs
@@ -1,7 +1,8 @@
 //! Various utilities for cratesfyi
 
 
-pub use self::build_doc::{build_doc, get_package, source_path, update_sources};
+pub use self::build_doc::{build_doc, get_package, source_path, update_sources, resolve_deps};
+pub use self::build_doc_rustwide::build_doc_rustwide;
 pub use self::copy::{copy_dir, copy_doc_dir};
 pub use self::github_updater::github_updater;
 pub use self::release_activity_updater::update_release_activity;
@@ -12,6 +13,7 @@ pub use self::queue::add_crate_to_queue;
 
 mod github_updater;
 mod build_doc;
+mod build_doc_rustwide;
 mod copy;
 mod release_activity_updater;
 mod daemon;
From bbd19a59e8fb79c6a4cf8424e6d46e506780ff7c Mon Sep 17 00:00:00 2001
From: Pietro Albini 
Date: Wed, 11 Sep 2019 09:47:47 +0200
Subject: [PATCH 02/23] temporarily switch to rustwide's git repository
---
 Cargo.lock | 18 ++++++++++--------
 Cargo.toml |  2 +-
 2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 9e257463f..1d3e68a2b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -451,7 +451,7 @@ dependencies = [
  "rusoto_credential 0.40.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rusoto_s3 0.40.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustwide 0.1.0 (git+https://github.com/onur/crater.git?rev=6907da8)",
+ "rustwide 0.2.0 (git+https://github.com/rust-lang/rustwide)",
  "sass-rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "schemamama 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "schemamama_postgres 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2040,7 +2040,7 @@ dependencies = [
 
 [[package]]
 name = "remove_dir_all"
-version = "0.5.1"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2193,16 +2193,18 @@ dependencies = [
 
 [[package]]
 name = "rustwide"
-version = "0.1.0"
-source = "git+https://github.com/onur/crater.git?rev=6907da8#6907da82bfcbcd74a25e24c50a834aae8a552d42"
+version = "0.2.0"
+source = "git+https://github.com/rust-lang/rustwide#fa1480bdedd4fd3f242e4f669839064ba088bf08"
 dependencies = [
  "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "reqwest 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2661,7 +2663,7 @@ version = "0.3.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -2673,7 +2675,7 @@ dependencies = [
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -3447,7 +3449,7 @@ dependencies = [
 "checksum regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0b2f0808e7d7e4fb1cb07feb6ff2f4bc827938f24f8c2e6a3beb7370af544bdd"
 "checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
 "checksum regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d76410686f9e3a17f06128962e0ecc5755870bb890c34820c7af7f1db2e1d48"
-"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
+"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
 "checksum reqwest 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1d68c7bf0b1dc3860b80c6d31d05808bf54cdc1bfc70a4680893791becd083ae"
 "checksum route-recognizer 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3255338088df8146ba63d60a9b8e3556f1146ce2973bc05a75181a42ce2256"
 "checksum router 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9b1797ff166029cb632237bb5542696e54961b4cf75a324c6f05c9cf0584e4e"
@@ -3460,7 +3462,7 @@ dependencies = [
 "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
 "checksum rustfix 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "af7c21531a91512a4a51b490be6ba1c8eff34fdda0dc5bf87dc28d86748aac56"
 "checksum rusttype 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b8eb11f5b0a98c8eca2fb1483f42646d8c340e83e46ab416f8a063a0fd0eeb20"
-"checksum rustwide 0.1.0 (git+https://github.com/onur/crater.git?rev=6907da8)" = ""
+"checksum rustwide 0.2.0 (git+https://github.com/rust-lang/rustwide)" = ""
 "checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7"
 "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f"
 "checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9"
diff --git a/Cargo.toml b/Cargo.toml
index 28aa08da1..db8528f63 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -39,7 +39,7 @@ tokio = "0.1"
 systemstat = "0.1.4"
 prometheus = { version = "0.7.0", default-features = false }
 lazy_static = "1.0.0"
-rustwide = { git = "https://github.com/onur/crater.git", rev = "6907da8" }
+rustwide = { git =  "https://github.com/rust-lang/rustwide" }
 
 # iron dependencies
 iron = "0.5"
From 8059fdc5175e606d571d3fe449105117ade4f062 Mon Sep 17 00:00:00 2001
From: Pietro Albini 
Date: Wed, 11 Sep 2019 09:48:56 +0200
Subject: [PATCH 03/23] correctly fetch rustwide's rustc version
---
 src/utils/build_doc_rustwide.rs | 33 ++++++++++++++++++++++++++-------
 1 file changed, 26 insertions(+), 7 deletions(-)
diff --git a/src/utils/build_doc_rustwide.rs b/src/utils/build_doc_rustwide.rs
index 87c1cb1bc..dc2e49212 100644
--- a/src/utils/build_doc_rustwide.rs
+++ b/src/utils/build_doc_rustwide.rs
@@ -1,11 +1,14 @@
-use cargo::core::{enable_nightly_features, Package, SourceId, Workspace};
+use cargo::core::{enable_nightly_features, Package, SourceId, Workspace as CargoWorkspace};
 use cargo::sources::SourceConfigMap;
 use cargo::util::{internal, Config};
 use error::Result;
-use rustwide::{cmd::SandboxBuilder, Crate, Toolchain, WorkspaceBuilder};
+use rustwide::{
+    cmd::{Command, SandboxBuilder},
+    Crate, Toolchain, Workspace, WorkspaceBuilder,
+};
 use std::collections::HashSet;
 use std::path::Path;
-use utils::{get_current_versions, parse_rustc_version, resolve_deps};
+use utils::{parse_rustc_version, resolve_deps};
 use Metadata;
 
 pub fn build_doc_rustwide(name: &str, version: &str, target: Option<&str>) -> Result {
@@ -36,7 +39,7 @@ pub fn build_doc_rustwide(name: &str, version: &str, target: Option<&str>) -> Re
         let source_id = try!(SourceId::crates_io(&config));
         let source_cfg_map = try!(SourceConfigMap::new(&config));
         let manifest_path = build.host_source_dir().join("Cargo.toml");
-        let ws = Workspace::new(&manifest_path, &config)?;
+        let ws = CargoWorkspace::new(&manifest_path, &config)?;
         let pkg = ws.load(&manifest_path)?;
 
         let metadata = Metadata::from_package(&pkg).map_err(|e| internal(e.to_string()))?;
@@ -45,9 +48,10 @@ pub fn build_doc_rustwide(name: &str, version: &str, target: Option<&str>) -> Re
             "-Z".to_string(),
             "unstable-options".to_string(),
             "--resource-suffix".to_string(),
-            // FIXME: We need to get rustc version inside of container.
-            //        Our get_current_versions gets rustc version from host system not container.
-            format!("-{}", parse_rustc_version(get_current_versions()?.0)?),
+            format!(
+                "-{}",
+                parse_rustc_version(rustc_version(&rustwide_workspace, &toolchain)?)?
+            ),
             "--static-root-path".to_string(),
             "/".to_string(),
             "--disable-per-crate-search".to_string(),
@@ -99,3 +103,18 @@ pub fn build_doc_rustwide(name: &str, version: &str, target: Option<&str>) -> Re
 
     Ok(pkg)
 }
+
+fn rustc_version(workspace: &Workspace, toolchain: &Toolchain) -> Result {
+    let res = Command::new(workspace, toolchain.rustc())
+        .args(&["--version"])
+        .log_output(false)
+        .run_capture()?;
+
+    if let Some(line) = res.stdout_lines().iter().next() {
+        Ok(line.clone())
+    } else {
+        Err(::failure::err_msg(
+            "invalid output returned by `rustc --version`",
+        ))
+    }
+}
From c11554521f6dbf5bf28c8a54b90b3ae5307bc9e3 Mon Sep 17 00:00:00 2001
From: Pietro Albini 
Date: Wed, 11 Sep 2019 09:49:26 +0200
Subject: [PATCH 04/23] move sandbox configuration to constants
---
 src/utils/build_doc_rustwide.rs | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/utils/build_doc_rustwide.rs b/src/utils/build_doc_rustwide.rs
index dc2e49212..97d52ac5d 100644
--- a/src/utils/build_doc_rustwide.rs
+++ b/src/utils/build_doc_rustwide.rs
@@ -11,6 +11,10 @@ use std::path::Path;
 use utils::{parse_rustc_version, resolve_deps};
 use Metadata;
 
+// TODO: 1GB might not be enough
+const SANDBOX_MEMORY_LIMIT: usize = 1024 * 1025 * 1024; // 1GB
+const SANDBOX_NETWORKING: bool = false;
+
 pub fn build_doc_rustwide(name: &str, version: &str, target: Option<&str>) -> Result {
     // TODO: Handle workspace path correctly
     let rustwide_workspace =
@@ -26,11 +30,9 @@ pub fn build_doc_rustwide(name: &str, version: &str, target: Option<&str>) -> Re
     let krate = Crate::crates_io(name, version);
     krate.fetch(&rustwide_workspace)?;
 
-    // Configure a sandbox with 1GB of RAM and no network access
-    // TODO: 1GB might not be enough
     let sandbox = SandboxBuilder::new()
-        .memory_limit(Some(1024 * 1024 * 1024))
-        .enable_networking(false);
+        .memory_limit(Some(SANDBOX_MEMORY_LIMIT))
+        .enable_networking(SANDBOX_NETWORKING);
 
     let mut build_dir = rustwide_workspace.build_dir(&format!("{}-{}", name, version));
     let pkg = build_dir.build(&toolchain, &krate, sandbox, |build| {
From 4dd22ee450c4458913432630c427f47be0049df9 Mon Sep 17 00:00:00 2001
From: Pietro Albini 
Date: Wed, 11 Sep 2019 10:15:47 +0200
Subject: [PATCH 05/23] build docs with rustwide on different targets
---
 src/utils/build_doc_rustwide.rs | 7 +++++++
 1 file changed, 7 insertions(+)
diff --git a/src/utils/build_doc_rustwide.rs b/src/utils/build_doc_rustwide.rs
index 97d52ac5d..fcdb508c5 100644
--- a/src/utils/build_doc_rustwide.rs
+++ b/src/utils/build_doc_rustwide.rs
@@ -26,6 +26,9 @@ pub fn build_doc_rustwide(name: &str, version: &str, target: Option<&str>) -> Re
         name: "nightly".into(),
     };
     toolchain.install(&rustwide_workspace)?;
+    if let Some(target) = target {
+        toolchain.add_target(&rustwide_workspace, target)?;
+    }
 
     let krate = Crate::crates_io(name, version);
     krate.fetch(&rustwide_workspace)?;
@@ -83,6 +86,10 @@ pub fn build_doc_rustwide(name: &str, version: &str, target: Option<&str>) -> Re
         if metadata.no_default_features {
             cargo_args.push("--no-default-features".to_owned());
         }
+        if let Some(target) = target {
+            cargo_args.push("--target".into());
+            cargo_args.push(target.into());
+        }
 
         // TODO: We need to use build result here
         // FIXME: We also need build log (basically stderr message)
From 0f037c39dd2aec42f73ea3b0843e83f5cf06dd88 Mon Sep 17 00:00:00 2001
From: Pietro Albini 
Date: Wed, 11 Sep 2019 11:07:44 +0200
Subject: [PATCH 06/23] use the cargo metadata cli instead of the library to
 resolve deps
---
 src/utils/build_doc_rustwide.rs |  42 ++++++++----
 src/utils/cargo_metadata.rs     | 115 ++++++++++++++++++++++++++++++++
 src/utils/mod.rs                |   1 +
 3 files changed, 144 insertions(+), 14 deletions(-)
 create mode 100644 src/utils/cargo_metadata.rs
diff --git a/src/utils/build_doc_rustwide.rs b/src/utils/build_doc_rustwide.rs
index fcdb508c5..e0a3eb44a 100644
--- a/src/utils/build_doc_rustwide.rs
+++ b/src/utils/build_doc_rustwide.rs
@@ -1,21 +1,24 @@
-use cargo::core::{enable_nightly_features, Package, SourceId, Workspace as CargoWorkspace};
-use cargo::sources::SourceConfigMap;
+use cargo::core::{enable_nightly_features, Workspace as CargoWorkspace};
 use cargo::util::{internal, Config};
 use error::Result;
 use rustwide::{
     cmd::{Command, SandboxBuilder},
     Crate, Toolchain, Workspace, WorkspaceBuilder,
 };
-use std::collections::HashSet;
 use std::path::Path;
-use utils::{parse_rustc_version, resolve_deps};
+use utils::cargo_metadata::CargoMetadata;
+use utils::parse_rustc_version;
 use Metadata;
 
 // TODO: 1GB might not be enough
 const SANDBOX_MEMORY_LIMIT: usize = 1024 * 1025 * 1024; // 1GB
 const SANDBOX_NETWORKING: bool = false;
 
-pub fn build_doc_rustwide(name: &str, version: &str, target: Option<&str>) -> Result {
+pub fn build_doc_rustwide(
+    name: &str,
+    version: &str,
+    target: Option<&str>,
+) -> Result {
     // TODO: Handle workspace path correctly
     let rustwide_workspace =
         WorkspaceBuilder::new(Path::new("/tmp/docs-builder"), "docsrs").init()?;
@@ -41,14 +44,15 @@ pub fn build_doc_rustwide(name: &str, version: &str, target: Option<&str>) -> Re
     let pkg = build_dir.build(&toolchain, &krate, sandbox, |build| {
         enable_nightly_features();
         let config = Config::default()?;
-        let source_id = try!(SourceId::crates_io(&config));
-        let source_cfg_map = try!(SourceConfigMap::new(&config));
         let manifest_path = build.host_source_dir().join("Cargo.toml");
         let ws = CargoWorkspace::new(&manifest_path, &config)?;
         let pkg = ws.load(&manifest_path)?;
 
         let metadata = Metadata::from_package(&pkg).map_err(|e| internal(e.to_string()))?;
 
+        let cargo_metadata =
+            CargoMetadata::load(&rustwide_workspace, &toolchain, &build.host_source_dir())?;
+
         let mut rustdoc_flags: Vec = vec![
             "-Z".to_string(),
             "unstable-options".to_string(),
@@ -62,14 +66,11 @@ pub fn build_doc_rustwide(name: &str, version: &str, target: Option<&str>) -> Re
             "--disable-per-crate-search".to_string(),
         ];
 
-        let source = try!(source_cfg_map.load(source_id, &HashSet::new()));
-        let _lock = try!(config.acquire_package_cache_lock());
-
-        for (name, dep) in try!(resolve_deps(&pkg, &config, source)) {
+        for dep in &cargo_metadata.root_dependencies() {
             rustdoc_flags.push("--extern-html-root-url".to_string());
             rustdoc_flags.push(format!(
                 "{}=https://docs.rs/{}/{}",
-                name.replace("-", "_"),
+                dep.name().replace("-", "_"),
                 dep.name(),
                 dep.version()
             ));
@@ -107,19 +108,32 @@ pub fn build_doc_rustwide(name: &str, version: &str, target: Option<&str>) -> Re
             .run();
 
         // TODO: We need to return build result as well
-        Ok(pkg)
+        Ok(BuildDocOutput {
+            package_version: cargo_metadata.root().version().to_string(),
+        })
     })?;
 
     Ok(pkg)
 }
 
+pub struct BuildDocOutput {
+    package_version: String,
+}
+
+impl BuildDocOutput {
+    pub fn package_version(&self) -> &str {
+        &self.package_version
+    }
+}
+
 fn rustc_version(workspace: &Workspace, toolchain: &Toolchain) -> Result {
     let res = Command::new(workspace, toolchain.rustc())
         .args(&["--version"])
         .log_output(false)
         .run_capture()?;
 
-    if let Some(line) = res.stdout_lines().iter().next() {
+    let mut iter = res.stdout_lines().iter();
+    if let (Some(line), None) = (iter.next(), iter.next()) {
         Ok(line.clone())
     } else {
         Err(::failure::err_msg(
diff --git a/src/utils/cargo_metadata.rs b/src/utils/cargo_metadata.rs
new file mode 100644
index 000000000..05e7227e8
--- /dev/null
+++ b/src/utils/cargo_metadata.rs
@@ -0,0 +1,115 @@
+use error::Result;
+use rustwide::{cmd::Command, Toolchain, Workspace};
+use std::collections::{HashMap, HashSet};
+use std::path::Path;
+
+pub(crate) struct CargoMetadata {
+    packages: HashMap,
+    deps_graph: HashMap>,
+    root_id: String,
+}
+
+impl CargoMetadata {
+    pub(crate) fn load(
+        workspace: &Workspace,
+        toolchain: &Toolchain,
+        source_dir: &Path,
+    ) -> Result {
+        let res = Command::new(workspace, toolchain.cargo())
+            .args(&["metadata", "--format-version", "1"])
+            .cd(source_dir)
+            .log_output(false)
+            .run_capture()?;
+
+        let mut iter = res.stdout_lines().iter();
+        let metadata = if let (Some(serialized), None) = (iter.next(), iter.next()) {
+            ::rustc_serialize::json::decode::(serialized)?
+        } else {
+            return Err(::failure::err_msg(
+                "invalid output returned by `cargo metadata`",
+            ));
+        };
+
+        // Convert from Vecs to HashMaps and HashSets to get more efficient lookups
+        Ok(CargoMetadata {
+            packages: metadata
+                .packages
+                .into_iter()
+                .map(|pkg| {
+                    (
+                        pkg.id,
+                        Package {
+                            name: pkg.name,
+                            version: pkg.version,
+                        },
+                    )
+                })
+                .collect(),
+            deps_graph: metadata
+                .resolve
+                .nodes
+                .into_iter()
+                .map(|node| (node.id, node.deps.into_iter().map(|d| d.pkg).collect()))
+                .collect(),
+            root_id: metadata.resolve.root,
+        })
+    }
+
+    pub(crate) fn root_dependencies(&self) -> Vec<&Package> {
+        let ids = &self.deps_graph[&self.root_id];
+        self.packages
+            .iter()
+            .filter(|(id, _pkg)| ids.contains(id.as_str()))
+            .map(|(_id, pkg)| pkg)
+            .collect()
+    }
+
+    pub(crate) fn root(&self) -> &Package {
+        &self.packages[&self.root_id]
+    }
+}
+
+pub(crate) struct Package {
+    name: String,
+    version: String,
+}
+
+impl Package {
+    pub(crate) fn name(&self) -> &str {
+        &self.name
+    }
+
+    pub(crate) fn version(&self) -> &str {
+        &self.version
+    }
+}
+
+#[derive(RustcDecodable)]
+struct DeserializedMetadata {
+    packages: Vec,
+    resolve: DeserializedResolve,
+}
+
+#[derive(RustcDecodable)]
+struct DeserializedPackage {
+    id: String,
+    name: String,
+    version: String,
+}
+
+#[derive(RustcDecodable)]
+struct DeserializedResolve {
+    root: String,
+    nodes: Vec,
+}
+
+#[derive(RustcDecodable)]
+struct DeserializedResolveNode {
+    id: String,
+    deps: Vec,
+}
+
+#[derive(RustcDecodable)]
+struct DeserializedResolveDep {
+    pkg: String,
+}
diff --git a/src/utils/mod.rs b/src/utils/mod.rs
index f3b24d708..eb13836a1 100644
--- a/src/utils/mod.rs
+++ b/src/utils/mod.rs
@@ -11,6 +11,7 @@ pub use self::rustc_version::{parse_rustc_version, get_current_versions, command
 pub use self::html::extract_head_and_body;
 pub use self::queue::add_crate_to_queue;
 
+mod cargo_metadata;
 mod github_updater;
 mod build_doc;
 mod build_doc_rustwide;
From 844e2dcf32adfdb855e2104dd87ae4f3fa78f04c Mon Sep 17 00:00:00 2001
From: Pietro Albini 
Date: Wed, 11 Sep 2019 11:59:31 +0200
Subject: [PATCH 07/23] remove last uses of the cargo library from rustwide
---
 src/docbuilder/metadata.rs      |  8 ++++++--
 src/utils/build_doc_rustwide.rs | 27 ++++++++-------------------
 2 files changed, 14 insertions(+), 21 deletions(-)
diff --git a/src/docbuilder/metadata.rs b/src/docbuilder/metadata.rs
index e99e10cb4..0919938f3 100644
--- a/src/docbuilder/metadata.rs
+++ b/src/docbuilder/metadata.rs
@@ -60,10 +60,14 @@ pub struct Metadata {
 
 
 impl Metadata {
-    pub fn from_package(pkg: &Package) -> Result {
+    pub(crate) fn from_package(pkg: &Package) -> Result {
         let src_path = pkg.manifest_path().parent().ok_or_else(|| err_msg("Source path not available"))?;
+        Metadata::from_source_dir(src_path)
+    }
+
+    pub(crate) fn from_source_dir(source_dir: &Path) -> Result {
         for c in ["Cargo.toml.orig", "Cargo.toml"].iter() {
-            let manifest_path = src_path.clone().join(c);
+            let manifest_path = source_dir.clone().join(c);
             if manifest_path.exists() {
                 return Ok(Metadata::from_manifest(manifest_path));
             }
diff --git a/src/utils/build_doc_rustwide.rs b/src/utils/build_doc_rustwide.rs
index e0a3eb44a..e02af23c5 100644
--- a/src/utils/build_doc_rustwide.rs
+++ b/src/utils/build_doc_rustwide.rs
@@ -1,5 +1,3 @@
-use cargo::core::{enable_nightly_features, Workspace as CargoWorkspace};
-use cargo::util::{internal, Config};
 use error::Result;
 use rustwide::{
     cmd::{Command, SandboxBuilder},
@@ -20,38 +18,29 @@ pub fn build_doc_rustwide(
     target: Option<&str>,
 ) -> Result {
     // TODO: Handle workspace path correctly
-    let rustwide_workspace =
-        WorkspaceBuilder::new(Path::new("/tmp/docs-builder"), "docsrs").init()?;
+    let workspace = WorkspaceBuilder::new(Path::new("/tmp/docs-builder"), "docsrs").init()?;
 
     // TODO: Instead of using just nightly, we can pin a version.
     //       Docs.rs can only use nightly (due to unstable docs.rs features in rustdoc)
     let toolchain = Toolchain::Dist {
         name: "nightly".into(),
     };
-    toolchain.install(&rustwide_workspace)?;
+    toolchain.install(&workspace)?;
     if let Some(target) = target {
-        toolchain.add_target(&rustwide_workspace, target)?;
+        toolchain.add_target(&workspace, target)?;
     }
 
     let krate = Crate::crates_io(name, version);
-    krate.fetch(&rustwide_workspace)?;
+    krate.fetch(&workspace)?;
 
     let sandbox = SandboxBuilder::new()
         .memory_limit(Some(SANDBOX_MEMORY_LIMIT))
         .enable_networking(SANDBOX_NETWORKING);
 
-    let mut build_dir = rustwide_workspace.build_dir(&format!("{}-{}", name, version));
+    let mut build_dir = workspace.build_dir(&format!("{}-{}", name, version));
     let pkg = build_dir.build(&toolchain, &krate, sandbox, |build| {
-        enable_nightly_features();
-        let config = Config::default()?;
-        let manifest_path = build.host_source_dir().join("Cargo.toml");
-        let ws = CargoWorkspace::new(&manifest_path, &config)?;
-        let pkg = ws.load(&manifest_path)?;
-
-        let metadata = Metadata::from_package(&pkg).map_err(|e| internal(e.to_string()))?;
-
-        let cargo_metadata =
-            CargoMetadata::load(&rustwide_workspace, &toolchain, &build.host_source_dir())?;
+        let metadata = Metadata::from_source_dir(&build.host_source_dir())?;
+        let cargo_metadata = CargoMetadata::load(&workspace, &toolchain, &build.host_source_dir())?;
 
         let mut rustdoc_flags: Vec = vec![
             "-Z".to_string(),
@@ -59,7 +48,7 @@ pub fn build_doc_rustwide(
             "--resource-suffix".to_string(),
             format!(
                 "-{}",
-                parse_rustc_version(rustc_version(&rustwide_workspace, &toolchain)?)?
+                parse_rustc_version(rustc_version(&workspace, &toolchain)?)?
             ),
             "--static-root-path".to_string(),
             "/".to_string(),
From 5965cc898dc259a391b331382e1b7d131063a06a Mon Sep 17 00:00:00 2001
From: Pietro Albini 
Date: Wed, 11 Sep 2019 12:14:28 +0200
Subject: [PATCH 08/23] record the build log during rustwide builds
---
 src/bin/cratesfyi.rs            |  4 ++-
 src/utils/build_doc_rustwide.rs | 44 ++++++++++++++++++++++-----------
 2 files changed, 32 insertions(+), 16 deletions(-)
diff --git a/src/bin/cratesfyi.rs b/src/bin/cratesfyi.rs
index e8f3943db..6d056b626 100644
--- a/src/bin/cratesfyi.rs
+++ b/src/bin/cratesfyi.rs
@@ -5,6 +5,7 @@ extern crate clap;
 extern crate log;
 extern crate env_logger;
 extern crate time;
+extern crate rustwide;
 
 
 use std::env;
@@ -308,5 +309,6 @@ fn logger_init() {
                 record.args())
     });
     builder.parse(&env::var("RUST_LOG").unwrap_or("cratesfyi=info".to_owned()));
-    builder.init();
+
+    rustwide::logging::init_with(builder.build());
 }
diff --git a/src/utils/build_doc_rustwide.rs b/src/utils/build_doc_rustwide.rs
index e02af23c5..99e7428d3 100644
--- a/src/utils/build_doc_rustwide.rs
+++ b/src/utils/build_doc_rustwide.rs
@@ -1,6 +1,8 @@
 use error::Result;
+use log::LevelFilter;
 use rustwide::{
     cmd::{Command, SandboxBuilder},
+    logging::{self, LogStorage},
     Crate, Toolchain, Workspace, WorkspaceBuilder,
 };
 use std::path::Path;
@@ -9,8 +11,10 @@ use utils::parse_rustc_version;
 use Metadata;
 
 // TODO: 1GB might not be enough
-const SANDBOX_MEMORY_LIMIT: usize = 1024 * 1025 * 1024; // 1GB
+const SANDBOX_MEMORY_LIMIT: usize = 1024 * 1024 * 1024; // 1GB
 const SANDBOX_NETWORKING: bool = false;
+const SANDBOX_MAX_LOG_SIZE: usize = 1024 * 1024; // 1MB
+const SANDBOX_MAX_LOG_LINES: usize = 10_000;
 
 pub fn build_doc_rustwide(
     name: &str,
@@ -81,24 +85,29 @@ pub fn build_doc_rustwide(
             cargo_args.push(target.into());
         }
 
-        // TODO: We need to use build result here
-        // FIXME: We also need build log (basically stderr message)
-        let result = build
-            .cargo()
-            .env(
-                "RUSTFLAGS",
-                metadata
-                    .rustc_args
-                    .map(|args| args.join(""))
-                    .unwrap_or("".to_owned()),
-            )
-            .env("RUSTDOCFLAGS", rustdoc_flags.join(" "))
-            .args(&cargo_args)
-            .run();
+        let mut storage = LogStorage::new(LevelFilter::Info);
+        storage.set_max_size(SANDBOX_MAX_LOG_SIZE);
+        storage.set_max_lines(SANDBOX_MAX_LOG_LINES);
+
+        logging::capture(&storage, || {
+            build
+                .cargo()
+                .env(
+                    "RUSTFLAGS",
+                    metadata
+                        .rustc_args
+                        .map(|args| args.join(""))
+                        .unwrap_or("".to_owned()),
+                )
+                .env("RUSTDOCFLAGS", rustdoc_flags.join(" "))
+                .args(&cargo_args)
+                .run()
+        })?;
 
         // TODO: We need to return build result as well
         Ok(BuildDocOutput {
             package_version: cargo_metadata.root().version().to_string(),
+            build_log: storage.to_string(),
         })
     })?;
 
@@ -107,12 +116,17 @@ pub fn build_doc_rustwide(
 
 pub struct BuildDocOutput {
     package_version: String,
+    build_log: String,
 }
 
 impl BuildDocOutput {
     pub fn package_version(&self) -> &str {
         &self.package_version
     }
+
+    pub fn build_log(&self) -> &str {
+        &self.build_log
+    }
 }
 
 fn rustc_version(workspace: &Workspace, toolchain: &Toolchain) -> Result {
From c004725d4115e84e86985b47473b5107a1a2456a Mon Sep 17 00:00:00 2001
From: Pietro Albini 
Date: Thu, 12 Sep 2019 10:37:24 +0200
Subject: [PATCH 09/23] extract some code from chroot_builder into docbuilder
Those methods will also be used by the rustwide builder in future
commits.
---
 src/docbuilder/chroot_builder.rs |  7 ++-----
 src/docbuilder/mod.rs            | 11 +++++++++++
 2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/src/docbuilder/chroot_builder.rs b/src/docbuilder/chroot_builder.rs
index aea0fe6c5..8e95d8e0d 100644
--- a/src/docbuilder/chroot_builder.rs
+++ b/src/docbuilder/chroot_builder.rs
@@ -65,10 +65,7 @@ impl DocBuilder {
     /// Builds package documentation in chroot environment and adds into cratesfyi database
     pub fn build_package(&mut self, name: &str, version: &str) -> Result {
         // Skip crates according to options
-        if (self.options.skip_if_log_exists &&
-            self.cache.contains(&format!("{}-{}", name, version)[..])) ||
-           (self.options.skip_if_exists &&
-            self.db_cache.contains(&format!("{}-{}", name, version)[..])) {
+        if !self.should_build(name, version) {
             return Ok(false);
         }
 
@@ -113,7 +110,7 @@ impl DocBuilder {
         try!(self.clean(&pkg));
 
         // add package into build cache
-        self.cache.insert(format!("{}-{}", name, version));
+        self.add_to_cache(name, version);
 
         Ok(res.build_success)
     }
diff --git a/src/docbuilder/mod.rs b/src/docbuilder/mod.rs
index 635fe2d55..006ccc19c 100644
--- a/src/docbuilder/mod.rs
+++ b/src/docbuilder/mod.rs
@@ -119,4 +119,15 @@ impl DocBuilder {
     pub fn options(&self) -> &DocBuilderOptions {
         &self.options
     }
+
+    fn add_to_cache(&mut self, name: &str, version: &str) {
+        self.cache.insert(format!("{}-{}", name, version));
+    }
+
+    fn should_build(&self, name: &str, version: &str) -> bool {
+        let name = format!("{}-{}", name, version);
+        let local = self.options.skip_if_log_exists && self.cache.contains(&name);
+        let db = self.options.skip_if_exists && self.db_cache.contains(&name);
+        !(local || db)
+    }
 }
From 9d2b6b8e930725b76692bfb51ac716670653d3c5 Mon Sep 17 00:00:00 2001
From: Pietro Albini 
Date: Thu, 12 Sep 2019 11:55:13 +0200
Subject: [PATCH 10/23] switch add_package to use cargo metadata
---
 src/db/add_package.rs            | 136 ++++++++++++++-----------------
 src/db/mod.rs                    |   4 +-
 src/docbuilder/chroot_builder.rs |  18 ++--
 src/utils/build_doc_rustwide.rs  |   8 +-
 src/utils/cargo_metadata.rs      | 111 +++++++++++++++++++------
 src/utils/mod.rs                 |   1 +
 6 files changed, 165 insertions(+), 113 deletions(-)
diff --git a/src/db/add_package.rs b/src/db/add_package.rs
index 7def3504a..550899078 100644
--- a/src/db/add_package.rs
+++ b/src/db/add_package.rs
@@ -1,16 +1,14 @@
 
 use ChrootBuilderResult;
 use Metadata;
-use utils::source_path;
+use utils::MetadataPackage;
 use regex::Regex;
 
 use std::io::prelude::*;
 use std::io::BufReader;
-use std::path::{Path, PathBuf};
+use std::path::Path;
 use std::fs;
 
-use cargo::core::{Package, TargetKind};
-use cargo::core::dependency::Kind;
 use rustc_serialize::json::{Json, ToJson};
 use slug::slugify;
 use reqwest::Client;
@@ -24,27 +22,28 @@ use failure::err_msg;
 /// Adds a package into database.
 ///
 /// Package must be built first.
-pub fn add_package_into_database(conn: &Connection,
-                                 pkg: &Package,
+pub(crate) fn add_package_into_database(conn: &Connection,
+                                 metadata_pkg: &MetadataPackage,
+                                 source_dir: &Path,
                                  res: &ChrootBuilderResult,
                                  files: Option,
                                  doc_targets: Vec)
                                  -> Result {
     debug!("Adding package into database");
-    let crate_id = try!(initialize_package_in_database(&conn, &pkg));
-    let dependencies = convert_dependencies(&pkg);
-    let rustdoc = get_rustdoc(&pkg).unwrap_or(None);
-    let readme = get_readme(&pkg).unwrap_or(None);
-    let (release_time, yanked, downloads) = try!(get_release_time_yanked_downloads(&pkg));
-    let is_library = match pkg.targets()[0].kind() {
-        &TargetKind::Lib(_) => true,
+    let crate_id = try!(initialize_package_in_database(&conn, metadata_pkg));
+    let dependencies = convert_dependencies(metadata_pkg);
+    let rustdoc = get_rustdoc(metadata_pkg, source_dir).unwrap_or(None);
+    let readme = get_readme(metadata_pkg, source_dir).unwrap_or(None);
+    let (release_time, yanked, downloads) = try!(get_release_time_yanked_downloads(metadata_pkg));
+    let is_library = match metadata_pkg.targets[0].kind.as_slice() {
+        &[ref kind] if kind == "lib" => true,
         _ => false,
     };
-    let metadata = Metadata::from_package(pkg)?;
+    let metadata = Metadata::from_source_dir(source_dir)?;
 
     let release_id: i32 = {
         let rows = try!(conn.query("SELECT id FROM releases WHERE crate_id = $1 AND version = $2",
-                                   &[&crate_id, &format!("{}", pkg.manifest().version())]));
+                                   &[&crate_id, &format!("{}", metadata_pkg.version)]));
 
         if rows.len() == 0 {
             let rows = try!(conn.query("INSERT INTO releases (
@@ -62,29 +61,29 @@ pub fn add_package_into_database(conn: &Connection,
                                         )
                                         RETURNING id",
                                        &[&crate_id,
-                                         &format!("{}", pkg.manifest().version()),
+                                         &metadata_pkg.version,
                                          &release_time,
                                          &dependencies.to_json(),
-                                         &pkg.targets()[0].name().replace("-", "_"),
+                                         &metadata_pkg.targets[0].name.replace("-", "_"),
                                          &yanked,
                                          &res.build_success,
                                          &res.have_doc,
                                          &false, // TODO: Add test status somehow
-                                         &pkg.manifest().metadata().license,
-                                         &pkg.manifest().metadata().repository,
-                                         &pkg.manifest().metadata().homepage,
-                                         &pkg.manifest().metadata().description,
+                                         &metadata_pkg.license,
+                                         &metadata_pkg.repository,
+                                         &metadata_pkg.homepage,
+                                         &metadata_pkg.description,
                                          &rustdoc,
                                          &readme,
-                                         &pkg.manifest().metadata().authors.to_json(),
-                                         &pkg.manifest().metadata().keywords.to_json(),
+                                         &metadata_pkg.authors.to_json(),
+                                         &metadata_pkg.keywords.to_json(),
                                          &res.have_examples,
                                          &downloads,
                                          &files,
                                          &doc_targets.to_json(),
                                          &is_library,
                                          &res.rustc_version,
-                                         &pkg.manifest().metadata().documentation,
+                                         &metadata_pkg.documentation,
                                          &metadata.default_target]));
             // return id
             rows.get(0).get(0)
@@ -116,38 +115,38 @@ pub fn add_package_into_database(conn: &Connection,
                                  default_target = $25
                              WHERE crate_id = $1 AND version = $2",
                             &[&crate_id,
-                              &format!("{}", pkg.manifest().version()),
+                              &format!("{}", metadata_pkg.version),
                               &release_time,
                               &dependencies.to_json(),
-                              &pkg.targets()[0].name().replace("-", "_"),
+                              &metadata_pkg.targets[0].name.replace("-", "_"),
                               &yanked,
                               &res.build_success,
                               &res.have_doc,
                               &false, // TODO: Add test status somehow
-                              &pkg.manifest().metadata().license,
-                              &pkg.manifest().metadata().repository,
-                              &pkg.manifest().metadata().homepage,
-                              &pkg.manifest().metadata().description,
+                              &metadata_pkg.license,
+                              &metadata_pkg.repository,
+                              &metadata_pkg.homepage,
+                              &metadata_pkg.description,
                               &rustdoc,
                               &readme,
-                              &pkg.manifest().metadata().authors.to_json(),
-                              &pkg.manifest().metadata().keywords.to_json(),
+                              &metadata_pkg.authors.to_json(),
+                              &metadata_pkg.keywords.to_json(),
                               &res.have_examples,
                               &downloads,
                               &files,
                               &doc_targets.to_json(),
                               &is_library,
                               &res.rustc_version,
-                              &pkg.manifest().metadata().documentation,
+                              &metadata_pkg.documentation,
                               &metadata.default_target]));
             rows.get(0).get(0)
         }
     };
 
 
-    try!(add_keywords_into_database(&conn, &pkg, &release_id));
-    try!(add_authors_into_database(&conn, &pkg, &release_id));
-    try!(add_owners_into_database(&conn, &pkg, &crate_id));
+    try!(add_keywords_into_database(&conn, &metadata_pkg, &release_id));
+    try!(add_authors_into_database(&conn, &metadata_pkg, &release_id));
+    try!(add_owners_into_database(&conn, &metadata_pkg, &crate_id));
 
 
     // Update versions
@@ -159,13 +158,12 @@ pub fn add_package_into_database(conn: &Connection,
         if let Some(versions_array) = versions.as_array_mut() {
             let mut found = false;
             for version in versions_array.clone() {
-                if &semver::Version::parse(version.as_string().unwrap()).unwrap() ==
-                   pkg.manifest().version() {
+                if version.as_string().unwrap() == metadata_pkg.version {
                     found = true;
                 }
             }
             if !found {
-                versions_array.push(format!("{}", &pkg.manifest().version()).to_json());
+                versions_array.push(format!("{}", &metadata_pkg.version).to_json());
             }
         }
         let _ = conn.query("UPDATE crates SET versions = $1 WHERE id = $2",
@@ -177,7 +175,7 @@ pub fn add_package_into_database(conn: &Connection,
 
 
 /// Adds a build into database
-pub fn add_build_into_database(conn: &Connection,
+pub(crate) fn add_build_into_database(conn: &Connection,
                                release_id: &i32,
                                res: &ChrootBuilderResult)
                                -> Result {
@@ -196,13 +194,12 @@ pub fn add_build_into_database(conn: &Connection,
 }
 
 
-fn initialize_package_in_database(conn: &Connection, pkg: &Package) -> Result {
-    let mut rows = try!(conn.query("SELECT id FROM crates WHERE name = $1",
-                                   &[&pkg.manifest().name().as_str()]));
+fn initialize_package_in_database(conn: &Connection, pkg: &MetadataPackage) -> Result {
+    let mut rows = try!(conn.query("SELECT id FROM crates WHERE name = $1", &[&pkg.name]));
     // insert crate into database if it is not exists
     if rows.len() == 0 {
         rows = try!(conn.query("INSERT INTO crates (name) VALUES ($1) RETURNING id",
-                               &[&pkg.manifest().name().as_str()]));
+                               &[&pkg.name]));
     }
     Ok(rows.get(0).get(0))
 }
@@ -210,16 +207,12 @@ fn initialize_package_in_database(conn: &Connection, pkg: &Package) -> Result
-fn convert_dependencies(pkg: &Package) -> Vec<(String, String, String)> {
+fn convert_dependencies(pkg: &MetadataPackage) -> Vec<(String, String, String)> {
     let mut dependencies: Vec<(String, String, String)> = Vec::new();
-    for dependency in pkg.manifest().dependencies() {
-        let name = dependency.package_name().to_string();
-        let version = format!("{}", dependency.version_req());
-        let kind = match dependency.kind() {
-            Kind::Normal => "normal",
-            Kind::Development => "dev",
-            Kind::Build => "build",
-        };
+    for dependency in &pkg.dependencies {
+        let name = dependency.name.clone();
+        let version = dependency.req.clone();
+        let kind = dependency.kind.as_ref().map(|s| s.clone()).unwrap_or_else(|| "normal".into());
         dependencies.push((name, version, kind.to_string()));
     }
     dependencies
@@ -227,9 +220,8 @@ fn convert_dependencies(pkg: &Package) -> Vec<(String, String, String)> {
 
 
 /// Reads readme if there is any read defined in Cargo.toml of a Package
-fn get_readme(pkg: &Package) -> Result
 
+  Global sandbox limits
+
+  
+  All the builds on docs.rs are executed inside a sandbox with limited
+  resources. The current limits are the following:
+  
+
+  
+    
+      {{#each content.limits}}
+      
+        | {{{@key}}}+ | {{this}}+ | 
+      {{/each}}
+    
+  
+
+  
+  If a build fails because it hit one of those limits please
+  open an issue
+  to get them increased for your crate.
+  
+
   Redirections
 
   
diff --git a/templates/builds.hbs b/templates/builds.hbs
index c32fac506..630661ea7 100644
--- a/templates/builds.hbs
+++ b/templates/builds.hbs
@@ -8,14 +8,12 @@
     
       Build #{{build_details.id}} {{build_details.build_time}}
     
-    
-$ rustc --version
+    $ rustc --version
 {{build_details.rustc_version}}
 $ cratesfyi --version
 {{build_details.cratesfyi_version}}
 $ cratesfyi ...
-{{build_details.output}}
-    
+{{build_details.output}}
     {{/if}}
 
     
@@ -36,6 +34,31 @@ $ cratesfyi ...
     
     {{/each}}
     
+
+    
+      
{{metadata.name}}'s sandbox limits
+
+      
+      All the builds on docs.rs are executed inside a sandbox with limited
+      resources. The limits for this crate are the following:
+      
+
+      
+        
+          {{#each limits}}
+          
+            | {{{@key}}}+ | {{this}}+ | 
+          {{/each}}
+        
+      
+      
+      If a build fails because it hit one of those limits please
+      open an issue
+      to get them increased.
+      
+