Skip to content

Commit 62fdcf6

Browse files
committed
Add docs.rs metadata and custom builds
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: #29, #48 and #50 - [ ] Save default target to database. - [ ] Install system dependencies before building a package.
1 parent 1dbc521 commit 62fdcf6

File tree

6 files changed

+193
-5
lines changed

6 files changed

+193
-5
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ libc = "0.2"
3232
hoedown = "5.0"
3333
badge = { version = "0", path = "src/web/badge" }
3434
error-chain = "0.5"
35+
toml = "0.2"
3536

3637
[dependencies.cargo]
3738
git = "https://github.com/rust-lang/cargo.git"

src/docbuilder/metadata.rs

+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
2+
use std::path::Path;
3+
use cargo::core::Package;
4+
use toml;
5+
6+
7+
/// Metadata for custom builds
8+
///
9+
/// You can customize docs.rs builds by defining `[package.metadata.docs.rs]` table in your
10+
/// crates' `Cargo.toml`.
11+
///
12+
/// An example metadata:
13+
///
14+
/// ```text
15+
/// [package]
16+
/// name = "test"
17+
///
18+
/// [package.metadata.docs.rs]
19+
/// features = [ "feature1", "feature2" ]
20+
/// all-features = true
21+
/// no-default-features = true
22+
/// default-target = "x86_64-unknown-linux-gnu"
23+
/// rustc-args = [ "--example-rustc-arg" ]
24+
/// rustdoc-args = [ "--example-rustdoc-arg" ]
25+
/// dependencies = [ "example-system-dependency" ]
26+
/// ```
27+
///
28+
/// You can define one or more fields in your `Cargo.toml`.
29+
pub struct Metadata {
30+
/// List of features docs.rs will build.
31+
///
32+
/// By default, docs.rs will only build default features.
33+
pub features: Option<Vec<String>>,
34+
35+
/// Set `all-features` to true if you want docs.rs to build all features for your crate
36+
pub all_features: bool,
37+
38+
/// Docs.rs will always build default features.
39+
///
40+
/// Set `no-default-fatures` to `false` if you want to build only certain features.
41+
pub no_default_features: bool,
42+
43+
/// Docs.rs is running on `x86_64-unknown-linux-gnu` target system and default documentation
44+
/// is always built on this target. You can change default target by setting this.
45+
pub default_target: Option<String>,
46+
47+
/// List of command line arguments for `rustc`.
48+
pub rustc_args: Option<Vec<String>>,
49+
50+
/// List of command line arguments for `rustdoc`.
51+
pub rustdoc_args: Option<Vec<String>>,
52+
53+
/// System dependencies.
54+
///
55+
/// Docs.rs is running on a Debian jessie.
56+
pub dependencies: Option<Vec<String>>,
57+
}
58+
59+
60+
61+
impl Metadata {
62+
pub fn from_package(pkg: &Package) -> Metadata {
63+
Metadata::from_manifest(pkg.manifest_path())
64+
}
65+
66+
pub fn from_manifest<P: AsRef<Path>>(path: P) -> Metadata {
67+
use std::fs::File;
68+
use std::io::Read;
69+
let mut f = match File::open(path) {
70+
Ok(f) => f,
71+
Err(_) => return Metadata::default(),
72+
};
73+
let mut s = String::new();
74+
if let Err(_) = f.read_to_string(&mut s) {
75+
return Metadata::default();
76+
}
77+
Metadata::from_str(&s)
78+
}
79+
80+
81+
// This is similar to Default trait but it's private
82+
fn default() -> Metadata {
83+
Metadata {
84+
features: None,
85+
all_features: false,
86+
no_default_features: false,
87+
default_target: None,
88+
rustc_args: None,
89+
rustdoc_args: None,
90+
dependencies: None,
91+
}
92+
}
93+
94+
95+
fn from_str(manifest: &str) -> Metadata {
96+
let mut metadata = Metadata::default();
97+
98+
let manifest = match toml::Parser::new(manifest).parse() {
99+
Some(m) => m,
100+
None => return metadata,
101+
};
102+
103+
if let Some(table) = manifest.get("package").and_then(|p| p.as_table())
104+
.and_then(|p| p.get("metadata")).and_then(|p| p.as_table())
105+
.and_then(|p| p.get("docs")).and_then(|p| p.as_table())
106+
.and_then(|p| p.get("rs")).and_then(|p| p.as_table()) {
107+
metadata.features = table.get("features").and_then(|f| f.as_slice())
108+
.and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
109+
metadata.no_default_features = table.get("no-default-features")
110+
.and_then(|v| v.as_bool()).unwrap_or(metadata.no_default_features);
111+
metadata.all_features = table.get("all-features")
112+
.and_then(|v| v.as_bool()).unwrap_or(metadata.all_features);
113+
metadata.default_target = table.get("default-target")
114+
.and_then(|v| v.as_str()).map(|v| v.to_owned());
115+
metadata.rustc_args = table.get("rustc-args").and_then(|f| f.as_slice())
116+
.and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
117+
metadata.rustdoc_args = table.get("rustdoc-args").and_then(|f| f.as_slice())
118+
.and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
119+
metadata.dependencies = table.get("dependencies").and_then(|f| f.as_slice())
120+
.and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
121+
}
122+
123+
metadata
124+
}
125+
}
126+
127+
128+
129+
#[cfg(test)]
130+
mod test {
131+
extern crate env_logger;
132+
use super::Metadata;
133+
134+
#[test]
135+
fn test_cratesfyi_metadata() {
136+
let _ = env_logger::init();
137+
let manifest = r#"
138+
[package]
139+
name = "test"
140+
141+
[package.metadata.docs.rs]
142+
features = [ "feature1", "feature2" ]
143+
all-features = true
144+
no-default-features = true
145+
default-target = "x86_64-unknown-linux-gnu"
146+
rustc-args = [ "--example-rustc-arg" ]
147+
rustdoc-args = [ "--example-rustdoc-arg" ]
148+
dependencies = [ "example-system-dependency" ]
149+
"#;
150+
151+
let metadata = Metadata::from_str(manifest);
152+
153+
assert!(metadata.features.is_some());
154+
assert!(metadata.all_features == true);
155+
assert!(metadata.no_default_features == true);
156+
assert!(metadata.default_target.is_some());
157+
assert!(metadata.rustc_args.is_some());
158+
assert!(metadata.rustdoc_args.is_some());
159+
160+
let features = metadata.features.unwrap();
161+
assert_eq!(features.len(), 2);
162+
assert_eq!(features[0], "feature1".to_owned());
163+
assert_eq!(features[1], "feature2".to_owned());
164+
165+
assert_eq!(metadata.default_target.unwrap(), "x86_64-unknown-linux-gnu".to_owned());
166+
167+
let rustc_args = metadata.rustc_args.unwrap();
168+
assert_eq!(rustc_args.len(), 1);
169+
assert_eq!(rustc_args[0], "--example-rustc-arg".to_owned());
170+
171+
let rustdoc_args = metadata.rustdoc_args.unwrap();
172+
assert_eq!(rustdoc_args.len(), 1);
173+
assert_eq!(rustdoc_args[0], "--example-rustdoc-arg".to_owned());
174+
175+
let dependencies = metadata.dependencies.unwrap();
176+
assert_eq!(dependencies.len(), 1);
177+
assert_eq!(dependencies[0], "example-system-dependency".to_owned());
178+
}
179+
}

