-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
261 additions
and
222 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,19 @@ | ||
# android shell | ||
|
||
TODO | ||
```ignore | ||
USAGE: | ||
android shell | ||
OPTIONS: | ||
-h, --help Print help information | ||
``` | ||
|
||
## What it does | ||
|
||
It simply asks `adb` to attach a shell to your connected android device / emulator by executing `adb shell`. | ||
|
||
## Example | ||
|
||
```sh | ||
$ android shell | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,8 @@ | ||
pub mod build; | ||
pub mod create; | ||
pub mod devices; | ||
pub mod install; | ||
pub mod launch; | ||
pub mod link; | ||
pub mod run; | ||
pub mod build; | ||
pub mod create; | ||
pub mod devices; | ||
pub mod install; | ||
pub mod launch; | ||
pub mod link; | ||
pub mod run; | ||
pub mod shell; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
use anyhow::{bail, Result}; | ||
use clap::Parser; | ||
|
||
#[derive(Parser, Debug)] | ||
pub struct Shell {} | ||
|
||
pub fn handle(_args: Shell) -> Result<()> { | ||
// Try to run adb shell | ||
let query_status = android_cli::attach_shell()?; | ||
|
||
if !query_status.success() { | ||
bail!("failed to attach shell"); | ||
} | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,168 +1,172 @@ | ||
mod utils; | ||
|
||
use anyhow::{Context, Result}; | ||
use guidon::{GitOptions, Guidon, TryNew}; | ||
use itertools::Itertools; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
use std::{ | ||
collections::BTreeMap, | ||
path::{Path, PathBuf}, | ||
process::{Command, ExitStatus}, | ||
}; | ||
|
||
use utils::{find_adb, find_gradle}; | ||
|
||
pub const VERSION: &str = env!("CARGO_PKG_VERSION"); | ||
pub const DEFAULT_MAIN_ACTIVITY: &str = "MainActivity"; | ||
|
||
const DEFAULT_TEMPLATE_REPO: &str = "https://github.com/SyedAhkam/android-cli-template"; | ||
const TEMPLATE_REV: &str = "master"; | ||
|
||
const DOTFILE_COMMENT: &str = "// DO NOT MODIFY; Generated by Android CLI for internal usage.\n"; | ||
|
||
#[derive(Debug, Serialize, Deserialize)] | ||
pub struct DotAndroid { | ||
pub project_name: String, | ||
pub package_id: String, | ||
pub gen_at_version: String, | ||
pub main_activity_name: String, | ||
} | ||
|
||
pub fn copy_template(dest: &Path, vars: BTreeMap<String, String>) -> Result<()> { | ||
let git_options = GitOptions::builder() | ||
.repo(DEFAULT_TEMPLATE_REPO) | ||
.rev(TEMPLATE_REV) | ||
.build() | ||
.unwrap(); | ||
|
||
let mut guidon = Guidon::try_new(git_options)?; | ||
|
||
guidon.variables(vars); | ||
guidon.apply_template(dest)?; | ||
|
||
Ok(()) | ||
} | ||
|
||
pub fn create_local_properties_file(root: &Path, sdk_path: &str) -> Result<()> { | ||
let sdk_path = Path::new(sdk_path); | ||
let prop_file_path = PathBuf::new().join(root).join("local.properties"); | ||
|
||
// It is necessary to escape paths on windows | ||
let content = if cfg!(windows) { | ||
format!("sdk.dir={}", sdk_path.display()).replace("\\", "\\\\") | ||
} else { | ||
format!("sdk.dir={}", sdk_path.display()) | ||
}; | ||
|
||
if sdk_path.exists() { | ||
std::fs::write(prop_file_path, content).context("Unable to write local.properties file")?; | ||
} else { | ||
eprintln!("warning: did not create local.properties file because of invalid sdk path") | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
pub fn invoke_gradle_command(cmd: &str) -> Result<ExitStatus> { | ||
let gradle_path = find_gradle().context("ERROR: Gradle not found on system")?; | ||
|
||
let mut run = Command::new(gradle_path); | ||
run.arg(cmd); | ||
|
||
println!( | ||
"Invoking Gradle: {} {}", | ||
&run.get_program().to_string_lossy(), | ||
&run.get_args().map(|arg| arg.to_string_lossy()).join(" ") | ||
); | ||
|
||
Ok(run.status()?) | ||
} | ||
|
||
pub fn invoke_adb_command(args: &[&str]) -> Result<ExitStatus> { | ||
let adb_path = find_adb().context("ERROR: ADB not found on system")?; | ||
|
||
let mut run = Command::new(adb_path); | ||
run.args(args); | ||
|
||
println!( | ||
"Invoking ADB: {} {}", | ||
&run.get_program().to_string_lossy(), | ||
&run.get_args().map(|arg| arg.to_string_lossy()).join(" ") | ||
); | ||
|
||
Ok(run.status()?) | ||
} | ||
|
||
pub fn create_dot_android( | ||
dest: &Path, | ||
project_name: String, | ||
package_id: String, | ||
main_activity_name: Option<String>, | ||
) -> Result<()> { | ||
// Construct the structure | ||
let dot_android = DotAndroid { | ||
package_id, | ||
project_name, | ||
gen_at_version: VERSION.to_owned(), | ||
main_activity_name: main_activity_name.unwrap_or(DEFAULT_MAIN_ACTIVITY.to_owned()), | ||
}; | ||
|
||
// Serialize into Ron | ||
let mut ron_contents = | ||
ron::ser::to_string_pretty(&dot_android, ron::ser::PrettyConfig::default())?; | ||
|
||
// Add a comment at top | ||
ron_contents.insert_str(0, DOTFILE_COMMENT); | ||
|
||
// Write to file | ||
let path = PathBuf::from(dest).join(".android"); | ||
std::fs::write(path, ron_contents).context("failed to write .android file")?; | ||
|
||
Ok(()) | ||
} | ||
|
||
pub fn get_dot_android() -> Option<DotAndroid> { | ||
if let Ok(contents) = std::fs::read_to_string(".android") { | ||
return ron::from_str::<DotAndroid>(&contents).ok(); | ||
}; | ||
|
||
None | ||
} | ||
|
||
pub fn install_apk(is_release: bool) -> Result<ExitStatus> { | ||
let output_dir = PathBuf::from("app/build/outputs/apk"); | ||
|
||
let apk_path = match is_release { | ||
true => output_dir.join("release/app-release.apk"), | ||
false => output_dir.join("debug/app-debug.apk"), | ||
}; | ||
|
||
Ok(invoke_adb_command(&["install", apk_path.to_str().unwrap()]) | ||
.context("failed to run adb command")?) | ||
} | ||
|
||
pub fn trigger_build(is_release: bool) -> Result<ExitStatus> { | ||
// Decide gradle subcommand to use | ||
let cmd = match is_release { | ||
true => "assembleRelease", | ||
false => "assembleDebug", | ||
}; | ||
|
||
Ok(invoke_gradle_command(cmd).context("failed to invoke gradle command")?) | ||
} | ||
|
||
pub fn launch_activity(package_id: String, activity_name: String) -> Result<ExitStatus> { | ||
Ok(invoke_adb_command(&[ | ||
"shell", | ||
"am", | ||
"start", | ||
"-n", | ||
&format!("{}/.{}", package_id, activity_name), | ||
]) | ||
.context("failed to invoke adb command")?) | ||
} | ||
|
||
pub fn query_devices() -> Result<ExitStatus> { | ||
Ok(invoke_adb_command(&["devices"]).context("failed to invoke adb command")?) | ||
} | ||
mod utils; | ||
|
||
use anyhow::{Context, Result}; | ||
use guidon::{GitOptions, Guidon, TryNew}; | ||
use itertools::Itertools; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
use std::{ | ||
collections::BTreeMap, | ||
path::{Path, PathBuf}, | ||
process::{Command, ExitStatus}, | ||
}; | ||
|
||
use utils::{find_adb, find_gradle}; | ||
|
||
pub const VERSION: &str = env!("CARGO_PKG_VERSION"); | ||
pub const DEFAULT_MAIN_ACTIVITY: &str = "MainActivity"; | ||
|
||
const DEFAULT_TEMPLATE_REPO: &str = "https://github.com/SyedAhkam/android-cli-template"; | ||
const TEMPLATE_REV: &str = "master"; | ||
|
||
const DOTFILE_COMMENT: &str = "// DO NOT MODIFY; Generated by Android CLI for internal usage.\n"; | ||
|
||
#[derive(Debug, Serialize, Deserialize)] | ||
pub struct DotAndroid { | ||
pub project_name: String, | ||
pub package_id: String, | ||
pub gen_at_version: String, | ||
pub main_activity_name: String, | ||
} | ||
|
||
pub fn copy_template(dest: &Path, vars: BTreeMap<String, String>) -> Result<()> { | ||
let git_options = GitOptions::builder() | ||
.repo(DEFAULT_TEMPLATE_REPO) | ||
.rev(TEMPLATE_REV) | ||
.build() | ||
.unwrap(); | ||
|
||
let mut guidon = Guidon::try_new(git_options)?; | ||
|
||
guidon.variables(vars); | ||
guidon.apply_template(dest)?; | ||
|
||
Ok(()) | ||
} | ||
|
||
pub fn create_local_properties_file(root: &Path, sdk_path: &str) -> Result<()> { | ||
let sdk_path = Path::new(sdk_path); | ||
let prop_file_path = PathBuf::new().join(root).join("local.properties"); | ||
|
||
// It is necessary to escape paths on windows | ||
let content = if cfg!(windows) { | ||
format!("sdk.dir={}", sdk_path.display()).replace("\\", "\\\\") | ||
} else { | ||
format!("sdk.dir={}", sdk_path.display()) | ||
}; | ||
|
||
if sdk_path.exists() { | ||
std::fs::write(prop_file_path, content).context("Unable to write local.properties file")?; | ||
} else { | ||
eprintln!("warning: did not create local.properties file because of invalid sdk path") | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
pub fn invoke_gradle_command(cmd: &str) -> Result<ExitStatus> { | ||
let gradle_path = find_gradle().context("ERROR: Gradle not found on system")?; | ||
|
||
let mut run = Command::new(gradle_path); | ||
run.arg(cmd); | ||
|
||
println!( | ||
"Invoking Gradle: {} {}", | ||
&run.get_program().to_string_lossy(), | ||
&run.get_args().map(|arg| arg.to_string_lossy()).join(" ") | ||
); | ||
|
||
Ok(run.status()?) | ||
} | ||
|
||
pub fn invoke_adb_command(args: &[&str]) -> Result<ExitStatus> { | ||
let adb_path = find_adb().context("ERROR: ADB not found on system")?; | ||
|
||
let mut run = Command::new(adb_path); | ||
run.args(args); | ||
|
||
println!( | ||
"Invoking ADB: {} {}", | ||
&run.get_program().to_string_lossy(), | ||
&run.get_args().map(|arg| arg.to_string_lossy()).join(" ") | ||
); | ||
|
||
Ok(run.status()?) | ||
} | ||
|
||
pub fn create_dot_android( | ||
dest: &Path, | ||
project_name: String, | ||
package_id: String, | ||
main_activity_name: Option<String>, | ||
) -> Result<()> { | ||
// Construct the structure | ||
let dot_android = DotAndroid { | ||
package_id, | ||
project_name, | ||
gen_at_version: VERSION.to_owned(), | ||
main_activity_name: main_activity_name.unwrap_or(DEFAULT_MAIN_ACTIVITY.to_owned()), | ||
}; | ||
|
||
// Serialize into Ron | ||
let mut ron_contents = | ||
ron::ser::to_string_pretty(&dot_android, ron::ser::PrettyConfig::default())?; | ||
|
||
// Add a comment at top | ||
ron_contents.insert_str(0, DOTFILE_COMMENT); | ||
|
||
// Write to file | ||
let path = PathBuf::from(dest).join(".android"); | ||
std::fs::write(path, ron_contents).context("failed to write .android file")?; | ||
|
||
Ok(()) | ||
} | ||
|
||
pub fn get_dot_android() -> Option<DotAndroid> { | ||
if let Ok(contents) = std::fs::read_to_string(".android") { | ||
return ron::from_str::<DotAndroid>(&contents).ok(); | ||
}; | ||
|
||
None | ||
} | ||
|
||
pub fn install_apk(is_release: bool) -> Result<ExitStatus> { | ||
let output_dir = PathBuf::from("app/build/outputs/apk"); | ||
|
||
let apk_path = match is_release { | ||
true => output_dir.join("release/app-release.apk"), | ||
false => output_dir.join("debug/app-debug.apk"), | ||
}; | ||
|
||
Ok(invoke_adb_command(&["install", apk_path.to_str().unwrap()]) | ||
.context("failed to run adb command")?) | ||
} | ||
|
||
pub fn trigger_build(is_release: bool) -> Result<ExitStatus> { | ||
// Decide gradle subcommand to use | ||
let cmd = match is_release { | ||
true => "assembleRelease", | ||
false => "assembleDebug", | ||
}; | ||
|
||
Ok(invoke_gradle_command(cmd).context("failed to invoke gradle command")?) | ||
} | ||
|
||
pub fn launch_activity(package_id: String, activity_name: String) -> Result<ExitStatus> { | ||
Ok(invoke_adb_command(&[ | ||
"shell", | ||
"am", | ||
"start", | ||
"-n", | ||
&format!("{}/.{}", package_id, activity_name), | ||
]) | ||
.context("failed to invoke adb command")?) | ||
} | ||
|
||
pub fn query_devices() -> Result<ExitStatus> { | ||
Ok(invoke_adb_command(&["devices"]).context("failed to invoke adb command")?) | ||
} | ||
|
||
pub fn attach_shell() -> Result<ExitStatus> { | ||
Ok(invoke_adb_command(&["shell"]).context("failed to invoke adb command")?) | ||
} |
Oops, something went wrong.