From 61711efd69e8eaafe3affc938ac91362f59c54ce Mon Sep 17 00:00:00 2001 From: Priyansh Prajapati <88396544+itsspriyansh@users.noreply.github.com> Date: Tue, 20 Aug 2024 00:26:37 +0530 Subject: [PATCH] Add support for Android dotcommands. (#47) --- src/commands/android/dotcommands.ts | 96 +++++++++++++++++++++++++++++ src/commands/android/index.ts | 9 ++- src/constants.ts | 1 + src/index.ts | 4 +- 4 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 src/commands/android/dotcommands.ts diff --git a/src/commands/android/dotcommands.ts b/src/commands/android/dotcommands.ts new file mode 100644 index 0000000..e9378f0 --- /dev/null +++ b/src/commands/android/dotcommands.ts @@ -0,0 +1,96 @@ +import colors from 'ansi-colors'; +import {spawnSync} from 'child_process'; +import * as dotenv from 'dotenv'; +import path from 'path'; + +import {ANDROID_DOTCOMMANDS} from '../../constants'; +import Logger from '../../logger'; +import {getPlatformName} from '../../utils'; +import {Platform, SdkBinary} from './interfaces'; +import {checkJavaInstallation, getBinaryLocation, getBinaryNameForOS, getSdkRootFromEnv} from './utils/common'; + +export class AndroidDotCommand { + dotcmd: string; + args: string[]; + sdkRoot: string; + rootDir: string; + platform: Platform; + androidHomeInGlobalEnv: boolean; + + constructor(dotcmd: string, argv: string[], rootDir = process.cwd()) { + this.dotcmd = dotcmd; + this.args = argv.slice(1); + this.sdkRoot = ''; + this.rootDir = rootDir; + this.platform = getPlatformName(); + this.androidHomeInGlobalEnv = false; + } + + async run(): Promise { + if (!ANDROID_DOTCOMMANDS.includes(this.dotcmd)) { + Logger.log(colors.red(`Unknown dot command passed: ${this.dotcmd}\n`)); + + Logger.log('Run Android SDK command line tools using the following command:'); + Logger.log(colors.cyan('npx @nightwatch/mobile-helper [options|args]\n')); + + Logger.log(`Available Dot Commands: ${colors.magenta(ANDROID_DOTCOMMANDS.join(', '))}`); + Logger.log(`(Example command: ${colors.gray('npx @nightwatch/mobile-helper android.emulator @nightwatch-android-11')})\n`); + + return false; + } + + const javaInstalled = checkJavaInstallation(this.rootDir); + if (!javaInstalled) { + return false; + } + + this.loadEnvFromDotEnv(); + + const sdkRootEnv = getSdkRootFromEnv(this.rootDir, this.androidHomeInGlobalEnv); + if (!sdkRootEnv) { + Logger.log(`Run: ${colors.cyan('npx @nightwatch/mobile-helper android --standalone')} to fix this issue.`); + Logger.log(`(Remove the ${colors.gray('--standalone')} flag from the above command if using the tool for testing.)\n`); + + return false; + } + this.sdkRoot = sdkRootEnv; + + return this.executeDotCommand(); + } + + loadEnvFromDotEnv(): void { + this.androidHomeInGlobalEnv = 'ANDROID_HOME' in process.env; + dotenv.config({path: path.join(this.rootDir, '.env')}); + } + + buildCommand(): string { + const binaryName = this.dotcmd.split('.')[1] as SdkBinary; + const binaryLocation = getBinaryLocation(this.sdkRoot, this.platform, binaryName, true); + + let cmd: string; + if (binaryLocation === 'PATH') { + const binaryFullName = getBinaryNameForOS(this.platform, binaryName); + cmd = `${binaryFullName}`; + } else { + const binaryFullName = path.basename(binaryLocation); + const binaryDirPath = path.dirname(binaryLocation); + cmd = path.join(binaryDirPath, binaryFullName); + } + + return cmd; + } + + executeDotCommand(): boolean { + const cmd = this.buildCommand(); + const result = spawnSync(cmd, this.args, {stdio: 'inherit'}); + + if (result.error) { + console.error(result.error); + + return false; + } + + return result.status === 0; + } +} + diff --git a/src/commands/android/index.ts b/src/commands/android/index.ts index ed7ef0a..f224c3b 100644 --- a/src/commands/android/index.ts +++ b/src/commands/android/index.ts @@ -4,9 +4,14 @@ import {AndroidSetup} from './androidSetup'; import {Options} from './interfaces'; import {AndroidSubcommand} from './subcommands'; import {getSubcommandHelp} from './utils/common'; +import {AndroidDotCommand} from './dotcommands'; -export function handleAndroidCommand(args: string[], options: Options): void { - if (args.length === 1) { +export function handleAndroidCommand(args: string[], options: Options, argv: string[]): void { + if (args[0].includes('.')) { + // Here args[0] represents the android dot command + const androidDotCommand = new AndroidDotCommand(args[0], argv, process.cwd()); + androidDotCommand.run(); + } else if (args.length === 1) { const androidSetup = new AndroidSetup(options); androidSetup.run(); } else if (args.length === 2) { diff --git a/src/constants.ts b/src/constants.ts index 89bb1b4..86c6ca1 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1 +1,2 @@ export const AVAILABLE_COMMANDS = ['android', 'ios']; +export const ANDROID_DOTCOMMANDS = ['android.emulator', 'android.avdmanager', 'android.sdkmanager', 'android.adb']; diff --git a/src/index.ts b/src/index.ts index 24b9c4d..b99e756 100644 --- a/src/index.ts +++ b/src/index.ts @@ -25,8 +25,8 @@ export const run = () => { console.log(`${colors.red('No command passed.')}\n`); } showHelp(); - } else if (args[0] === 'android') { - handleAndroidCommand(args, options); + } else if (args[0].split('.')[0] === 'android') { + handleAndroidCommand(args, options, argv); } else if (args[0] === 'ios') { if (args.length > 1) { // ios command does not accept subcommands.