Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to cargo-subcommand 0.8.0 with clap argument parser #238

Merged
merged 8 commits into from
Sep 23, 2022
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ members = [
"ndk-sys",
"cargo-apk",
]

[patch.crates-io]
cargo-subcommand = { git = "https://github.com/dvc94ch/cargo-subcommand", branch = "master" }
MarijnS95 marked this conversation as resolved.
Show resolved Hide resolved
3 changes: 2 additions & 1 deletion cargo-apk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ repository = "https://github.com/rust-windowing/android-ndk-rs"
[dependencies]
anyhow = "1.0.57"
cargo-subcommand = "0.7"
clap = { version = "3", features = ["derive"] }
dunce = "1"
env_logger = "0.9"
log = "0.4"
ndk-build = { path = "../ndk-build", version = "0.8.0" }
serde = "1"
thiserror = "1.0.31"
thiserror = "1"
toml = "0.5"
24 changes: 9 additions & 15 deletions cargo-apk/src/apk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,12 @@ pub struct ApkBuilder<'a> {
build_dir: PathBuf,
build_targets: Vec<Target>,
device_serial: Option<String>,
no_logcat: bool,
}

impl<'a> ApkBuilder<'a> {
pub fn from_subcommand(
cmd: &'a Subcommand,
device_serial: Option<String>,
no_logcat: bool,
) -> Result<Self, Error> {
let ndk = Ndk::from_env()?;
let mut manifest = Manifest::parse_from_toml(cmd.manifest())?;
Expand Down Expand Up @@ -101,7 +99,6 @@ impl<'a> ApkBuilder<'a> {
build_dir,
build_targets,
device_serial,
no_logcat,
})
}

