Skip to content

Commit 63bc4c8

Browse files
Dirbaiorichardeoin
andcommitted
Add cargo-batch.
Co-Authored-By: Richard Meadows <962920+richardeoin@users.noreply.github.com>
1 parent 2c8d176 commit 63bc4c8

File tree

7 files changed

+335
-40
lines changed

7 files changed

+335
-40
lines changed

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,11 @@ name = "cargo"
251251
test = false
252252
doc = false
253253

254+
[[bin]]
255+
name = "cargo-batch"
256+
test = false
257+
doc = false
258+
254259
[features]
255260
vendored-openssl = ["openssl/vendored"]
256261
vendored-libgit2 = ["libgit2-sys/vendored"]

src/bin/cargo-batch.rs

Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
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+
}

src/cargo/core/compiler/build_context/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::util::errors::CargoResult;
1010
use crate::util::interning::InternedString;
1111
use crate::util::Rustc;
1212
use std::collections::{HashMap, HashSet};
13+
use std::path::PathBuf;
1314

1415
mod target_info;
1516
pub use self::target_info::{
@@ -78,6 +79,8 @@ pub struct BuildContext<'a, 'gctx> {
7879

7980
/// The list of all kinds that are involved in this build
8081
pub all_kinds: HashSet<CompileKind>,
82+
83+
pub unit_export_dirs: HashMap<Unit, PathBuf>,
8184
}
8285

8386
impl<'a, 'gctx> BuildContext<'a, 'gctx> {
@@ -111,6 +114,7 @@ impl<'a, 'gctx> BuildContext<'a, 'gctx> {
111114
unit_graph,
112115
scrape_units,
113116
all_kinds,
117+
unit_export_dirs: HashMap::new(),
114118
})
115119
}
116120

src/cargo/core/compiler/build_context/target_info.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -873,9 +873,9 @@ pub struct RustcTargetData<'gctx> {
873873
host_info: TargetInfo,
874874

875875
/// Build information for targets that we're building for.
876-
target_config: HashMap<CompileTarget, TargetConfig>,
876+
pub target_config: HashMap<CompileTarget, TargetConfig>,
877877
/// Information about the target platform that we're building for.
878-
target_info: HashMap<CompileTarget, TargetInfo>,
878+
pub target_info: HashMap<CompileTarget, TargetInfo>,
879879
}
880880

881881
impl<'gctx> RustcTargetData<'gctx> {

0 commit comments

Comments
 (0)