From 6f8f9c95ebc2cf3b3e122b6cc59f041b8b0dd74a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=9C=E6=9C=A8?= Date: Sat, 3 Feb 2018 11:49:46 +0800 Subject: [PATCH 1/2] rewrite bin/rokid with node.js add spawn for execution add env value ROKID_CLI_ADB_PATH as ADB path normalize run_script filename --- .gitignore | 1 + bin/rokid.js | 193 +++++++++++++++++++++++++++++++++++++++++++ example/package.json | 24 ++++++ package.json | 1 + 4 files changed, 219 insertions(+) create mode 100644 bin/rokid.js create mode 100644 example/package.json diff --git a/.gitignore b/.gitignore index 497a3af..d7cdb53 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.vscode/ node_modules/ build/ diff --git a/bin/rokid.js b/bin/rokid.js new file mode 100644 index 0000000..726917c --- /dev/null +++ b/bin/rokid.js @@ -0,0 +1,193 @@ +#!/usr/bin/env node + +// Setup. + +const fs = require('fs'); +const path = require('path'); +const exec = require('child_process').exec; +const execSync = require('child_process').execSync; +const spawn = require('child_process').spawn; +const spawnSync = require('child_process').spawnSync; + +const VERSION = "0.10.1" +var ADB = "" +var NODE_PATH = 'NODE_PATH=' + path.posix.join('/', 'usr', 'lib', 'node_models'); +var TMP_DIR = path.posix.join('/', 'tmp'); + +function display_help() { + console.log(` +Usage: rokid [command] + +rokid help Get helps +rokid search Search your devices and configuring network +rokid devices List connected devices +rokid run [file] Run scripts on device +rokid shell Wait for an connectable device and shell +rokid test Run tests on your device +rokid log Show the logs of connected device by comma-based filter + +rokid@${VERSION}`); +} + +function display_version() { + console.log(`rokid@${VERSION}`); +} + +function get_cli_root() { + return path.resolve(__dirname, '..'); +} + +// 执行纯属脚本时使用 +function exec_go(command, callback) { + let ch = exec(command.join(' ')); + process.stdin.pipe(ch.stdin); + ch.stdout.pipe(process.stdout); + ch.stderr.pipe(process.stdout); +} + +function execSync_go(command, callback) { + let ch = execSync(command.join(' ')); + console.log(ch.toString().trim()); +} + +function spawn_go(command, callback) { + spawn(command[0], command.slice(1), { + stdio: [ + process.stdin, + process.stdout, + process.stderr + ] + }); +} + +// 带有流输出时使用 +function spawnSync_go(command, callback) { + let ch = spawnSync(command[0], command.slice(1), { + stdio: [ + process.stdin, + process.stdout, + process.stderr + ] + }); + if (callback) callback(); + return ch; +} + +function run_exec(command, callback) { // TODO: I don't know which child_process is the best choice or choicing function by command execute file type. + // console.log(command.join(' ')); + return spawnSync_go(command, callback); +} + +function init_adb() { + if (process.env.hasOwnProperty('ROKIDOS_CLI_ADB_PATH') && + process.env['ROKIDOS_CLI_ADB_PATH']) { + ADB = process.env['ROKIDOS_CLI_ADB_PATH']; + } else { + ADB = path.join(get_cli_root(), 'tools', 'adb'); + } + console.log('use adb:', ADB); +} + +function build_rpp() { + let config = path.join(get_cli_root(), 'webpack.config.js'); + execSync_go([ + path.join(get_cli_root(), 'node_modules', '.bin', 'webpack'), + '--config', + config + ]); + + execSync_go([ + 'node', + path.join(get_cli_root(), 'postbuild.js') + ]); +} + +function log(filter) { + // change the workdir to source dir + process.chdir(get_cli_root()); + run_script(path.join('lib', 'log-filter.js'), filter); +} + +function install_rpp(rpp_path) { + if (!rpp_path || rpp_path.length <= 0) { + build_rpp(); + fs.readdirSync(process.cwd()).forEach(function (file) { + if (file.search(/\.rpp/i) > 0) { + rpp_path = file + } + }) + } + run_exec([ADB, 'shell', 'mkdir', '-p', path.posix.join(TMP_DIR, 'installers')]); + run_exec([ADB, 'push', rpp_path, path.posix.join(TMP_DIR, 'installers')]); + run_exec([ADB, 'shell', 'pkgm-install', rpp_path]); + console.log("\033[32m$rpp_path installed\033[0m\n"); +} + +function run_script(filename, param) { + if (filename) filename = path.normalize(filename); + let filename_remote = path.posix.join(TMP_DIR, ...filename.split(path.sep)); + run_exec([ADB, 'push', filename, filename_remote]); + run_exec([ADB, 'shell', NODE_PATH, 'node', filename_remote, param ? param : '']); + run_exec([ADB, 'shell', 'rm', filename_remote]); +} + +function run_test(dir) { + let testdir = path.posix.join(TMP_DIR, 'tests'); + // create test directory + run_exec([ADB, 'shell', 'mkdir', '-p', testdir]); + run_exec([ADB, 'push', 'tests', testdir]); + // # change the workdir to source dir + run_exec([ADB, 'push', path.join(get_cli_root(), 'lib'), testdir]); + run_exec([ADB, 'shell', 'node', path.posix.join(testdir, 'lib', 'executor.js'), dir ? dir : '']); + run_exec([ADB, 'shell', 'rm', '-r', testdir]); // TODO: not work, I think it should add a key bind. +} + +function debug_mode() { + run_exec([ADB, 'shell', 'killall', '-9', 'ams']); + run_exec([ADB, 'shell', 'killall', '-9', 'node']); + run_exec([ADB, 'shell', NODE_PATH, 'ams']); +} + +function adb_commands(action, param) { + init_adb(); + run_exec([ADB, 'wait-for-device'], function () {}); + switch (action) { + case 'devices': + case 'shell': + run_exec([ADB, action]); + break; + case 'node': + run_exec([ADB, 'shell', NODE_PATH, 'node']); + break; + case 'search': + exec_go(['rokid-search']); + break; + case 'log': + log(); + break; + case 'install': + install_rpp(param); + break; + case 'build': + build_rpp(param); + break; + case 'run': + run_script(param); + break; + case 'test': + run_test(param); + break; + case 'debug': + debug_mode(); + break; + case '-V': + case '--version': + display_version(); + break; + default: + display_help(); + break; + } +} + +adb_commands(process.argv[2], process.argv[3]); \ No newline at end of file diff --git a/example/package.json b/example/package.json new file mode 100644 index 0000000..2c3a7be --- /dev/null +++ b/example/package.json @@ -0,0 +1,24 @@ +{ + "name": "@rokidapp/rokidos-cli_example", + "version": "1.0.0", + "description": "example app for rokidos", + "main": "app.js", + "scripts": {}, + "repository": { + "type": "git", + "url": "git@github.com/rokid/rokidos-cli/example" + }, + "keywords": [ + "nodejs", + "rokid" + ], + "author": "example", + "license": "MIT", + "metadata": { + "type": "cut", + "skills": [ + "example" + ], + "native": true + } +} \ No newline at end of file diff --git a/package.json b/package.json index 3cd38d4..2e5f7e7 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "bin": { "ro": "bin/rokid", "rokid": "bin/rokid", + "rokid-node": "bin/rokid.js", "rokid-search": "bin/rokid-search" }, "repository": { From 33b981a82d277bf998b4575ec517e50077ad16a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=9C=E6=9C=A8?= Date: Mon, 5 Feb 2018 10:20:55 +0800 Subject: [PATCH 2/2] format example code change info color with yellow --- example/app.js | 2 +- example/tests/cloud-confirm.spec.js | 24 ++++++++++++++---------- lib/executor.js | 5 +++-- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/example/app.js b/example/app.js index 1a0a29e..49ef728 100644 --- a/example/app.js +++ b/example/app.js @@ -5,4 +5,4 @@ const app = require('@rokid/ams')(); app.on('request', (data) => { // handler }); -app.start(); +app.start(); \ No newline at end of file diff --git a/example/tests/cloud-confirm.spec.js b/example/tests/cloud-confirm.spec.js index 1ce5980..d9eab03 100644 --- a/example/tests/cloud-confirm.spec.js +++ b/example/tests/cloud-confirm.spec.js @@ -8,36 +8,40 @@ test('test 7 play', (t) => { 'intent': 'play_random', 'pattern': '^$iwant?$play$one?$keyword$', 'slots': {} - }, { - 'appId':'RCAC74F187F34C94B93EE3BAECFCE2E3', - 'response': { + }, { + 'appId': 'RCAC74F187F34C94B93EE3BAECFCE2E3', + 'response': { 'action': { 'version': '2.0.0', 'type': 'NORMAL', 'form': 'scene', 'shouldEndSession': true, 'directives': [{ - 'type':'voice', + 'type': 'voice', 'action': 'PLAY', - 'disableEvent':false, + 'disableEvent': false, 'item': { - 'itemId':'newstestitemid', + 'itemId': 'newstestitemid', 'tts': '晚上好,若琪为您播放晚间新闻摘要,首先我们来看看社会新闻。' } }, { - 'type':'confirm', + 'type': 'confirm', 'confirmIntent': 'nlp intent to confirm', 'confirmSlot': 'nlp slot to confirm', 'optionWords': ['word1', 'word2'] }] } }, - 'startWithActiveWord':false, - 'version':'2.0.0' + 'startWithActiveWord': false, + 'version': '2.0.0' }); Promise.all([ - t.assert('Voice.FINISHED', {voice: {item: 'newstestitemid'}}), + t.assert('Voice.FINISHED', { + voice: { + item: 'newstestitemid' + } + }), t.assert('siren.statechange', 'open'), ]).then(() => { t.done(); diff --git a/lib/executor.js b/lib/executor.js index 2d359cb..16fad84 100644 --- a/lib/executor.js +++ b/lib/executor.js @@ -9,6 +9,7 @@ const asserts = []; const filter = process.argv[2]; const redify = (text) => '\033[31m' + text + '\033[0m'; const greyify = (text) => '\033[1;30m' + text + '\033[0m'; +const yellowify = (text) => '\033[33m' + text + '\033[0m'; const greenify = (text) => '\033[32m' + text + '\033[0m'; class TestCase { @@ -149,11 +150,11 @@ dispatcher.on('line', (line) => { } const item = asserts[0]; if (!item) { - console.info(greyify(` .skip ${name} ${JSON.stringify(val)}`)); + console.info(yellowify(` .skip ${name} ${JSON.stringify(val)}`)); return; } if (item.name !== name) { - console.info(greyify(` .skip ${name} ${JSON.stringify(val)}`)); + console.info(yellowify(` .skip ${name} ${JSON.stringify(val)}`)); return; } asserts.shift();