UNPKG

@webos-tools/cli

Version:

Command Line Interface for development webOS application and service

319 lines (285 loc) 9.34 kB
#!/usr/bin/env node /* * Copyright (c) 2020-2024 LG Electronics Inc. * * SPDX-License-Identifier: Apache-2.0 */ const async = require('async'), fs = require('fs'), nopt = require('nopt'), log = require('npmlog'), path = require('path'), launchLib = require('./../lib/launch'), commonTools = require('./../lib/base/common-tools'); const version = commonTools.version, cliControl = commonTools.cliControl, help = commonTools.help, setupDevice = commonTools.setupDevice, appdata = commonTools.appdata, errHndl = commonTools.errMsg; const processName = path.basename(process.argv[1]).replace(/.js/, ''); process.on('uncaughtException', function(err) { log.error('uncaughtException', err.toString()); log.verbose('uncaughtException', err.stack); cliControl.end(-1); }); if (process.argv.length === 2) { process.argv.splice(2, 0, '--help'); } const knownOpts = { "running": Boolean, "close": Boolean, "hosted": Boolean, "host-ip": [String, null], "display": [String, null], "params": [String, Array], "inspect": Boolean, "open": Boolean, "simulator": [String, null], "simulator-path": [String, null], "device": [String, null], "device-list": Boolean, "version": Boolean, "help": Boolean, "hidden-help": Boolean, "level": ['silly', 'verbose', 'info', 'http', 'warn', 'error'] }; const shortHands = { "r": ["--running"], "c": ["--close"], "H": ["--hosted"], "I": ["--host-ip"], "dp": ["--display"], "p": ["--params"], "i": ["--inspect"], "o": ["--open"], "s": ["--simulator"], "sp": ["--simulator-path"], "d": ["--device"], "D": ["--device-list"], "V": ["--version"], "h": ["--help"], "hh": ["--hidden-help"], "v": ["--level", "verbose"], }; const argv = nopt(knownOpts, shortHands, process.argv, 2 /* drop 'node' & 'ares-*.js' */); log.heading = processName; log.level = argv.level || 'warn'; launchLib.log.level = log.level; log.verbose("argv", argv); /** * For consistent of "$command -v", argv is used. * By nopt, argv is parsed and set key-value in argv object. * If -v or --level option is input with command, it is set key-value in argv. * After it is deleted, If remained key is only one in argv object * (If any other are remained, it's mean another options is input) * and there is no remaining after parsing the input command by nopt * (If any other are remained, it's mean another parameters ares input), * each command of webOS CLI print help message with log message. */ if (argv.level) { delete argv.level; if (argv.argv.remain.length === 0 && (Object.keys(argv)).length === 1) { argv.help = true; } } const options = { device: argv.device, inspect: argv.open || argv.inspect, open: argv.open, installMode: "Installed", display: argv.display, hostIp: argv["host-ip"], simulator: argv.simulator, simulatorPath: argv["simulator-path"] }, appId = argv.argv.remain[0]; if (argv.argv.remain.length > 1) { finish("Please check arguments"); } let op, params = {}; if (argv.help || argv['hidden-help']) { showUsage(argv['hidden-help']); cliControl.end(); } else if (argv.close) { op = close; } else if (argv.running) { op = running; } else if (argv['device-list']) { op = deviceList; } else if (argv.version) { version.showVersionAndExit(); } else if (argv.hosted) { options.installMode = "Hosted"; op = launchHostedApp; } else if (argv.simulator) { op = launchSimulator; } else if (argv['simulator-path']) { if (!argv.simulator) { finish(errHndl.getErrMsg("USE_WITH_OPTIONS", "simulator, simulator-path")); } } else { op = launch; } if (op) { version.checkNodeVersion(function() { async.series([ op.bind(this) ], finish); }); } function showUsage(hiddenFlag) { if (hiddenFlag) { help.display(processName, appdata.getConfig(true).profile, hiddenFlag); } else { help.display(processName, appdata.getConfig(true).profile); } } function deviceList() { setupDevice.showDeviceList(finish); } function launch() { const pkgId = appId; params = getParams(); log.info("launch()", "pkgId:", pkgId); if (!pkgId) { showUsage(); cliControl.end(-1); } else { launchLib.launch(options, pkgId, params, finish, outputTxt); } } function launchHostedApp() { const pkgId = appdata.getConfig(true).profile === "signage" ? "com.lg.app.signage.dev" : "com.sdk.ares.hostedapp"; log.info("launchHostedApp():", "pkgId:", pkgId, ", appDir:", appId); if (!appId) { return finish(errHndl.getErrMsg("EMPTY_VALUE", "APP_DIR")); } if (!fs.existsSync(path.normalize(appId))) { return finish(errHndl.getErrMsg("NOT_EXIST_PATH", appId)); } if (options.hostIp) { if (options.hostIp === "true") { return finish(errHndl.getErrMsg("EMPTY_VALUE", "HOST_IP")); } else { const ipFormat = /^(?:(?:\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])$/mg; if (!ipFormat.exec(options.hostIp)) { return finish(errHndl.getErrMsg("INVALID_IP", options.hostIp)); } } } options.hostedurl = fs.realpathSync(appId); params = getParams(); launchLib.launch(options, pkgId, params, finish, outputTxt); } function getParams() { const inputParams = argv.params || []; params = {}; if (inputParams.length === 1 && inputParams[0].indexOf('{') !== -1 && inputParams[0].indexOf('}') !== -1 && ((inputParams[0].split("'").length - 1) % 2) === 0) { // eslint-disable-next-line no-useless-escape inputParams[0] = inputParams[0].replace(/\'/g,'"'); } inputParams.forEach(function(strParam) { try { const data = JSON.parse(strParam); for (const k in data) { params[k] = data[k]; } } catch (err) { const tokens = strParam.split('='); if (tokens.length === 2) { params[tokens[0]] = tokens[1]; } else { log.warn('Ignoring invalid arguments:', strParam); } } }); if (argv.display !== undefined && isNaN(Number(argv.display))) { return finish(errHndl.getErrMsg("INVALID_DISPLAY")); } log.info("getParams()", "params:", JSON.stringify(params)); return params; } function close() { const pkgId = appId; params = getParams(); log.info("close()", "pkgId:", pkgId); if (!pkgId) { showUsage(); cliControl.end(-1); } launchLib.close(options, pkgId, params, finish); } function running() { launchLib.listRunningApp(options, function(err, runningApps) { let strRunApps = ""; let cnt = 0; if (err) { return finish(err); } if (runningApps instanceof Array) runningApps.forEach(function(runApp) { if (cnt++ !== 0) { strRunApps = strRunApps.concat('\n'); } strRunApps = strRunApps.concat(runApp.id); if (runApp.displayId !== undefined) { strRunApps += " - display " + runApp.displayId; } }); finish(null, {msg: strRunApps}); }); } function launchSimulator() { log.info("launchSimulator():", "simulator:", options.simulator, "/ simulatorPath:", options.simulator, "/ appDir:", appId); const curConfigData = appdata.getConfig(); if (curConfigData.profile !== "tv") { return finish(errHndl.getErrMsg("NOT_SUPPORT_OPTION", curConfigData.profile)); } if (options.simulator === 'true') { return finish(errHndl.getErrMsg("EMPTY_VALUE", "WEBOS_TV_VERSION")); } if (options.simulatorPath === 'true') { return finish(errHndl.getErrMsg("EMPTY_VALUE", "simlator-path")); } if (!appId) { return finish(errHndl.getErrMsg("EMPTY_VALUE", "APP_DIR")); } else { const appDir = path.resolve(appId); if (!fs.existsSync(appDir)) { return finish(errHndl.getErrMsg("NOT_EXIST_PATH", appId)); } else if (!fs.statSync(appDir).isDirectory()) { return finish(errHndl.getErrMsg("NOT_DIRTYPE_PATH", appId)); } params = getParams(); launchLib.launchSimulator(options, appDir, params, finish, outputTxt); } } function outputTxt(value) { log.info("outputTxt()", "value:", value); console.log(value); } function finish(err, value) { log.info("finish()"); if (err) { // handle err from getErrMsg() if (Array.isArray(err) && err.length > 0) { for (const index in err) { log.error(err[index].heading, err[index].message); } log.verbose(err[0].stack); } else { // handle general err (string & object) log.error(err.toString()); log.verbose(err.stack); } cliControl.end(-1); } else { log.verbose("finish()", "value:", value); if (value && value.msg) { console.log(value.msg); } cliControl.end(); } }