@toa.io/cli 1.0.1-dev.0 → 1.1.0-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toa.io/cli",
3
- "version": "1.0.1-dev.0",
3
+ "version": "1.1.0-canary.0",
4
4
  "description": "Toa CLI",
5
5
  "author": "temich <tema.gurtovoy@gmail.com>",
6
6
  "homepage": "https://github.com/toa-io/toa#readme",
@@ -23,12 +23,12 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "@toa.io/console": "0.6.0",
26
- "@toa.io/generic": "0.10.0-dev.0",
27
- "@toa.io/kubernetes": "0.7.4-dev.0",
28
- "@toa.io/norm": "1.0.1-dev.0",
29
- "@toa.io/yaml": "0.7.5-dev.0",
26
+ "@toa.io/generic": "0.11.0-canary.0",
27
+ "@toa.io/kubernetes": "0.7.5-canary.0",
28
+ "@toa.io/norm": "1.1.0-canary.0",
29
+ "@toa.io/yaml": "0.7.6-canary.0",
30
30
  "find-up": "5.0.0",
31
31
  "yargs": "17.6.2"
32
32
  },
33
- "gitHead": "5e7998b39ea6111a2cf7d38fad8aeae71d742621"
33
+ "gitHead": "0adb45e6d6d309b21b976d257ac0a4fc48d866b3"
34
34
  }
package/readme.md CHANGED
@@ -2,43 +2,36 @@
2
2
 
3
3
  ## Development
4
4
 
5
- ### configure
5
+ ### compose
6
6
 
7
- Outputs shell commands to manipulate local environment variables, thus must be piped
8
- with `source /dev/stdin` to apply.
7
+ Run composition.
9
8
 
10
9
  <dl>
11
- <dt><code>toa configure &lt;key&gt; [value]</code></dt>
10
+ <dt><code>toa compose [paths]</code></dt>
12
11
  <dd>
13
- Set Configuration Object key. Nested keys are addressed with dot notation.
14
-
15
- <code>--path</code> path to component (default <code>.</code>)<br/>
16
- <code>--reset</code> clear <code>key</code><br/>
17
-
18
- #### Examples
19
-
20
- > It is assumed you are in the component's directory, use `--path` otherwise.
21
-
22
- ```shell
23
- # set new value
24
- $ toa configure foo 'new value' | source /dev/stdin
25
- ```
12
+ <code>paths</code> glob patterns to look for components<br/>
13
+ <code>--kill</code> shutdown composition after it's started<br/>
14
+ <code>--dock</code> run in Docker using current <code>.env</code><br/>
15
+ <code>--bindnings</code> override bindings (obsolete)<br/>
16
+ </dd>
17
+ </dl>
26
18
 
27
- ```shell
28
- # clear key
29
- $ toa configure bar.baz --reset | source /dev/stdin
30
- ```
19
+ ### env
31
20
 
32
- </dd>
33
- <dt><code>toa configure reset</code></dt>
34
- <dd>Remove Configuration Object.</dd>
35
- <dt><code>toa configure print</code></dt>
36
- <dd>Output Configuration Object as YAML.
21
+ Export environment to a `.env` file.
37
22
 
38
- <code>--json</code> as JSON
23
+ <dl>
24
+ <dt><code>toa env [environment]</code></dt>
25
+ <dd>
26
+ <code>environment</code> deployment environment name (default <code>local</code>).<br/>
27
+ <code>--path</code> path to context (default <code>.</code>)<br/>
39
28
  </dd>
40
29
  </dl>
41
30
 
31
+ Credentials specified in `.env` file are preserved.
32
+
33
+ > It is recommended to add `.env` to `.gitignore`.
34
+
42
35
  ### replay
43
36
 
