| use crate::{ |
| autotest, build_binary, build_doc, |
| build_rustc::build_rustc, |
| check_binary, |
| cross::run_pkg_config, |
| device::{netls, ssh, start_emulator, stop_emulator, StartEmulatorOptions}, |
| enable_networking, format_project, |
| package::make_package, |
| random_story_name, run_binary, run_cargo, run_configure, run_program_on_target, |
| run_switches_to_mode, run_tests, |
| sdk::TargetOptions, |
| write_config, FuchsiaConfig, RunCargoOptions, RunMode, DEFAULT_MOD_NAME, |
| }; |
| use failure::Error; |
| use std::path::PathBuf; |
| use structopt::StructOpt; |
| |
| #[derive(Debug, StructOpt)] |
| enum FargoCommand { |
| /// Auto build and test in Fuchsia device or emulator |
| Autotest(Autotest), |
| /// Build binary targeting Fuchsia device or emulator |
| Build(Build), |
| /// Build rustc targeting Fuchsia |
| BuildRustc(BuildRustc), |
| /// Run a cargo command for Fuchsia. Use -- to indicate that all following arguments should be |
| /// passed to cargo. |
| Cargo(Cargo), |
| /// Check binary targeting Fuchsia device or emulator |
| Check(Build), |
| /// Run a configure script for the cross compilation environment |
| Configure(Configure), |
| /// Build a package's documentation |
| Doc(Doc), |
| /// Enable networking for a running emulator |
| EnableNetworking, |
| /// Run cargo fmt using the Fuchsia toolchain |
| Fmt, |
| /// List visible Fuchsia devices |
| ListDevices, |
| /// Make a Fuchsia package from an unstripped binary |
| MakePackage(MakePackage), |
| /// Run pkg-config for the cross compilation environment |
| PkgConfig(PkgConfig), |
| /// Stop all Fuchsia emulators and start a new one |
| Restart(Start), |
| /// Act as as custom runner for Cargo targeting a Fuchsia device |
| RunOnTarget(RunOnTarget), |
| /// Run binary on Fuchsia device or emulator |
| Run(Run), |
| /// Open a shell on Fuchsia device or emulator |
| Ssh, |
| /// Start a Fuchsia emulator |
| Start(Start), |
| /// Stop all Fuchsia emulators |
| Stop, |
| /// Run unit tests on Fuchsia device or emulator |
| Test(Test), |
| /// Write a .cargo/config file to allow cargo to operate correctly for Fuchsia |
| WriteConfig, |
| } |
| |
| #[derive(Debug, StructOpt)] |
| struct Autotest { |
| /// Build artifacts in release mode, with optimizations. |
| #[structopt(long)] |
| release: bool, |
| |
| /// Path to sandbox file to use when running. |
| #[structopt(long)] |
| cmx_path: Option<PathBuf>, |
| |
| /// Display all output when running tests. |
| #[structopt(long)] |
| nocapture: bool, |
| } |
| |
| #[derive(Debug, StructOpt)] |
| struct Build { |
| /// Build artifacts in release mode, with optimizations. |
| #[structopt(long)] |
| release: bool, |
| |
| /// Build artifacts in release mode, with optimizations. |
| #[structopt(short = "p", long)] |
| package: Option<String>, |
| |
| /// Name of the bin target to run. |
| #[structopt(long)] |
| bin: Option<String>, |
| |
| /// Build only the specified test target. |
| #[structopt(long)] |
| test: Option<String>, |
| |
| /// Build all the tests. |
| #[structopt(long)] |
| tests: bool, |
| |
| /// Build a specific example from the examples/ dir. |
| #[structopt(long)] |
| example: Option<String>, |
| |
| /// Build all the examples. |
| #[structopt(long)] |
| examples: bool, |
| } |
| |
| #[derive(Debug, StructOpt)] |
| struct BuildRustc { |
| #[structopt(long)] |
| rust_root: PathBuf, |
| } |
| |
| #[derive(Debug, StructOpt)] |
| struct Cargo { |
| subcommand: String, |
| cargo_params: Vec<String>, |
| } |
| |
| #[derive(Debug, StructOpt)] |
| struct Configure { |
| /// Don't pass --host to configure. |
| #[structopt(long)] |
| no_host: bool, |
| |
| configure_params: Vec<String>, |
| } |
| |
| #[derive(Debug, StructOpt)] |
| struct Doc { |
| /// Opens the docs in a browser after the operation |
| #[structopt(long)] |
| open: bool, |
| |
| /// Don't build documentation for dependencies |
| #[structopt(long)] |
| no_deps: bool, |
| } |
| |
| #[derive(Debug, StructOpt)] |
| struct MakePackage { |
| /// Path to the binary to package |
| #[structopt(long)] |
| binary_path: PathBuf, |
| |
| /// Path to sandbox file to use when running. |
| #[structopt(long)] |
| cmx_path: Option<PathBuf>, |
| |
| /// Name of app as it appears in the manifest file. |
| #[structopt(long, default_value = "app")] |
| app_name: String, |
| } |
| |
| #[derive(Debug, StructOpt)] |
| struct PkgConfig { |
| pkg_config_params: Vec<String>, |
| } |
| |
| #[derive(Debug, StructOpt)] |
| struct Run { |
| /// Build artifacts in release mode, with optimizations. |
| #[structopt(long)] |
| release: bool, |
| |
| /// Use run to run the binary. |
| #[structopt(long)] |
| run_with_run: bool, |
| |
| /// Use tiles_ctl add to run the binary. |
| #[structopt(long)] |
| run_with_tiles: bool, |
| |
| /// Use Use sessionctl to run the binary. |
| #[structopt(long)] |
| run_with_sessionctl: bool, |
| |
| /// Name of app as it appears in the manifest file. |
| #[structopt(long, default_value = "app")] |
| app_name: String, |
| |
| /// Name of story to pass to sessionctl. |
| #[structopt(short = "n", long)] |
| story_name: Option<String>, |
| |
| /// Name of mod to pass to sessionctl. |
| #[structopt(short, long)] |
| mod_name: Option<String>, |
| |
| /// Path to sandbox file to use when running. |
| #[structopt(long)] |
| cmx_path: Option<PathBuf>, |
| |
| /// Package to build. |
| #[structopt(short, long)] |
| package: Option<String>, |
| |
| /// Name of the bin target to run. |
| #[structopt(long)] |
| bin: Option<String>, |
| |
| /// Run a specific example from the examples/ dir. |
| #[structopt(long)] |
| example: Option<String>, |
| } |
| |
| #[derive(Debug, StructOpt)] |
| struct RunOnTarget { |
| /// Path to the binary to run. |
| binary_to_run: String, |
| |
| /// Use run to run the binary. |
| #[structopt(long)] |
| run_with_run: bool, |
| |
| /// Use tiles_ctl add to run the binary. |
| #[structopt(long)] |
| run_with_tiles: bool, |
| |
| /// Use Use sessionctl to run the binary. |
| #[structopt(long)] |
| run_with_sessionctl: bool, |
| |
| /// Name of app as it appears in the manifest file. |
| #[structopt(long, default_value = "app")] |
| app_name: String, |
| |
| /// Name of story to pass to sessionctl. |
| #[structopt(short = "n", long)] |
| story_name: Option<String>, |
| |
| /// Name of mod to pass to sessionctl. |
| #[structopt(short, long)] |
| mod_name: Option<String>, |
| |
| /// Path to sandbox file to use when running. |
| #[structopt(long)] |
| cmx_path: Option<PathBuf>, |
| |
| /// Additional arguments for the binary. |
| runner_args: Vec<String>, |
| |
| /// Display all output when running tests. |
| #[structopt(long)] |
| nocapture: bool, |
| } |
| |
| #[derive(Debug, StructOpt)] |
| struct Start { |
| /// Start aemu instead of qemu |
| #[structopt(short = "a")] |
| aemu: bool, |
| |
| /// Start a simulator with graphics enabled. |
| #[structopt(short = "g")] |
| graphics: bool, |
| |
| /// Start a simulator with acceleration (for qemu, Linux only) |
| #[structopt(short = "k")] |
| with_acceleration: bool, |
| |
| /// Don't set up networking |
| #[structopt(long)] |
| no_net: bool, |
| |
| /// Do not launch the virtual console service if this option is present |
| #[structopt(long)] |
| disable_virtcon: bool, |
| start_params: Vec<String>, |
| } |
| |
| #[derive(Debug, StructOpt)] |
| struct Test { |
| /// Build artifacts in release mode, with optimizations. |
| #[structopt(long)] |
| release: bool, |
| |
| /// Use run to run the test. |
| #[structopt(long)] |
| run_with_run: bool, |
| |
| #[structopt(long)] |
| /// Test only the specified test target. |
| test: Option<String>, |
| |
| /// Display all output when running tests. |
| #[structopt(long)] |
| nocapture: bool, |
| |
| /// Name of the bin target to test. |
| #[structopt(long)] |
| bin: Option<String>, |
| |
| /// RunTest a specific example from the examples/ dir. |
| #[structopt(long)] |
| example: Option<String>, |
| |
| /// Arguments to pass to the test runner. |
| #[structopt(long)] |
| test_args: Option<String>, |
| |
| /// Path to sandbox file to use when testing via run. |
| #[structopt(long)] |
| cmx_path: Option<PathBuf>, |
| |
| /// Package to build. |
| #[structopt(short, long)] |
| package: Option<String>, |
| |
| test_params: Vec<String>, |
| } |
| |
| #[derive(Debug, StructOpt)] |
| #[structopt(name = "fargo", about = "Fargo is a prototype Fuchsia-specific wrapper around Cargo.")] |
| struct FargoOption { |
| /// Print verbose output while performing commands |
| #[structopt(short, long)] |
| verbose: bool, |
| |
| /// Disable the setting of CC, AR and such environmental variables |
| #[structopt(long)] |
| disable_cross_env: bool, |
| |
| /// Name of device to target, needed if there are multiple devices visible on the network |
| #[structopt(short = "N", long)] |
| device_name: Option<String>, |
| |
| /// Path to Cargo.toml |
| #[structopt(long, global = true)] |
| manifest_path: Option<PathBuf>, |
| |
| #[structopt(subcommand)] |
| command: FargoCommand, |
| } |
| |
| fn to_opt_str(value: &Option<String>) -> Option<&str> { |
| value.as_ref().map(String::as_str) |
| } |
| |
| fn build_params(build_opts: &Build) -> Vec<&str> { |
| let mut params = vec![]; |
| if let Some(package) = build_opts.package.as_ref() { |
| params.push("--package"); |
| params.push(package); |
| } |
| if let Some(bin) = build_opts.bin.as_ref() { |
| params.push("--bin"); |
| params.push(bin); |
| } |
| if let Some(test) = build_opts.test.as_ref() { |
| params.push("--test"); |
| params.push(&test); |
| } |
| if build_opts.tests { |
| params.push("--tests"); |
| } |
| if let Some(example) = build_opts.example.as_ref() { |
| params.push("--example"); |
| params.push(example); |
| } |
| if build_opts.examples { |
| params.push("--examples"); |
| } |
| params |
| } |
| |
| #[doc(hidden)] |
| pub fn run() -> Result<(), Error> { |
| let opt = FargoOption::from_args(); |
| let verbose = opt.verbose; |
| let fuchsia_config = FuchsiaConfig::new_from_fx_exec()?; |
| if verbose { |
| println!("fuchsia_config = {:#?}", fuchsia_config); |
| } |
| |
| let target_options = |
| TargetOptions::new(&fuchsia_config, opt.device_name.as_ref().map(String::as_str)); |
| let run_cargo_options = RunCargoOptions { verbose, ..RunCargoOptions::default() }; |
| |
| match opt.command { |
| FargoCommand::Autotest(autotest_opts) => { |
| return autotest( |
| &run_cargo_options |
| .release(autotest_opts.release) |
| .manifest_path(opt.manifest_path) |
| .cmx_path(autotest_opts.cmx_path) |
| .nocapture(autotest_opts.nocapture), |
| &target_options, |
| ); |
| } |
| |
| FargoCommand::Build(build_opts) => { |
| let params = build_params(&build_opts); |
| build_binary( |
| &run_cargo_options.release(build_opts.release).manifest_path(opt.manifest_path), |
| &target_options, |
| ¶ms, |
| )?; |
| return Ok(()); |
| } |
| |
| FargoCommand::BuildRustc(build_rustc_opts) => { |
| return build_rustc(&build_rustc_opts.rust_root, &target_options); |
| } |
| |
| FargoCommand::Cargo(cargo_opts) => { |
| let cargo_params: Vec<&str> = |
| cargo_opts.cargo_params.iter().map(String::as_str).collect(); |
| return run_cargo( |
| &RunCargoOptions { |
| verbose, |
| release: false, |
| nocapture: false, |
| run_mode: RunMode::Run, |
| story_name: None, |
| mod_name: None, |
| disable_cross: opt.disable_cross_env, |
| manifest_path: None, |
| cmx_path: None, |
| app_name: None, |
| }, |
| cargo_opts.subcommand.as_ref(), |
| &cargo_params, |
| &target_options, |
| None, |
| None, |
| ); |
| } |
| |
| FargoCommand::Check(build_opts) => { |
| let params = build_params(&build_opts); |
| check_binary( |
| &run_cargo_options.release(build_opts.release).manifest_path(opt.manifest_path), |
| &target_options, |
| ¶ms, |
| )?; |
| return Ok(()); |
| } |
| |
| FargoCommand::Configure(config_opts) => { |
| let configure_params: Vec<&str> = |
| config_opts.configure_params.iter().map(String::as_str).collect(); |
| run_configure(opt.verbose, config_opts.no_host, &configure_params, &target_options)?; |
| return Ok(()); |
| } |
| |
| FargoCommand::Doc(doc_opts) => { |
| return build_doc( |
| &run_cargo_options.manifest_path(opt.manifest_path), |
| &target_options, |
| doc_opts.no_deps, |
| doc_opts.open, |
| ); |
| } |
| |
| FargoCommand::EnableNetworking => { |
| return enable_networking(); |
| } |
| |
| FargoCommand::Fmt => { |
| format_project(opt.manifest_path)?; |
| return Ok(()); |
| } |
| |
| FargoCommand::ListDevices => { |
| return netls(opt.verbose, &target_options); |
| } |
| |
| FargoCommand::MakePackage(make_package_opts) => { |
| println!( |
| "make package {}", |
| make_package( |
| verbose, |
| &target_options, |
| &make_package_opts.binary_path, |
| &make_package_opts.cmx_path, |
| &make_package_opts.app_name |
| )? |
| ); |
| return Ok(()); |
| } |
| |
| FargoCommand::PkgConfig(pkg_config_opts) => { |
| let pkg_params: Vec<&str> = |
| pkg_config_opts.pkg_config_params.iter().map(String::as_str).collect(); |
| let exit_code = run_pkg_config(verbose, &pkg_params, &target_options)?; |
| if exit_code != 0 { |
| ::std::process::exit(exit_code); |
| } |
| return Ok(()); |
| } |
| |
| FargoCommand::Restart(start_opts) => { |
| stop_emulator()?; |
| |
| let fx_run_params: Vec<&str> = |
| start_opts.start_params.iter().map(String::as_str).collect(); |
| |
| return start_emulator( |
| &StartEmulatorOptions { |
| verbose: verbose, |
| aemu: start_opts.aemu, |
| with_graphics: start_opts.graphics, |
| with_acceleration: start_opts.with_acceleration, |
| with_networking: !start_opts.no_net, |
| disable_virtcon: start_opts.disable_virtcon, |
| }, |
| &fx_run_params, |
| ); |
| } |
| |
| FargoCommand::Run(run) => { |
| let mut params = vec![]; |
| |
| if let Some(package) = run.package.as_ref() { |
| params.push("--package"); |
| params.push(package); |
| } |
| if let Some(bin) = run.bin.as_ref() { |
| params.push("--bin"); |
| params.push(bin); |
| } |
| |
| if let Some(example) = run.example.as_ref() { |
| params.push("--example"); |
| params.push(example); |
| } |
| |
| let run_mode = run_switches_to_mode(run.run_with_tiles, run.run_with_sessionctl); |
| return run_binary( |
| &run_cargo_options |
| .release(run.release) |
| .run_mode(run_mode) |
| .story_name(&to_opt_str(&run.story_name)) |
| .mod_name(&to_opt_str(&run.mod_name)) |
| .app_name(&Some(&run.app_name)) |
| .manifest_path(opt.manifest_path) |
| .cmx_path(run.cmx_path), |
| &target_options, |
| ¶ms, |
| ); |
| } |
| |
| FargoCommand::RunOnTarget(run_on_target) => { |
| let run_cargo_options = run_cargo_options.cmx_path(run_on_target.cmx_path); |
| let run_params: Vec<&str> = run_on_target.runner_args.iter().map(|s| &**s).collect(); |
| let run_mode = run_switches_to_mode( |
| run_on_target.run_with_tiles, |
| run_on_target.run_with_sessionctl, |
| ); |
| |
| return run_program_on_target( |
| &run_on_target.binary_to_run, |
| verbose, |
| run_on_target.nocapture, |
| &fuchsia_config, |
| &target_options, |
| run_mode, |
| &run_cargo_options.cmx_path, |
| &run_on_target.story_name.unwrap_or(random_story_name()), |
| &run_on_target.mod_name.unwrap_or(DEFAULT_MOD_NAME.to_string()), |
| &run_on_target.app_name, |
| &run_params, |
| None, |
| ); |
| } |
| |
| FargoCommand::Ssh => { |
| return ssh(opt.verbose, &fuchsia_config, &target_options, ""); |
| } |
| |
| FargoCommand::Start(start_opts) => { |
| let fx_run_params: Vec<&str> = |
| start_opts.start_params.iter().map(String::as_str).collect(); |
| |
| return start_emulator( |
| &StartEmulatorOptions { |
| verbose: verbose, |
| aemu: start_opts.aemu, |
| with_graphics: start_opts.graphics, |
| with_acceleration: start_opts.with_acceleration, |
| with_networking: !start_opts.no_net, |
| disable_virtcon: start_opts.disable_virtcon, |
| }, |
| &fx_run_params, |
| ); |
| } |
| |
| FargoCommand::Stop => { |
| return stop_emulator(); |
| } |
| |
| FargoCommand::Test(test_opts) => { |
| let mut params = vec![]; |
| if let Some(package) = test_opts.package.as_ref() { |
| params.push("--package"); |
| params.push(package); |
| } |
| |
| if let Some(bin) = test_opts.bin.as_ref() { |
| params.push("--bin"); |
| params.push(bin); |
| } |
| |
| if let Some(example) = test_opts.example.as_ref() { |
| params.push("--example"); |
| params.push(example); |
| } |
| |
| let test_params: Vec<&str> = test_opts.test_params.iter().map(String::as_str).collect(); |
| |
| params.extend(test_params); |
| |
| if let Some(test) = test_opts.test.as_ref() { |
| params.push("--test"); |
| params.push(test); |
| } |
| |
| let test_args = test_opts.test_args; |
| |
| let run_mode = run_switches_to_mode(false, false); |
| return run_tests( |
| &run_cargo_options |
| .cmx_path(test_opts.cmx_path) |
| .run_mode(run_mode) |
| .release(test_opts.release) |
| .manifest_path(opt.manifest_path) |
| .nocapture(test_opts.nocapture), |
| false, |
| &target_options, |
| ¶ms, |
| to_opt_str(&test_args), |
| ); |
| } |
| |
| FargoCommand::WriteConfig => { |
| return write_config(&run_cargo_options, &target_options); |
| } |
| } |
| } |