native-run
Advanced tools
Comparing version 0.0.1 to 0.0.2
@@ -11,4 +11,8 @@ "use strict"; | ||
.map(device => deviceToTarget(device)); | ||
const virtualDevices = (await avd_1.getAVDs(sdk)) | ||
.map(avd => avdToTarget(avd)); | ||
const avds = await avd_1.getInstalledAVDs(sdk); | ||
const defaultAvd = await avd_1.getDefaultAVD(sdk, avds); | ||
if (!avds.includes(defaultAvd)) { | ||
avds.push(defaultAvd); | ||
} | ||
const virtualDevices = avds.map(avd => avdToTarget(avd)); | ||
if (args.includes('--json')) { | ||
@@ -28,5 +32,10 @@ process.stdout.write(JSON.stringify({ devices, virtualDevices })); | ||
process.stdout.write('\nVirtual Devices:\n\n'); | ||
for (const avd of virtualDevices) { | ||
process.stdout.write(` ${formatTarget(avd)}\n`); | ||
if (virtualDevices.length === 0) { | ||
process.stdout.write(' No virtual devices found\n'); | ||
} | ||
else { | ||
for (const avd of virtualDevices) { | ||
process.stdout.write(` ${formatTarget(avd)}\n`); | ||
} | ||
} | ||
} | ||
@@ -33,0 +42,0 @@ exports.run = run; |
@@ -5,2 +5,3 @@ "use strict"; | ||
const cli_1 = require("../utils/cli"); | ||
const log_1 = require("../utils/log"); | ||
const adb_1 = require("./utils/adb"); | ||
@@ -23,8 +24,8 @@ const avd_1 = require("./utils/avd"); | ||
const device = await selectDevice(sdk, args); | ||
process.stdout.write(`Selected ${device.type === 'hardware' ? 'hardware device' : 'emulator'} ${device.serial}\n`); | ||
log_1.log(`Selected ${device.type === 'hardware' ? 'hardware device' : 'emulator'} ${device.serial}\n`); | ||
await adb_1.waitForBoot(sdk, device); | ||
await run_1.installApkToDevice(sdk, device, apk, app); | ||
process.stdout.write(`Starting application activity ${app}/${activity}...\n`); | ||
log_1.log(`Starting application activity ${app}/${activity}...\n`); | ||
await adb_1.startActivity(sdk, device, app, activity); | ||
process.stdout.write(`Run Successful\n`); | ||
log_1.log(`Run Successful\n`); | ||
} | ||
@@ -34,3 +35,3 @@ exports.run = run; | ||
const devices = await adb_1.getDevices(sdk); | ||
const avds = await avd_1.getAVDs(sdk); | ||
const avds = await avd_1.getInstalledAVDs(sdk); | ||
const target = cli_1.getOptionValue(args, '--target'); | ||
@@ -44,4 +45,3 @@ const preferEmulator = args.includes('--emulator'); | ||
else { | ||
throw new errors_1.RunException(`Target not found: ${target}\n` + | ||
`Use --list to select a valid target`); | ||
throw new errors_1.RunException(`Target not found: ${target}`, errors_1.ERR_TARGET_NOT_FOUND); | ||
} | ||
@@ -48,0 +48,0 @@ } |
@@ -6,17 +6,24 @@ "use strict"; | ||
const sdk = await sdk_1.getSDK(); | ||
const packages = await sdk_1.findAllSDKPackages(sdk); | ||
const sdkinfo = Object.assign({}, sdk, { packages }); | ||
if (args.includes('--json')) { | ||
process.stdout.write(JSON.stringify(sdk)); | ||
process.stdout.write(JSON.stringify(sdkinfo)); | ||
return; | ||
} | ||
process.stdout.write(`${formatSDK(sdk)}\n\n`); | ||
process.stdout.write(`${formatSDKInfo(sdkinfo)}\n\n`); | ||
} | ||
exports.run = run; | ||
function formatSDK(sdk) { | ||
function formatSDKInfo(sdk) { | ||
return ` | ||
SDK Root: ${sdk.root} | ||
SDK Tools: ${sdk.tools.path} (${sdk.tools.version}) | ||
SDK Platform Tools: ${sdk.platformTools.path} (${sdk.platformTools.version}) | ||
Android Emulator: ${sdk.emulator.path} (${sdk.emulator.version}) | ||
AVDs Home: ${sdk.avds.home} | ||
SDK: ${sdk.root} | ||
${sdk.packages.map(p => formatSDKPackage(p)).join('')} | ||
`.trim(); | ||
} | ||
function formatSDKPackage(p) { | ||
return ` | ||
Name: ${p.name} | ||
Path: ${p.path} | ||
Version: ${p.version}${p.apiLevel ? ` (API ${p.apiLevel})` : ''} | ||
Location: ${p.location} | ||
`; | ||
} |
@@ -5,2 +5,3 @@ "use strict"; | ||
const Debug = require("debug"); | ||
const path = require("path"); | ||
const split2 = require("split2"); | ||
@@ -10,2 +11,3 @@ const through2 = require("through2"); | ||
const process_1 = require("../../utils/process"); | ||
const sdk_1 = require("./sdk"); | ||
const modulePrefix = 'native-run:android:utils:adb'; | ||
@@ -20,6 +22,7 @@ const ADB_GETPROP_MAP = new Map([ | ||
const debug = Debug(`${modulePrefix}:${getDevices.name}`); | ||
const adbBin = `${sdk.platformTools.path}/adb`; | ||
const platformTools = await sdk_1.getSDKPackage(path.join(sdk.root, 'platform-tools')); | ||
const adbBin = `${platformTools.location}/adb`; | ||
const args = ['devices', '-l']; | ||
debug('Invoking adb: %O %O', adbBin, args); | ||
const { stdout } = await process_1.execFile(adbBin, args); | ||
const { stdout } = await process_1.execFile(adbBin, args, { env: sdk_1.supplementProcessEnv(sdk) }); | ||
const devices = parseAdbDevices(stdout); | ||
@@ -40,6 +43,7 @@ await Promise.all(devices.map(async (device) => { | ||
const debug = Debug(`${modulePrefix}:${getDeviceProperty.name}`); | ||
const adbBin = `${sdk.platformTools.path}/adb`; | ||
const platformTools = await sdk_1.getSDKPackage(path.join(sdk.root, 'platform-tools')); | ||
const adbBin = `${platformTools.location}/adb`; | ||
const args = ['-s', device.serial, 'shell', 'getprop', property]; | ||
debug('Invoking adb: %O %O', adbBin, args); | ||
const { stdout } = await process_1.execFile(adbBin, args); | ||
const { stdout } = await process_1.execFile(adbBin, args, { env: sdk_1.supplementProcessEnv(sdk) }); | ||
return stdout.trim(); | ||
@@ -51,7 +55,8 @@ } | ||
const re = /^\[([a-z0-9\.]+)\]: \[(.*)\]$/; | ||
const adbBin = `${sdk.platformTools.path}/adb`; | ||
const platformTools = await sdk_1.getSDKPackage(path.join(sdk.root, 'platform-tools')); | ||
const adbBin = `${platformTools.location}/adb`; | ||
const args = ['-s', device.serial, 'shell', 'getprop']; | ||
debug('Invoking adb: %O %O', adbBin, args); | ||
const propAllowList = [...ADB_GETPROP_MAP.keys()]; | ||
const { stdout } = await process_1.execFile(adbBin, args); | ||
const { stdout } = await process_1.execFile(adbBin, args, { env: sdk_1.supplementProcessEnv(sdk) }); | ||
const properties = {}; | ||
@@ -72,6 +77,7 @@ for (const line of stdout.split('\n')) { | ||
const debug = Debug(`${modulePrefix}:${waitForDevice.name}`); | ||
const adbBin = `${sdk.platformTools.path}/adb`; | ||
const platformTools = await sdk_1.getSDKPackage(path.join(sdk.root, 'platform-tools')); | ||
const adbBin = `${platformTools.location}/adb`; | ||
const args = ['-s', serial, 'wait-for-any-device']; | ||
debug('Invoking adb: %O %O', adbBin, args); | ||
await process_1.execFile(adbBin, args); | ||
await process_1.execFile(adbBin, args, { env: sdk_1.supplementProcessEnv(sdk) }); | ||
debug('Device %s is connected to ADB!', serial); | ||
@@ -96,6 +102,7 @@ } | ||
const debug = Debug(`${modulePrefix}:${installApk.name}`); | ||
const adbBin = `${sdk.platformTools.path}/adb`; | ||
const platformTools = await sdk_1.getSDKPackage(path.join(sdk.root, 'platform-tools')); | ||
const adbBin = `${platformTools.location}/adb`; | ||
const args = ['-s', device.serial, 'install', '-r', '-t', apk]; | ||
debug('Invoking adb: %O %O', adbBin, args); | ||
const p = child_process_1.spawn(adbBin, args, { stdio: 'pipe' }); | ||
const p = child_process_1.spawn(adbBin, args, { stdio: 'pipe', env: sdk_1.supplementProcessEnv(sdk) }); | ||
return new Promise((resolve, reject) => { | ||
@@ -128,6 +135,7 @@ p.on('close', code => { | ||
const debug = Debug(`${modulePrefix}:${uninstallApp.name}`); | ||
const adbBin = `${sdk.platformTools.path}/adb`; | ||
const platformTools = await sdk_1.getSDKPackage(path.join(sdk.root, 'platform-tools')); | ||
const adbBin = `${platformTools.location}/adb`; | ||
const args = ['-s', device.serial, 'uninstall', app]; | ||
debug('Invoking adb: %O %O', adbBin, args); | ||
await process_1.execFile(adbBin, args); | ||
await process_1.execFile(adbBin, args, { env: sdk_1.supplementProcessEnv(sdk) }); | ||
} | ||
@@ -153,6 +161,7 @@ exports.uninstallApp = uninstallApp; | ||
const debug = Debug(`${modulePrefix}:${startActivity.name}`); | ||
const adbBin = `${sdk.platformTools.path}/adb`; | ||
const platformTools = await sdk_1.getSDKPackage(path.join(sdk.root, 'platform-tools')); | ||
const adbBin = `${platformTools.location}/adb`; | ||
const args = ['-s', device.serial, 'shell', 'am', 'start', '-W', '-n', `${packageName}/${activityName}`]; | ||
debug('Invoking adb: %O %O', adbBin, args); | ||
await process_1.execFile(adbBin, args); | ||
await process_1.execFile(adbBin, args, { env: sdk_1.supplementProcessEnv(sdk) }); | ||
} | ||
@@ -159,0 +168,0 @@ exports.startActivity = startActivity; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const utils_fs_1 = require("@ionic/utils-fs"); | ||
const Debug = require("debug"); | ||
const path = require("path"); | ||
const fs_1 = require("../../utils/fs"); | ||
const pathlib = require("path"); | ||
const errors_1 = require("../../errors"); | ||
const ini_1 = require("../../utils/ini"); | ||
const object_1 = require("../../utils/object"); | ||
const sdk_1 = require("./sdk"); | ||
const modulePrefix = 'native-run:android:utils:avd'; | ||
@@ -14,12 +17,13 @@ exports.isAVDINI = (o) => o | ||
exports.isAVDConfigINI = (o) => o | ||
&& (typeof o.AvdId === 'undefined' || typeof o.AvdId === 'string') | ||
&& (typeof o['avd.ini.displayname'] === 'undefined' || typeof o['avd.ini.displayname'] === 'string') | ||
&& (typeof o['hw.lcd.density'] === 'undefined' || typeof o['hw.lcd.density'] === 'string') | ||
&& (typeof o['hw.lcd.height'] === 'undefined' || typeof o['hw.lcd.height'] === 'string') | ||
&& (typeof o['hw.lcd.width'] === 'undefined' || typeof o['hw.lcd.width'] === 'string'); | ||
&& (typeof o['hw.lcd.width'] === 'undefined' || typeof o['hw.lcd.width'] === 'string') | ||
&& (typeof o['image.sysdir.1'] === 'undefined' || typeof o['image.sysdir.1'] === 'string'); | ||
async function getAVDINIs(sdk) { | ||
const debug = Debug(`${modulePrefix}:${getAVDINIs.name}`); | ||
const contents = await fs_1.readdir(sdk.avds.home); | ||
const contents = await utils_fs_1.readDir(sdk.avdHome); | ||
const iniFilePaths = contents | ||
.filter(f => path.extname(f) === '.ini') | ||
.map(f => path.resolve(sdk.avds.home, f)); | ||
.filter(f => pathlib.extname(f) === '.ini') | ||
.map(f => pathlib.resolve(sdk.avdHome, f)); | ||
debug('Discovered AVD ini files: %O', iniFilePaths); | ||
@@ -33,4 +37,4 @@ const iniFiles = await Promise.all(iniFilePaths.map(async (f) => [f, await ini_1.readINI(f, exports.isAVDINI)])); | ||
function getAVDFromConfigINI(inipath, ini, configini) { | ||
const inibasename = path.basename(inipath); | ||
const id = inibasename.substring(0, inibasename.length - path.extname(inibasename).length); | ||
const inibasename = pathlib.basename(inipath); | ||
const id = inibasename.substring(0, inibasename.length - pathlib.extname(inibasename).length); | ||
const name = configini['avd.ini.displayname'] | ||
@@ -54,3 +58,3 @@ ? String(configini['avd.ini.displayname']) | ||
async function getAVDFromINI(inipath, ini) { | ||
const configini = await ini_1.readINI(path.resolve(ini.path, 'config.ini'), exports.isAVDConfigINI); | ||
const configini = await ini_1.readINI(pathlib.resolve(ini.path, 'config.ini'), exports.isAVDConfigINI); | ||
if (configini) { | ||
@@ -61,99 +65,122 @@ return getAVDFromConfigINI(inipath, ini, configini); | ||
exports.getAVDFromINI = getAVDFromINI; | ||
async function getAVDs(sdk) { | ||
async function getInstalledAVDs(sdk) { | ||
const avdInis = await getAVDINIs(sdk); | ||
const possibleAvds = await Promise.all(avdInis.map(([inipath, ini]) => getAVDFromINI(inipath, ini))); | ||
const avds = possibleAvds.filter((avd) => typeof avd !== 'undefined'); | ||
const defaultAvd = await getDefaultAVD(sdk, avds); | ||
if (!avds.includes(defaultAvd)) { | ||
avds.push(defaultAvd); | ||
} | ||
return avds; | ||
} | ||
exports.getAVDs = getAVDs; | ||
const DEFAULT_AVD_ID = 'Pixel_2_API_28'; | ||
const DEFAULT_AVD_INI = { | ||
'avd.ini.encoding': 'UTF-8', | ||
'target': 'android-28', | ||
'path.rel': `avd/${DEFAULT_AVD_ID}.avd`, | ||
}; | ||
const DEFAULT_AVD_CONFIG_INI = { | ||
'AvdId': DEFAULT_AVD_ID, | ||
'abi.type': 'x86', | ||
'avd.ini.displayname': 'Pixel 2 API 28', | ||
'avd.ini.encoding': 'UTF-8', | ||
'hw.accelerometer': 'yes', | ||
'hw.audioInput': 'yes', | ||
'hw.battery': 'yes', | ||
'hw.camera.back': 'virtualscene', | ||
'hw.camera.front': 'emulated', | ||
'hw.cpu.arch': 'x86', | ||
'hw.cpu.ncore': '4', | ||
// 'hw.device.hash2': 'MD5:bc5032b2a871da511332401af3ac6bb0', | ||
'hw.device.manufacturer': 'Google', | ||
'hw.device.name': 'pixel_2', | ||
'hw.gps': 'yes', | ||
'hw.gpu.enabled': 'yes', | ||
'hw.gpu.mode': 'auto', | ||
'hw.initialOrientation': 'Portrait', | ||
'hw.keyboard': 'yes', | ||
'hw.lcd.density': '420', | ||
'hw.lcd.height': '1920', | ||
'hw.lcd.width': '1080', | ||
'hw.ramSize': '1536', | ||
'hw.sdCard': 'yes', | ||
'hw.sensors.orientation': 'yes', | ||
'hw.sensors.proximity': 'yes', | ||
'image.sysdir.1': 'system-images/android-28/google_apis/x86/', | ||
'sdcard.size': '100M', | ||
'showDeviceFrame': 'yes', | ||
'skin.dynamic': 'yes', | ||
'skin.name': 'pixel_2', | ||
'tag.display': 'Google APIs', | ||
'tag.id': 'google_apis', | ||
}; | ||
function getDefaultAVDPath(sdk) { | ||
return path.join(sdk.avds.home, `${DEFAULT_AVD_ID}.avd`); | ||
exports.getInstalledAVDs = getInstalledAVDs; | ||
async function getDefaultAVDSchematic(sdk) { | ||
const debug = Debug(`${modulePrefix}:${getDefaultAVDSchematic.name}`); | ||
const packages = await sdk_1.findAllSDKPackages(sdk); | ||
const apis = await sdk_1.getAPILevels(packages); | ||
const fullAPILevels = apis.filter(api => api.full); | ||
if (fullAPILevels.length === 0) { | ||
throw new errors_1.AVDException('No full API installation found. Install the platform and sources of an API level.', errors_1.ERR_NO_FULL_API_INSTALLATION); | ||
} | ||
for (const api of fullAPILevels) { | ||
try { | ||
const schematic = await createAVDSchematic(sdk, api); | ||
if (schematic) { | ||
debug('Using schematic %s for default AVD', schematic.id); | ||
return schematic; | ||
} | ||
} | ||
catch (e) { | ||
if (!(e instanceof errors_1.AVDException)) { | ||
throw e; | ||
} | ||
debug('Issue with API %s: %s', api.level, e.message); | ||
} | ||
} | ||
throw new errors_1.AVDException('No suitable API installation found.', errors_1.ERR_NO_SUITABLE_API_INSTALLATION); | ||
} | ||
exports.getDefaultAVDPath = getDefaultAVDPath; | ||
function getDefaultAVDINI(sdk) { | ||
const avdpath = getDefaultAVDPath(sdk); | ||
return [ | ||
path.join(sdk.avds.home, `${DEFAULT_AVD_ID}.ini`), | ||
Object.assign({ 'path': avdpath }, DEFAULT_AVD_INI), | ||
]; | ||
} | ||
exports.getDefaultAVDINI = getDefaultAVDINI; | ||
function getDefaultAVDConfigINI(sdk) { | ||
const avdpath = getDefaultAVDPath(sdk); | ||
return [ | ||
path.join(avdpath, 'config.ini'), | ||
Object.assign({ 'skin.path': path.join(sdk.root, 'skins', 'pixel_2') }, DEFAULT_AVD_CONFIG_INI), | ||
]; | ||
} | ||
exports.getDefaultAVDConfigINI = getDefaultAVDConfigINI; | ||
exports.getDefaultAVDSchematic = getDefaultAVDSchematic; | ||
async function getDefaultAVD(sdk, avds) { | ||
const defaultAvd = avds.find(avd => avd.id === DEFAULT_AVD_ID); | ||
const defaultAvdSchematic = await getDefaultAVDSchematic(sdk); | ||
const defaultAvd = avds.find(avd => avd.id === defaultAvdSchematic.id); | ||
if (defaultAvd) { | ||
return defaultAvd; | ||
} | ||
return createDefaultAVD(sdk); | ||
return createAVD(sdk, defaultAvdSchematic); | ||
} | ||
exports.getDefaultAVD = getDefaultAVD; | ||
async function createDefaultAVD(sdk) { | ||
const [inipath, ini] = getDefaultAVDINI(sdk); | ||
const [configinipath, configini] = getDefaultAVDConfigINI(sdk); | ||
await fs_1.mkdirp(path.dirname(configinipath)); | ||
const writeConfigFile = async (p, f) => { | ||
const ini = Object.keys(f).sort().reduce((acc, k) => { | ||
acc[k] = f[k]; | ||
return acc; | ||
}, {}); | ||
await ini_1.writeINI(p, ini); | ||
}; | ||
async function createAVD(sdk, schematic) { | ||
const { id, ini, configini } = schematic; | ||
await utils_fs_1.mkdirp(pathlib.join(sdk.avdHome, `${id}.avd`)); | ||
await Promise.all([ | ||
writeConfigFile(inipath, ini), | ||
writeConfigFile(configinipath, configini), | ||
ini_1.writeINI(pathlib.join(sdk.avdHome, `${id}.ini`), ini), | ||
ini_1.writeINI(pathlib.join(sdk.avdHome, `${id}.avd`, 'config.ini'), configini), | ||
]); | ||
return getAVDFromConfigINI(inipath, ini, configini); | ||
return getAVDFromConfigINI(pathlib.join(sdk.avdHome, `${id}.ini`), ini, configini); | ||
} | ||
exports.createDefaultAVD = createDefaultAVD; | ||
exports.createAVD = createAVD; | ||
async function loadPartialSchematic(api) { | ||
if (api.level === '28') { | ||
return Promise.resolve().then(() => require('../data/avds/Pixel_2_API_28.json')); | ||
} | ||
else if (api.level === '27') { | ||
return Promise.resolve().then(() => require('../data/avds/Pixel_2_API_27.json')); | ||
} | ||
else if (api.level === '26') { | ||
return Promise.resolve().then(() => require('../data/avds/Pixel_2_API_26.json')); | ||
} | ||
else if (api.level === '25') { | ||
return Promise.resolve().then(() => require('../data/avds/Pixel_API_25.json')); | ||
} | ||
else if (api.level === '24') { | ||
return Promise.resolve().then(() => require('../data/avds/Nexus_5X_API_24.json')); | ||
} | ||
throw new errors_1.AVDException(`Unsupported API level: ${api.level}`, errors_1.ERR_UNSUPPORTED_API_LEVEL); | ||
} | ||
exports.loadPartialSchematic = loadPartialSchematic; | ||
async function createAVDSchematic(sdk, api) { | ||
const debug = Debug(`${modulePrefix}:${createAVDSchematic.name}`); | ||
debug('Attempting to build AVD schematic for API %s', api.level); | ||
const partialSchematic = await loadPartialSchematic(api); | ||
debug('Schematic %s matches', partialSchematic.id); | ||
const avdpath = pathlib.join(sdk.avdHome, `${partialSchematic.id}.avd`); | ||
const skinpath = getSkinPathByName(sdk, partialSchematic.configini['skin.name']); | ||
const schematic = { | ||
id: partialSchematic.id, | ||
ini: object_1.sort(Object.assign({}, partialSchematic.ini, { 'path': avdpath, 'path.rel': `avd/${partialSchematic.id}.avd` })), | ||
configini: object_1.sort(Object.assign({}, partialSchematic.configini, { 'skin.path': skinpath })), | ||
}; | ||
await validateAVDSchematic(sdk, schematic); | ||
return schematic; | ||
} | ||
exports.createAVDSchematic = createAVDSchematic; | ||
async function validateAVDSchematic(sdk, schematic) { | ||
const { configini } = schematic; | ||
const skinpath = configini['skin.path']; | ||
const sysdir = configini['image.sysdir.1']; | ||
if (!skinpath) { | ||
throw new errors_1.AVDException(`${schematic.id} does not have a skin defined.`, errors_1.ERR_INVALID_SKIN); | ||
} | ||
if (!sysdir) { | ||
throw new errors_1.AVDException(`${schematic.id} does not have a system image defined.`, errors_1.ERR_INVALID_SYSTEM_IMAGE); | ||
} | ||
await validateSkinPath(skinpath); | ||
await validateSystemImagePath(sdk, sysdir); | ||
} | ||
exports.validateAVDSchematic = validateAVDSchematic; | ||
async function validateSkinPath(skinpath) { | ||
const stat = await utils_fs_1.statSafe(pathlib.join(skinpath, 'layout')); | ||
if (!stat || !stat.isFile()) { | ||
throw new errors_1.AVDException(`${skinpath} is an invalid skin.`, errors_1.ERR_INVALID_SKIN); | ||
} | ||
} | ||
exports.validateSkinPath = validateSkinPath; | ||
async function validateSystemImagePath(sdk, sysdir) { | ||
const p = pathlib.join(sdk.root, sysdir, 'package.xml'); | ||
const stat = await utils_fs_1.statSafe(p); | ||
if (!stat || !stat.isFile()) { | ||
throw new errors_1.AVDException(`${p} is an invalid system image package.`, errors_1.ERR_INVALID_SYSTEM_IMAGE); | ||
} | ||
} | ||
exports.validateSystemImagePath = validateSystemImagePath; | ||
function getSkinPathByName(sdk, name) { | ||
const path = pathlib.join(sdk.root, 'skins', name); | ||
return path; | ||
} | ||
exports.getSkinPathByName = getSkinPathByName; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const utils_fs_1 = require("@ionic/utils-fs"); | ||
const child_process_1 = require("child_process"); | ||
@@ -11,4 +12,5 @@ const Debug = require("debug"); | ||
const errors_1 = require("../../errors"); | ||
const fs_1 = require("../../utils/fs"); | ||
const fn_1 = require("../../utils/fn"); | ||
const adb_1 = require("./adb"); | ||
const sdk_1 = require("./sdk"); | ||
const modulePrefix = 'native-run:android:utils:emulator'; | ||
@@ -38,10 +40,11 @@ /** | ||
const debug = Debug(`${modulePrefix}:${spawnEmulator.name}`); | ||
const emulatorBin = `${sdk.emulator.path}/emulator`; | ||
const args = ['-avd', avd.id, '-port', port.toString()]; | ||
const emulator = await sdk_1.getSDKPackage(path.join(sdk.root, 'emulator')); | ||
const emulatorBin = `${emulator.location}/emulator`; | ||
const args = ['-avd', avd.id, '-port', port.toString(), '-verbose']; | ||
debug('Invoking emulator: %O %O', emulatorBin, args); | ||
const p = child_process_1.spawn(emulatorBin, args, { detached: true, stdio: ['ignore', 'pipe', 'pipe'] }); | ||
const p = child_process_1.spawn(emulatorBin, args, { detached: true, stdio: ['ignore', 'pipe', 'pipe'], env: sdk_1.supplementProcessEnv(sdk) }); | ||
p.unref(); | ||
return new Promise((_resolve, _reject) => { | ||
const resolve = () => { _resolve(); cleanup(); }; | ||
const reject = err => { _reject(err); cleanup(); }; | ||
const resolve = fn_1.once(() => { _resolve(); cleanup(); }); | ||
const reject = fn_1.once(err => { _reject(err); cleanup(); }); | ||
adb_1.waitForDevice(sdk, `emulator-${port}`).then(() => resolve(), err => reject(err)); | ||
@@ -124,3 +127,3 @@ const eventParser = through2((chunk, enc, cb) => { | ||
debug('Connected to %s:%d', host, port); | ||
fs_1.readFile(path.resolve(os.homedir(), '.emulator_console_auth_token'), 'utf8') | ||
utils_fs_1.readFile(path.resolve(os.homedir(), '.emulator_console_auth_token'), { encoding: 'utf8' }) | ||
.then(contents => resolve(contents.trim()), err => reject(err)); | ||
@@ -144,6 +147,6 @@ }); | ||
}, 3000); | ||
const cleanup = () => { | ||
const cleanup = fn_1.once(() => { | ||
clearTimeout(timer); | ||
sock.end(); | ||
}; | ||
}); | ||
sock.on('timeout', () => { | ||
@@ -150,0 +153,0 @@ reject(new errors_1.EmulatorException(`Socket timeout on ${host}:${port}`)); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const utils_fs_1 = require("@ionic/utils-fs"); | ||
const Debug = require("debug"); | ||
const os = require("os"); | ||
const path = require("path"); | ||
const fs_1 = require("../../utils/fs"); | ||
const properties_1 = require("./properties"); | ||
const pathlib = require("path"); | ||
const errors_1 = require("../../errors"); | ||
const modulePrefix = 'native-run:android:utils:sdk'; | ||
const homedir = os.homedir(); | ||
const SDK_DIRECTORIES = new Map([ | ||
['darwin', [pathlib.join(homedir, 'Library', 'Android', 'sdk')]], | ||
['linux', [pathlib.join(homedir, 'Android', 'sdk')]], | ||
['win32', [pathlib.join('%LOCALAPPDATA%', 'Android', 'sdk')]], | ||
]); | ||
async function getSDK() { | ||
const debug = Debug(`${modulePrefix}:${getSDK.name}`); | ||
const root = await resolveSDKRoot(); | ||
// TODO: validate root and resolve source.properties | ||
const [toolsPath, platformToolsPath, emulatorPath, avdHome,] = await Promise.all([ | ||
resolveToolsPath(root), | ||
resolvePlatformToolsPath(root), | ||
resolveEmulatorPath(root), | ||
resolveAVDHome(root), | ||
]); | ||
const [toolsVersion, platformToolsVersion, emulatorVersion,] = await Promise.all([ | ||
getAndroidPackageVersion(toolsPath), | ||
getAndroidPackageVersion(platformToolsPath), | ||
getAndroidPackageVersion(emulatorPath), | ||
]); | ||
const sdk = { | ||
root, | ||
tools: { | ||
path: toolsPath, | ||
version: toolsVersion, | ||
const emulatorHome = await resolveEmulatorHome(); | ||
const avdHome = await resolveAVDHome(); | ||
return { root, emulatorHome, avdHome }; | ||
} | ||
exports.getSDK = getSDK; | ||
async function getAPILevels(packages) { | ||
const debug = Debug(`${modulePrefix}:${getAPILevels.name}`); | ||
const levels = [ | ||
...new Set(packages | ||
.map(pkg => pkg.apiLevel) | ||
.filter((apiLevel) => typeof apiLevel !== 'undefined')), | ||
].sort((a, b) => a <= b ? 1 : -1); | ||
debug('Discovered installed API Levels: %O', levels); | ||
return levels.map(level => { | ||
const pkgs = packages.filter(pkg => pkg.apiLevel === level); | ||
const full = Boolean(pkgs.find(pkg => pkg.path === `platforms;android-${level}`) && | ||
pkgs.find(pkg => pkg.path === `sources;android-${level}`)); | ||
return { | ||
level, | ||
packages: pkgs, | ||
full, | ||
}; | ||
}); | ||
} | ||
exports.getAPILevels = getAPILevels; | ||
const pkgcache = new Map(); | ||
async function findAllSDKPackages(sdk) { | ||
const debug = Debug(`${modulePrefix}:${findAllSDKPackages.name}`); | ||
if (sdk.packages) { | ||
return sdk.packages; | ||
} | ||
const sourcesRe = /^sources\/android-\d+\/.+\/.+/; | ||
debug('Walking %s to discover SDK packages', sdk.root); | ||
const contents = await utils_fs_1.readDirp(sdk.root, { | ||
filter: item => pathlib.basename(item.path) === 'package.xml', | ||
walkerOptions: { | ||
pathFilter: p => { | ||
if ([ | ||
'bin', | ||
'bin64', | ||
'lib', | ||
'lib64', | ||
'include', | ||
'clang-include', | ||
'skins', | ||
'data', | ||
'examples', | ||
'resources', | ||
'systrace', | ||
'extras', | ||
].includes(pathlib.basename(p))) { | ||
return false; | ||
} | ||
if (p.match(sourcesRe)) { | ||
return false; | ||
} | ||
return true; | ||
}, | ||
}, | ||
platformTools: { | ||
path: platformToolsPath, | ||
version: platformToolsVersion, | ||
}, | ||
emulator: { | ||
path: emulatorPath, | ||
version: emulatorVersion, | ||
}, | ||
avds: { | ||
home: avdHome, | ||
}, | ||
}; | ||
debug('SDK info:\n%O', sdk); | ||
return sdk; | ||
}); | ||
sdk.packages = await Promise.all(contents | ||
.map(p => pathlib.dirname(p)) | ||
.map(p => getSDKPackage(p))); | ||
sdk.packages.sort((a, b) => a.name >= b.name ? 1 : -1); | ||
return sdk.packages; | ||
} | ||
exports.getSDK = getSDK; | ||
exports.findAllSDKPackages = findAllSDKPackages; | ||
async function getSDKPackage(location) { | ||
const debug = Debug(`${modulePrefix}:${getSDKPackage.name}`); | ||
let pkg = pkgcache.get(location); | ||
if (!pkg) { | ||
const packageXmlPath = pathlib.join(location, 'package.xml'); | ||
debug('Parsing %s', packageXmlPath); | ||
try { | ||
const packageXml = await readPackageXml(packageXmlPath); | ||
const name = getNameFromPackageXml(packageXml); | ||
const version = getVersionFromPackageXml(packageXml); | ||
const path = getPathFromPackageXml(packageXml); | ||
const apiLevel = getAPILevelFromPackageXml(packageXml); | ||
pkg = { | ||
path, | ||
location, | ||
version, | ||
name, | ||
apiLevel, | ||
}; | ||
} | ||
catch (e) { | ||
debug('Encountered error with %s: %O', packageXmlPath, e); | ||
if (e.code === 'ENOENT') { | ||
throw new errors_1.SDKException(`SDK package not found by location: ${location}.`, errors_1.ERR_SDK_PACKAGE_NOT_FOUND); | ||
} | ||
throw e; | ||
} | ||
pkgcache.set(location, pkg); | ||
} | ||
return pkg; | ||
} | ||
exports.getSDKPackage = getSDKPackage; | ||
async function readPackageXml(path) { | ||
const et = await Promise.resolve().then(() => require('elementtree')); | ||
const contents = await utils_fs_1.readFile(path, { encoding: 'utf8' }); | ||
const etree = et.parse(contents); | ||
return etree; | ||
} | ||
exports.readPackageXml = readPackageXml; | ||
function getPathFromPackageXml(packageXml) { | ||
const localPackage = packageXml.find('./localPackage'); | ||
if (!localPackage) { | ||
throw new errors_1.SDKException(`Invalid SDK package.`, errors_1.ERR_INVALID_SDK_PACKAGE); | ||
} | ||
const path = localPackage.get('path'); | ||
if (!path) { | ||
throw new errors_1.SDKException(`Invalid SDK package path.`, errors_1.ERR_INVALID_SDK_PACKAGE); | ||
} | ||
return path.toString(); | ||
} | ||
exports.getPathFromPackageXml = getPathFromPackageXml; | ||
function getAPILevelFromPackageXml(packageXml) { | ||
const apiLevel = packageXml.find('./localPackage/type-details/api-level'); | ||
return apiLevel && apiLevel.text ? apiLevel.text.toString() : undefined; | ||
} | ||
exports.getAPILevelFromPackageXml = getAPILevelFromPackageXml; | ||
function getNameFromPackageXml(packageXml) { | ||
const name = packageXml.find('./localPackage/display-name'); | ||
if (!name || !name.text) { | ||
throw new errors_1.SDKException(`Invalid SDK package name.`, errors_1.ERR_INVALID_SDK_PACKAGE); | ||
} | ||
return name.text.toString(); | ||
} | ||
exports.getNameFromPackageXml = getNameFromPackageXml; | ||
function getVersionFromPackageXml(packageXml) { | ||
const versionElements = [ | ||
packageXml.find('./localPackage/revision/major'), | ||
packageXml.find('./localPackage/revision/minor'), | ||
packageXml.find('./localPackage/revision/micro'), | ||
]; | ||
const textFromElement = (e) => e && e.text ? e.text.toString() : ''; | ||
const versions = []; | ||
for (const version of versionElements.map(textFromElement)) { | ||
if (!version) { | ||
break; | ||
} | ||
versions.push(version); | ||
} | ||
if (versions.length === 0) { | ||
throw new errors_1.SDKException(`Invalid SDK package version.`, errors_1.ERR_INVALID_SDK_PACKAGE); | ||
} | ||
return versions.join('.'); | ||
} | ||
exports.getVersionFromPackageXml = getVersionFromPackageXml; | ||
async function resolveSDKRoot() { | ||
@@ -52,3 +173,3 @@ const debug = Debug(`${modulePrefix}:${resolveSDKRoot.name}`); | ||
// defined and valid. | ||
if (process.env.ANDROID_HOME && await fs_1.isDir(process.env.ANDROID_HOME)) { | ||
if (process.env.ANDROID_HOME && await utils_fs_1.isDir(process.env.ANDROID_HOME)) { | ||
debug('Using $ANDROID_HOME at %s', process.env.ANDROID_HOME); | ||
@@ -59,75 +180,57 @@ return process.env.ANDROID_HOME; | ||
// No valid $ANDROID_HOME, try $ANDROID_SDK_ROOT. | ||
if (process.env.ANDROID_SDK_ROOT && await fs_1.isDir(process.env.ANDROID_SDK_ROOT)) { | ||
if (process.env.ANDROID_SDK_ROOT && await utils_fs_1.isDir(process.env.ANDROID_SDK_ROOT)) { | ||
debug('Using $ANDROID_SDK_ROOT at %s', process.env.ANDROID_SDK_ROOT); | ||
return process.env.ANDROID_SDK_ROOT; | ||
} | ||
// TODO: No valid $ANDROID_SDK_ROOT, try searching common SDK directories. | ||
throw new Error(`No valid Android SDK root found.`); | ||
} | ||
exports.resolveSDKRoot = resolveSDKRoot; | ||
async function resolveToolsPath(root) { | ||
const debug = Debug(`${modulePrefix}:${resolveToolsPath.name}`); | ||
const p = path.join(root, 'tools'); | ||
debug('Looking at %s for tools path', p); | ||
if (await fs_1.isDir(p)) { | ||
debug('Using %s', p); | ||
return p; | ||
const sdkDirs = SDK_DIRECTORIES.get(process.platform); | ||
if (!sdkDirs) { | ||
throw new errors_1.SDKException(`Unsupported platform: ${process.platform}`); | ||
} | ||
throw new Error(`No valid Android SDK Tools path found.`); | ||
} | ||
exports.resolveToolsPath = resolveToolsPath; | ||
async function resolvePlatformToolsPath(root) { | ||
const debug = Debug(`${modulePrefix}:${resolvePlatformToolsPath.name}`); | ||
const p = path.join(root, 'platform-tools'); | ||
debug('Looking at %s for platform-tools path', p); | ||
if (await fs_1.isDir(p)) { | ||
debug('Using %s', p); | ||
return p; | ||
} | ||
throw new Error(`No valid Android SDK Platform Tools path found.`); | ||
} | ||
exports.resolvePlatformToolsPath = resolvePlatformToolsPath; | ||
async function resolveEmulatorPath(root) { | ||
const debug = Debug(`${modulePrefix}:${resolveEmulatorPath.name}`); | ||
// The emulator was separated out from tools as of 25.3.0 (March 2017) | ||
const paths = [path.join(root, 'emulator'), path.join(root, 'tools')]; | ||
for (const p of paths) { | ||
debug('Looking at %s for emulator path', p); | ||
if (await fs_1.isDir(p)) { | ||
debug('Using %s', p); | ||
return p; | ||
debug('Looking at following directories: %O', sdkDirs); | ||
for (const sdkDir of sdkDirs) { | ||
if (await utils_fs_1.isDir(sdkDir)) { | ||
debug('Using %s', sdkDir); | ||
return sdkDir; | ||
} | ||
} | ||
throw new Error(`No valid Android Emulator path found.`); | ||
throw new errors_1.SDKException(`No valid Android SDK root found.`, errors_1.ERR_SDK_NOT_FOUND); | ||
} | ||
exports.resolveEmulatorPath = resolveEmulatorPath; | ||
exports.isAndroidPackage = (o) => o && typeof o['Pkg.Revision'] === 'string'; | ||
async function getAndroidPackageVersion(pkgPath) { | ||
const sourcePropsPath = path.resolve(pkgPath, 'source.properties'); | ||
const sourceProps = await properties_1.readProperties(sourcePropsPath, exports.isAndroidPackage); | ||
if (!sourceProps) { | ||
throw new Error(`Invalid package file: ${sourcePropsPath}`); | ||
exports.resolveSDKRoot = resolveSDKRoot; | ||
async function resolveEmulatorHome() { | ||
const debug = Debug(`${modulePrefix}:${resolveEmulatorHome.name}`); | ||
debug('Looking for $ANDROID_EMULATOR_HOME'); | ||
// Try $ANDROID_EMULATOR_HOME | ||
if (process.env.ANDROID_EMULATOR_HOME && await utils_fs_1.isDir(process.env.ANDROID_EMULATOR_HOME)) { | ||
debug('Using $ANDROID_EMULATOR_HOME at %s', process.env.$ANDROID_EMULATOR_HOME); | ||
return process.env.ANDROID_EMULATOR_HOME; | ||
} | ||
return sourceProps['Pkg.Revision']; | ||
// Try $HOME/.android/ | ||
const homeEmulatorHome = pathlib.join(homedir, '.android'); | ||
if (await utils_fs_1.isDir(homeEmulatorHome)) { | ||
debug('Using $HOME/.android/ at %s', homeEmulatorHome); | ||
return homeEmulatorHome; | ||
} | ||
throw new errors_1.SDKException(`No valid Android Emulator home found.`, errors_1.ERR_EMULATOR_HOME_NOT_FOUND); | ||
} | ||
exports.getAndroidPackageVersion = getAndroidPackageVersion; | ||
async function resolveAVDHome(root) { | ||
exports.resolveEmulatorHome = resolveEmulatorHome; | ||
async function resolveAVDHome() { | ||
const debug = Debug(`${modulePrefix}:${resolveAVDHome.name}`); | ||
debug('Looking for $ANDROID_AVD_HOME'); | ||
// Try $ANDROID_AVD_HOME | ||
if (process.env.ANDROID_AVD_HOME && await fs_1.isDir(process.env.ANDROID_AVD_HOME)) { | ||
if (process.env.ANDROID_AVD_HOME && await utils_fs_1.isDir(process.env.ANDROID_AVD_HOME)) { | ||
debug('Using $ANDROID_AVD_HOME at %s', process.env.$ANDROID_AVD_HOME); | ||
return process.env.ANDROID_AVD_HOME; | ||
} | ||
// Try $ANDROID_SDK_ROOT/.android/avd/ and then $HOME/.android/avd/ | ||
const paths = [path.join(root, '.android', 'avd'), path.join(homedir, '.android', 'avd')]; | ||
for (const p of paths) { | ||
debug('Looking at %s for AVD home', p); | ||
if (await fs_1.isDir(p)) { | ||
debug('Using %s', p); | ||
return p; | ||
} | ||
// Try $HOME/.android/avd/ | ||
const homeAvdHome = pathlib.join(homedir, '.android', 'avd'); | ||
if (await utils_fs_1.isDir(homeAvdHome)) { | ||
debug('Using $HOME/.android/avd/ at %s', homeAvdHome); | ||
return homeAvdHome; | ||
} | ||
throw new Error(`No valid Android AVD root found.`); | ||
throw new errors_1.SDKException(`No valid Android AVD home found.`, errors_1.ERR_AVD_HOME_NOT_FOUND); | ||
} | ||
exports.resolveAVDHome = resolveAVDHome; | ||
function supplementProcessEnv(sdk) { | ||
return Object.assign({}, process.env, { ANDROID_SDK_ROOT: sdk.root, ANDROID_EMULATOR_HOME: sdk.emulatorHome, ANDROID_AVD_HOME: sdk.avdHome }); | ||
} | ||
exports.supplementProcessEnv = supplementProcessEnv; |
@@ -14,10 +14,23 @@ "use strict"; | ||
exports.ERR_AVD_HOME_NOT_FOUND = 'ERR_AVD_HOME_NOT_FOUND'; | ||
exports.ERR_EMULATOR_HOME_NOT_FOUND = 'ERR_EMULATOR_HOME_NOT_FOUND'; | ||
exports.ERR_INCOMPATIBLE_UPDATE = 'ERR_INCOMPATIBLE_UPDATE'; | ||
exports.ERR_INVALID_SDK_PACKAGE = 'ERR_INVALID_SDK_PACKAGE'; | ||
exports.ERR_INVALID_SERIAL = 'ERR_INVALID_SERIAL'; | ||
exports.ERR_INVALID_SKIN = 'ERR_INVALID_SKIN'; | ||
exports.ERR_INVALID_SYSTEM_IMAGE = 'ERR_INVALID_SYSTEM_IMAGE'; | ||
exports.ERR_NON_ZERO_EXIT = 'ERR_NON_ZERO_EXIT'; | ||
exports.ERR_NO_AVDS_FOUND = 'ERR_NO_AVDS_FOUND'; | ||
exports.ERR_NO_FULL_API_INSTALLATION = 'ERR_NO_FULL_API_INSTALLATION'; | ||
exports.ERR_NO_SUITABLE_API_INSTALLATION = 'ERR_NO_SUITABLE_API_INSTALLATION'; | ||
exports.ERR_SDK_NOT_FOUND = 'ERR_SDK_NOT_FOUND'; | ||
exports.ERR_SDK_PACKAGE_NOT_FOUND = 'ERR_SDK_PACKAGE_NOT_FOUND'; | ||
exports.ERR_TARGET_NOT_FOUND = 'ERR_TARGET_NOT_FOUND'; | ||
exports.ERR_UNKNOWN_AVD = 'ERR_UNKNOWN_AVD'; | ||
exports.ERR_INVALID_SERIAL = 'ERR_INVALID_SERIAL'; | ||
exports.ERR_UNSUPPORTED_API_LEVEL = 'ERR_UNSUPPORTED_API_LEVEL'; | ||
class ADBException extends Exception { | ||
} | ||
exports.ADBException = ADBException; | ||
class AVDException extends Exception { | ||
} | ||
exports.AVDException = AVDException; | ||
class EmulatorException extends Exception { | ||
@@ -29,1 +42,4 @@ } | ||
exports.RunException = RunException; | ||
class SDKException extends Exception { | ||
} | ||
exports.SDKException = SDKException; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const Debug = require("debug"); | ||
const path = require("path"); | ||
const errors_1 = require("./errors"); | ||
@@ -9,3 +10,3 @@ const debug = Debug('native-run'); | ||
if (args.includes('--version')) { | ||
const pkg = require('../package.json'); | ||
const pkg = await Promise.resolve().then(() => require(path.resolve(__dirname, '../package.json'))); | ||
process.stdout.write(pkg.version + '\n'); | ||
@@ -33,13 +34,22 @@ return; | ||
catch (e) { | ||
if (e instanceof errors_1.Exception) { | ||
process.stderr.write(`${e.message}\n`); | ||
process.exitCode = e.exitCode; | ||
} | ||
else { | ||
debug('Caught fatal error: %O', e); | ||
process.stderr.write(String(e.stack ? e.stack : e)); | ||
process.exitCode = 1; | ||
} | ||
debug('Caught fatal error: %O', e); | ||
process.exitCode = e instanceof errors_1.Exception ? e.exitCode : 1; | ||
process.stdout.write(serializeError(e)); | ||
} | ||
} | ||
exports.run = run; | ||
function serializeError(e) { | ||
let error; | ||
let code; | ||
if (e instanceof errors_1.Exception) { | ||
error = e.message; | ||
code = e.code; | ||
} | ||
else { | ||
error = String(e.stack ? e.stack : e); | ||
} | ||
if (process.argv.includes('--json')) { | ||
return JSON.stringify({ error, code }); | ||
} | ||
return `${code ? code : 'ERR_UNKNOWN'}: ${error}\n`; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const utils_fs_1 = require("@ionic/utils-fs"); | ||
const path_1 = require("path"); | ||
const cli_1 = require("../utils/cli"); | ||
const fs_1 = require("../utils/fs"); | ||
const process_1 = require("../utils/process"); | ||
@@ -21,3 +21,3 @@ const list_1 = require("./list"); | ||
const developerDiskImagePath = await getDeveloperDiskImagePath(version, xCodePath); | ||
if (!fs_1.safeStat(developerDiskImagePath)) { | ||
if (!utils_fs_1.statSafe(developerDiskImagePath)) { | ||
throw new Error(`No Developer Disk Image found for SDK ${version} at\n${developerDiskImagePath}.`); | ||
@@ -73,3 +73,3 @@ } | ||
try { | ||
const versionDirs = await fs_1.readdir(`${xCodePath}/Platforms/iPhoneOS.platform/DeviceSupport/`); | ||
const versionDirs = await utils_fs_1.readDir(`${xCodePath}/Platforms/iPhoneOS.platform/DeviceSupport/`); | ||
// Can look like "11.2 (15C107)" | ||
@@ -76,0 +76,0 @@ for (const dir of versionDirs) { |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const utils_fs_1 = require("@ionic/utils-fs"); | ||
const Debug = require("debug"); | ||
const util = require("util"); | ||
const fs_1 = require("./fs"); | ||
const debug = Debug('native-run:android:utils:ini'); | ||
@@ -10,3 +10,3 @@ async function readINI(p, guard = (o) => true) { | ||
try { | ||
const contents = await fs_1.readFile(p, 'utf8'); | ||
const contents = await utils_fs_1.readFile(p, { encoding: 'utf8' }); | ||
const config = ini.decode(contents); | ||
@@ -28,4 +28,4 @@ if (!guard(config)) { | ||
const contents = ini.encode(o); | ||
await fs_1.writeFile(p, contents, 'utf8'); | ||
await utils_fs_1.writeFile(p, contents, { encoding: 'utf8' }); | ||
} | ||
exports.writeINI = writeINI; |
{ | ||
"name": "native-run", | ||
"version": "0.0.1", | ||
"version": "0.0.2", | ||
"description": "A CLI for running apps on iOS/Android devices and simulators/emulators", | ||
@@ -30,3 +30,5 @@ "bin": { | ||
"dependencies": { | ||
"@ionic/utils-fs": "0.0.1", | ||
"debug": "^3.1.0", | ||
"elementtree": "^0.1.7", | ||
"ini": "^1.3.5", | ||
@@ -40,2 +42,3 @@ "split2": "^3.0.0", | ||
"@types/ini": "^1.3.29", | ||
"@types/ncp": "^2.0.1", | ||
"@types/node": "~8.9.0", | ||
@@ -49,3 +52,3 @@ "@types/split2": "^2.1.6", | ||
"tslint": "^5.11.0", | ||
"tslint-ionic-rules": "0.0.17", | ||
"tslint-ionic-rules": "0.0.18", | ||
"typescript": "^3.0.1" | ||
@@ -52,0 +55,0 @@ }, |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
71869
33
1755
7
13
18
+ Added@ionic/utils-fs@0.0.1
+ Addedelementtree@^0.1.7
+ Added@ionic/utils-fs@0.0.1(transitive)
+ Addedelementtree@0.1.7(transitive)
+ Addedncp@2.0.0(transitive)
+ Addedsax@1.1.4(transitive)