From c2133c5c6b22257e8fa24760c4b917aba7295b2e Mon Sep 17 00:00:00 2001 From: jcesarmobile Date: Wed, 1 Jul 2020 22:27:43 +0200 Subject: [PATCH] feat(cli): add hooks to capacitor commands for custom platforms (#3091) Co-authored-by: Dan Imhoff Co-authored-by: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> --- cli/src/common.ts | 38 +++++++++++++++++++-- cli/src/tasks/add.ts | 73 +++++++++++++++++++++++------------------ cli/src/tasks/copy.ts | 30 +++++++++++------ cli/src/tasks/open.ts | 41 ++++++++++++++--------- cli/src/tasks/sync.ts | 43 ++++++++++++++---------- cli/src/tasks/update.ts | 46 ++++++++++++++++---------- 6 files changed, 176 insertions(+), 95 deletions(-) diff --git a/cli/src/common.ts b/cli/src/common.ts index c409fc2d5c..205f133c7e 100644 --- a/cli/src/common.ts +++ b/cli/src/common.ts @@ -1,5 +1,5 @@ import { Config } from './config'; -import { exec } from 'child_process'; +import { exec, spawn } from 'child_process'; import { setTimeout } from 'timers'; import { basename, dirname, join, parse, resolve } from 'path'; import { copyAsync, existsAsync, readFileAsync, renameAsync, writeFileAsync } from './util/fs'; @@ -252,6 +252,21 @@ export function wait(time: number) { return new Promise((resolve) => setTimeout(resolve, time)); } +export function runPlatformHook(command: string): Promise { + return new Promise((resolve, reject) => { + const cmd = spawn(command, { + stdio: 'inherit', + shell: true + }); + cmd.on('close', (code) => { + resolve(''); + }); + cmd.on('error', (err) => { + reject(err); + }); + }); +} + export function runCommand(command: string): Promise { return new Promise((resolve, reject) => { exec(command, (error, stdout, stderr) => { @@ -420,7 +435,26 @@ export async function checkPlatformVersions(config: Config, platform: string) { } } -export function resolveNode(config: Config, ...pathSegments: any[]): string | null { +export function resolvePlatform(config: Config, platform: string): string | null { + if (platform[0] !== '@') { + const core = resolveNode(config, `@capacitor/${platform}`); + + if (core) { + return core; + } + + const community = resolveNode(config, `@capacitor-community/${platform}`); + + if (community) { + return community; + } + } + + // third-party + return resolveNode(config, platform); +} + +export function resolveNode(config: Config, ...pathSegments: string[]): string | null { const id = pathSegments[0]; const path = pathSegments.slice(1); diff --git a/cli/src/tasks/add.ts b/cli/src/tasks/add.ts index e49d913723..3c58c666cf 100644 --- a/cli/src/tasks/add.ts +++ b/cli/src/tasks/add.ts @@ -5,50 +5,59 @@ import { addElectron } from '../electron/add'; import { addIOS, addIOSChecks } from '../ios/add'; import { editProjectSettingsAndroid } from '../android/common'; import { editProjectSettingsIOS } from '../ios/common'; -import { check, checkAppConfig, checkPackage, checkWebDir, log, logError, logFatal, logInfo, runTask, writePrettyJSON } from '../common'; +import { check, checkAppConfig, checkPackage, checkWebDir, hasYarn, log, logError, logFatal, logInfo, resolvePlatform, runCommand, runPlatformHook, runTask, writePrettyJSON } from '../common'; import { sync } from './sync'; import chalk from 'chalk'; import { resolve } from 'path'; export async function addCommand(config: Config, selectedPlatformName: string) { + if (selectedPlatformName && !config.isValidPlatform(selectedPlatformName)) { + const platformFolder = resolvePlatform(config, selectedPlatformName); + if (platformFolder) { + const result = await runPlatformHook(`cd "${platformFolder}" && ${await hasYarn(config) ? 'yarn' : 'npm'} run capacitor:add`); + log(result); + } else { + logError(`platform ${selectedPlatformName} not found`); + } + } else { + const platformName = await config.askPlatform( + selectedPlatformName, + `Please choose a platform to add:` + ); - const platformName = await config.askPlatform( - selectedPlatformName, - `Please choose a platform to add:` - ); - - if (platformName === config.web.name) { - webWarning(); - return; - } + if (platformName === config.web.name) { + webWarning(); + return; + } - const existingPlatformDir = config.platformDirExists(platformName); - if (existingPlatformDir) { - logFatal(`"${platformName}" platform already exists. - To add a new "${platformName}" platform, please remove "${existingPlatformDir}" and run this command again. - WARNING! your native IDE project will be completely removed.`); - } + const existingPlatformDir = config.platformDirExists(platformName); + if (existingPlatformDir) { + logFatal(`"${platformName}" platform already exists. + To add a new "${platformName}" platform, please remove "${existingPlatformDir}" and run this command again. + WARNING! your native IDE project will be completely removed.`); + } - try { - await check( - config, - [checkPackage, checkAppConfig, ...addChecks(config, platformName)] - ); - await generateCapacitorConfig(config); - await check(config, [checkWebDir]); - await doAdd(config, platformName); - await editPlatforms(config, platformName); + try { + await check( + config, + [checkPackage, checkAppConfig, ...addChecks(config, platformName)] + ); + await generateCapacitorConfig(config); + await check(config, [checkWebDir]); + await doAdd(config, platformName); + await editPlatforms(config, platformName); - if (shouldSync(config, platformName)) { - await sync(config, platformName, false); - } + if (shouldSync(config, platformName)) { + await sync(config, platformName, false); + } - if (platformName === config.ios.name || platformName === config.android.name) { - log(chalk`\nNow you can run {green {bold npx cap open ${platformName}}} to launch ${platformName === config.ios.name ? 'Xcode' : 'Android Studio'}`); + if (platformName === config.ios.name || platformName === config.android.name) { + log(chalk`\nNow you can run {green {bold npx cap open ${platformName}}} to launch ${platformName === config.ios.name ? 'Xcode' : 'Android Studio'}`); + } + } catch (e) { + logFatal(e); } - } catch (e) { - logFatal(e); } } diff --git a/cli/src/tasks/copy.ts b/cli/src/tasks/copy.ts index c50167f234..6005d16091 100644 --- a/cli/src/tasks/copy.ts +++ b/cli/src/tasks/copy.ts @@ -1,5 +1,5 @@ import { Config } from '../config'; -import { checkWebDir, logError, logFatal, logInfo, resolveNode, runTask } from '../common'; +import { checkWebDir, hasYarn, log, logError, logFatal, logInfo, resolveNode, resolvePlatform, runCommand, runPlatformHook, runTask } from '../common'; import { existsAsync } from '../util/fs'; import { allSerial } from '../util/promise'; import { copyWeb } from '../web/copy'; @@ -10,15 +10,25 @@ import { getCordovaPlugins, handleCordovaPluginsJS, writeCordovaAndroidManifest import chalk from 'chalk'; export async function copyCommand(config: Config, selectedPlatformName: string) { - const platforms = config.selectPlatforms(selectedPlatformName); - if (platforms.length === 0) { - logInfo(`There are no platforms to copy yet. Create one with \`capacitor create\`.`); - return; - } - try { - await allSerial(platforms.map(platformName => () => copy(config, platformName))); - } catch (e) { - logError(e); + if (selectedPlatformName && !config.isValidPlatform(selectedPlatformName)) { + const platformFolder = resolvePlatform(config, selectedPlatformName); + if (platformFolder) { + const result = await runPlatformHook(`cd "${platformFolder}" && ${await hasYarn(config) ? 'yarn' : 'npm'} run capacitor:copy`); + log(result); + } else { + logError(`platform ${selectedPlatformName} not found`); + } + } else { + const platforms = config.selectPlatforms(selectedPlatformName); + if (platforms.length === 0) { + logInfo(`There are no platforms to copy yet. Create one with \`capacitor create\`.`); + return; + } + try { + await allSerial(platforms.map(platformName => () => copy(config, platformName))); + } catch (e) { + logError(e); + } } } diff --git a/cli/src/tasks/open.ts b/cli/src/tasks/open.ts index df933a9168..be19740467 100644 --- a/cli/src/tasks/open.ts +++ b/cli/src/tasks/open.ts @@ -1,26 +1,35 @@ import { Config } from '../config'; -import { logFatal, logInfo, runTask } from '../common'; +import { hasYarn, log, logError, logFatal, logInfo, resolvePlatform, runPlatformHook, runTask } from '../common'; import { openAndroid } from '../android/open'; import { openElectron } from '../electron/open'; import { openIOS } from '../ios/open'; -export async function openCommand(config: Config, selectedPlatform: string) { - const platforms = config.selectPlatforms(selectedPlatform); - let platformName: string; - if (platforms.length === 0) { - logInfo(`There are no platforms to open yet. Create one with "capacitor add".`); - return; - } else if (platforms.length === 1) { - platformName = platforms[0]; +export async function openCommand(config: Config, selectedPlatformName: string) { + if (selectedPlatformName && !config.isValidPlatform(selectedPlatformName)) { + const platformFolder = resolvePlatform(config, selectedPlatformName); + if (platformFolder) { + const result = await runPlatformHook(`cd "${platformFolder}" && ${await hasYarn(config) ? 'yarn' : 'npm'} run capacitor:open`); + log(result); + } else { + logError(`platform ${selectedPlatformName} not found`); + } } else { - platformName = await config.askPlatform('', `Please choose a platform to open:`); - } - - try { - await open(config, platformName); + const platforms = config.selectPlatforms(selectedPlatformName); + let platformName: string; + if (platforms.length === 0) { + logInfo(`There are no platforms to open yet. Create one with "capacitor add".`); + return; + } else if (platforms.length === 1) { + platformName = platforms[0]; + } else { + platformName = await config.askPlatform('', `Please choose a platform to open:`); + } - } catch (e) { - logFatal(e); + try { + await open(config, platformName); + } catch (e) { + logFatal(e); + } } } diff --git a/cli/src/tasks/sync.ts b/cli/src/tasks/sync.ts index fb562b8a42..d69b5ade59 100644 --- a/cli/src/tasks/sync.ts +++ b/cli/src/tasks/sync.ts @@ -1,6 +1,6 @@ import { Config } from '../config'; -import { copy } from './copy'; -import { update, updateChecks } from './update'; +import { copy, copyCommand } from './copy'; +import { update, updateChecks, updateCommand } from './update'; import { check, checkPackage, checkWebDir, log, logError, logFatal, logInfo } from '../common'; import { allSerial } from '../util/promise'; @@ -8,21 +8,30 @@ import { allSerial } from '../util/promise'; /** * Sync is a copy and an update in one. */ -export async function syncCommand(config: Config, selectedPlatform: string, deployment: boolean) { - const then = +new Date; - const platforms = config.selectPlatforms(selectedPlatform); - if (platforms.length === 0) { - logInfo(`There are no platforms to sync yet. Create one with "capacitor create".`); - return; - } - try { - await check(config, [checkPackage, checkWebDir, ...updateChecks(config, platforms)]); - await allSerial(platforms.map(platformName => () => sync(config, platformName, deployment))); - const now = +new Date; - const diff = (now - then) / 1000; - log(`Sync finished in ${diff}s`); - } catch (e)  { - logFatal(e); +export async function syncCommand(config: Config, selectedPlatformName: string, deployment: boolean) { + if (selectedPlatformName && !config.isValidPlatform(selectedPlatformName)) { + try { + await copyCommand(config, selectedPlatformName); + } catch (e) { + logError(e); + } + await updateCommand(config, selectedPlatformName, deployment); + } else { + const then = +new Date; + const platforms = config.selectPlatforms(selectedPlatformName); + if (platforms.length === 0) { + logInfo(`There are no platforms to sync yet. Create one with "capacitor create".`); + return; + } + try { + await check(config, [checkPackage, checkWebDir, ...updateChecks(config, platforms)]); + await allSerial(platforms.map(platformName => () => sync(config, platformName, deployment))); + const now = +new Date; + const diff = (now - then) / 1000; + log(`Sync finished in ${diff}s`); + } catch (e)  { + logFatal(e); + } } } diff --git a/cli/src/tasks/update.ts b/cli/src/tasks/update.ts index 1b5b684a04..71572918f1 100644 --- a/cli/src/tasks/update.ts +++ b/cli/src/tasks/update.ts @@ -2,29 +2,39 @@ import { Config } from '../config'; import { updateAndroid } from '../android/update'; import { updateIOS, updateIOSChecks } from '../ios/update'; import { allSerial } from '../util/promise'; -import { CheckFunction, check, checkPackage, log, logError, logFatal, logInfo, runTask } from '../common'; +import { CheckFunction, check, checkPackage, hasYarn, log, logError, logFatal, logInfo, resolvePlatform, runCommand, runPlatformHook, runTask } from '../common'; import chalk from 'chalk'; export async function updateCommand(config: Config, selectedPlatformName: string, deployment: boolean) { - const then = +new Date; - const platforms = config.selectPlatforms(selectedPlatformName); - if (platforms.length === 0) { - logInfo(`There are no platforms to update yet. Create one with "capacitor create".`); - return; - } - try { - await check( - config, - [checkPackage, ...updateChecks(config, platforms)] - ); + if (selectedPlatformName && !config.isValidPlatform(selectedPlatformName)) { + const platformFolder = resolvePlatform(config, selectedPlatformName); + if (platformFolder) { + const result = await runPlatformHook(`cd "${platformFolder}" && ${await hasYarn(config) ? 'yarn' : 'npm'} run capacitor:update`); + log(result); + } else { + logError(`platform ${selectedPlatformName} not found`); + } + } else { + const then = +new Date; + const platforms = config.selectPlatforms(selectedPlatformName); + if (platforms.length === 0) { + logInfo(`There are no platforms to update yet. Create one with "capacitor create".`); + return; + } + try { + await check( + config, + [checkPackage, ...updateChecks(config, platforms)] + ); - await allSerial(platforms.map(platformName => async () => await update(config, platformName, deployment))); - const now = +new Date; - const diff = (now - then) / 1000; - log(`Update finished in ${diff}s`); - } catch (e) { - logFatal(e); + await allSerial(platforms.map(platformName => async () => await update(config, platformName, deployment))); + const now = +new Date; + const diff = (now - then) / 1000; + log(`Update finished in ${diff}s`); + } catch (e) { + logFatal(e); + } } }