From 65cef53277444c173ff928dc4ef196f0dae4c8a7 Mon Sep 17 00:00:00 2001 From: Dan Imhoff Date: Tue, 3 Nov 2020 08:28:55 -0800 Subject: [PATCH] feat(cli): STUDIO_PATH environment variable (#3755) --- cli/src/android/open.ts | 84 ++++++++++++----------------------------- cli/src/config.ts | 79 ++++++++++++++++++++++++++++---------- cli/src/definitions.ts | 3 +- cli/src/web/copy.ts | 2 +- 4 files changed, 85 insertions(+), 83 deletions(-) diff --git a/cli/src/android/open.ts b/cli/src/android/open.ts index 6e4c943a6f..6ce6fba48f 100644 --- a/cli/src/android/open.ts +++ b/cli/src/android/open.ts @@ -1,73 +1,37 @@ import { pathExists } from '@ionic/utils-fs'; +import Debug from 'debug'; import open from 'open'; -import { runCommand } from '../common'; +import c from '../colors'; import type { Config } from '../definitions'; -import { OS } from '../definitions'; import { logger } from '../log'; -export async function openAndroid(config: Config): Promise { - logger.info(`Opening Android project at ${config.android.platformDir}.`); +const debug = Debug('capacitor:android:open'); +export async function openAndroid(config: Config): Promise { + const androidStudioPath = config.android.studioPath; const dir = config.android.platformDirAbs; - switch (config.cli.os) { - case OS.Mac: { - await open(dir, { app: 'android studio', wait: false }); - break; - } - case OS.Windows: { - let androidStudioPath = config.windows.androidStudioPath; - try { - if (!(await pathExists(androidStudioPath))) { - let commandResult = await runCommand('REG', [ - 'QUERY', - 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Android Studio', - '/v', - 'Path', - ]); - commandResult = commandResult.replace(/(\r\n|\n|\r)/gm, ''); - const ix = commandResult.indexOf('REG_SZ'); - if (ix > 0) { - androidStudioPath = - commandResult.substring(ix + 6).trim() + '\\bin\\studio64.exe'; - } - } - } catch (e) { - androidStudioPath = ''; - } - if (androidStudioPath) { - open(dir, { app: androidStudioPath, wait: false }); - } else { - logger.error( - 'Android Studio not found.\n' + - 'Make sure it\'s installed and configure "windowsAndroidStudioPath" in your capacitor.config.json to point to the location of studio64.exe, using JavaScript-escaped paths:\n' + - 'Example:\n' + - '{\n' + - ' "windowsAndroidStudioPath": "C:\\\\Program Files\\\\Android\\\\Android Studio\\\\bin\\\\studio64.exe"\n' + - '}', - ); - } - break; + try { + if (!(await pathExists(androidStudioPath))) { + throw new Error(`Android Studio does not exist at: ${androidStudioPath}`); } - case OS.Linux: { - const linuxError = () => { - logger.error( - 'Unable to launch Android Studio.\n' + - 'You must configure "linuxAndroidStudioPath" in your capacitor.config.json to point to the location of studio.sh, using JavaScript-escaped paths:\n' + - 'Example:\n' + - '{\n' + - ' "linuxAndroidStudioPath": "/usr/local/android-studio/bin/studio.sh"\n' + - '}', - ); - }; - try { - await open(dir, { app: config.linux.androidStudioPath, wait: true }); - } catch (e) { - linuxError(); - } - break; - } + await open(dir, { app: androidStudioPath, wait: false }); + logger.info( + `Opening Android project at: ${c.strong(config.android.platformDir)}.`, + ); + } catch (e) { + debug('Error opening Android Studio: %O', e); + + logger.error( + 'Unable to launch Android Studio. Is it installed?\n' + + `Attempted to open Android Studio at: ${c.strong( + androidStudioPath, + )}\n` + + `You can configure this with the ${c.input( + 'STUDIO_PATH', + )} environment variable.`, + ); } } diff --git a/cli/src/config.ts b/cli/src/config.ts index ce480547d9..5a0739a7ad 100644 --- a/cli/src/config.ts +++ b/cli/src/config.ts @@ -1,6 +1,8 @@ -import { readJSON } from 'fs-extra'; +import { pathExists, readJSON } from '@ionic/utils-fs'; +import Debug from 'debug'; import { dirname, join, resolve } from 'path'; +import { runCommand } from './common'; import type { Config, ExternalConfig, @@ -12,6 +14,8 @@ import type { } from './definitions'; import { OS } from './definitions'; +const debug = Debug('capacitor:config'); + export const EXTERNAL_CONFIG_FILE = 'capacitor.config.json'; export async function loadConfig(): Promise { @@ -26,19 +30,9 @@ export async function loadConfig(): Promise { const webDir = extConfig.webDir ?? 'www'; const cli = await loadCLIConfig(cliRootDir); - return { - windows: { - androidStudioPath: - extConfig.windowsAndroidStudioPath ?? - 'C:\\Program Files\\Android\\Android Studio\\bin\\studio64.exe', - }, - linux: { - androidStudioPath: - extConfig.linuxAndroidStudioPath ?? - '/usr/local/android-studio/bin/studio.sh', - }, - android: await loadAndroidConfig(appRootDir, extConfig, cli.assetsDir), - ios: await loadIOSConfig(appRootDir, extConfig, cli.assetsDir), + const config = { + android: await loadAndroidConfig(appRootDir, extConfig, cli), + ios: await loadIOSConfig(appRootDir, extConfig, cli), web: await loadWebConfig(appRootDir, webDir), cli, app: { @@ -57,6 +51,10 @@ export async function loadConfig(): Promise { bundledWebRuntime: extConfig.bundledWebRuntime ?? false, }, }; + + debug('config: %O', config); + + return config; } async function loadCLIConfig(rootDir: string): Promise { @@ -74,7 +72,7 @@ async function loadCLIConfig(rootDir: string): Promise { async function loadAndroidConfig( rootDir: string, extConfig: ExternalConfig, - assetDir: string, + cliConfig: CLIConfig, ): Promise { const name = 'android'; const platformDir = extConfig.android?.path ?? 'android'; @@ -85,10 +83,12 @@ async function loadAndroidConfig( const templateName = 'android-template'; const pluginsFolderName = 'capacitor-cordova-android-plugins'; + const studioPath = await determineAndroidStudioPath(cliConfig.os); return { name, minVersion: '21', + studioPath, platformDir, platformDirAbs, webDir, @@ -100,8 +100,8 @@ async function loadAndroidConfig( assets: { templateName, pluginsFolderName, - templateDir: resolve(assetDir, templateName), - pluginsDir: resolve(assetDir, pluginsFolderName), + templateDir: resolve(cliConfig.assetsDir, templateName), + pluginsDir: resolve(cliConfig.assetsDir, pluginsFolderName), }, }; } @@ -109,7 +109,7 @@ async function loadAndroidConfig( async function loadIOSConfig( rootDir: string, extConfig: ExternalConfig, - assetDir: string, + cliConfig: CLIConfig, ): Promise { const name = 'ios'; const platformDir = extConfig.ios?.path ?? 'ios'; @@ -131,8 +131,8 @@ async function loadIOSConfig( assets: { templateName, pluginsFolderName, - templateDir: resolve(assetDir, templateName), - pluginsDir: resolve(assetDir, pluginsFolderName), + templateDir: resolve(cliConfig.assetsDir, templateName), + pluginsDir: resolve(cliConfig.assetsDir, pluginsFolderName), }, }; } @@ -164,6 +164,45 @@ function determineOS(os: NodeJS.Platform): OS { return OS.Unknown; } +async function determineAndroidStudioPath(os: OS): Promise { + if (process.env.STUDIO_PATH) { + return process.env.STUDIO_PATH; + } + + switch (os) { + case OS.Mac: + return '/Applications/Android Studio.app'; + case OS.Windows: { + let p = 'C:\\Program Files\\Android\\Android Studio\\bin\\studio64.exe'; + + try { + if (!(await pathExists(p))) { + let commandResult = await runCommand('REG', [ + 'QUERY', + 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Android Studio', + '/v', + 'Path', + ]); + commandResult = commandResult.replace(/(\r\n|\n|\r)/gm, ''); + const i = commandResult.indexOf('REG_SZ'); + if (i > 0) { + p = commandResult.substring(i + 6).trim() + '\\bin\\studio64.exe'; + } + } + } catch (e) { + debug(`Error checking registry for Android Studio path: %O`, e); + break; + } + + return p; + } + case OS.Linux: + return '/usr/local/android-studio/bin/studio.sh'; + } + + return ''; +} + async function loadExternalConfig(p: string): Promise { try { return await readJSON(p); diff --git a/cli/src/definitions.ts b/cli/src/definitions.ts index d673d91401..3ee0064a28 100644 --- a/cli/src/definitions.ts +++ b/cli/src/definitions.ts @@ -85,6 +85,7 @@ export interface AppConfig { } export interface AndroidConfig extends PlatformConfig { + readonly studioPath: string; readonly minVersion: string; readonly webDir: string; readonly webDirAbs: string; @@ -107,8 +108,6 @@ export interface IOSConfig extends PlatformConfig { export type WebConfig = PlatformConfig; export interface Config { - readonly windows: WindowsConfig; - readonly linux: LinuxConfig; readonly android: AndroidConfig; readonly ios: IOSConfig; readonly web: WebConfig; diff --git a/cli/src/web/copy.ts b/cli/src/web/copy.ts index 7cfe793277..934b658248 100644 --- a/cli/src/web/copy.ts +++ b/cli/src/web/copy.ts @@ -1,4 +1,4 @@ -import { copy } from 'fs-extra'; +import { copy } from '@ionic/utils-fs'; import { join } from 'path'; import c from '../colors';