1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use std::collections::HashSet;
use std::fs;
use std::path::Path;
use std::process::Command;
use core::{Package, PackageIdSpec};
use ops;
use util::CargoResult;
pub struct DocOptions<'a> {
pub open_result: bool,
pub compile_opts: ops::CompileOptions<'a>,
}
pub fn doc(manifest_path: &Path,
options: &DocOptions) -> CargoResult<()> {
let package = try!(Package::for_path(manifest_path, options.compile_opts.config));
let mut lib_names = HashSet::new();
let mut bin_names = HashSet::new();
if options.compile_opts.spec.is_empty() {
for target in package.targets().iter().filter(|t| t.documented()) {
if target.is_lib() {
assert!(lib_names.insert(target.crate_name()));
} else {
assert!(bin_names.insert(target.crate_name()));
}
}
for bin in bin_names.iter() {
if lib_names.contains(bin) {
bail!("cannot document a package where a library and a binary \
have the same name. Consider renaming one or marking \
the target as `doc = false`")
}
}
}
try!(ops::compile(manifest_path, &options.compile_opts));
if options.open_result {
let name = if options.compile_opts.spec.len() > 1 {
bail!("Passing multiple packages and `open` is not supported")
} else if options.compile_opts.spec.len() == 1 {
try!(PackageIdSpec::parse(&options.compile_opts.spec[0]))
.name().replace("-", "_")
} else {
match lib_names.iter().chain(bin_names.iter()).nth(0) {
Some(s) => s.to_string(),
None => return Ok(())
}
};
let target_dir = options.compile_opts.config.target_dir(&package);
let path = target_dir.join("doc").join(&name).join("index.html");
let path = path.into_path_unlocked();
if fs::metadata(&path).is_ok() {
let mut shell = options.compile_opts.config.shell();
match open_docs(&path) {
Ok(m) => try!(shell.status("Launching", m)),
Err(e) => {
try!(shell.warn(
"warning: could not determine a browser to open docs with, tried:"));
for method in e {
try!(shell.warn(format!("\t{}", method)));
}
}
}
}
}
Ok(())
}
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
use std::env;
let mut methods = Vec::new();
match env::var("BROWSER"){
Ok(name) => match Command::new(name).arg(path).status() {
Ok(_) => return Ok("$BROWSER"),
Err(_) => methods.push("$BROWSER")
},
Err(_) => ()
}
for m in ["xdg-open", "gnome-open", "kde-open"].iter() {
match Command::new(m).arg(path).status() {
Ok(_) => return Ok(m),
Err(_) => methods.push(m)
}
}
Err(methods)
}
#[cfg(target_os = "windows")]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
match Command::new("cmd").arg("/C").arg("start").arg("").arg(path).status() {
Ok(_) => return Ok("cmd /C start"),
Err(_) => return Err(vec!["cmd /C start"])
};
}
#[cfg(target_os = "macos")]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
match Command::new("open").arg(path).status() {
Ok(_) => return Ok("open"),
Err(_) => return Err(vec!["open"])
};
}