Skip to content

Commit

Permalink
Add docs.rs metadata and custom builds
Browse files Browse the repository at this point in the history
This patch is adding `Metadata` type used in `cargo::ops::CompileOptions` to customize
docs.rs builds.

An example metadata in Cargo.toml:

```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"
rustc-args = [ "--example-rustc-arg" ]
rustdoc-args = [ "--example-rustdoc-arg" ]
dependencies = [ "example-system-dependency" ]
```

This patch is still work in progress and aiming to fix: rust-lang#29, rust-lang#48 and rust-lang#50

- [ ] Save default target to database.
- [ ] Install system dependencies before building a package.
  • Loading branch information
onur committed Oct 20, 2016
1 parent 1dbc521 commit 62fdcf6
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 5 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ libc = "0.2"
hoedown = "5.0"
badge = { version = "0", path = "src/web/badge" }
error-chain = "0.5"
toml = "0.2"

[dependencies.cargo]
git = "https://github.com/rust-lang/cargo.git"
Expand Down
179 changes: 179 additions & 0 deletions src/docbuilder/metadata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@

use std::path::Path;
use cargo::core::Package;
use toml;


/// 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"
/// rustc-args = [ "--example-rustc-arg" ]
/// 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<Vec<String>>,

/// 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<String>,

/// List of command line arguments for `rustc`.
pub rustc_args: Option<Vec<String>>,

/// List of command line arguments for `rustdoc`.
pub rustdoc_args: Option<Vec<String>>,

/// System dependencies.
///
/// Docs.rs is running on a Debian jessie.
pub dependencies: Option<Vec<String>>,
}



impl Metadata {
pub fn from_package(pkg: &Package) -> Metadata {
Metadata::from_manifest(pkg.manifest_path())
}

pub fn from_manifest<P: AsRef<Path>>(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,
rustc_args: None,
rustdoc_args: None,
dependencies: None,
}
}


fn from_str(manifest: &str) -> Metadata {
let mut metadata = Metadata::default();

let manifest = match toml::Parser::new(manifest).parse() {
Some(m) => m,
None => 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_slice())
.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.rustc_args = table.get("rustc-args").and_then(|f| f.as_slice())
.and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
metadata.rustdoc_args = table.get("rustdoc-args").and_then(|f| f.as_slice())
.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_slice())
.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.rustc_args.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 rustc_args = metadata.rustc_args.unwrap();
assert_eq!(rustc_args.len(), 1);
assert_eq!(rustc_args[0], "--example-rustc-arg".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());
}
}
1 change: 1 addition & 0 deletions src/docbuilder/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

pub mod options;
pub mod metadata;
mod chroot_builder;
mod crates;
mod queue;
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ extern crate url;
extern crate params;
extern crate libc;
extern crate badge;
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 errors;
Expand Down
14 changes: 9 additions & 5 deletions src/utils/build_doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use cargo::util::{CargoResult, Config, human, Filesystem};
use cargo::sources::SourceConfigMap;
use cargo::ops;

use Metadata;


/// Builds documentation of a crate and version.
///
Expand Down Expand Up @@ -42,20 +44,22 @@ pub fn build_doc(name: &str, vers: Option<&str>, target: Option<&str>) -> CargoR
let target_dir = PathBuf::from(current_dir)
.join(format!("{}-{}", pkg.manifest().name(), pkg.manifest().version()));

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: &[],
mode: ops::CompileMode::Doc { deps: false },
release: false,
message_format: ops::MessageFormat::Human,
filter: ops::CompileFilter::new(true, &[], &[], &[], &[]),
target_rustc_args: None,
target_rustdoc_args: None,
target_rustc_args: metadata.rustc_args.as_ref().map(Vec::as_slice),
target_rustdoc_args: metadata.rustdoc_args.as_ref().map(Vec::as_slice),
};

let ws = try!(Workspace::one(pkg, &config, Some(Filesystem::new(target_dir))));
Expand Down

0 comments on commit 62fdcf6

Please sign in to comment.