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

feat(cli): STUDIO_PATH environment variable #3755

Merged
merged 2 commits into from
Nov 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 24 additions & 60 deletions cli/src/android/open.ts
Original file line number Diff line number Diff line change
@@ -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<void> {
logger.info(`Opening Android project at ${config.android.platformDir}.`);
const debug = Debug('capacitor:android:open');

export async function openAndroid(config: Config): Promise<void> {
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.`,
);
}
}
79 changes: 59 additions & 20 deletions cli/src/config.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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<Config> {
Expand All @@ -26,19 +30,9 @@ export async function loadConfig(): Promise<Config> {
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: {
Expand All @@ -57,6 +51,10 @@ export async function loadConfig(): Promise<Config> {
bundledWebRuntime: extConfig.bundledWebRuntime ?? false,
},
};

debug('config: %O', config);

return config;
}

async function loadCLIConfig(rootDir: string): Promise<CLIConfig> {
Expand All @@ -74,7 +72,7 @@ async function loadCLIConfig(rootDir: string): Promise<CLIConfig> {
async function loadAndroidConfig(
rootDir: string,
extConfig: ExternalConfig,
assetDir: string,
cliConfig: CLIConfig,
): Promise<AndroidConfig> {
const name = 'android';
const platformDir = extConfig.android?.path ?? 'android';
Expand All @@ -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,
Expand All @@ -100,16 +100,16 @@ async function loadAndroidConfig(
assets: {
templateName,
pluginsFolderName,
templateDir: resolve(assetDir, templateName),
pluginsDir: resolve(assetDir, pluginsFolderName),
templateDir: resolve(cliConfig.assetsDir, templateName),
pluginsDir: resolve(cliConfig.assetsDir, pluginsFolderName),
},
};
}

async function loadIOSConfig(
rootDir: string,
extConfig: ExternalConfig,
assetDir: string,
cliConfig: CLIConfig,
): Promise<IOSConfig> {
const name = 'ios';
const platformDir = extConfig.ios?.path ?? 'ios';
Expand All @@ -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),
},
};
}
Expand Down Expand Up @@ -164,6 +164,45 @@ function determineOS(os: NodeJS.Platform): OS {
return OS.Unknown;
}

async function determineAndroidStudioPath(os: OS): Promise<string> {
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<ExternalConfig> {
try {
return await readJSON(p);
Expand Down
3 changes: 1 addition & 2 deletions cli/src/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export interface AppConfig {
}

export interface AndroidConfig extends PlatformConfig {
readonly studioPath: string;
readonly minVersion: string;
readonly webDir: string;
readonly webDirAbs: string;
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion cli/src/web/copy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { copy } from 'fs-extra';
import { copy } from '@ionic/utils-fs';
import { join } from 'path';

import c from '../colors';
Expand Down