/src/cargo/ops/cargo_doc.rs

https://gitlab.com/alx741/cargo · Rust · 114 lines · 97 code · 13 blank · 4 comment · 22 complexity · a5ad959af4849fb0d9115965689ede39 MD5 · raw file

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