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): add capacitor run command #3599

Merged
merged 39 commits into from
Oct 16, 2020
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
8c3d3e0
strip params from check functions
imhoffd Sep 9, 2020
2762d7f
resolveNode doesn't need config
imhoffd Sep 9, 2020
ca1510d
remove public config methods and unused properties
imhoffd Sep 10, 2020
172f594
config refactor
imhoffd Sep 10, 2020
5381669
readonly
imhoffd Sep 10, 2020
8665579
bug fixes
imhoffd Sep 10, 2020
b2c4f92
fix tests
imhoffd Sep 10, 2020
5b0f13a
be more clear about resolving package.json
imhoffd Sep 10, 2020
ff836cb
Merge branch 'main' into config-refactor
imhoffd Sep 14, 2020
a9ee8be
Merge branch 'main' into config-refactor
imhoffd Sep 16, 2020
c04c10f
refactor platformDir
imhoffd Sep 16, 2020
b6f3407
implement ios.path and android.path
imhoffd Sep 16, 2020
16ce02c
Merge branch 'main' into config-refactor
imhoffd Sep 17, 2020
151a41f
Update cli/src/config.ts
imhoffd Sep 18, 2020
be4e89d
show plugin config last when adding it
imhoffd Sep 18, 2020
8cf2ac8
Merge branch 'main' into config-refactor
imhoffd Sep 18, 2020
74b85be
write plugin last (attempt 2 😂)
imhoffd Sep 21, 2020
146907d
FS refactor
imhoffd Sep 21, 2020
f0e4d09
wip
imhoffd Sep 22, 2020
2b2242c
Merge remote-tracking branch 'origin/main' into feat-2294
imhoffd Sep 22, 2020
9cf740d
Merge branch 'feat-2294' into run-command
imhoffd Sep 22, 2020
9801331
refactor runCommand to use subprocess lib
imhoffd Sep 22, 2020
953e91b
poc for android
imhoffd Sep 22, 2020
c7865fc
test fix
imhoffd Sep 22, 2020
6d1f242
Merge remote-tracking branch 'origin/main' into run-command
imhoffd Sep 23, 2020
9eeb26a
target and list options
imhoffd Sep 28, 2020
b358102
debug messages
imhoffd Sep 28, 2020
b189dc2
ignore DerivedData where builds are placed
imhoffd Sep 28, 2020
a4815bc
Merge branch 'main' into run-command
imhoffd Sep 29, 2020
4b276fe
native-run not installed error
imhoffd Sep 29, 2020
f8a8941
remove unused spinner option
imhoffd Sep 29, 2020
8ec1a27
Merge branch 'main' into run-command
imhoffd Oct 13, 2020
7a67f8a
fix lint
imhoffd Oct 13, 2020
4704349
Merge branch 'main' into run-command
jcesarmobile Oct 14, 2020
07ae679
Merge branch 'main' into run-command
jcesarmobile Oct 14, 2020
e00cd79
Merge branch 'main' into run-command
jcesarmobile Oct 15, 2020
4304e17
show example install command
imhoffd Oct 15, 2020
0b110df
add native-run as dependency of CLI
imhoffd Oct 15, 2020
38bdbca
Merge branch 'main' into run-command
jcesarmobile Oct 16, 2020
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
11 changes: 6 additions & 5 deletions cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,21 @@
},
"license": "MIT",
"dependencies": {
"@ionic/cli-framework-output": "^2.2.0",
"@ionic/utils-terminal": "^2.2.1",
"@ionic/cli-framework-output": "^2.2.1",
"@ionic/utils-fs": "^3.1.5",
"@ionic/utils-subprocess": "^2.1.6",
"@ionic/utils-terminal": "^2.3.0",
"commander": "^6.0.0",
"fs-extra": "^9.0.1",
"debug": "^4.2.0",
"kleur": "^4.1.1",
"open": "^7.1.0",
"plist": "^3.0.1",
"prompts": "^2.3.2",
"semver": "^7.3.2",
"which": "^2.0.2",
"xml2js": "^0.4.19"
},
"devDependencies": {
"@types/debug": "^4.1.5",
"@types/fs-extra": "^9.0.1",
"@types/jest": "^26.0.4",
"@types/open": "^6.1.0",
Expand All @@ -63,7 +65,6 @@
"@types/semver": "^7.3.1",
"@types/slice-ansi": "^4.0.0",
"@types/tmp": "^0.2.0",
"@types/which": "^1.0.28",
"@types/xml2js": "^0.4.2",
"jest": "^26.1.0",
"rimraf": "^3.0.2",
Expand Down
14 changes: 6 additions & 8 deletions cli/src/android/add.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { pathExists, writeFile } from '@ionic/utils-fs';
import { homedir } from 'os';
import { join } from 'path';

import c from '../colors';
import { copyTemplate, runCommand, runTask } from '../common';
import type { Config } from '../definitions';
import { existsAsync, writeFileAsync } from '../util/fs';

export async function addAndroid(config: Config): Promise<void> {
await runTask(
Expand All @@ -24,7 +24,7 @@ export async function addAndroid(config: Config): Promise<void> {

async function createLocalProperties(platformDir: string) {
const defaultAndroidPath = join(homedir(), 'Library/Android/sdk');
if (await existsAsync(defaultAndroidPath)) {
if (await pathExists(defaultAndroidPath)) {
const localSettings = `
## This file is automatically generated by Android Studio.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
Expand All @@ -37,11 +37,9 @@ async function createLocalProperties(platformDir: string) {
# header note.
sdk.dir=${defaultAndroidPath}
`;
await writeFileAsync(
join(platformDir, 'local.properties'),
localSettings,
'utf8',
);
await writeFile(join(platformDir, 'local.properties'), localSettings, {
encoding: 'utf-8',
});

// Only sync if we were able to create the local properties above, otherwise
// this will fail
Expand All @@ -57,5 +55,5 @@ sdk.dir=${defaultAndroidPath}
}

async function gradleSync(platformDir: string) {
await runCommand(`${platformDir}/gradlew`);
await runCommand(`${platformDir}/gradlew`, []);
}
59 changes: 31 additions & 28 deletions cli/src/android/common.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,44 @@
import { mkdirs } from 'fs-extra';
import {
copy,
remove,
mkdirp,
readFile,
pathExists,
writeFile,
} from '@ionic/utils-fs';
import { join, resolve } from 'path';

import { checkCapacitorPlatform } from '../common';
import { getIncompatibleCordovaPlugins } from '../cordova';
import type { Config } from '../definitions';
import type { Plugin } from '../plugin';
import { PluginType, getPluginPlatform } from '../plugin';
import {
convertToUnixPath,
copyAsync,
existsAsync,
existsSync,
readFileAsync,
removeAsync,
writeFileAsync,
} from '../util/fs';
import { convertToUnixPath } from '../util/fs';

export async function checkAndroidPackage(
config: Config,
): Promise<string | null> {
return checkCapacitorPlatform(config, 'android');
}

export function getAndroidPlugins(allPlugins: Plugin[]): Plugin[] {
const resolved = allPlugins.map(plugin => resolvePlugin(plugin));
return resolved.filter(plugin => !!plugin) as Plugin[];
export async function getAndroidPlugins(
allPlugins: Plugin[],
): Promise<Plugin[]> {
const resolved = await Promise.all(
allPlugins.map(async plugin => await resolvePlugin(plugin)),
);
return resolved.filter((plugin): plugin is Plugin => !!plugin);
}

export function resolvePlugin(plugin: Plugin): Plugin | null {
export async function resolvePlugin(plugin: Plugin): Promise<Plugin | null> {
const platform = 'android';
if (plugin.manifest?.android) {
let pluginFilesPath = plugin.manifest.android.src
? plugin.manifest.android.src
: platform;
const absolutePath = join(plugin.rootPath, pluginFilesPath, plugin.id);
// Android folder shouldn't have subfolders, but they used to, so search for them for compatibility reasons
if (existsSync(absolutePath)) {
if (await pathExists(absolutePath)) {
pluginFilesPath = join(platform, plugin.id);
}
plugin.android = {
Expand Down Expand Up @@ -79,13 +82,13 @@ export async function editProjectSettingsAndroid(
'app/build.gradle',
);

let manifestContent = await readFileAsync(manifestPath, 'utf8');
let manifestContent = await readFile(manifestPath, { encoding: 'utf-8' });

manifestContent = manifestContent.replace(
/com.getcapacitor.myapp/g,
`${appId}`,
);
await writeFileAsync(manifestPath, manifestContent, 'utf8');
await writeFile(manifestPath, manifestContent, { encoding: 'utf-8' });

const domainPath = appId.split('.').join('/');
// Make the package source path to the new plugin Java file
Expand All @@ -94,11 +97,11 @@ export async function editProjectSettingsAndroid(
`app/src/main/java/${domainPath}`,
);

if (!(await existsAsync(newJavaPath))) {
await mkdirs(newJavaPath);
if (!(await pathExists(newJavaPath))) {
await mkdirp(newJavaPath);
}

await copyAsync(
await copy(
resolve(
config.android.platformDirAbs,
'app/src/main/java/com/getcapacitor/myapp/MainActivity.java',
Expand All @@ -107,7 +110,7 @@ export async function editProjectSettingsAndroid(
);

if (appId.split('.')[1] !== 'getcapacitor') {
await removeAsync(
await remove(
resolve(
config.android.platformDirAbs,
'app/src/main/java/com/getcapacitor',
Expand All @@ -117,7 +120,7 @@ export async function editProjectSettingsAndroid(

// Remove our template 'com' folder if their ID doesn't have it
if (appId.split('.')[0] !== 'com') {
await removeAsync(
await remove(
resolve(config.android.platformDirAbs, 'app/src/main/java/com/'),
);
}
Expand All @@ -128,34 +131,34 @@ export async function editProjectSettingsAndroid(
newJavaPath,
'MainActivity.java',
);
let activityContent = await readFileAsync(activityPath, 'utf8');
let activityContent = await readFile(activityPath, { encoding: 'utf-8' });

activityContent = activityContent.replace(
/package ([^;]*)/,
`package ${appId}`,
);
await writeFileAsync(activityPath, activityContent, 'utf8');
await writeFile(activityPath, activityContent, { encoding: 'utf-8' });

// Update the applicationId in build.gradle
let gradleContent = await readFileAsync(buildGradlePath, 'utf8');
let gradleContent = await readFile(buildGradlePath, { encoding: 'utf-8' });
gradleContent = gradleContent.replace(
/applicationId "[^"]+"/,
`applicationId "${appId}"`,
);

await writeFileAsync(buildGradlePath, gradleContent, 'utf8');
await writeFile(buildGradlePath, gradleContent, { encoding: 'utf-8' });

// Update the settings in res/values/strings.xml
const stringsPath = resolve(
config.android.platformDirAbs,
'app/src/main/res/values/strings.xml',
);
let stringsContent = await readFileAsync(stringsPath, 'utf8');
let stringsContent = await readFile(stringsPath, { encoding: 'utf-8' });
stringsContent = stringsContent.replace(/com.getcapacitor.myapp/g, appId);
stringsContent = stringsContent.replace(
/My App/g,
appName.replace(/'/g, `\\'`),
);

await writeFileAsync(stringsPath, stringsContent);
await writeFile(stringsPath, stringsContent);
}
26 changes: 13 additions & 13 deletions cli/src/android/doctor.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { pathExists, readFile } from '@ionic/utils-fs';
import { accessSync } from 'fs';
import { join } from 'path';

import c from '../colors';
import { check, logFatal, logSuccess, readXML } from '../common';
import type { Config } from '../definitions';
import { existsAsync, readFileAsync } from '../util/fs';

export async function doctorAndroid(config: Config): Promise<void> {
try {
Expand All @@ -21,29 +21,29 @@ export async function doctorAndroid(config: Config): Promise<void> {

async function checkAppSrcDirs(config: Config) {
const appDir = join(config.android.platformDirAbs, 'app');
if (!(await existsAsync(appDir))) {
if (!(await pathExists(appDir))) {
return `${c.strong('app')} directory is missing in ${
config.android.platformDir
}`;
}

const appSrcDir = join(appDir, 'src');
if (!(await existsAsync(appSrcDir))) {
if (!(await pathExists(appSrcDir))) {
return `${c.strong('src')} directory is missing in ${appDir}`;
}

const appSrcMainDir = join(appSrcDir, 'main');
if (!(await existsAsync(appSrcMainDir))) {
if (!(await pathExists(appSrcMainDir))) {
return `${c.strong('main')} directory is missing in ${appSrcDir}`;
}

const appSrcMainAssetsDir = join(appSrcMainDir, 'assets');
if (!(await existsAsync(appSrcMainAssetsDir))) {
if (!(await pathExists(appSrcMainAssetsDir))) {
return `${c.strong('assets')} directory is missing in ${appSrcMainDir}`;
}

const appSrcMainAssetsWwwDir = join(appSrcMainAssetsDir, 'public');
if (!(await existsAsync(appSrcMainAssetsWwwDir))) {
if (!(await pathExists(appSrcMainAssetsWwwDir))) {
return `${c.strong(
'public',
)} directory is missing in ${appSrcMainAssetsDir}`;
Expand All @@ -53,7 +53,7 @@ async function checkAppSrcDirs(config: Config) {
appSrcMainAssetsWwwDir,
'index.html',
);
if (!(await existsAsync(appSrcMainAssetsWwwIndexHtmlDir))) {
if (!(await pathExists(appSrcMainAssetsWwwIndexHtmlDir))) {
return `${c.strong(
'index.html',
)} file is missing in ${appSrcMainAssetsWwwDir}`;
Expand All @@ -66,7 +66,7 @@ async function checkAndroidManifestFile(config: Config, appSrcMainDir: string) {
const manifestFileName = 'AndroidManifest.xml';
const manifestFilePath = join(appSrcMainDir, manifestFileName);

if (!(await existsAsync(manifestFilePath))) {
if (!(await pathExists(manifestFilePath))) {
return `${c.strong(manifestFileName)} is missing in ${appSrcMainDir}`;
}

Expand Down Expand Up @@ -183,7 +183,7 @@ async function checkPackage(
}

const appSrcMainJavaDir = join(appSrcMainDir, 'java');
if (!(await existsAsync(appSrcMainJavaDir))) {
if (!(await pathExists(appSrcMainJavaDir))) {
return `${c.strong('java')} directory is missing in ${appSrcMainDir}`;
}

Expand All @@ -208,7 +208,7 @@ async function checkPackage(
const mainActivityClassFileName = `${mainActivityClassName}.java`;
const mainActivityClassFilePath = join(checkPath, mainActivityClassFileName);

if (!(await existsAsync(mainActivityClassFilePath))) {
if (!(await pathExists(mainActivityClassFilePath))) {
return `Main activity file (${mainActivityClassFileName}) is missing in ${checkPath}`;
}

Expand All @@ -220,11 +220,11 @@ async function checkBuildGradle(config: Config, packageId: string) {
const fileName = 'build.gradle';
const filePath = join(appDir, fileName);

if (!(await existsAsync(filePath))) {
if (!(await pathExists(filePath))) {
return `${fileName} file is missing in ${appDir}`;
}

let fileContent = await readFileAsync(filePath, 'utf8');
let fileContent = await readFile(filePath, { encoding: 'utf-8' });

fileContent = fileContent.replace(/'|"/g, '').replace(/\s+/g, ' ');

Expand All @@ -243,7 +243,7 @@ async function checkGradlew(config: Config) {
const fileName = 'gradlew';
const filePath = join(config.android.platformDirAbs, fileName);

if (!(await existsAsync(filePath))) {
if (!(await pathExists(filePath))) {
return `${c.strong(fileName)} file is missing in ${
config.android.platformDir
}`;
Expand Down
13 changes: 8 additions & 5 deletions cli/src/android/open.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { pathExists } from '@ionic/utils-fs';
import open from 'open';

import { runCommand } from '../common';
import type { Config } from '../definitions';
import { OS } from '../definitions';
import { logger } from '../log';
import { existsSync } from '../util/fs';

export async function openAndroid(config: Config): Promise<void> {
logger.info(`Opening Android project at ${config.android.platformDir}.`);
Expand All @@ -19,10 +19,13 @@ export async function openAndroid(config: Config): Promise<void> {
case OS.Windows: {
let androidStudioPath = config.windows.androidStudioPath;
try {
if (!existsSync(androidStudioPath)) {
let commandResult = await runCommand(
'REG QUERY "HKEY_LOCAL_MACHINE\\SOFTWARE\\Android Studio" /v Path',
);
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) {
Expand Down
Loading