src/docbuilder/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
pub mod options;
3+
pub mod metadata;
34
mod chroot_builder;
45
mod crates;
56
mod queue;

src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@ extern crate url;
2626
extern crate params;
2727
extern crate libc;
2828
extern crate badge;
29+
extern crate toml;
2930

3031
pub use self::docbuilder::DocBuilder;
3132
pub use self::docbuilder::ChrootBuilderResult;
3233
pub use self::docbuilder::options::DocBuilderOptions;
34+
pub use self::docbuilder::metadata::Metadata;
3335
pub use self::web::start_web_server;
3436

3537
pub mod errors;

src/utils/build_doc.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use cargo::util::{CargoResult, Config, human, Filesystem};
1111
use cargo::sources::SourceConfigMap;
1212
use cargo::ops;
1313

14+
use Metadata;
15+
1416

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

47+
let metadata = Metadata::from_package(&pkg);
48+
4549
let opts = ops::CompileOptions {
4650
config: &config,
4751
jobs: None,
4852
target: target,
49-
features: &[],
50-
all_features: false,
51-
no_default_features: false,
53+
features: &metadata.features.unwrap_or(Vec::new()),
54+
all_features: metadata.all_features,
55+
no_default_features: metadata.no_default_features,
5256
spec: &[],
5357
mode: ops::CompileMode::Doc { deps: false },
5458
release: false,
5559
message_format: ops::MessageFormat::Human,
5660
filter: ops::CompileFilter::new(true, &[], &[], &[], &[]),
57-
target_rustc_args: None,
58-
target_rustdoc_args: None,
61+
target_rustc_args: metadata.rustc_args.as_ref().map(Vec::as_slice),
62+
target_rustdoc_args: metadata.rustdoc_args.as_ref().map(Vec::as_slice),
5963
};
6064

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

0 commit comments

Comments
 (0)