Expand All @@ -118,7 +115,7 @@ impl<'a> ApkBuilder<'a> {
let triple = target.rust_triple();
cargo.arg("--target").arg(triple);
}
cargo.args(self.cmd.args());
self.cmd.args().apply(&mut cargo);
MarijnS95 marked this conversation as resolved.
Show resolved Hide resolved
if !cargo.status()?.success() {
return Err(NdkError::CmdFailed(cargo).into());
}
Expand Down Expand Up @@ -184,12 +181,8 @@ impl<'a> ApkBuilder<'a> {

for target in &self.build_targets {
let triple = target.rust_triple();
let build_dir = dunce::simplified(self.cmd.target_dir())
.join(triple)
.join(self.cmd.profile());
let artifact = build_dir
.join(artifact)
.join(artifact.file_name(CrateType::Cdylib, triple));
let build_dir = self.cmd.build_dir(Some(triple));
let artifact = self.cmd.artifact(artifact, Some(triple), CrateType::Cdylib);

let mut cargo = cargo_ndk(
&self.ndk,
Expand All @@ -201,7 +194,7 @@ impl<'a> ApkBuilder<'a> {
if self.cmd.target().is_none() {
cargo.arg("--target").arg(triple);
}
cargo.args(self.cmd.args());
self.cmd.args().apply(&mut cargo);

if !cargo.status()?.success() {
return Err(NdkError::CmdFailed(cargo).into());
Expand Down Expand Up @@ -243,12 +236,12 @@ impl<'a> ApkBuilder<'a> {
Ok(apk.add_pending_libs_and_align()?.sign(signing_key)?)
}

pub fn run(&self, artifact: &Artifact) -> Result<(), Error> {
pub fn run(&self, artifact: &Artifact, no_logcat: bool) -> Result<(), Error> {
let apk = self.build(artifact)?;
apk.install(self.device_serial.as_deref())?;
let pid = apk.start(self.device_serial.as_deref())?;

if !self.no_logcat {
if !no_logcat {
self.ndk
.adb(self.device_serial.as_deref())?
.arg("logcat")
Expand All @@ -275,15 +268,16 @@ impl<'a> ApkBuilder<'a> {
Ok(())
}

pub fn default(&self) -> Result<(), Error> {
pub fn default(&self, cargo_cmd: &str) -> Result<(), Error> {
for target in &self.build_targets {
let mut cargo = cargo_ndk(
&self.ndk,
*target,
self.min_sdk_version(),
self.cmd.target_dir(),
)?;
cargo.args(self.cmd.args());
cargo.arg(cargo_cmd);
self.cmd.args().apply(&mut cargo);

if self.cmd.target().is_none() {
let triple = target.rust_triple();
Expand Down
181 changes: 89 additions & 92 deletions cargo-apk/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,112 +1,109 @@
use cargo_apk::{ApkBuilder, Error};
use cargo_subcommand::Subcommand;
use std::process::Command;
use clap::Parser;

#[derive(Parser)]
struct Cmd {
#[clap(subcommand)]
apk: ApkCmd,
}

#[derive(clap::Subcommand)]
enum ApkCmd {
/// Helps cargo build apks for Android
Apk {
#[clap(subcommand)]
cmd: ApkSubCmd,
},
}

#[derive(Parser)]
struct Args {
#[clap(flatten)]
subcommand_args: cargo_subcommand::Args,
/// Use device with the given serial (see `adb devices`)
#[clap(short, long)]
device: Option<String>,
}

#[derive(clap::Subcommand)]
#[clap(trailing_var_arg = true)]
enum ApkSubCmd {
/// Analyze the current package and report errors, but don't build object files nor an apk
#[clap(visible_alias = "c")]
Check {
#[clap(flatten)]
args: Args,
},
/// Compile the current package and create an apk
#[clap(visible_alias = "b")]
Build {
#[clap(flatten)]
args: Args,
},
/// Invoke `cargo` under the detected NDK environment
#[clap(name = "--")]
Ndk {
cargo_cmd: String,
#[clap(flatten)]
args: Args,
},
/// Run a binary or example apk of the local package
#[clap(visible_alias = "r")]
Run {
MarijnS95 marked this conversation as resolved.
Show resolved Hide resolved
#[clap(flatten)]
args: Args,
/// Do not print or follow `logcat` after running the app
#[clap(short, long)]
no_logcat: bool,
},
/// Start a gdb session attached to an adb device with symbols loaded
Gdb {
#[clap(flatten)]
args: Args,
},
/// Print the version of cargo-apk
Version,
}

fn main() -> anyhow::Result<()> {
env_logger::init();
let args = std::env::args();
let mut device_serial = None;
let mut no_logcat = false;
let cmd = Subcommand::new(args, "apk", |name, value| match name {
"--device" => {
if let Some(value) = value {
println!("Running on {}", value);
device_serial = Some(value.to_owned());
Ok(true)
} else {
Err(cargo_subcommand::Error::InvalidArgs)
}
}
"--no-logcat" => {
no_logcat = true;
Ok(true)
let Cmd {
apk: ApkCmd::Apk { cmd },
} = Cmd::parse();
match cmd {
ApkSubCmd::Check { args } => {
let cmd = Subcommand::new(args.subcommand_args)?;
let builder = ApkBuilder::from_subcommand(&cmd, args.device)?;
builder.check()?;
}
_ => Ok(false),
})
.map_err(Error::Subcommand)?;

let builder = ApkBuilder::from_subcommand(&cmd, device_serial, no_logcat)?;

match cmd.cmd() {
"check" | "c" => builder.check()?,
"build" | "b" => {
ApkSubCmd::Build { args } => {
let cmd = Subcommand::new(args.subcommand_args)?;
let builder = ApkBuilder::from_subcommand(&cmd, args.device)?;
for artifact in cmd.artifacts() {
builder.build(artifact)?;
}
}
"run" | "r" => {
anyhow::ensure!(cmd.artifacts().len() == 1, Error::invalid_args());
builder.run(&cmd.artifacts()[0])?;
ApkSubCmd::Ndk { cargo_cmd, args } => {
let cmd = Subcommand::new(args.subcommand_args)?;
let builder = ApkBuilder::from_subcommand(&cmd, args.device)?;
builder.default(&cargo_cmd)?;
}
"--" => {
builder.default()?;
ApkSubCmd::Run { args, no_logcat } => {
let cmd = Subcommand::new(args.subcommand_args)?;
let builder = ApkBuilder::from_subcommand(&cmd, args.device)?;
anyhow::ensure!(cmd.artifacts().len() == 1, Error::invalid_args());
builder.run(&cmd.artifacts()[0], no_logcat)?;
}
"gdb" => {
ApkSubCmd::Gdb { args } => {
let cmd = Subcommand::new(args.subcommand_args)?;
let builder = ApkBuilder::from_subcommand(&cmd, args.device)?;
anyhow::ensure!(cmd.artifacts().len() == 1, Error::invalid_args());
builder.gdb(&cmd.artifacts()[0])?;
}
"help" => {
if let Some(arg) = cmd.args().get(0) {
match &**arg {
"build" | "b" | "check" | "c" | "run" | "r" | "test" | "t" | "doc" => {
run_cargo(&cmd)?
}
"gdb" => print_gdb_help(),
_ => print_help(),
}
} else {
print_help();
}
}
"version" => {
ApkSubCmd::Version => {
println!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
}
_ => print_help(),
}

Ok(())
}

fn run_cargo(cmd: &Subcommand) -> Result<(), Error> {
Command::new("cargo")
.arg(cmd.cmd())
.args(cmd.args())
.status()?;
Ok(())
}

fn print_help() {
println!(
r#"cargo-apk
Helps cargo build apk's for android

USAGE:
cargo apk [SUBCOMMAND]

SUBCOMMAND:
check, c Checks that the current package builds without creating an apk
build, b Compiles the current package and creates an apk
run, r Run a binary or example of the local package
gdb Start a gdb session attached to an adb device with symbols loaded
version Print the version of cargo-apk

FLAGS:
--no-logcat Don't print and follow `logcat` after running the application.

OPTIONS:
--device <serial> Use device with the given serial. See `adb devices` for a list of
connected Android devices.
"#
);
}

fn print_gdb_help() {
println!(
r#"cargo-apk gdb
Start a gdb session attached to an adb device with symbols loaded

USAGE:
cargo apk gdb
"#
);
}