|
| 1 | +#![warn(rust_2018_idioms)] // while we're getting used to 2018 |
| 2 | +#![allow(clippy::all)] |
| 3 | +#![warn(clippy::needless_borrow)] |
| 4 | +#![warn(clippy::redundant_clone)] |
| 5 | + |
| 6 | +use cargo::core::compiler::{ |
| 7 | + unit_graph, BuildContext, BuildRunner, DefaultExecutor, Executor, UnitInterner, |
| 8 | +}; |
| 9 | +use cargo::core::shell::Shell; |
| 10 | +use cargo::core::Workspace; |
| 11 | +use cargo::ops::CompileOptions; |
| 12 | +use cargo::util::network::http::{http_handle, needs_custom_http_transport}; |
| 13 | +use cargo::util::{command_prelude, CliResult, GlobalContext}; |
| 14 | +use std::env; |
| 15 | +use std::sync::Arc; |
| 16 | + |
| 17 | +use crate::command_prelude::*; |
| 18 | + |
| 19 | +fn main() { |
| 20 | + setup_logger(); |
| 21 | + |
| 22 | + let mut config = match GlobalContext::default() { |
| 23 | + Ok(cfg) => cfg, |
| 24 | + Err(e) => { |
| 25 | + let mut shell = Shell::new(); |
| 26 | + cargo::exit_with_error(e.into(), &mut shell) |
| 27 | + } |
| 28 | + }; |
| 29 | + |
| 30 | + let result = main2(&mut config); |
| 31 | + |
| 32 | + match result { |
| 33 | + Err(e) => cargo::exit_with_error(e, &mut *config.shell()), |
| 34 | + Ok(()) => {} |
| 35 | + } |
| 36 | +} |
| 37 | + |
| 38 | +fn main2(config: &mut GlobalContext) -> CliResult { |
| 39 | + let args: Vec<_> = env::args().collect(); |
| 40 | + let mut subargs = args.split(|x| *x == "---"); |
| 41 | + |
| 42 | + let mut global_args = subargs.next().unwrap().to_vec(); |
| 43 | + if global_args.len() >= 2 && global_args[1] == "batch" { |
| 44 | + global_args.remove(1); |
| 45 | + } |
| 46 | + let global_args = Command::new("cargo-batch") |
| 47 | + .arg_unit_graph() |
| 48 | + .arg_target_dir() |
| 49 | + .arg( |
| 50 | + opt( |
| 51 | + "verbose", |
| 52 | + "Use verbose output (-vv very verbose/build.rs output)", |
| 53 | + ) |
| 54 | + .short('v') |
| 55 | + .action(ArgAction::Count) |
| 56 | + .global(true), |
| 57 | + ) |
| 58 | + .arg_silent_suggestion() |
| 59 | + .arg( |
| 60 | + opt("color", "Coloring: auto, always, never") |
| 61 | + .value_name("WHEN") |
| 62 | + .global(true), |
| 63 | + ) |
| 64 | + .arg( |
| 65 | + flag("frozen", "Require Cargo.lock and cache are up to date") |
| 66 | + .help_heading(heading::MANIFEST_OPTIONS) |
| 67 | + .global(true), |
| 68 | + ) |
| 69 | + .arg( |
| 70 | + flag("locked", "Require Cargo.lock is up to date") |
| 71 | + .help_heading(heading::MANIFEST_OPTIONS) |
| 72 | + .global(true), |
| 73 | + ) |
| 74 | + .arg( |
| 75 | + flag("offline", "Run without accessing the network") |
| 76 | + .help_heading(heading::MANIFEST_OPTIONS) |
| 77 | + .global(true), |
| 78 | + ) |
| 79 | + .arg(multi_opt("config", "KEY=VALUE", "Override a configuration value").global(true)) |
| 80 | + .arg( |
| 81 | + Arg::new("unstable-features") |
| 82 | + .help("Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details") |
| 83 | + .short('Z') |
| 84 | + .value_name("FLAG") |
| 85 | + .action(ArgAction::Append) |
| 86 | + .global(true), |
| 87 | + ) |
| 88 | + .try_get_matches_from(global_args)?; |
| 89 | + |
| 90 | + config_configure(config, &global_args)?; |
| 91 | + init_git_transports(config); |
| 92 | + |
| 93 | + let unit_graph = global_args.flag("unit-graph"); |
| 94 | + |
| 95 | + struct CommandState<'a> { |
| 96 | + ws: Workspace<'a>, |
| 97 | + compile_opts: CompileOptions, |
| 98 | + } |
| 99 | + |
| 100 | + let mut cmds = Vec::new(); |
| 101 | + for args in subargs { |
| 102 | + let cli = build_cli(); |
| 103 | + let args = cli.try_get_matches_from(args)?; |
| 104 | + //println!("args opts: {:#?}", args); |
| 105 | + |
| 106 | + let ws = args.workspace(config)?; |
| 107 | + |
| 108 | + let mut compile_opts = args.compile_options( |
| 109 | + config, |
| 110 | + CompileMode::Build, |
| 111 | + Some(&ws), |
| 112 | + ProfileChecking::Custom, |
| 113 | + )?; |
| 114 | + if let Some(out_dir) = args.value_of_path("out-dir", config) { |
| 115 | + compile_opts.build_config.export_dir = Some(out_dir); |
| 116 | + } else if let Some(out_dir) = config.build_config()?.out_dir.as_ref() { |
| 117 | + let out_dir = out_dir.resolve_path(config); |
| 118 | + compile_opts.build_config.export_dir = Some(out_dir); |
| 119 | + } |
| 120 | + //if compile_opts.build_config.export_dir.is_some() { |
| 121 | + // config |
| 122 | + // .cli_unstable() |
| 123 | + // .fail_if_stable_opt("--out-dir", 6790)?; |
| 124 | + //} |
| 125 | + |
| 126 | + //println!("compile opts: {:#?}", compile_opts); |
| 127 | + cmds.push(CommandState { ws, compile_opts }); |
| 128 | + } |
| 129 | + |
| 130 | + let interner = UnitInterner::new(); |
| 131 | + let mut merged_bcx: Option<BuildContext<'_, '_>> = None; |
| 132 | + |
| 133 | + for cmd in &cmds { |
| 134 | + let mut bcx = cargo::ops::create_bcx(&cmd.ws, &cmd.compile_opts, &interner).unwrap(); |
| 135 | + if let Some(export_dir) = &cmd.compile_opts.build_config.export_dir { |
| 136 | + for root in &bcx.roots { |
| 137 | + bcx.unit_export_dirs |
| 138 | + .insert(root.clone(), export_dir.clone()); |
| 139 | + } |
| 140 | + } |
| 141 | + |
| 142 | + if let Some(merged_bcx) = &mut merged_bcx { |
| 143 | + // merge!!! |
| 144 | + merged_bcx.unit_graph.extend(bcx.unit_graph); |
| 145 | + merged_bcx.roots.extend(bcx.roots); |
| 146 | + merged_bcx.unit_export_dirs.extend(bcx.unit_export_dirs); |
| 147 | + merged_bcx.all_kinds.extend(bcx.all_kinds); |
| 148 | + merged_bcx |
| 149 | + .target_data |
| 150 | + .target_config |
| 151 | + .extend(bcx.target_data.target_config); |
| 152 | + merged_bcx |
| 153 | + .target_data |
| 154 | + .target_info |
| 155 | + .extend(bcx.target_data.target_info); |
| 156 | + merged_bcx.packages.packages.extend(bcx.packages.packages); |
| 157 | + merged_bcx |
| 158 | + .packages |
| 159 | + .sources |
| 160 | + .borrow_mut() |
| 161 | + .add_source_map(bcx.packages.sources.into_inner()); |
| 162 | + } else { |
| 163 | + merged_bcx = Some(bcx) |
| 164 | + } |
| 165 | + } |
| 166 | + |
| 167 | + let bcx = merged_bcx.unwrap(); |
| 168 | + |
| 169 | + if unit_graph { |
| 170 | + unit_graph::emit_serialized_unit_graph(&bcx.roots, &bcx.unit_graph, bcx.ws.gctx())?; |
| 171 | + return Ok(()); |
| 172 | + } |
| 173 | + |
| 174 | + // util::profile disappeared between cargo 1.76 and cargo 1.78 |
| 175 | + // let _p = cargo::util::profile::start("compiling"); |
| 176 | + let cx = BuildRunner::new(&bcx)?; |
| 177 | + let exec: Arc<dyn Executor> = Arc::new(DefaultExecutor); |
| 178 | + cx.compile(&exec)?; |
| 179 | + |
| 180 | + Ok(()) |
| 181 | +} |
| 182 | + |
| 183 | +fn config_configure(config: &mut GlobalContext, args: &ArgMatches) -> CliResult { |
| 184 | + let arg_target_dir = &args.value_of_path("target-dir", config); |
| 185 | + let verbose = args.verbose(); |
| 186 | + // quiet is unusual because it is redefined in some subcommands in order |
| 187 | + // to provide custom help text. |
| 188 | + let quiet = args.flag("quiet"); |
| 189 | + let color = args.get_one::<String>("color").map(String::as_str); |
| 190 | + let frozen = args.flag("frozen"); |
| 191 | + let locked = args.flag("locked"); |
| 192 | + let offline = args.flag("offline"); |
| 193 | + let mut unstable_flags = vec![]; |
| 194 | + if let Some(values) = args.get_many::<String>("unstable-features") { |
| 195 | + unstable_flags.extend(values.cloned()); |
| 196 | + } |
| 197 | + let mut config_args = vec![]; |
| 198 | + if let Some(values) = args.get_many::<String>("config") { |
| 199 | + config_args.extend(values.cloned()); |
| 200 | + } |
| 201 | + config.configure( |
| 202 | + verbose, |
| 203 | + quiet, |
| 204 | + color, |
| 205 | + frozen, |
| 206 | + locked, |
| 207 | + offline, |
| 208 | + arg_target_dir, |
| 209 | + &unstable_flags, |
| 210 | + &config_args, |
| 211 | + )?; |
| 212 | + Ok(()) |
| 213 | +} |
| 214 | + |
| 215 | +pub fn build_cli() -> Command { |
| 216 | + subcommand("build") |
| 217 | + .about("Compile a local package and all of its dependencies") |
| 218 | + .arg_ignore_rust_version() |
| 219 | + .arg_future_incompat_report() |
| 220 | + .arg_message_format() |
| 221 | + .arg_silent_suggestion() |
| 222 | + .arg_package_spec( |
| 223 | + "Package to build (see `cargo help pkgid`)", |
| 224 | + "Build all packages in the workspace", |
| 225 | + "Exclude packages from the build", |
| 226 | + ) |
| 227 | + .arg_targets_all( |
| 228 | + "Build only this package's library", |
| 229 | + "Build only the specified binary", |
| 230 | + "Build all binaries", |
| 231 | + "Build only the specified example", |
| 232 | + "Build all examples", |
| 233 | + "Build only the specified test target", |
| 234 | + "Build all tests", |
| 235 | + "Build only the specified bench target", |
| 236 | + "Build all benches", |
| 237 | + "Build all targets", |
| 238 | + ) |
| 239 | + .arg_features() |
| 240 | + .arg_release("Build artifacts in release mode, with optimizations") |
| 241 | + .arg_profile("Build artifacts with the specified profile") |
| 242 | + .arg_parallel() |
| 243 | + .arg_target_triple("Build for the target triple") |
| 244 | + .arg( |
| 245 | + opt( |
| 246 | + "out-dir", |
| 247 | + "Copy final artifacts to this directory (unstable)", |
| 248 | + ) |
| 249 | + .value_name("PATH") |
| 250 | + .help_heading(heading::COMPILATION_OPTIONS), |
| 251 | + ) |
| 252 | + .arg_build_plan() |
| 253 | + .arg_unit_graph() |
| 254 | + .arg_timings() |
| 255 | + .arg_manifest_path() |
| 256 | + .after_help("Run `cargo help build` for more detailed information.\n") |
| 257 | +} |
| 258 | + |
| 259 | +fn setup_logger() { |
| 260 | + let env = tracing_subscriber::EnvFilter::from_env("CARGO_LOG"); |
| 261 | + |
| 262 | + tracing_subscriber::fmt() |
| 263 | + .with_timer(tracing_subscriber::fmt::time::Uptime::default()) |
| 264 | + .with_ansi(std::io::IsTerminal::is_terminal(&std::io::stderr())) |
| 265 | + .with_writer(std::io::stderr) |
| 266 | + .with_env_filter(env) |
| 267 | + .init(); |
| 268 | + tracing::trace!(start = humantime::format_rfc3339(std::time::SystemTime::now()).to_string()); |
| 269 | +} |
| 270 | + |
| 271 | +/// Configure libgit2 to use libcurl if necessary. |
| 272 | +/// |
| 273 | +/// If the user has a non-default network configuration, then libgit2 will be |
| 274 | +/// configured to use libcurl instead of the built-in networking support so |
| 275 | +/// that those configuration settings can be used. |
| 276 | +fn init_git_transports(config: &GlobalContext) { |
| 277 | + match needs_custom_http_transport(config) { |
| 278 | + Ok(true) => {} |
| 279 | + _ => return, |
| 280 | + } |
| 281 | + |
| 282 | + let handle = match http_handle(config) { |
| 283 | + Ok(handle) => handle, |
| 284 | + Err(..) => return, |
| 285 | + }; |
| 286 | + |
| 287 | + // The unsafety of the registration function derives from two aspects: |
| 288 | + // |
| 289 | + // 1. This call must be synchronized with all other registration calls as |
| 290 | + // well as construction of new transports. |
| 291 | + // 2. The argument is leaked. |
| 292 | + // |
| 293 | + // We're clear on point (1) because this is only called at the start of this |
| 294 | + // binary (we know what the state of the world looks like) and we're mostly |
| 295 | + // clear on point (2) because we'd only free it after everything is done |
| 296 | + // anyway |
| 297 | + unsafe { |
| 298 | + git2_curl::register(handle); |
| 299 | + } |
| 300 | +} |
0 commit comments