44
37
  [Replay](/extensions/sampling/docs/replay.md) samples. Reports in [TAP](https://testanything.org)
@@ -47,11 +40,12 @@ format.
47
40
  <dl>
48
41
  <dt><code>toa replay [paths...]</code></dt>
49
42
  <dd>
50
- <code>paths</code> path(s) to component(s) or a context (default <code>.</code>)<br/>
51
- <code>--integration</code> replay integration tests only<br/>
52
- <code>--component &lt;id&gt;</code> replay samples for specified component id<br/>
53
- <code>--operation &lt;name&gt;</code> replay samples for specified operation<br/>
54
- <code>--title &lt;regexp&gt;</code> regexp to match sample titles<br/>
43
+ <code>paths</code> Path(s) to component(s) or a context (default <code>.</code>).<br/>
44
+ <code>--integration</code> Replay integration tests only.<br/>
45
+ <code>--component &lt;id&gt;</code> Replay samples for a specified component <code>id</code>.<br/>
46
+ <code>--operation &lt;name&gt;</code> Replay samples for specified operation.<br/>
47
+ <code>--title &lt;regexp&gt;</code> Regexp to match sample titles.<br/>
48
+ <code>--dock</code> Run in Docker. Applicable only for component samples.
55
49
  </dd>
56
50
  </dl>
57
51
 
@@ -60,17 +54,15 @@ format.
60
54
  ```shell
61
55
  $ toa replay
62
56
  $ toa replay ./path/to/component
63
- $ toa replay ./components/a ./components/b
57
+ $ toa replay ./components/a ./components/b --dock
64
58
  $ toa replay ./components/*
65
59
  $ toa replay ./path/to/context
66
60
  $ toa replay --title "should add numbers"
67
61
  ```
68
62
 
69
- If path is a context directory (containing `context.toa.yaml` file), samples for components within
63
+ If a path is a context directory (containing `context.toa.yaml` file), samples for components within
70
64
  the context will be found and replayed sequentially.
71
65
 
72
- ## Exporting
73
-
74
66
  ### export manifest
75
67
 
76
68
  <dl>
@@ -82,24 +74,9 @@ the context will be found and replayed sequentially.
82
74
  </dd>
83
75
  </dl>
84
76
 
85
- ### env
86
-
87
- <dl>
88
- <dt><code>toa env [environment]</code></dt>
89
- <dd>Select environment. Set local environment variables to <code>.env</code> file.
90
-
91
- <code>environment</code> deployment environment name (default <code>local</code>).<br/>
92
- <code>--path</code> path to context (default <code>.</code>)<br/>
93
- </dd>
94
- </dl>
95
-
96
- > It is recommended to add `.env` to `.gitignore`.
97
-
98
- > Credentials specified in a `.env` file are preserved during environment selection.
99
-
100
- ## Deployment
77
+ ## Operations
101
78
 
102
- > Deployment commands use current `kubectl` context.
79
+ > Commands use current Kubernetes context.
103
80
 
104
81
  ### deploy
105
82
 
@@ -114,16 +91,8 @@ the context will be found and replayed sequentially.
114
91
  ### conceal
115
92
 
116
93
  <dl>
117
- <dt>
118
- <code>toa conceal</code>
119
- <img src="https://img.shields.io/badge/Not_Implemented-red" alt="Not Implemented"/>
120
- </dt>
121
- <dd>Deploy new declared secrets.
122
-
123
- <code>--reset</code> don't skip already deployed</dd>
124
-
125
94
  <dt><code>toa conceal &lt;secret&gt; &lt;key&gt; &lt;value&gt;</code></dt>
126
- <dd>Deploy a <code>key</code> with a <code>value</code> to a <code>secret</code>.</dd>
95
+ <dd>Deploy a <code>key</code> with a <code>value</code> to a secret named <code>toa-{secret}</code>.</dd>
127
96
  </dl>
128
97
 
129
98
  ### reveal
@@ -134,3 +103,21 @@ the context will be found and replayed sequentially.
134
103
  </dt>
135
104
  <dd>Print keys and values of a secret.</dd>
136
105
  </dl>
106
+
107
+ ### shell
108
+
109
+ <dl>
110
+ <dt>
111
+ <code>toa shell [image]</code>
112
+ </dt>
113
+ <dd>Run interactive shell inside a disposable pod.
114
+
115
+ <code>image</code> Docker image<br/>
116
+ </dd>
117
+ </dl>
118
+
119
+ Extra arguments can be passed:
120
+
121
+ ```shell
122
+ $ toa shell -- ping 1.1
123
+ ```
@@ -4,10 +4,6 @@ const { build } = require('../handlers/build')
4
4
 
5
5
  const builder = (yargs) => {
6
6
  yargs
7
- .positional('environment', {
8
- type: 'string',
9
- desc: 'Deployment environment'
10
- })
11
7
  .option('path', {
12
8
  alias: 'p',
13
9
  group: 'Command options:',
@@ -17,7 +13,7 @@ const builder = (yargs) => {
17
13
  })
18
14
  }
19
15
 
20
- exports.command = 'build [environment]'
21
- exports.desc = 'Build and push docker images'
16
+ exports.command = 'build'
17
+ exports.desc = 'Build Docker images'
22
18
  exports.builder = builder
23
19
  exports.handler = build
@@ -12,10 +12,20 @@ const builder = (yargs) => {
12
12
  default: '.'
13
13
  })
14
14
  .array('paths')
15
+ .option('kill', {
16
+ group: 'Command options:',
17
+ type: 'boolean',
18
+ desc: 'Immediate shutdown'
19
+ })
20
+ .option('dock', {
21
+ group: 'Command options:',
22
+ type: 'boolean',
23
+ desc: 'Run in Docker'
24
+ })
15
25
  .option('bindings', {
16
26
  group: 'Command options:',
17
27
  type: 'string',
18
- desc: 'Bindings'
28
+ desc: 'OBSOLETE'
19
29
  })
20
30
  .array('bindings')
21
31
  .example([
@@ -6,7 +6,7 @@ const builder = (yargs) => {
6
6
  yargs
7
7
  .positional('target', {
8
8
  type: 'string',
9
- desc: 'Export target path'
9
+ desc: 'Path to export to'
10
10
  })
11
11
  .positional('environment', {
12
12
  type: 'string',
@@ -21,7 +21,7 @@ const builder = (yargs) => {
21
21
  })
22
22
  }
23
23
 
24
- exports.command = ['deployment <target> [environment]', 'dep']
24
+ exports.command = ['deployment <environment> <target>', 'dep']
25
25
  exports.desc = 'Export context deployment'
26
26
  exports.builder = builder
27
27
  exports.handler = dump
@@ -6,7 +6,7 @@ const builder = (yargs) => {
6
6
  yargs
7
7
  .positional('target', {
8
8
  type: 'string',
9
- desc: 'Export target path'
9
+ desc: 'Path to export to'
10
10
  })
11
11
  .option('path', {
12
12
  alias: 'p',
@@ -17,7 +17,7 @@ const builder = (yargs) => {
17
17
  })
18
18
  }
19
19
 
20
- exports.command = ['images [target]', 'imgs']
20
+ exports.command = ['images <target>', 'img']
21
21
  exports.desc = 'Export docker image sources'
22
22
  exports.builder = builder
23
23
  exports.handler = prepare
@@ -0,0 +1,19 @@
1
+ 'use strict'
2
+
3
+ const { push } = require('../handlers/push')
4
+
5
+ const builder = (yargs) => {
6
+ yargs
7
+ .option('path', {
8
+ alias: 'p',
9
+ group: 'Command options:',
10
+ type: 'string',
11
+ desc: 'Path to context',
12
+ default: '.'
13
+ })
14
+ }
15
+
16
+ exports.command = 'push'
17
+ exports.desc = 'Build and push Docker images'
18
+ exports.builder = builder
19
+ exports.handler = push
@@ -4,6 +4,10 @@
4
4
 
5
5
  const { replay } = require('../handlers/replay')
6
6
 
7
+ /*
8
+ !!! OPTIONS MUST BE SYNCHRONIZED WITH ../handlers/.replay/args !!!
9
+ */
10
+
7
11
  const builder = (yargs) => {
8
12
  yargs
9
13
  .positional('paths', {
@@ -35,6 +39,13 @@ const builder = (yargs) => {
35
39
  group: 'Command options:',
36
40
  describe: 'Replay samples with titles matching given regexp'
37
41
  })
42
+ .option('dock', {
43
+ alias: 'd',
44
+ type: 'boolean',
45
+ default: false,
46
+ group: 'Command options:',
47
+ describe: 'Replay inside Docker container'
48
+ })
38
49
  }
39
50
 
40
51
  exports.command = 'replay [paths...]'
@@ -0,0 +1,22 @@
1
+ 'use strict'
2
+
3
+ const { shell } = require('../handlers/shell')
4
+
5
+ const builder = (yargs) => {
6
+ yargs
7
+ .positional('image', {
8
+ group: 'Command options:',
9
+ type: 'string',
10
+ desc: 'Docker image',
11
+ default: 'alpine'
12
+ })
13
+ .example([
14
+ ['$0 shell'],
15
+ ['$0 shell -- ping localhost']
16
+ ])
17
+ }
18
+
19
+ exports.command = 'shell [image]'
20
+ exports.desc = 'Run interactive shell from the current Kubernetes context'
21
+ exports.builder = builder
22
+ exports.handler = shell
@@ -6,9 +6,9 @@ const { context: find } = require('../util/find')
6
6
 
7
7
  const build = async (argv) => {
8
8
  const path = find(argv.path)
9
- const operator = await boot.deployment(path, argv.environment)
9
+ const registry = await boot.registry(path)
10
10
 
11
- await operator.build()
11
+ await registry.build()
12
12
  }
13
13
 
14
14
  exports.build = build
@@ -1,14 +1,38 @@
1
1
  'use strict'
2
2
 
3
+ const { file: { dot } } = require('@toa.io/filesystem')
4
+ const { pick } = require('@toa.io/generic')
3
5
  const boot = require('@toa.io/boot')
4
6
 
7
+ const docker = require('./docker')
5
8
  const { components: find } = require('../util/find')
6
9
 
10
+ /**
11
+ * @param {Record<string, string | boolean>} argv
12
+ * @return {Promise<void>}
13
+ */
7
14
  async function compose (argv) {
15
+ if (argv.dock === true) return dock(argv)
16
+
8
17
  const paths = find(argv.paths)
9
18
  const composition = await boot.composition(paths, argv)
10
19
 
11
20
  await composition.connect()
21
+
22
+ if (argv.kill === true) await composition.disconnect()
23
+ }
24
+
25
+ /**
26
+ * @param {Record<string, string | string[] | boolean>} argv
27
+ * @return {Promise<void>}
28
+ */
29
+ async function dock (argv) {
30
+ const envFile = await dot('env')
31
+ const repository = await docker.build(argv.paths)
32
+ const args = pick(argv, ['kill', 'bindings'])
33
+ const command = docker.command('toa compose *', args)
34
+
35
+ await docker.run(repository, command, ['--env-file', envFile])
12
36
  }
13
37
 
14
38
  exports.compose = compose
@@ -4,8 +4,12 @@ const { secrets } = require('@toa.io/kubernetes')
4
4
 
5
5
  const conceal = async (argv) => {
6
6
  const { secret, key, value } = argv
7
+ const prefixed = PREFIX + secret
7
8
 
8
- await secrets.store(secret, { [key]: value })
9
+ await secrets.store(prefixed, { [key]: value })
9
10
  }
10
11
 
12
+ const PREFIX = 'toa-'
13
+
11
14
  exports.conceal = conceal
15
+ exports.PREFIX = PREFIX
@@ -0,0 +1,67 @@
1
+ 'use strict'
2
+
3
+ const { newid } = require('@toa.io/generic')
4
+ const { component: load } = require('@toa.io/norm')
5
+ const { deployment: { Factory } } = require('@toa.io/operations')
6
+ const runtime = require('@toa.io/runtime')
7
+
8
+ const find = require('../../util/find')
9
+
10
+ /**
11
+ * @param {string[]} paths
12
+ * @return {Promise<string>}
13
+ */
14
+ async function build (paths) {
15
+ const context = await createContext(/** @type {string[]} */ paths)
16
+ const factory = new Factory(context)
17
+ const registry = factory.registry()
18
+
19
+ await registry.build()
20
+
21
+ const composition = context.compositions[0].name
22
+
23
+ return `${context.name}/composition-${composition}`
24
+ }
25
+
26
+ /**
27
+ * @param {string[]} patterns
28
+ * @return {Promise<toa.norm.Context>}
29
+ */
30
+ async function createContext (patterns) {
31
+ const paths = patterns.map((pattern) => find.components(pattern))
32
+ const components = await loadComponents(paths)
33
+ const rnd = newid().substring(0, 6)
34
+ const name = 'replay-' + rnd
35
+
36
+ return {
37
+ name: 'toa-temp',
38
+ runtime: {
39
+ version: runtime.version
40
+ },
41
+ registry: {
42
+ platforms: null
43
+ },
44
+ compositions: [{
45
+ name,
46
+ components
47
+ }]
48
+ }
49
+ }
50
+
51
+ /**
52
+ * @param {string[]} paths
53
+ * @return {Promise<toa.norm.Component[]>}
54
+ */
55
+ async function loadComponents (paths) {
56
+ const components = []
57
+
58
+ for (const path of paths) {
59
+ const component = await load(path)
60
+
61
+ components.push(component)
62
+ }
63
+
64
+ return components
65
+ }
66
+
67
+ exports.build = build
@@ -0,0 +1,23 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * @param {string} command
5
+ * @param {Record<string, any>} args
6
+ */
7
+ const command = (command, args) => {
8
+ const options = []
9
+
10
+ for (const [name, value] of Object.entries(args)) {
11
+ if (value === undefined) continue
12
+
13
+ options.push('--' + name)
14
+
15
+ if (typeof value !== 'boolean') options.push(`"${value}"`)
16
+ }
17
+
18
+ const argumentLine = options.join(' ')
19
+
20
+ return command + ' ' + argumentLine
21
+ }
22
+
23
+ exports.command = command
@@ -0,0 +1,9 @@
1
+ 'use strict'
2
+
3
+ const { build } = require('./build')
4
+ const { command } = require('./command')
5
+ const { run } = require('./run')
6
+
7
+ exports.build = build
8
+ exports.command = command
9
+ exports.run = run
@@ -0,0 +1,36 @@
1
+ 'use strict'
2
+
3
+ const { spawn, exec } = require('node:child_process')
4
+ const { promisify } = require('node:util')
5
+
6
+ const { promex } = require('@toa.io/generic')
7
+
8
+ const execute = promisify(exec)
9
+
10
+ /**
11
+ * @param {string} repository
12
+ * @param {string} command
13
+ * @param {string[]} runArguments
14
+ * @return {Promise<void>}
15
+ */
16
+ async function run (repository, command, runArguments) {
17
+ const imagesResult =
18
+ /** @type {{ stdout: string }} */
19
+ await execute(`docker images -q ${repository} | head -n 1`)
20
+
21
+ const id = imagesResult.stdout.trim()
22
+ const args = ['run', '--rm', ...(runArguments ?? []), id, 'sh', '-c', command]
23
+ const done = promex()
24
+
25
+ console.log('toa> docker', args)
26
+
27
+ const running = await spawn('docker', args, { stdio: 'inherit' })
28
+
29
+ running.on('exit', done.resolve)
30
+
31
+ await done
32
+
33
+ await execute(`docker rmi ${id}`)
34
+ }
35
+
36
+ exports.run = run
@@ -13,4 +13,12 @@ const prepare = async (argv) => {
13
13
  console.log(path)
14
14
  }
15
15
 
16
+ // const prepare = async (argv) => {
17
+ // const context = find(argv.path)
18
+ // const registry = await boot.registry(context)
19
+ // const path = await registry.prepare(argv.target)
20
+ //
21
+ // console.log(path)
22
+ // }
23
+
16
24
  exports.prepare = prepare
@@ -0,0 +1,14 @@
1
+ 'use strict'
2
+
3
+ const boot = require('@toa.io/boot')
4
+
5
+ const { context: find } = require('../util/find')
6
+
7
+ const push = async (argv) => {
8
+ const path = find(argv.path)
9
+ const registry = await boot.registry(path)
10
+
11
+ await registry.push()
12
+ }
13
+
14
+ exports.push = push
@@ -1,10 +1,17 @@
1
1
  'use strict'
2
2
 
3
+ const { pick } = require('@toa.io/generic')
4
+ const { context, components } = require('@toa.io/userland/samples')
5
+
3
6
  const find = require('../util/find')
7
+ const docker = require('./docker')
4
8
 
9
+ /**
10
+ * @param {Record<string, string | boolean>} argv
11
+ * @return {Promise<void>}
12
+ */
5
13
  async function replay (argv) {
6
- // prevent loading userland which is intended for local use only
7
- const { context, components } = require('@toa.io/userland/samples')
14
+ if (argv.dock) return dock(argv)
8
15
 
9
16
  /** @type {boolean} */
10
17
  let ok
@@ -16,7 +23,8 @@ async function replay (argv) {
16
23
  component: argv.component,
17
24
  integration: argv.integration,
18
25
  operation: argv.operation,
19
- title: argv.title
26
+ title: argv.title,
27
+ runner: { bail: true }
20
28
  }
21
29
 
22
30
  if (paths !== null) {
@@ -36,6 +44,18 @@ async function replay (argv) {
36
44
  process.on('beforeExit', () => console.log(message))
37
45
  }
38
46
 
47
+ /**
48
+ * @param {Record<string, string | string[] | boolean>} argv
49
+ * @return {Promise<void>}
50
+ */
51
+ async function dock (argv) {
52
+ const repository = await docker.build(argv.paths)
53
+ const args = pick(argv, ['component', 'operation', 'integration', 'title'])
54
+ const command = docker.command('toa replay *', args)
55
+
56
+ await docker.run(repository, command)
57
+ }
58
+
39
59
  const GREEN = '\x1b[32m'
40
60
  const RED = '\x1b[31m'
41
61
  const RESET = '\x1b[0m'
@@ -3,8 +3,11 @@
3
3
  const { secrets } = require('@toa.io/kubernetes')
4
4
  const { remap, decode } = require('@toa.io/generic')
5
5
 
6
+ const { PREFIX } = require('./conceal')
7
+
6
8
  const reveal = async (argv) => {
7
- const secret = await secrets.get(argv.secret)
9
+ const prefixed = PREFIX + argv.secret
10
+ const secret = await secrets.get(prefixed)
8
11
  const values = remap(secret.data, decode)
9
12
 
10
13
  for (const [key, value] of Object.entries(values)) {
@@ -0,0 +1,29 @@
1
+ 'use strict'
2
+
3
+ const { spawn } = require('node:child_process')
4
+ const { newid } = require('@toa.io/generic')
5
+
6
+ const shell = async (argv) => {
7
+ const rnd = newid().substring(0, 6)
8
+
9
+ const args = [
10
+ 'run',
11
+ 'shell-' + rnd,
12
+ '--rm',
13
+ '-i',
14
+ '--tty',
15
+ '--image',
16
+ argv.image,
17
+ '--restart=Never',
18
+ '--'
19
+ ]
20
+
21
+ const extra = argv._.splice(1)
22
+
23
+ if (extra.length > 0) args.push(...extra)
24
+ else args.push('sh')
25
+
26
+ await spawn('kubectl', args, { stdio: 'inherit' })
27
+ }
28
+
29
+ exports.shell = shell
package/src/program.js CHANGED
@@ -19,7 +19,7 @@ yargs(process.argv.slice(2))
19
19
  .fail((msg, err) => {
20
20
  const actual = err || new Error(msg)
21
21
 
22
- console.error(process.env.TOA_DEBUG === '1' ? actual : actual.message)
22
+ console.error(actual)
23
23
 
24
24
  process.exit(actual.exitCode > 0 ? actual.exitCode : 1)
25
25
  })
package/src/util/find.js CHANGED
@@ -17,7 +17,7 @@ const find = (from, filename, test) => {
17
17
 
18
18
  if (found.size === 0) {
19
19
  if (test === true) return null
20
- else throw new Error(`File '${filename}' is found in ${from.join(', ')}`)
20
+ else throw new Error(`File '${filename}' is not found in ${from.join(', ')}`)
21
21
  }
22
22
 
23
23
  return [...found]
@@ -1,43 +0,0 @@
1
- 'use strict'
2
-
3
- const { configure } = require('../handlers/configure')
4
-
5
- const builder = (yargs) => {
6
- yargs
7
- .positional('key', {
8
- type: 'string',
9
- desc: 'Configuration Object key'
10
- })
11
- .positional('value', {
12
- type: 'string',
13
- desc: 'Key value'
14
- })
15
- .option('path', {
16
- alias: 'p',
17
- group: 'Command options:',
18
- describe: 'Path to component',
19
- type: 'string',
20
- default: '.'
21
- })
22
- .option('reset', {
23
- group: 'Command options:',
24
- type: 'boolean',
25
- desc: 'Remove Configuration Object key'
26
- })
27
- .option('json', {
28
- group: 'Command options:',
29
- type: 'boolean',
30
- desc: 'Print as JSON'
31
- })
32
- .example([
33
- ['$0 configure myKey \'new value\' | source /dev/stdin'],
34
- ['$0 configure myObject.myKey --reset | source /dev/stdin'],
35
- ['$0 configure reset | source /dev/stdin'],
36
- ['$0 configure print --json']
37
- ])
38
- }
39
-
40
- exports.command = 'configure [key] [value]'
41
- exports.desc = 'Output shell command to update local environment Configuration Object'
42
- exports.builder = builder
43
- exports.handler = configure
@@ -1,15 +0,0 @@
1
- 'use strict'
2
-
3
- const { dump } = require('@toa.io/yaml')
4
-
5
- const reset = (provider) => console.log('unset ' + provider.key)
6
-
7
- const print = async (provider, argv) => {
8
- await provider.connect()
9
-
10
- const formatter = argv.json ? JSON.stringify : dump
11
-
12
- console.log(formatter(provider.object))
13
- }
14
-
15
- exports.subcommands = { print, reset }
@@ -1,46 +0,0 @@
1
- 'use strict'
2
-
3
- const boot = require('@toa.io/boot')
4
-
5
- const { Factory } = require('@toa.io/extensions.configuration')
6
-
7
- const { subcommands } = require('./.configure/subcommands')
8
- const { components: find } = require('../util/find')
9
-
10
- async function configure (argv) {
11
- const path = find(argv.path)
12
- const manifest = await boot.manifest(path)
13
- const factory = new Factory()
14
- const provider = factory.provider(manifest)
15
-
16
- if (argv.value === undefined && subcommands[argv.key] !== undefined) {
17
- await subcommands[argv.key](provider, argv)
18
-
19
- return
20
- }
21
-
22
- await provider.connect()
23
-
24
- let key = argv.key
25
- let value = argv.value
26
-
27
- // :(
28
- if (key !== undefined) {
29
- if (value === undefined && key.includes('=')) [key, value] = key.split('=')
30
-
31
- if (value === undefined) {
32
- if (argv.reset !== true) throw new Error('Key value expected')
33
- else provider.unset(key)
34
- } else provider.set(key, value)
35
- }
36
-
37
- let command
38
- const exported = provider.export()
39
-
40
- if (exported === undefined) command = `unset ${provider.key}`
41
- else command = `export ${provider.key}=` + exported
42
-
43
- console.log(command)
44
- }
45
-
46
- exports.configure = configure