Skip to content

Commit 3747387

Browse files
committed
Support using '-' as input filename for getting data from stdin
1 parent cebc138 commit 3747387

File tree

6 files changed

+112
-78
lines changed

6 files changed

+112
-78
lines changed

agent/apps/ztm/script/cli.js

Lines changed: 67 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,74 @@
11
export default function ({ app, api, utils }) {
2-
var $handler
2+
var $ctx
3+
var $script
4+
var $argv
5+
var $output
36

47
return pipeline($=>$
5-
.onStart(ctx => main(ctx))
8+
.onStart(c => {
9+
$ctx = c
10+
return new MessageStart
11+
})
12+
.pipe(
13+
function () {
14+
try {
15+
return utils.parseArgv($ctx.argv, {
16+
help: text => {
17+
$output = new Data(text)
18+
$output.push('\n')
19+
return 'output'
20+
},
21+
commands: [
22+
{
23+
title: 'Execute a script on a remote endpoint',
24+
usage: '<filename>',
25+
options: `
26+
--, --args ... Pass all options afterwards to the script
27+
`,
28+
action: (args) => {
29+
$argv = args['--args'] || []
30+
var filename = args['<filename>']
31+
if (filename === '-') {
32+
$script = new Data
33+
return 'read'
34+
}
35+
var pathname = os.path.resolve($ctx.cwd, filename)
36+
$script = os.read(pathname)
37+
return 'exec'
38+
}
39+
}
40+
]
41+
})
42+
} catch (err) {
43+
$output = new Data('ztm: ')
44+
$output.push(err.message || err.toString())
45+
$output.push('\n')
46+
return 'output'
47+
}
48+
}, {
49+
'output': $=>$.replaceData().replaceStreamStart(() => [$output, new StreamEnd]),
50+
'exec': $=>$.replaceData().replaceStreamStart(() => exec().then(output => [output, new StreamEnd])),
51+
'read': $=>$.replaceData(data => { $script.push(data) }).replaceStreamEnd(() => exec().then(output => [output, new StreamEnd])),
52+
}
53+
)
654
)
755

8-
function main({ argv, cwd, endpoint }) {
9-
var buffer = new Data
10-
11-
function output(str) {
12-
buffer.push(str)
13-
}
14-
15-
function flush() {
16-
return Promise.resolve([buffer, new StreamEnd])
17-
}
18-
19-
function error(err) {
20-
output('ztm: ')
21-
output(err.message || err.toString())
22-
output('\n')
23-
return flush()
24-
}
25-
26-
try {
27-
return utils.parseArgv(argv, {
28-
help: text => Promise.resolve(output(text + '\n')),
29-
commands: [
30-
{
31-
title: 'Execute a script on a remote endpoint',
32-
usage: '<filename>',
33-
options: `
34-
--, --args ... Pass all options afterwards to the script
35-
`,
36-
action: (args) => {
37-
var filename = args['<filename>']
38-
var pathname = os.path.resolve(cwd, filename)
39-
var script = os.read(pathname)
40-
var argv = args['--args'] || []
41-
return pipeline($=>$
42-
.onStart(new Message(
43-
{
44-
method: 'POST',
45-
path: `/api/script?argv=${URL.encodeComponent(JSON.stringify(argv))}`
46-
},
47-
script
48-
))
49-
.pipe(api.executeScriptRemote, () => endpoint.id)
50-
.replaceMessage(res => {
51-
output(res?.body || new Data)
52-
return new StreamEnd
53-
})
54-
).spawn()
55-
}
56-
}
57-
]
58-
}).then(flush).catch(error)
59-
60-
} catch (err) { return error(err) }
56+
function exec() {
57+
var ep = $ctx.endpoint.id
58+
return pipeline($=>$
59+
.onStart(new Message(
60+
{
61+
method: 'POST',
62+
path: `/api/script?argv=${URL.encodeComponent(JSON.stringify($argv))}`
63+
},
64+
$script
65+
))
66+
.pipe(api.executeScriptRemote, () => ep)
67+
.replaceMessage(res => {
68+
$output = res?.body || new Data
69+
return new StreamEnd
70+
})
71+
.onEnd(() => $output)
72+
).spawn()
6173
}
6274
}

agent/cmdline.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export default function (argv, { commands, notes, help, fallback }) {
9292

9393
function matchCommand(pattern, argv) {
9494
var i = argv.findIndex(
95-
(arg, i) => arg.startsWith('-') || arg !== pattern[i]
95+
(arg, i) => (arg.length > 1 && arg.startsWith('-')) || arg !== pattern[i]
9696
)
9797
return i < 0 ? argv.length : i
9898
}
@@ -101,7 +101,7 @@ function parseCommand(pattern, argv, rest) {
101101
var values = {}
102102
var i = argv.findIndex((arg, i) => {
103103
var tok = pattern[i]
104-
if (arg.startsWith('-')) return true
104+
if (arg.length > 1 && arg.startsWith('-')) return true
105105
if (!tok) throw `Excessive positional argument: ${arg}`
106106
if (tok.startsWith('[') || tok.startsWith('<')) {
107107
values[tok] = arg
@@ -152,7 +152,7 @@ function parseOptions(format, argv) {
152152
addOption(currentOption, arg)
153153
return
154154
}
155-
if (arg.startsWith('-')) {
155+
if (arg.length > 1 && arg.startsWith('-')) {
156156
endOption(currentOption)
157157
currentOption = undefined
158158
} else {
@@ -162,7 +162,7 @@ function parseOptions(format, argv) {
162162
}
163163
if (arg.startsWith('--')) {
164164
currentOption = arg
165-
} else if (arg.startsWith('-')) {
165+
} else if (arg.length > 1 && arg.startsWith('-')) {
166166
if (arg.length === 2) {
167167
currentOption = arg
168168
} else {

ca/cmdline.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export default function (argv, { commands, notes, help, fallback }) {
9292

9393
function matchCommand(pattern, argv) {
9494
var i = argv.findIndex(
95-
(arg, i) => arg.startsWith('-') || arg !== pattern[i]
95+
(arg, i) => (arg.length > 1 && arg.startsWith('-')) || arg !== pattern[i]
9696
)
9797
return i < 0 ? argv.length : i
9898
}
@@ -101,7 +101,7 @@ function parseCommand(pattern, argv, rest) {
101101
var values = {}
102102
var i = argv.findIndex((arg, i) => {
103103
var tok = pattern[i]
104-
if (arg.startsWith('-')) return true
104+
if (arg.length > 1 && arg.startsWith('-')) return true
105105
if (!tok) throw `Excessive positional argument: ${arg}`
106106
if (tok.startsWith('[') || tok.startsWith('<')) {
107107
values[tok] = arg
@@ -131,7 +131,8 @@ function parseOptions(format, argv) {
131131
if (t.endsWith(',')) t = t.substring(0, t.length - 1)
132132
aliases.push(t)
133133
} else {
134-
if (t.endsWith('...]') || t.endsWith('...>')) type = 'array'
134+
if (t === '...') type = 'remainder array'
135+
else if (t.endsWith('...]') || t.endsWith('...>')) type = 'array'
135136
else if (t.startsWith('[')) type = 'optional string'
136137
else if (t.startsWith('<')) type = 'string'
137138
else type = 'boolean'
@@ -147,7 +148,11 @@ function parseOptions(format, argv) {
147148

148149
argv.forEach(arg => {
149150
if (currentOption) {
150-
if (arg.startsWith('-')) {
151+
if (options[currentOption]?.type === 'remainder array') {
152+
addOption(currentOption, arg)
153+
return
154+
}
155+
if (arg.length > 1 && arg.startsWith('-')) {
151156
endOption(currentOption)
152157
currentOption = undefined
153158
} else {
@@ -157,7 +162,7 @@ function parseOptions(format, argv) {
157162
}
158163
if (arg.startsWith('--')) {
159164
currentOption = arg
160-
} else if (arg.startsWith('-')) {
165+
} else if (arg.length > 1 && arg.startsWith('-')) {
161166
if (arg.length === 2) {
162167
currentOption = arg
163168
} else {
@@ -182,6 +187,7 @@ function parseOptions(format, argv) {
182187
option.value = value
183188
break
184189
case 'array':
190+
case 'remainder array':
185191
option.value ??= []
186192
option.value.push(value)
187193
break
@@ -236,6 +242,7 @@ function tokenize(str) {
236242
function stripIndentation(s, indent) {
237243
var lines = s.split('\n')
238244
if (lines[0].trim() === '') lines.shift()
245+
if (lines[lines.length - 1].trim() === '') lines.pop()
239246
var depth = lines[0].length - lines[0].trimStart().length
240247
var padding = ' '.repeat(indent || 0)
241248
return lines.map(l => padding + l.substring(depth)).join('\n')

cli/cmdline.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export default function (argv, { commands, notes, help, fallback }) {
9292

9393
function matchCommand(pattern, argv) {
9494
var i = argv.findIndex(
95-
(arg, i) => arg.startsWith('-') || arg !== pattern[i]
95+
(arg, i) => (arg.length > 1 && arg.startsWith('-')) || arg !== pattern[i]
9696
)
9797
return i < 0 ? argv.length : i
9898
}
@@ -101,7 +101,7 @@ function parseCommand(pattern, argv, rest) {
101101
var values = {}
102102
var i = argv.findIndex((arg, i) => {
103103
var tok = pattern[i]
104-
if (arg.startsWith('-')) return true
104+
if (arg.length > 1 && arg.startsWith('-')) return true
105105
if (!tok) throw `Excessive positional argument: ${arg}`
106106
if (tok.startsWith('[') || tok.startsWith('<')) {
107107
values[tok] = arg
@@ -131,7 +131,8 @@ function parseOptions(format, argv) {
131131
if (t.endsWith(',')) t = t.substring(0, t.length - 1)
132132
aliases.push(t)
133133
} else {
134-
if (t.endsWith('...]') || t.endsWith('...>')) type = 'array'
134+
if (t === '...') type = 'remainder array'
135+
else if (t.endsWith('...]') || t.endsWith('...>')) type = 'array'
135136
else if (t.startsWith('[')) type = 'optional string'
136137
else if (t.startsWith('<')) type = 'string'
137138
else type = 'boolean'
@@ -147,7 +148,11 @@ function parseOptions(format, argv) {
147148

148149
argv.forEach(arg => {
149150
if (currentOption) {
150-
if (arg.startsWith('-')) {
151+
if (options[currentOption]?.type === 'remainder array') {
152+
addOption(currentOption, arg)
153+
return
154+
}
155+
if (arg.length > 1 && arg.startsWith('-')) {
151156
endOption(currentOption)
152157
currentOption = undefined
153158
} else {
@@ -157,7 +162,7 @@ function parseOptions(format, argv) {
157162
}
158163
if (arg.startsWith('--')) {
159164
currentOption = arg
160-
} else if (arg.startsWith('-')) {
165+
} else if (arg.length > 1 && arg.startsWith('-')) {
161166
if (arg.length === 2) {
162167
currentOption = arg
163168
} else {
@@ -182,6 +187,7 @@ function parseOptions(format, argv) {
182187
option.value = value
183188
break
184189
case 'array':
190+
case 'remainder array':
185191
option.value ??= []
186192
option.value.push(value)
187193
break

cli/main.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ function doCommand(meshName, epName, argv, program) {
177177
usage: 'invite <username>',
178178
options: `
179179
-i, --identity <pathname> Specify an input file to read the user identity from
180-
Read from stdin if not specified
180+
Use '-' to read from stdin
181181
-p, --permit <pathname> Specify an output file to write the user permit to
182182
Print the user permit to stdout if not specified
183183
`,
@@ -302,7 +302,8 @@ function doCommand(meshName, epName, argv, program) {
302302
usage: 'publish <object type> <object name>',
303303
notes: `Available object types include: file, app`,
304304
options: `
305-
-i, --input <pathname> Specify a local file containing the data to publish (default: read from stdin)
305+
-i, --input <pathname> Specify a local file containing the data to publish
306+
Use '-' to read data from stdin
306307
Only applicable when publishing a file
307308
`,
308309
action: (args) => {
@@ -757,9 +758,10 @@ function exec(argv) {
757758

758759
function invite(name, identity, permit, mesh) {
759760
if (!mesh) throw `no mesh specified`
761+
if (!identity) throw `missing option --identity`
760762
var username = normalizeName(name)
761763
var data = new Data
762-
return pipy.read(identity || '-', $=>$.handleData(d => data.push(d))).then(
764+
return pipy.read(identity, $=>$.handleData(d => data.push(d))).then(
763765
() => client.post(`/api/meshes/${mesh.name}/permits/${username}`, data).then(ret => {
764766
if (permit) {
765767
try {
@@ -1100,9 +1102,10 @@ function publishApp(name) {
11001102
}
11011103

11021104
function publishFile(name, input, mesh) {
1105+
if (!input) throw 'missing option --input'
11031106
var path = os.path.normalize(name)
11041107
var data = new Data
1105-
return pipy.read(input || '-', $=>$.handleData(d => data.push(d))).then(
1108+
return pipy.read(input, $=>$.handleData(d => data.push(d))).then(
11061109
() => client.post(os.path.join(`/api/meshes/${mesh.name}/file-data/`, path), data)
11071110
)
11081111
}

hub/cmdline.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export default function (argv, { commands, notes, help, fallback }) {
9292

9393
function matchCommand(pattern, argv) {
9494
var i = argv.findIndex(
95-
(arg, i) => arg.startsWith('-') || arg !== pattern[i]
95+
(arg, i) => (arg.length > 1 && arg.startsWith('-')) || arg !== pattern[i]
9696
)
9797
return i < 0 ? argv.length : i
9898
}
@@ -101,7 +101,7 @@ function parseCommand(pattern, argv, rest) {
101101
var values = {}
102102
var i = argv.findIndex((arg, i) => {
103103
var tok = pattern[i]
104-
if (arg.startsWith('-')) return true
104+
if (arg.length > 1 && arg.startsWith('-')) return true
105105
if (!tok) throw `Excessive positional argument: ${arg}`
106106
if (tok.startsWith('[') || tok.startsWith('<')) {
107107
values[tok] = arg
@@ -131,7 +131,8 @@ function parseOptions(format, argv) {
131131
if (t.endsWith(',')) t = t.substring(0, t.length - 1)
132132
aliases.push(t)
133133
} else {
134-
if (t.endsWith('...]') || t.endsWith('...>')) type = 'array'
134+
if (t === '...') type = 'remainder array'
135+
else if (t.endsWith('...]') || t.endsWith('...>')) type = 'array'
135136
else if (t.startsWith('[')) type = 'optional string'
136137
else if (t.startsWith('<')) type = 'string'
137138
else type = 'boolean'
@@ -147,7 +148,11 @@ function parseOptions(format, argv) {
147148

148149
argv.forEach(arg => {
149150
if (currentOption) {
150-
if (arg.startsWith('-')) {
151+
if (options[currentOption]?.type === 'remainder array') {
152+
addOption(currentOption, arg)
153+
return
154+
}
155+
if (arg.length > 1 && arg.startsWith('-')) {
151156
endOption(currentOption)
152157
currentOption = undefined
153158
} else {
@@ -157,7 +162,7 @@ function parseOptions(format, argv) {
157162
}
158163
if (arg.startsWith('--')) {
159164
currentOption = arg
160-
} else if (arg.startsWith('-')) {
165+
} else if (arg.length > 1 && arg.startsWith('-')) {
161166
if (arg.length === 2) {
162167
currentOption = arg
163168
} else {
@@ -182,6 +187,7 @@ function parseOptions(format, argv) {
182187
option.value = value
183188
break
184189
case 'array':
190+
case 'remainder array':
185191
option.value ??= []
186192
option.value.push(value)
187193
break

0 commit comments

Comments
 (0)