From a0bd15eaa6fd25c9f62e0dd0900dd44e5fa3c31a Mon Sep 17 00:00:00 2001 From: Lorenz Sieben Date: Mon, 21 Oct 2024 19:30:07 +0200 Subject: [PATCH 1/3] Fixes #11: Install emulator package in `createEmulator` --- docs/README.md | 49 +++++++++++++++++++++++++++++++++++++++++-------- src/emulator.ts | 5 ++++- src/index.ts | 27 ++++++++++++++++++++++----- 3 files changed, 67 insertions(+), 14 deletions(-) diff --git a/docs/README.md b/docs/README.md index d5998a8..20c762f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -22,6 +22,7 @@ andromatic - [getAndroidDevToolPath](README.md#getandroiddevtoolpath) - [installAndroidDevTool](README.md#installandroiddevtool) - [installPackages](README.md#installpackages) +- [isInstalled](README.md#isinstalled) - [listPackages](README.md#listpackages) - [runAndroidDevTool](README.md#runandroiddevtool) - [updatePackages](README.md#updatepackages) @@ -377,7 +378,7 @@ The path to the installed tool's executable. #### Defined in -[index.ts:340](https://github.com/tweaselORG/andromatic/blob/main/src/index.ts#L340) +[index.ts:357](https://github.com/tweaselORG/andromatic/blob/main/src/index.ts#L357) ___ @@ -406,7 +407,7 @@ The path to the installed tool's executable. #### Defined in -[index.ts:293](https://github.com/tweaselORG/andromatic/blob/main/src/index.ts#L293) +[index.ts:310](https://github.com/tweaselORG/andromatic/blob/main/src/index.ts#L310) ___ @@ -431,15 +432,47 @@ The path to `$ANDROID_HOME` where the packages are installed. #### Defined in -[index.ts:266](https://github.com/tweaselORG/andromatic/blob/main/src/index.ts#L266) +[index.ts:283](https://github.com/tweaselORG/andromatic/blob/main/src/index.ts#L283) + +___ + +### isInstalled + +▸ **isInstalled**(`packageName`, `version?`): `Promise`<`boolean`\> + +Checks whether a package has been installed by `sdkmanager`. + +#### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `packageName` | `string` | Name of the package to check. Should match the `sdkmanager` package path. | +| `version?` | `string` | If needed, additional check if the specified version ist installed. | + +#### Returns + +`Promise`<`boolean`\> + +A boolean which is true if the package is currently installed. + +#### Defined in + +[index.ts:270](https://github.com/tweaselORG/andromatic/blob/main/src/index.ts#L270) ___ ### listPackages -▸ **listPackages**(): `Promise`<[`AvailablePackage`](README.md#availablepackage)[]\> +▸ **listPackages**(`options?`): `Promise`<[`AvailablePackage`](README.md#availablepackage)[]\> -Fetch a list of available packages that can be installed by `sdkmanager`. +Fetch a list of available or installed packages that can be or have been installed by `sdkmanager`. + +#### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `options?` | `Object` | If `ìnstalled` is true, fetch a list of all installed packages (instead of ones available for install). | +| `options.installed` | `boolean` | - | #### Returns @@ -449,7 +482,7 @@ An array of packages, each with their package path, version and description. #### Defined in -[index.ts:237](https://github.com/tweaselORG/andromatic/blob/main/src/index.ts#L237) +[index.ts:239](https://github.com/tweaselORG/andromatic/blob/main/src/index.ts#L239) ___ @@ -479,7 +512,7 @@ The result from execa, see: https://github.com/sindresorhus/execa#childprocess. #### Defined in -[index.ts:409](https://github.com/tweaselORG/andromatic/blob/main/src/index.ts#L409) +[index.ts:426](https://github.com/tweaselORG/andromatic/blob/main/src/index.ts#L426) ___ @@ -495,4 +528,4 @@ Update all installed packages to the latest version using `sdkmanager`. #### Defined in -[index.ts:275](https://github.com/tweaselORG/andromatic/blob/main/src/index.ts#L275) +[index.ts:292](https://github.com/tweaselORG/andromatic/blob/main/src/index.ts#L292) diff --git a/src/emulator.ts b/src/emulator.ts index 29f35aa..cc3b9a4 100644 --- a/src/emulator.ts +++ b/src/emulator.ts @@ -1,7 +1,7 @@ import fs from 'fs-extra'; import { join } from 'path'; import type { MergeExclusive } from 'type-fest'; -import { ensureSdkmanager, installPackages, runAndroidDevTool } from './index'; +import { ensureSdkmanager, installPackages, isInstalled, runAndroidDevTool } from './index'; /** * The options for creating an emulator using the {@link createEmulator} function. @@ -94,6 +94,9 @@ export const createEmulator = async (name: string, options: EmulatorOptions) => for (const dir of ['platforms', 'platform-tools']) if (!(await fs.pathExists(join(androidHome, dir)))) await fs.ensureDir(join(androidHome, dir)); + // The `emulator` package is required by avdmanager, so we need to check for it + if (!(await isInstalled('emulator'))) await installPackages('emulator'); + await runAndroidDevTool('avdmanager', [ 'create', 'avd', diff --git a/src/index.ts b/src/index.ts index 8b12895..dbb283e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -230,14 +230,16 @@ export type AvailablePackage = { description: string; }; /** - * Fetch a list of available packages that can be installed by `sdkmanager`. + * Fetch a list of available or installed packages that can be or have been installed by `sdkmanager`. * + * @param options If `ìnstalled` is true, fetch a list of all installed packages (instead of ones available for + * install). * @returns An array of packages, each with their package path, version and description. */ -export const listPackages = async (): Promise => { +export const listPackages = async (options?: { installed: boolean }): Promise => { const { sdkmanager, env } = await ensureSdkmanager(); - const { stdout } = await execa(sdkmanager, ['--list'], { env }); + const { stdout } = await execa(sdkmanager, [options?.installed ? '--list_installed' : '--list'], { env }); const lines = stdout.split('\n'); /* @@ -246,15 +248,30 @@ export const listPackages = async (): Promise => { ------- | ------- | ------- add-ons;addon-google_apis-google-15 | 3 | Google APIs */ - const availableHeaderIndex = lines.findIndex((line) => line.startsWith('Available Packages:')); + const headerIndex = lines.findIndex((line) => + line.startsWith(options?.installed ? 'Installed packages:' : 'Available Packages:') + ); return lines - .slice(availableHeaderIndex + 3) + .slice(headerIndex + 3) .map((line) => line.split('|').map((v) => v.trim())) .map(([path, version, description]) => ({ path, version, description })) .filter((p): p is AvailablePackage => !!p.path && !!p.version && !!p.description); }; +/** + * Checks whether a package has been installed by `sdkmanager`. + * + * @param packageName Name of the package to check. Should match the `sdkmanager` package path. + * @param version If needed, additional check if the specified version ist installed. + * + * @returns A boolean which is true if the package is currently installed. + */ +export const isInstalled = async (packageName: string, version?: string) => + (await listPackages({ installed: true })).some( + (p) => p.path.startsWith(packageName) && (version ? p.version === version : true) + ); + /** * Install one or more packages using `sdkmanager`. The specified packages are installed or updated to the latest * version (if already installed) in an automatically created `$ANDROID_HOME` managed by andromatic. From 264f98da2610326595c4b317813777afe310acbf Mon Sep 17 00:00:00 2001 From: Lorenz Sieben Date: Wed, 23 Oct 2024 15:09:35 +0200 Subject: [PATCH 2/3] Directory instead of sdkmanager check for installation --- src/emulator.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/emulator.ts b/src/emulator.ts index cc3b9a4..5fbc2e8 100644 --- a/src/emulator.ts +++ b/src/emulator.ts @@ -1,7 +1,7 @@ import fs from 'fs-extra'; import { join } from 'path'; import type { MergeExclusive } from 'type-fest'; -import { ensureSdkmanager, installPackages, isInstalled, runAndroidDevTool } from './index'; +import { ensureSdkmanager, installPackages, runAndroidDevTool } from './index'; /** * The options for creating an emulator using the {@link createEmulator} function. @@ -95,7 +95,7 @@ export const createEmulator = async (name: string, options: EmulatorOptions) => if (!(await fs.pathExists(join(androidHome, dir)))) await fs.ensureDir(join(androidHome, dir)); // The `emulator` package is required by avdmanager, so we need to check for it - if (!(await isInstalled('emulator'))) await installPackages('emulator'); + if (!(await fs.pathExists(join(androidHome, 'emulator')))) await installPackages('emulator'); await runAndroidDevTool('avdmanager', [ 'create', From 8eae37186164dba6078d1e054710c775a429a64a Mon Sep 17 00:00:00 2001 From: Lorenz Sieben Date: Wed, 23 Oct 2024 15:10:30 +0200 Subject: [PATCH 3/3] Update src/index.ts Co-authored-by: Benjamin Altpeter --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index dbb283e..b9bb92b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -233,7 +233,7 @@ export type AvailablePackage = { * Fetch a list of available or installed packages that can be or have been installed by `sdkmanager`. * * @param options If `ìnstalled` is true, fetch a list of all installed packages (instead of ones available for - * install). + * install). Defaults to `false`. * @returns An array of packages, each with their package path, version and description. */ export const listPackages = async (options?: { installed: boolean }): Promise => {