diff --git a/Cargo.lock b/Cargo.lock index 6398b7632..a37a0dee2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,9 +1,9 @@ [root] name = "cratesfyi" -version = "0.3.4" +version = "0.4.0" dependencies = [ "badge 0.1.1", - "cargo 0.20.0 (git+https://github.com/rust-lang/cargo.git?rev=9fe7f07579d6d2672dd7e95c70adaea65d8e9a2e)", + "cargo 0.20.0 (git+https://github.com/onur/cargo.git?branch=docs.rs)", "clap 2.23.3 (registry+https://github.com/rust-lang/crates.io-index)", "comrak 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "crates-index-diff 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -29,6 +29,7 @@ dependencies = [ "staticfile 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -158,11 +159,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cargo" version = "0.20.0" -source = "git+https://github.com/rust-lang/cargo.git?rev=9fe7f07579d6d2672dd7e95c70adaea65d8e9a2e#9fe7f07579d6d2672dd7e95c70adaea65d8e9a2e" +source = "git+https://github.com/onur/cargo.git?branch=docs.rs#a2996e83fe5eea05b26b7f95465a4936c5171348" dependencies = [ "advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crates-io 0.9.0 (git+https://github.com/rust-lang/cargo.git?rev=9fe7f07579d6d2672dd7e95c70adaea65d8e9a2e)", + "crates-io 0.9.0 (git+https://github.com/onur/cargo.git?branch=docs.rs)", "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -182,6 +183,7 @@ dependencies = [ "openssl 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)", "psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -283,7 +285,7 @@ dependencies = [ [[package]] name = "crates-io" version = "0.9.0" -source = "git+https://github.com/rust-lang/cargo.git?rev=9fe7f07579d6d2672dd7e95c70adaea65d8e9a2e#9fe7f07579d6d2672dd7e95c70adaea65d8e9a2e" +source = "git+https://github.com/onur/cargo.git?branch=docs.rs#a2996e83fe5eea05b26b7f95465a4936c5171348" dependencies = [ "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1128,6 +1130,14 @@ dependencies = [ "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustc_version" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rusttype" version = "0.2.1" @@ -1624,7 +1634,7 @@ dependencies = [ "checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32" "checksum byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96c8b41881888cc08af32d47ac4edd52bc7fa27fef774be47a92443756451304" "checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8" -"checksum cargo 0.20.0 (git+https://github.com/rust-lang/cargo.git?rev=9fe7f07579d6d2672dd7e95c70adaea65d8e9a2e)" = "" +"checksum cargo 0.20.0 (git+https://github.com/onur/cargo.git?branch=docs.rs)" = "" "checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c" "checksum chrono 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d9123be86fd2a8f627836c235ecdf331fdd067ecf7ac05aa1a68fbcf2429f056" "checksum clap 2.23.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f57e9b63057a545ad2ecd773ea61e49422ed1b1d63d74d5da5ecaee55b3396cd" @@ -1634,7 +1644,7 @@ dependencies = [ "checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67" "checksum core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d" "checksum crates-index-diff 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "163413e7f795a28633d2e3d55765b059517dcfdad97013460fcbb9ac305a40f9" -"checksum crates-io 0.9.0 (git+https://github.com/rust-lang/cargo.git?rev=9fe7f07579d6d2672dd7e95c70adaea65d8e9a2e)" = "" +"checksum crates-io 0.9.0 (git+https://github.com/onur/cargo.git?branch=docs.rs)" = "" "checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" "checksum crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e34988f7e069e0b2f3bfc064295161e489b2d4e04a2e4248fb94360cdf00b4ec" "checksum curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c90e1240ef340dd4027ade439e5c7c2064dd9dc652682117bd50d1486a3add7b" @@ -1731,6 +1741,7 @@ dependencies = [ "checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" +"checksum rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9743a7670d88d5d52950408ecdb7c71d8986251ab604d4689dd2ca25c9bca69" "checksum rusttype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c64ffc93b0cc5a6f5e5e84da2a4082b0271e0a1dd76e821bdac570bda7797e" "checksum sass-rs 0.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "98552ea76b181c4c6d490619e273649432dff0333b8278c53529a86bb99e1a6e" "checksum sass-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a243aaa2ca9f52b55fdf0ac6b169cbe3e98ec45b0180fced467d4d090f52c0e" diff --git a/Cargo.toml b/Cargo.toml index ca080b357..3c4280f02 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cratesfyi" -version = "0.3.4" +version = "0.4.0" authors = ["Onur Aslan "] readme = "README.md" license = "MIT" @@ -27,6 +27,7 @@ libc = "0.2" badge = { version = "0", path = "src/web/badge" } error-chain = "0.10" comrak = { version = "0.1", default-features = false } +toml = "0.4" # iron dependencies iron = "0.5" @@ -36,8 +37,8 @@ params = "0.6" staticfile = { version = "0.4", features = [ "cache" ] } [dependencies.cargo] -git = "https://github.com/rust-lang/cargo.git" -rev = "9fe7f07579d6d2672dd7e95c70adaea65d8e9a2e" +git = "https://github.com/onur/cargo.git" +branch = "docs.rs" [dependencies.postgres] version = "0.14" diff --git a/src/bin/cratesfyi.rs b/src/bin/cratesfyi.rs index 8cc339d80..20a6cad1a 100644 --- a/src/bin/cratesfyi.rs +++ b/src/bin/cratesfyi.rs @@ -50,7 +50,7 @@ pub fn main() { .takes_value(true)) .arg(Arg::with_name("CHROOT_PATH") .short("c") - .long("chroot") + .long("chroot-path") .help("Sets chroot path") .takes_value(true)) .arg(Arg::with_name("CHROOT_USER") @@ -58,6 +58,11 @@ pub fn main() { .long("chroot-user") .help("Sets chroot user name") .takes_value(true)) + .arg(Arg::with_name("CONTAINER_NAME") + .short("n") + .long("container-name") + .help("Sets name of the container") + .takes_value(true)) .arg(Arg::with_name("CRATES_IO_INDEX_PATH") .long("crates-io-index-path") .help("Sets crates.io-index path") @@ -93,7 +98,8 @@ pub fn main() { building new crates")) .subcommand(SubCommand::with_name("unlock") .about("Unlocks cratesfyi daemon to continue \ - building new crates"))) + building new crates")) + .subcommand(SubCommand::with_name("print-options"))) .subcommand(SubCommand::with_name("start-web-server") .about("Starts web server") .arg(Arg::with_name("SOCKET_ADDR") @@ -158,6 +164,10 @@ pub fn main() { docbuilder_opts.chroot_user = chroot_user.to_string(); } + if let Some(container_name) = matches.value_of("CONTAINER_NAME") { + docbuilder_opts.container_name = container_name.to_string(); + } + if let Some(crates_io_index_path) = matches.value_of("CRATES_IO_INDEX_PATH") { docbuilder_opts.crates_io_index_path = PathBuf::from(crates_io_index_path); } @@ -189,6 +199,8 @@ pub fn main() { docbuilder.lock().expect("Failed to lock"); } else if let Some(_) = matches.subcommand_matches("unlock") { docbuilder.unlock().expect("Failed to unlock"); + } else if let Some(_) = matches.subcommand_matches("print-options") { + println!("{:?}", docbuilder.options()); } } else if let Some(matches) = matches.subcommand_matches("database") { diff --git a/src/db/add_package.rs b/src/db/add_package.rs index d3a331a8f..40063ffb5 100644 --- a/src/db/add_package.rs +++ b/src/db/add_package.rs @@ -1,5 +1,6 @@ use ChrootBuilderResult; +use Metadata; use utils::source_path; use regex::Regex; @@ -38,6 +39,7 @@ pub fn add_package_into_database(conn: &Connection, &TargetKind::Lib(_) => true, _ => false, }; + let metadata = Metadata::from_package(pkg); let release_id: i32 = { let rows = try!(conn.query("SELECT id FROM releases WHERE crate_id = $1 AND version = $2", @@ -51,11 +53,11 @@ pub fn add_package_into_database(conn: &Connection, homepage_url, description, description_long, readme, authors, keywords, have_examples, downloads, files, doc_targets, is_library, doc_rustc_version, - documentation_url + documentation_url, default_target ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, - $20, $21, $22, $23, $24 + $20, $21, $22, $23, $24, $25 ) RETURNING id", &[&crate_id, @@ -81,7 +83,8 @@ pub fn add_package_into_database(conn: &Connection, &doc_targets.to_json(), &is_library, &res.rustc_version, - &pkg.manifest().metadata().documentation])); + &pkg.manifest().metadata().documentation, + &metadata.default_target])); // return id rows.get(0).get(0) @@ -108,7 +111,8 @@ pub fn add_package_into_database(conn: &Connection, doc_targets = $21, is_library = $22, doc_rustc_version = $23, - documentation_url = $24 + documentation_url = $24, + default_target = $25 WHERE crate_id = $1 AND version = $2", &[&crate_id, &format!("{}", pkg.manifest().version()), @@ -133,7 +137,8 @@ pub fn add_package_into_database(conn: &Connection, &doc_targets.to_json(), &is_library, &res.rustc_version, - &pkg.manifest().metadata().documentation])); + &pkg.manifest().metadata().documentation, + &metadata.default_target])); rows.get(0).get(0) } }; diff --git a/src/db/mod.rs b/src/db/mod.rs index f188dac40..8ed55e23f 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -112,6 +112,7 @@ pub fn create_tables(conn: &Connection) -> Result<(), Error> { files JSON, doc_targets JSON DEFAULT '[]', doc_rustc_version VARCHAR(100) NOT NULL, + default_target VARCHAR(100), UNIQUE (crate_id, version) )", "CREATE TABLE authors ( diff --git a/src/docbuilder/chroot_builder.rs b/src/docbuilder/chroot_builder.rs index 5fb7935ab..fba903769 100644 --- a/src/docbuilder/chroot_builder.rs +++ b/src/docbuilder/chroot_builder.rs @@ -6,12 +6,27 @@ use db::{connect_db, add_package_into_database, add_build_into_database, add_pat use cargo::core::Package; use std::process::{Command, Output}; use std::path::PathBuf; +use std::fs::remove_dir_all; use postgres::Connection; use rustc_serialize::json::Json; use error::Result; use regex::Regex; +/// List of targets supported by docs.rs +const TARGETS: [&'static str; 8] = [ + "i686-apple-darwin", + "i686-pc-windows-gnu", + "i686-pc-windows-msvc", + "i686-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-gnu", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" +]; + + + #[derive(Debug)] pub struct ChrootBuilderResult { pub output: String, @@ -57,6 +72,8 @@ impl DocBuilder { info!("Building package {}-{}", name, version); + // Start with clean documentation directory + try!(self.remove_build_dir()); // Database connection let conn = try!(connect_db()); @@ -132,46 +149,9 @@ impl DocBuilder { /// Builds documentation of crate for every target and returns Vec of successfully targets fn build_package_for_all_targets(&self, package: &Package) -> Vec { - // Temporary skip tier 2 and tier 3 platforms - let targets = [// "aarch64-apple-ios", - // "aarch64-linux-android", - // "aarch64-unknown-linux-gnu", - // "arm-linux-androideabi", - // "arm-unknown-linux-gnueabi", - // "arm-unknown-linux-gnueabihf", - // "armv7-apple-ios", - // "armv7-linux-androideabi", - // "armv7-unknown-linux-gnueabihf", - // "armv7s-apple-ios", - // "i386-apple-ios", - // "i586-pc-windows-msvc", - // "i586-unknown-linux-gnu", - "i686-apple-darwin", - // "i686-linux-android", - "i686-pc-windows-gnu", - "i686-pc-windows-msvc", - // "i686-unknown-freebsd", - "i686-unknown-linux-gnu", - // "i686-unknown-linux-musl", - // "mips-unknown-linux-gnu", - // "mips-unknown-linux-musl", - // "mipsel-unknown-linux-gnu", - // "mipsel-unknown-linux-musl", - // "powerpc-unknown-linux-gnu", - // "powerpc64-unknown-linux-gnu", - // "powerpc64le-unknown-linux-gnu", - "x86_64-apple-darwin", - // "x86_64-apple-ios", - "x86_64-pc-windows-gnu", - "x86_64-pc-windows-msvc", - // "x86_64-rumprun-netbsd", - // "x86_64-unknown-freebsd", - "x86_64-unknown-linux-gnu" /* "x86_64-unknown-linux-musl", - * "x86_64-unknown-netbsd", */]; - let mut successfuly_targets = Vec::new(); - for target in targets.iter() { + for target in TARGETS.iter() { debug!("Building {} for {}", canonical_name(&package), target); let cmd = format!("cratesfyi doc {} ={} {}", package.manifest().name(), @@ -185,7 +165,7 @@ impl DocBuilder { let target_doc_path = PathBuf::from(&self.options.chroot_path) .join("home") .join(&self.options.chroot_user) - .join(canonical_name(&package)) + .join("cratesfyi") .join(&target) .join("doc"); if target_doc_path.exists() { @@ -219,7 +199,7 @@ impl DocBuilder { let crate_doc_path = PathBuf::from(&self.options.chroot_path) .join("home") .join(&self.options.chroot_user) - .join(canonical_name(&package)) + .join("cratesfyi") .join(target.unwrap_or("")); let destination = PathBuf::from(&self.options.destination) .join(format!("{}/{}", @@ -234,8 +214,22 @@ impl DocBuilder { /// Removes build directory of a package in chroot - fn remove_build_dir(&self, package: &Package) -> Result<()> { - let _ = self.chroot_command(format!("rm -rf {}", canonical_name(&package))); + fn remove_build_dir(&self) -> Result<()> { + let crate_doc_path = PathBuf::from(&self.options.chroot_path) + .join("home") + .join(&self.options.chroot_user) + .join("cratesfyi") + .join("doc"); + let _ = remove_dir_all(crate_doc_path); + for target in TARGETS.iter() { + let crate_doc_path = PathBuf::from(&self.options.chroot_path) + .join("home") + .join(&self.options.chroot_user) + .join("cratesfyi") + .join(target) + .join("doc"); + let _ = remove_dir_all(crate_doc_path); + } Ok(()) } @@ -248,7 +242,7 @@ impl DocBuilder { .join(package.manifest().name()); let source_path = source_path(&package).unwrap(); // Some crates don't have documentation, so we don't care if removing_dir_all fails - let _ = self.remove_build_dir(&package); + let _ = self.remove_build_dir(); let _ = remove_dir_all(documentation_path); let _ = remove_dir_all(source_path); Ok(()) @@ -280,7 +274,7 @@ impl DocBuilder { let crate_doc_path = PathBuf::from(&self.options.chroot_path) .join("home") .join(&self.options.chroot_user) - .join(canonical_name(&package)) + .join("cratesfyi") .join("doc") .join(package.targets()[0].name().replace("-", "_").to_string()); crate_doc_path.exists() @@ -381,7 +375,7 @@ impl DocBuilder { let source = PathBuf::from(&self.options.chroot_path) .join("home") .join(&self.options.chroot_user) - .join(canonical_name(&pkg)) + .join("cratesfyi") .join("doc"); // use copy_documentation destination directory so self.clean can remove it when diff --git a/src/docbuilder/metadata.rs b/src/docbuilder/metadata.rs new file mode 100644 index 000000000..4ccabb7bb --- /dev/null +++ b/src/docbuilder/metadata.rs @@ -0,0 +1,167 @@ + +use std::path::Path; +use cargo::core::Package; +use toml::Value; + + +/// Metadata for custom builds +/// +/// You can customize docs.rs builds by defining `[package.metadata.docs.rs]` table in your +/// crates' `Cargo.toml`. +/// +/// An example metadata: +/// +/// ```text +/// [package] +/// name = "test" +/// +/// [package.metadata.docs.rs] +/// features = [ "feature1", "feature2" ] +/// all-features = true +/// no-default-features = true +/// default-target = "x86_64-unknown-linux-gnu" +/// rustdoc-args = [ "--example-rustdoc-arg" ] +/// dependencies = [ "example-system-dependency" ] +/// ``` +/// +/// You can define one or more fields in your `Cargo.toml`. +pub struct Metadata { + /// List of features docs.rs will build. + /// + /// By default, docs.rs will only build default features. + pub features: Option>, + + /// Set `all-features` to true if you want docs.rs to build all features for your crate + pub all_features: bool, + + /// Docs.rs will always build default features. + /// + /// Set `no-default-fatures` to `false` if you want to build only certain features. + pub no_default_features: bool, + + /// Docs.rs is running on `x86_64-unknown-linux-gnu` target system and default documentation + /// is always built on this target. You can change default target by setting this. + pub default_target: Option, + + /// List of command line arguments for `rustdoc`. + pub rustdoc_args: Option>, + + /// System dependencies. + /// + /// Docs.rs is running on a Debian jessie. + pub dependencies: Option>, +} + + + +impl Metadata { + pub fn from_package(pkg: &Package) -> Metadata { + Metadata::from_manifest(pkg.manifest_path()) + } + + pub fn from_manifest>(path: P) -> Metadata { + use std::fs::File; + use std::io::Read; + let mut f = match File::open(path) { + Ok(f) => f, + Err(_) => return Metadata::default(), + }; + let mut s = String::new(); + if let Err(_) = f.read_to_string(&mut s) { + return Metadata::default(); + } + Metadata::from_str(&s) + } + + + // This is similar to Default trait but it's private + fn default() -> Metadata { + Metadata { + features: None, + all_features: false, + no_default_features: false, + default_target: None, + rustdoc_args: None, + dependencies: None, + } + } + + + fn from_str(manifest: &str) -> Metadata { + let mut metadata = Metadata::default(); + + let manifest = match manifest.parse::() { + Ok(m) => m, + Err(_) => return metadata, + }; + + if let Some(table) = manifest.get("package").and_then(|p| p.as_table()) + .and_then(|p| p.get("metadata")).and_then(|p| p.as_table()) + .and_then(|p| p.get("docs")).and_then(|p| p.as_table()) + .and_then(|p| p.get("rs")).and_then(|p| p.as_table()) { + metadata.features = table.get("features").and_then(|f| f.as_array()) + .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect()); + metadata.no_default_features = table.get("no-default-features") + .and_then(|v| v.as_bool()).unwrap_or(metadata.no_default_features); + metadata.all_features = table.get("all-features") + .and_then(|v| v.as_bool()).unwrap_or(metadata.all_features); + metadata.default_target = table.get("default-target") + .and_then(|v| v.as_str()).map(|v| v.to_owned()); + metadata.rustdoc_args = table.get("rustdoc-args").and_then(|f| f.as_array()) + .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect()); + metadata.dependencies = table.get("dependencies").and_then(|f| f.as_array()) + .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect()); + } + + metadata + } +} + + + +#[cfg(test)] +mod test { + extern crate env_logger; + use super::Metadata; + + #[test] + fn test_cratesfyi_metadata() { + let _ = env_logger::init(); + let manifest = r#" + [package] + name = "test" + + [package.metadata.docs.rs] + features = [ "feature1", "feature2" ] + all-features = true + no-default-features = true + default-target = "x86_64-unknown-linux-gnu" + rustc-args = [ "--example-rustc-arg" ] + rustdoc-args = [ "--example-rustdoc-arg" ] + dependencies = [ "example-system-dependency" ] + "#; + + let metadata = Metadata::from_str(manifest); + + assert!(metadata.features.is_some()); + assert!(metadata.all_features == true); + assert!(metadata.no_default_features == true); + assert!(metadata.default_target.is_some()); + assert!(metadata.rustdoc_args.is_some()); + + let features = metadata.features.unwrap(); + assert_eq!(features.len(), 2); + assert_eq!(features[0], "feature1".to_owned()); + assert_eq!(features[1], "feature2".to_owned()); + + assert_eq!(metadata.default_target.unwrap(), "x86_64-unknown-linux-gnu".to_owned()); + + let rustdoc_args = metadata.rustdoc_args.unwrap(); + assert_eq!(rustdoc_args.len(), 1); + assert_eq!(rustdoc_args[0], "--example-rustdoc-arg".to_owned()); + + let dependencies = metadata.dependencies.unwrap(); + assert_eq!(dependencies.len(), 1); + assert_eq!(dependencies[0], "example-system-dependency".to_owned()); + } +} diff --git a/src/docbuilder/mod.rs b/src/docbuilder/mod.rs index 6e065a653..3fe748abd 100644 --- a/src/docbuilder/mod.rs +++ b/src/docbuilder/mod.rs @@ -1,5 +1,6 @@ pub mod options; +pub mod metadata; mod chroot_builder; mod crates; mod queue; @@ -108,4 +109,9 @@ impl DocBuilder { } Ok(()) } + + /// Returns a reference of options + pub fn options(&self) -> &DocBuilderOptions { + &self.options + } } diff --git a/src/docbuilder/options.rs b/src/docbuilder/options.rs index 4fc223f63..11218367a 100644 --- a/src/docbuilder/options.rs +++ b/src/docbuilder/options.rs @@ -58,13 +58,14 @@ impl fmt::Debug for DocBuilderOptions { write!(f, "DocBuilderOptions {{ destination: {:?}, chroot_path: {:?}, \ crates_io_index_path: {:?}, \ - sources_path: {:?}, chroot_user: {:?}, \ + sources_path: {:?}, container_name: {:?}, chroot_user: {:?}, \ keep_build_directory: {:?}, skip_if_exists: {:?}, \ skip_if_log_exists: {:?}, debug: {:?} }}", self.destination, self.chroot_path, self.crates_io_index_path, self.sources_path, + self.container_name, self.chroot_user, self.keep_build_directory, self.skip_if_exists, diff --git a/src/lib.rs b/src/lib.rs index d1633dbec..e4311567f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,10 +27,12 @@ extern crate libc; extern crate badge; extern crate crates_index_diff; extern crate git2; +extern crate toml; pub use self::docbuilder::DocBuilder; pub use self::docbuilder::ChrootBuilderResult; pub use self::docbuilder::options::DocBuilderOptions; +pub use self::docbuilder::metadata::Metadata; pub use self::web::start_web_server; pub mod error; diff --git a/src/utils/build_doc.rs b/src/utils/build_doc.rs index f16cc1e5c..8e3e7901c 100644 --- a/src/utils/build_doc.rs +++ b/src/utils/build_doc.rs @@ -12,6 +12,8 @@ use cargo::util::{CargoResult, Config, human, Filesystem}; use cargo::sources::SourceConfigMap; use cargo::ops::{self, Packages, DefaultExecutor}; +use Metadata; + /// Builds documentation of a crate and version. /// @@ -40,16 +42,17 @@ pub fn build_doc(name: &str, vers: Option<&str>, target: Option<&str>) -> CargoR .unwrap_or(Err(human("PKG download error")))); let current_dir = try!(env::current_dir()); - let target_dir = PathBuf::from(current_dir) - .join(format!("{}-{}", pkg.manifest().name(), pkg.manifest().version())); + let target_dir = PathBuf::from(current_dir).join("cratesfyi"); + + let metadata = Metadata::from_package(&pkg); let opts = ops::CompileOptions { config: &config, jobs: None, target: target, - features: &[], - all_features: false, - no_default_features: false, + features: &metadata.features.unwrap_or(Vec::new()), + all_features: metadata.all_features, + no_default_features: metadata.no_default_features, spec: Packages::Packages(&[]), mode: ops::CompileMode::Doc { deps: false }, release: false, @@ -60,7 +63,7 @@ pub fn build_doc(name: &str, vers: Option<&str>, target: Option<&str>) -> CargoR &[], false, &[], false), target_rustc_args: None, - target_rustdoc_args: None, + target_rustdoc_args: metadata.rustdoc_args.as_ref().map(Vec::as_slice), }; let ws = try!(Workspace::ephemeral(pkg, &config, Some(Filesystem::new(target_dir)), false)); @@ -124,8 +127,10 @@ mod test { let doc = build_doc("rand", None, None); assert!(doc.is_ok()); - let doc = doc.unwrap(); - remove_dir_all(format!("{}-{}", doc.manifest().name(), doc.manifest().version())).unwrap(); + let root_path = Path::new("cratesfyi"); + assert!(root_path.join("doc").join("rand").exists()); + + remove_dir_all(root_path).unwrap(); let doc = build_doc("SOMECRATEWICHWILLBENVEREXISTS", None, None); assert!(doc.is_err()); diff --git a/src/utils/copy.rs b/src/utils/copy.rs index b52f0de4b..004d0ec81 100644 --- a/src/utils/copy.rs +++ b/src/utils/copy.rs @@ -33,7 +33,6 @@ pub fn copy_doc_dir>(target: P, target_platform: bool) -> Result<()> { let source = PathBuf::from(target.as_ref()).join("doc"); - debug!("Copying documentation from: {}", source.display()); copy_files_and_handle_html(source, destination.as_ref().to_path_buf(), true, diff --git a/src/web/crate_details.rs b/src/web/crate_details.rs index e9962443c..9c7b6aeb1 100644 --- a/src/web/crate_details.rs +++ b/src/web/crate_details.rs @@ -19,7 +19,7 @@ use semver; #[derive(Debug)] -struct CrateDetails { +pub struct CrateDetails { name: String, version: String, description: Option, @@ -37,13 +37,16 @@ struct CrateDetails { keywords: Option, have_examples: bool, // need to check this manually target_name: Option, - versions: Vec, + pub versions: Vec, github: bool, // is crate hosted in github github_stars: Option, github_forks: Option, github_issues: Option, metadata: MetaData, is_library: bool, + doc_targets: Option, + license: Option, + documentation_url: Option, } @@ -79,13 +82,16 @@ impl ToJson for CrateDetails { m.insert("github_issues".to_string(), self.github_issues.to_json()); m.insert("metadata".to_string(), self.metadata.to_json()); m.insert("is_library".to_string(), self.is_library.to_json()); + m.insert("doc_targets".to_string(), self.doc_targets.to_json()); + m.insert("license".to_string(), self.license.to_json()); + m.insert("documentation_url".to_string(), self.documentation_url.to_json()); m.to_json() } } impl CrateDetails { - fn new(conn: &Connection, name: &str, version: &str) -> Option { + pub fn new(conn: &Connection, name: &str, version: &str) -> Option { // get all stuff, I love you rustfmt let query = "SELECT crates.id, @@ -109,7 +115,10 @@ impl CrateDetails { crates.github_stars, crates.github_forks, crates.github_issues, - releases.is_library + releases.is_library, + releases.doc_targets, + releases.license, + releases.documentation_url FROM releases INNER JOIN crates ON releases.crate_id = crates.id WHERE crates.name = $1 AND releases.version = $2;"; @@ -176,6 +185,9 @@ impl CrateDetails { github_issues: rows.get(0).get(20), metadata: metadata, is_library: rows.get(0).get(21), + doc_targets: rows.get(0).get(22), + license: rows.get(0).get(23), + documentation_url: rows.get(0).get(24), }; if let Some(repository_url) = crate_details.repository_url.clone() { diff --git a/src/web/mod.rs b/src/web/mod.rs index 3ae707de5..dc242dec3 100644 --- a/src/web/mod.rs +++ b/src/web/mod.rs @@ -324,15 +324,14 @@ fn render_markdown(text: &str) -> String { /// Returns latest version if required version is not the latest /// req_version must be an exact version -fn latest_version(versions_json: &Json, req_version: &str) -> Option { +fn latest_version(versions_json: &Vec, req_version: &str) -> Option { let req_version = match Version::parse(req_version) { Ok(v) => v, Err(_) => return None, }; let versions = { let mut versions: Vec = Vec::new(); - for version in versions_json.as_array().unwrap() { - let version: String = version.as_string().unwrap().to_owned(); + for version in versions_json { let version = match Version::parse(&version) { Ok(v) => v, Err(_) => return None, @@ -472,18 +471,13 @@ mod test { #[test] fn test_latest_version() { - let json = r#" - [ - "1.0.0", - "1.1.0", - "0.9.0", - "0.9.1" - ] - "#; - let json = Json::from_str(json).unwrap(); - assert_eq!(latest_version(&json, "1.1.0"), None); - assert_eq!(latest_version(&json, "1.0.0"), Some("1.1.0".to_owned())); - assert_eq!(latest_version(&json, "0.9.0"), Some("1.1.0".to_owned())); - assert_eq!(latest_version(&json, "invalidversion"), None); + let versions = vec!["1.0.0".to_string(), + "1.1.0".to_string(), + "0.9.0".to_string(), + "0.9.1".to_string()]; + assert_eq!(latest_version(&versions, "1.1.0"), None); + assert_eq!(latest_version(&versions, "1.0.0"), Some("1.1.0".to_owned())); + assert_eq!(latest_version(&versions, "0.9.0"), Some("1.1.0".to_owned())); + assert_eq!(latest_version(&versions, "invalidversion"), None); } } diff --git a/src/web/rustdoc.rs b/src/web/rustdoc.rs index 02cb6e64e..a59560e84 100644 --- a/src/web/rustdoc.rs +++ b/src/web/rustdoc.rs @@ -3,8 +3,8 @@ use super::pool::Pool; use super::file::File; -use super::MetaData; use super::latest_version; +use super::crate_details::CrateDetails; use iron::prelude::*; use iron::{status, Url}; use iron::modifiers::Redirect; @@ -26,8 +26,7 @@ struct RustdocPage { pub name: String, pub version: String, pub description: Option, - pub metadata: Option, - pub platforms: Option, + pub crate_details: Option, } @@ -39,8 +38,7 @@ impl Default for RustdocPage { name: String::new(), version: String::new(), description: None, - metadata: None, - platforms: None, + crate_details: None, } } } @@ -55,8 +53,7 @@ impl ToJson for RustdocPage { m.insert("name".to_string(), self.name.to_json()); m.insert("version".to_string(), self.version.to_json()); m.insert("description".to_string(), self.description.to_json()); - m.insert("metadata".to_string(), self.metadata.to_json()); - m.insert("platforms".to_string(), self.platforms.to_json()); + m.insert("crate_details".to_string(), self.crate_details.to_json()); m.to_json() } } @@ -180,34 +177,10 @@ pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult { } } - // content.metadata = MetaData::from_crate(&conn, &name, &version); - let (metadata, platforms, latest_version) = { - let rows = ctry!(conn.query("SELECT crates.name, - releases.version, - releases.description, - releases.target_name, - releases.rustdoc_status, - doc_targets, - crates.versions - FROM releases - INNER JOIN crates ON crates.id = releases.crate_id - WHERE crates.name = $1 AND releases.version = $2", - &[&name, &version])); - - let metadata = MetaData { - name: rows.get(0).get(0), - version: rows.get(0).get(1), - description: rows.get(0).get(2), - target_name: rows.get(0).get(3), - rustdoc_status: rows.get(0).get(4), - }; - let platforms: Json = rows.get(0).get(5); - let versions = rows.get(0).get(6); - (Some(metadata), platforms, latest_version(&versions, &version)) - }; + let crate_details = cexpect!(CrateDetails::new(&conn, &name, &version)); + let latest_version = latest_version(&crate_details.versions, &version); - content.metadata = metadata; - content.platforms = Some(platforms); + content.crate_details = Some(crate_details); Page::new(content) .set_true("show_package_navigation") diff --git a/templates/crate_details.hbs b/templates/crate_details.hbs index e49eef232..2fffe3fa0 100644 --- a/templates/crate_details.hbs +++ b/templates/crate_details.hbs @@ -13,6 +13,7 @@ {{/each}}
  • Links
  • {{#if homepage_url}}
  • Homepage
  • {{/if}} + {{#if documentation_url}}
  • Documentation
  • {{/if}} {{#if github}}
  • {{github_stars}} {{github_forks}} {{github_issues}} diff --git a/templates/navigation_rustdoc.hbs b/templates/navigation_rustdoc.hbs index 865b14eba..2b6baec55 100644 --- a/templates/navigation_rustdoc.hbs +++ b/templates/navigation_rustdoc.hbs @@ -6,10 +6,77 @@ {{/unless}} Docs.rs - {{#with content.metadata}} + {{#with content.crate_details}} diff --git a/templates/rustdoc.hbs b/templates/rustdoc.hbs index 9d425552a..123c779e8 100644 --- a/templates/rustdoc.hbs +++ b/templates/rustdoc.hbs @@ -3,6 +3,7 @@ {{{content.rustdoc_head}}} + diff --git a/templates/style.scss b/templates/style.scss index 66191e974..7f036efc3 100644 --- a/templates/style.scss +++ b/templates/style.scss @@ -171,6 +171,44 @@ div.nav-container { display: inline; } } + + div.package-details-menu { + width: 350px; + + p.description { + font-family: $font-family-sans; + font-size: 0.8em; + color: #777; // color from pure + padding: .5em 1em; + margin: 0; + } + + ul.pure-menu-list { + width: 100%; + } + + div.right-border { + border-right: 1px solid $color-border; + } + + a.pure-menu-link { + word-wrap: normal; + white-space: normal; + } + + div.sub-menu { + max-height: 150px; + overflow-y: auto; + + ul.pure-menu-list { + border-top: none; + } + + li.pure-menu-item:last-child { + border-bottom: none; + } + } + } } }