Compare commits
3 Commits
95ba56491d
...
v3.0.2
Author | SHA1 | Date | |
---|---|---|---|
9a79e6a830 | |||
a1338aa9bc | |||
5e105efd9d |
99
completion/bash
Normal file
99
completion/bash
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#/usr/bin/env bash
|
||||||
|
|
||||||
|
LIBDIR=${LIBDIR:-'/usr/share/artools/lib'}
|
||||||
|
|
||||||
|
_artixpkg_pkgbase() {
|
||||||
|
source "${LIBDIR}"/pkg/git/config.sh
|
||||||
|
source "${LIBDIR}"/pkg/util.sh
|
||||||
|
ls -1 "${TREE_DIR_ARTIX}" | tr '\n' ' '
|
||||||
|
}
|
||||||
|
|
||||||
|
_artix_metro_completion() {
|
||||||
|
local cur prev comps repos autorepos comp_cword_exflag
|
||||||
|
source "${LIBDIR}"/pkg/db/db.sh 2>/dev/null
|
||||||
|
|
||||||
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||||
|
|
||||||
|
for ((i = COMP_CWORD - 1; i >= 0; i--)); do
|
||||||
|
if [[ ${COMP_WORDS[i]} != -* ]]; then
|
||||||
|
last_non_flag_word="${COMP_WORDS[i]}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
comps=""
|
||||||
|
comp_cword_exflag=0
|
||||||
|
comp_cword_all=0
|
||||||
|
for ((i = 0; i < ${#COMP_WORDS[@]} - 1; i++)); do
|
||||||
|
word="${COMP_WORDS[i]}"
|
||||||
|
comps_all+=" $word"
|
||||||
|
((comp_cword_all++))
|
||||||
|
if [[ $word != -* ]]; then
|
||||||
|
comps+=" $word"
|
||||||
|
((comp_cword_exflag++))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
comps="${comps:1}"
|
||||||
|
|
||||||
|
repos=""
|
||||||
|
for word in "${ARTIX_DB[@]}"; do
|
||||||
|
if [[ $word != -* ]]; then
|
||||||
|
repos+=" $word"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
repos="${repos:1}"
|
||||||
|
autorepos=""
|
||||||
|
for word in "${ARTIX_DB_MAP[@]}"; do
|
||||||
|
if [[ $word != -* ]]; then
|
||||||
|
autorepos+=" $word"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
autorepos="${autorepos:1}"
|
||||||
|
|
||||||
|
case "${prev}" in
|
||||||
|
"--token")
|
||||||
|
# this flag expects a parameter
|
||||||
|
COMPREPLY=()
|
||||||
|
;;
|
||||||
|
"-j"|"--job")
|
||||||
|
COMPREPLY=( $(compgen -f -- "$cur") )
|
||||||
|
;;
|
||||||
|
"--workspace")
|
||||||
|
COMPREPLY=( $(compgen -d -- "$cur") )
|
||||||
|
;;
|
||||||
|
"--start")
|
||||||
|
COMPREPLY=($(compgen -W "$(_artixpkg_pkgbase)" -- ${cur}))
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
local metroCommon="-h --help --start --token --workspace --increment "
|
||||||
|
case "${comps}" in
|
||||||
|
"artix-metro add"*)
|
||||||
|
case "${comp_cword_exflag}" in
|
||||||
|
2)
|
||||||
|
COMPREPLY=($(compgen -W "$metroCommon $autorepos $repos" -- ${cur}))
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
COMPREPLY=($(compgen -W "$metroCommon $(_artixpkg_pkgbase)" -- ${cur}))
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
"artix-metro move"*)
|
||||||
|
case "${comp_cword_exflag}" in
|
||||||
|
2|3)
|
||||||
|
COMPREPLY=($(compgen -W "$metroCommon $autorepos $repos" -- ${cur}))
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
COMPREPLY=($(compgen -W "$metroCommon $(_artixpkg_pkgbase)" -- ${cur}))
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
COMPREPLY=($(compgen -W "$metroCommon -j --job add move" -- ${cur}))
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
complete -F _artix_metro_completion artix-metro
|
61
completion/zsh
Normal file
61
completion/zsh
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
# Load necessary library files
|
||||||
|
LIBDIR=${LIBDIR:-'/usr/share/artools/lib'}
|
||||||
|
|
||||||
|
_artix_metro_completion() {
|
||||||
|
local -a metroCommon repos autorepos pkgbase
|
||||||
|
local curcontext="$curcontext" state
|
||||||
|
|
||||||
|
# Load external configurations
|
||||||
|
source "${LIBDIR}/pkg/db/db.sh" 2>/dev/null
|
||||||
|
|
||||||
|
# Common options
|
||||||
|
metroCommon=("-h" "--help" "--start" "--token" "--workspace" "--increment" "-j" "--job")
|
||||||
|
|
||||||
|
# Populate variables
|
||||||
|
repos=("${(s: :)ARTIX_DB}")
|
||||||
|
autorepos=("${(s: :)ARTIX_DB_MAP}")
|
||||||
|
pkgbase=("${(s: :)$(artix-metro --completion pkgbase)}")
|
||||||
|
|
||||||
|
# Handle command and argument contexts
|
||||||
|
_arguments -C \
|
||||||
|
'--token[Provide a token]: ' \
|
||||||
|
'-j[Specify a job]: :_files' \
|
||||||
|
'--job[Specify a job]: :_files' \
|
||||||
|
'--workspace[Specify a workspace]: :_files -/' \
|
||||||
|
'--start[Start a process]:pkgbase:(${pkgbase})' \
|
||||||
|
'1:command:(${metroCommon} add move)' \
|
||||||
|
'2:repo:(${metroCommon} ${autorepos} ${repos})' \
|
||||||
|
'*:pkgbase:->pkgbase'
|
||||||
|
|
||||||
|
# Contextual argument handling
|
||||||
|
case $state in
|
||||||
|
pkgbase)
|
||||||
|
case $words[2] in
|
||||||
|
add)
|
||||||
|
if (( CURRENT == 3 )); then
|
||||||
|
# First argument after "add" is a repo
|
||||||
|
_values "repo" "${metroCommon[@]}" "${autorepos[@]}" "${repos[@]}"
|
||||||
|
else
|
||||||
|
# Remaining arguments are pkgbase
|
||||||
|
_values "pkgbase" "${pkgbase[@]}"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
move)
|
||||||
|
if (( CURRENT == 3 )); then
|
||||||
|
# First repo for "move"
|
||||||
|
_values "repo" "${metroCommon[@]}" "${autorepos[@]}" "${repos[@]}"
|
||||||
|
elif (( CURRENT == 4 )); then
|
||||||
|
# Second repo for "move"
|
||||||
|
_values "repo" "${metroCommon[@]}" "${autorepos[@]}" "${repos[@]}"
|
||||||
|
else
|
||||||
|
# Remaining arguments are pkgbase
|
||||||
|
_values "pkgbase" "${pkgbase[@]}"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Register the completion function for artix-metro
|
||||||
|
compdef _artix_metro_completion artix-metro
|
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "artix-metro",
|
"name": "artix-metro",
|
||||||
"version": "3.0.0",
|
"version": "3.0.2",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "artix-metro",
|
"name": "artix-metro",
|
||||||
"version": "3.0.0",
|
"version": "3.0.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"artix-checkupdates": "1.0.1",
|
"artix-checkupdates": "1.0.1",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "artix-metro",
|
"name": "artix-metro",
|
||||||
"version": "3.0.0",
|
"version": "3.0.2",
|
||||||
"description": "Automate pushing packages to Artix",
|
"description": "Automate pushing packages to Artix",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"artix",
|
"artix",
|
||||||
@@ -13,7 +13,8 @@
|
|||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"distribution",
|
"distribution",
|
||||||
"bin"
|
"bin",
|
||||||
|
"completion"
|
||||||
],
|
],
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Cory Sanin",
|
"name": "Cory Sanin",
|
||||||
|
@@ -30,14 +30,16 @@ function removeQuotes(str: string) {
|
|||||||
|
|
||||||
class ArtoolsConfReader {
|
class ArtoolsConfReader {
|
||||||
|
|
||||||
async readConf(): Promise<ArtoolsConf> {
|
async readConf(silent: boolean = false): Promise<ArtoolsConf> {
|
||||||
const primaryLocation = path.join(os.homedir(), '.config', 'artools', 'artools-pkg.conf');
|
const primaryLocation = path.join(os.homedir(), '.config', 'artools', 'artools-pkg.conf');
|
||||||
const systemConf = path.join('/', 'etc', 'artools', 'artools-pkg.conf');
|
const systemConf = path.join('/', 'etc', 'artools', 'artools-pkg.conf');
|
||||||
try {
|
try {
|
||||||
return await this.readConfFile(primaryLocation);
|
return await this.readConfFile(primaryLocation);
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
|
if (!silent) {
|
||||||
console.error(`artools config at "${primaryLocation}" could not be read. ${ex}\nUsing system config "${systemConf}" instead.`);
|
console.error(`artools config at "${primaryLocation}" could not be read. ${ex}\nUsing system config "${systemConf}" instead.`);
|
||||||
|
}
|
||||||
return await this.readConfFile(systemConf);
|
return await this.readConfFile(systemConf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,12 @@
|
|||||||
import * as fsp from 'node:fs/promises';
|
import * as fsp from 'node:fs/promises';
|
||||||
import * as readline from 'node:readline/promises';
|
import * as readline from 'node:readline/promises';
|
||||||
|
import path from 'node:path';
|
||||||
import clc from 'cli-color';
|
import clc from 'cli-color';
|
||||||
import JSON5 from 'json5';
|
import JSON5 from 'json5';
|
||||||
import { Writable } from 'stream';
|
import { Writable } from 'stream';
|
||||||
import { Pusher } from './pusher.mjs';
|
import { Pusher } from './pusher.mjs';
|
||||||
|
import { isPasswordRequired } from './runCommand.mjs';
|
||||||
|
import { ArtoolsConfReader } from './artoolsconf.mjs';
|
||||||
import type { Job, ArtixpkgRepo } from './pusher.mts';
|
import type { Job, ArtixpkgRepo } from './pusher.mts';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -11,6 +14,9 @@ import type { Job, ArtixpkgRepo } from './pusher.mts';
|
|||||||
* @returns a promise that resolves the password
|
* @returns a promise that resolves the password
|
||||||
*/
|
*/
|
||||||
async function getGpgPass() {
|
async function getGpgPass() {
|
||||||
|
if ((process.env['SKIPGPGPASSPROMPT'] || '').toLowerCase() === 'true') {
|
||||||
|
return 'SKIP';
|
||||||
|
}
|
||||||
let muted = false;
|
let muted = false;
|
||||||
let mutableStdout = new Writable({
|
let mutableStdout = new Writable({
|
||||||
write: function (chunk, encoding, callback) {
|
write: function (chunk, encoding, callback) {
|
||||||
@@ -20,6 +26,11 @@ async function getGpgPass() {
|
|||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (! await isPasswordRequired()) {
|
||||||
|
console.log(clc.green('Looks like GPG agent is currently running and password is cached. '
|
||||||
|
+ 'If there is no timeout on your cached password, you can simply press enter.\n'
|
||||||
|
+ 'To skip this GPG password prompt next time, set $SKIPGPGPASSPROMPT to true'));
|
||||||
|
}
|
||||||
let rl = readline.createInterface({
|
let rl = readline.createInterface({
|
||||||
input: process.stdin,
|
input: process.stdin,
|
||||||
output: mutableStdout,
|
output: mutableStdout,
|
||||||
@@ -35,6 +46,7 @@ async function getGpgPass() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function artixMetro() {
|
async function artixMetro() {
|
||||||
|
let completion: boolean = false;
|
||||||
let job: Partial<Job> = {
|
let job: Partial<Job> = {
|
||||||
increment: false,
|
increment: false,
|
||||||
packages: []
|
packages: []
|
||||||
@@ -55,6 +67,29 @@ async function artixMetro() {
|
|||||||
const iPlus = i + 1;
|
const iPlus = i + 1;
|
||||||
const args = process.argv;
|
const args = process.argv;
|
||||||
switch (true) {
|
switch (true) {
|
||||||
|
case (arg === '--completion') && iPlus < args.length:
|
||||||
|
const comm = args[iPlus] as string;
|
||||||
|
completion = skipOne = true;
|
||||||
|
switch (comm) {
|
||||||
|
case ('pkgbase'):
|
||||||
|
(new ArtoolsConfReader()).readConf(true).then(async (conf) => {
|
||||||
|
try {
|
||||||
|
console.log(
|
||||||
|
(await fsp.readdir(path.join(conf.workspace, 'artixlinux'), { withFileTypes: true }))
|
||||||
|
.filter(dirent => dirent.isDirectory())
|
||||||
|
.map(dirent => dirent.name).join(' '));
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.error(`command "${comm}" not recognized`)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case (arg === '--job' || arg === '-j') && iPlus < args.length:
|
case (arg === '--job' || arg === '-j') && iPlus < args.length:
|
||||||
if (jobfile) {
|
if (jobfile) {
|
||||||
console.error(`multiple jobfiles provided. aborting.`);
|
console.error(`multiple jobfiles provided. aborting.`);
|
||||||
@@ -102,6 +137,10 @@ async function artixMetro() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (completion) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (helpFlag || (!jobfile && !job.repo)) {
|
if (helpFlag || (!jobfile && !job.repo)) {
|
||||||
console.log([
|
console.log([
|
||||||
`\nUsage: artix-metro [OPTIONS] [commands]...`,
|
`\nUsage: artix-metro [OPTIONS] [commands]...`,
|
||||||
@@ -139,6 +178,10 @@ async function artixMetro() {
|
|||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
if (completion) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let pusher = new Pusher({
|
let pusher = new Pusher({
|
||||||
gpgpass: process.env['GPGPASS'] || (await getGpgPass()) || ''
|
gpgpass: process.env['GPGPASS'] || (await getGpgPass()) || ''
|
||||||
});
|
});
|
||||||
|
@@ -4,11 +4,11 @@ import * as readline from 'node:readline/promises';
|
|||||||
import clc from 'cli-color';
|
import clc from 'cli-color';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import os from 'node:os';
|
import os from 'node:os';
|
||||||
import { spawn } from 'node:child_process';
|
|
||||||
import { Checkupdates } from 'artix-checkupdates';
|
import { Checkupdates } from 'artix-checkupdates';
|
||||||
import { Gitea } from './gitea.mjs'
|
import { Gitea } from './gitea.mjs'
|
||||||
import { ArtoolsConfReader, DefaultConf } from './artoolsconf.mjs';
|
import { ArtoolsConfReader, DefaultConf } from './artoolsconf.mjs';
|
||||||
import { snooze } from './snooze.mjs';
|
import { snooze } from './snooze.mjs';
|
||||||
|
import { runCommand, isPasswordRequired } from './runCommand.mjs';
|
||||||
import type { ArtixRepo } from 'artix-checkupdates';
|
import type { ArtixRepo } from 'artix-checkupdates';
|
||||||
import type { ArtoolsConf } from './artoolsconf.mts';
|
import type { ArtoolsConf } from './artoolsconf.mts';
|
||||||
|
|
||||||
@@ -26,22 +26,8 @@ interface Job extends Partial<ArtoolsConf> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const PACKAGE_ORG = 'packages';
|
const PACKAGE_ORG = 'packages';
|
||||||
const SIGNATUREEXPIRY = 30000;//in ms
|
|
||||||
const SIGNFILE = path.join(os.tmpdir(), 'signfile');
|
const SIGNFILE = path.join(os.tmpdir(), 'signfile');
|
||||||
|
|
||||||
/**
|
|
||||||
* Run a command (as a promise).
|
|
||||||
* @param command command to run
|
|
||||||
* @param args args to pass
|
|
||||||
* @returns true if success
|
|
||||||
*/
|
|
||||||
function runCommand(command: string, args: string[] = []): Promise<boolean> {
|
|
||||||
return new Promise((res, _) => {
|
|
||||||
let proc = spawn(command, args, { stdio: ['ignore', process.stdout, process.stderr] });
|
|
||||||
proc.on('exit', code => res(code === 0));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats text to be sent as a parameter to some command
|
* Formats text to be sent as a parameter to some command
|
||||||
* @param param
|
* @param param
|
||||||
@@ -54,15 +40,16 @@ function escapeCommandParam(param: string) {
|
|||||||
|
|
||||||
class Pusher {
|
class Pusher {
|
||||||
private _gitea: Gitea | null;
|
private _gitea: Gitea | null;
|
||||||
private _lastSign: number = 0;
|
|
||||||
private _config: PusherConfig;
|
private _config: PusherConfig;
|
||||||
private _artools: ArtoolsConf;
|
private _artools: ArtoolsConf;
|
||||||
private _constructed: Promise<void>;
|
private _constructed: Promise<void>;
|
||||||
|
private _createdSignfile: boolean;
|
||||||
|
|
||||||
constructor(config: PusherConfig = {}) {
|
constructor(config: PusherConfig = {}) {
|
||||||
this._gitea = null;
|
this._gitea = null;
|
||||||
this._artools = DefaultConf
|
this._artools = DefaultConf
|
||||||
this._config = config;
|
this._config = config;
|
||||||
|
this._createdSignfile = false;
|
||||||
this._constructed = (async () => {
|
this._constructed = (async () => {
|
||||||
try {
|
try {
|
||||||
this._artools = await (new ArtoolsConfReader()).readConf();
|
this._artools = await (new ArtoolsConfReader()).readConf();
|
||||||
@@ -78,13 +65,11 @@ class Pusher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async refreshGpg() {
|
async refreshGpg() {
|
||||||
let currentTime = (new Date()).getTime();
|
if (await isPasswordRequired()) {
|
||||||
if (this._config.gpgpass && currentTime - this._lastSign > SIGNATUREEXPIRY) {
|
|
||||||
console.log(clc.cyan('Refreshing signature...'));
|
console.log(clc.cyan('Refreshing signature...'));
|
||||||
await runCommand('touch', [SIGNFILE]);
|
this._createdSignfile ||= await runCommand('touch', [SIGNFILE]);
|
||||||
await runCommand('gpg', ['-a', '--passphrase', escapeCommandParam(this._config.gpgpass), '--batch', '--pinentry-mode', 'loopback', '--detach-sign', SIGNFILE]);
|
await runCommand('gpg', ['-a', '--passphrase', escapeCommandParam(this._config.gpgpass || ''), '--batch', '--pinentry-mode', 'loopback', '--detach-sign', SIGNFILE]);
|
||||||
await fsp.rm(`${SIGNFILE}.asc`);
|
await fsp.rm(`${SIGNFILE}.asc`);
|
||||||
this._lastSign = currentTime;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,6 +199,7 @@ class Pusher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(clc.greenBright('SUCCESS: All packages built'));
|
console.log(clc.greenBright('SUCCESS: All packages built'));
|
||||||
|
if (this._createdSignfile) {
|
||||||
try {
|
try {
|
||||||
await fsp.rm(SIGNFILE);
|
await fsp.rm(SIGNFILE);
|
||||||
}
|
}
|
||||||
@@ -222,6 +208,7 @@ class Pusher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default Pusher;
|
export default Pusher;
|
||||||
export { Pusher };
|
export { Pusher };
|
||||||
|
43
src/runCommand.mts
Normal file
43
src/runCommand.mts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { spawn } from 'node:child_process';
|
||||||
|
import type { SpawnOptions } from 'node:child_process';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run a command (as a promise).
|
||||||
|
* @param command command to run
|
||||||
|
* @param args args to pass
|
||||||
|
* @returns promise that yields true if success
|
||||||
|
*/
|
||||||
|
function runCommand(command: string, args: string[] = [], stdOutToLogs: boolean = true): Promise<boolean> {
|
||||||
|
return new Promise((res, _) => {
|
||||||
|
const opts: SpawnOptions = {stdio: stdOutToLogs ? ['pipe', 'inherit', 'inherit'] : 'pipe'};
|
||||||
|
const proc = spawn(command, args, opts);
|
||||||
|
proc.on('exit', code => res(code === 0));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if password input is necessary for signing
|
||||||
|
* @returns promise that yieds true if password is required
|
||||||
|
*/
|
||||||
|
function isPasswordRequired(): Promise<boolean> {
|
||||||
|
return new Promise(async (res, _) => {
|
||||||
|
if (! await runCommand('gpg-agent', [], false)) {
|
||||||
|
return res(true);
|
||||||
|
}
|
||||||
|
const proc = spawn('gpg-connect-agent', ['KEYINFO --list', '/bye'], { stdio: 'pipe' });
|
||||||
|
let outputstr = '';
|
||||||
|
proc.stdout.on('data', data => {
|
||||||
|
outputstr += data.toString();
|
||||||
|
});
|
||||||
|
proc.on('exit', async () => {
|
||||||
|
const keyinfo = outputstr.split('\n').filter(l => l.includes('KEYINFO'));
|
||||||
|
res(!keyinfo.find(l => {
|
||||||
|
const tokens = l.split(' ');
|
||||||
|
return tokens[0] === 'S' && tokens[1] === 'KEYINFO' && tokens[3] === 'D' && tokens[6] === '1';
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default runCommand;
|
||||||
|
export { runCommand, isPasswordRequired };
|
Reference in New Issue
Block a user