/cargo-container-tools/src/bin/cargo-build-plan/main.rs

https://github.com/denzp/cargo-wharf · Rust · 174 lines · 146 code · 28 blank · 0 comment · 7 complexity · cb1af5f63e728a9a71350e2c406d86b1 MD5 · raw file

  1. #![deny(warnings)]
  2. #![deny(clippy::all)]
  3. use std::env::{current_dir, current_exe};
  4. use std::fs::File;
  5. use std::io::{copy, BufWriter};
  6. use std::process::{exit, Command, Stdio};
  7. use std::sync::Arc;
  8. use cargo::core::compiler::{BuildConfig, CompileMode, DefaultExecutor, Executor};
  9. use cargo::core::{Shell, Workspace};
  10. use cargo::ops::{CompileFilter, CompileOptions, FilterRule, LibRule, Packages};
  11. use cargo::util::{config::Config, CargoResult};
  12. use clap::{crate_authors, crate_version, App, Arg, ArgMatches};
  13. use failure::{bail, ResultExt};
  14. fn main() {
  15. let matches = get_cli_app().get_matches();
  16. if let Err(error) = run(&matches) {
  17. cargo::handle_error(&error, &mut Shell::new());
  18. exit(1);
  19. }
  20. }
  21. fn get_cli_app() -> App<'static, 'static> {
  22. App::new("cargo-build-plan")
  23. .version(crate_version!())
  24. .author(crate_authors!())
  25. .about("Tiny Rust build plan writer")
  26. .args(&[
  27. {
  28. Arg::with_name("output")
  29. .long("output")
  30. .takes_value(true)
  31. .value_name("PATH")
  32. .default_value("-")
  33. .help("Build plan output path (or '-' for STDOUT)")
  34. },
  35. {
  36. Arg::with_name("manifest")
  37. .long("manifest-path")
  38. .takes_value(true)
  39. .value_name("PATH")
  40. .default_value("Cargo.toml")
  41. .help("Path to Cargo.toml")
  42. },
  43. {
  44. Arg::with_name("target")
  45. .long("target")
  46. .takes_value(true)
  47. .value_name("TARGET")
  48. .help("Target triple for which the code is compiled")
  49. },
  50. {
  51. Arg::with_name("release")
  52. .long("release")
  53. .takes_value(false)
  54. .help("Build artifacts in release mode, with optimizations")
  55. },
  56. {
  57. Arg::with_name("no_default_features")
  58. .long("no-default-features")
  59. .takes_value(false)
  60. .help("Disable crate default features")
  61. },
  62. {
  63. Arg::with_name("features")
  64. .long("feature")
  65. .takes_value(true)
  66. .value_name("NAME")
  67. .multiple(true)
  68. .help("Target triple for which the code is compiled")
  69. },
  70. ])
  71. }
  72. fn run(matches: &ArgMatches<'static>) -> CargoResult<()> {
  73. let mut writer = BufWriter::new(match matches.value_of("output").unwrap() {
  74. "-" => return run_stdout(matches),
  75. path => File::create(path)?,
  76. });
  77. let mut process = Command::new(current_exe()?);
  78. process.stdout(Stdio::piped());
  79. process.stderr(Stdio::inherit());
  80. if matches.is_present("release") {
  81. process.arg("--release");
  82. }
  83. if matches.is_present("no_default_features") {
  84. process.arg("--no-default-features");
  85. }
  86. if let Some(path) = matches.value_of("manifest") {
  87. process.arg("--manifest-path").arg(path);
  88. }
  89. if let Some(target) = matches.value_of("target") {
  90. process.arg("--target").arg(target);
  91. }
  92. for feature in matches.values_of("features").unwrap_or_default() {
  93. process.arg("--feature").arg(feature);
  94. }
  95. let mut child = process.spawn()?;
  96. copy(&mut child.stdout.take().unwrap(), &mut writer)
  97. .context("Unable to copy child stdout into output")?;
  98. let exit_code = child.wait().context("Failed to wait on child")?;
  99. if !exit_code.success() {
  100. bail!("Child process failed");
  101. }
  102. Ok(())
  103. }
  104. fn run_stdout(matches: &ArgMatches<'static>) -> CargoResult<()> {
  105. let mut config = Config::default()?;
  106. config.configure(0, None, &None, false, true, false, &None, &[])?;
  107. let mut build_config = BuildConfig::new(&config, Some(1), &None, CompileMode::Build)?;
  108. build_config.release = matches.is_present("release");
  109. build_config.force_rebuild = true;
  110. build_config.build_plan = true;
  111. build_config.requested_target = matches.value_of("target").map(String::from);
  112. let features = {
  113. matches
  114. .values_of("features")
  115. .unwrap_or_default()
  116. .map(String::from)
  117. .collect()
  118. };
  119. let options = CompileOptions {
  120. config: &config,
  121. build_config,
  122. features,
  123. all_features: false,
  124. no_default_features: matches.is_present("no_default_features"),
  125. spec: Packages::All,
  126. filter: CompileFilter::Only {
  127. all_targets: true,
  128. lib: LibRule::Default,
  129. bins: FilterRule::All,
  130. examples: FilterRule::All,
  131. tests: FilterRule::All,
  132. benches: FilterRule::All,
  133. },
  134. target_rustdoc_args: None,
  135. target_rustc_args: None,
  136. local_rustdoc_args: None,
  137. export_dir: None,
  138. };
  139. let executor: Arc<dyn Executor> = Arc::new(DefaultExecutor);
  140. let ws = Workspace::new(
  141. &current_dir()?.join(matches.value_of("manifest").unwrap()),
  142. &config,
  143. )?;
  144. cargo::ops::compile_ws(&ws, &options, &executor)?;
  145. Ok(())
  146. }