@altronix/cli 0.12.0 → 0.13.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/dist/about.js +1 -1
- package/dist/cloud.js +1 -1
- package/dist/index.js +113 -100
- package/dist/net.js +1 -1
- package/dist/plugin.js +1 -1
- package/dist/progress.ui.js +1 -1
- package/dist/select.ui.d.ts +1 -1
- package/dist/stress.js +1 -1
- package/dist/update.js +1 -1
- package/package.json +6 -6
- package/dist/build.d.ts +0 -2
- package/dist/build.js +0 -525
- package/dist/build.ui.d.ts +0 -27
- package/dist/build.ui.js +0 -95
- package/dist/keys.d.ts +0 -7
- package/dist/keys.js +0 -14
- package/dist/useStdoutDimensions.d.ts +0 -1
- package/dist/useStdoutDimensions.js +0 -17
package/dist/about.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { About, cborDecodeStr } from '@altronix/zdk';
|
|
1
|
+
import { About, cborDecodeStr } from '@altronix/zdk/common';
|
|
2
2
|
import { Linq } from '@altronix/device';
|
|
3
3
|
import { EmptyError, finalize, firstValueFrom, map, switchMap } from 'rxjs';
|
|
4
4
|
import logger from './logger.js';
|
package/dist/cloud.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cborDecodeNum, NetCloud } from '@altronix/zdk';
|
|
1
|
+
import { cborDecodeNum, NetCloud } from '@altronix/zdk/common';
|
|
2
2
|
import { Linq } from '@altronix/device';
|
|
3
3
|
import { concat, EmptyError, finalize, lastValueFrom, map, reduce, switchMap } from 'rxjs';
|
|
4
4
|
import logger from './logger.js';
|
package/dist/index.js
CHANGED
|
@@ -2,17 +2,8 @@
|
|
|
2
2
|
import { program } from 'commander';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import fs from 'fs';
|
|
5
|
-
import { build } from '
|
|
6
|
-
import { getAbout, getSite, setSite } from './about.js';
|
|
7
|
-
import { reboot, save, saveAndReboot } from './exe.js';
|
|
8
|
-
import { getNet, setNet, setDhcp } from './net.js';
|
|
5
|
+
import { build } from '@altronix/build';
|
|
9
6
|
import { fileURLToPath } from 'url';
|
|
10
|
-
import { getCloud, setCloud } from './cloud.js';
|
|
11
|
-
import { stress } from './stress.js';
|
|
12
|
-
import { update } from './update.js';
|
|
13
|
-
import { listen } from './listen.js';
|
|
14
|
-
import { getDemo, getHello } from './sample.js';
|
|
15
|
-
import { concurrent } from './concurrent.js';
|
|
16
7
|
// https://stackoverflow.com/questions/8817423/why-is-dirname-not-defined-in-node-repl
|
|
17
8
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
18
9
|
// Parse package.json to get version
|
|
@@ -51,95 +42,117 @@ program
|
|
|
51
42
|
.option('--matches-config [regex]', 'config regex match expr')
|
|
52
43
|
.option('-y, --yes', 'answer yes automatically')
|
|
53
44
|
.action(build);
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
device
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
device
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
device
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
device
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
device
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
device
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
device
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
device
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
45
|
+
// Device commands are optional - only available when @altronix/device can be loaded
|
|
46
|
+
async function registerDeviceCommands() {
|
|
47
|
+
try {
|
|
48
|
+
// Test if device package is available
|
|
49
|
+
await import('@altronix/device');
|
|
50
|
+
// Dynamically import device-dependent modules
|
|
51
|
+
const { getAbout, getSite, setSite } = await import('./about.js');
|
|
52
|
+
const { reboot, save, saveAndReboot } = await import('./exe.js');
|
|
53
|
+
const { getNet, setNet, setDhcp } = await import('./net.js');
|
|
54
|
+
const { getCloud, setCloud } = await import('./cloud.js');
|
|
55
|
+
const { stress } = await import('./stress.js');
|
|
56
|
+
const { update } = await import('./update.js');
|
|
57
|
+
const { listen } = await import('./listen.js');
|
|
58
|
+
const { getDemo, getHello } = await import('./sample.js');
|
|
59
|
+
const { concurrent } = await import('./concurrent.js');
|
|
60
|
+
const device = program
|
|
61
|
+
.command('device')
|
|
62
|
+
.description('manage zephyr device settings')
|
|
63
|
+
.option('-p, --port <PORT>', 'listen port for incoming device connections')
|
|
64
|
+
.option('-v, --verbose', 'print extra debug informating during request')
|
|
65
|
+
.option('-f, --first', 'perform request on first device we see (any device)');
|
|
66
|
+
device
|
|
67
|
+
.command('get-about')
|
|
68
|
+
.description('get about data on the device')
|
|
69
|
+
.action(getAbout);
|
|
70
|
+
device
|
|
71
|
+
.command('get-site')
|
|
72
|
+
.description('get the site ID of the device')
|
|
73
|
+
.action(getSite);
|
|
74
|
+
device
|
|
75
|
+
.command('set-site')
|
|
76
|
+
.description('set the site ID of the device')
|
|
77
|
+
.argument('<site>', 'new site id')
|
|
78
|
+
.action(setSite);
|
|
79
|
+
device
|
|
80
|
+
.command('save')
|
|
81
|
+
.description('save data to persistant storage. (does not reboot)')
|
|
82
|
+
.action(save);
|
|
83
|
+
device
|
|
84
|
+
.command('reboot')
|
|
85
|
+
.description('reboot the device. (does not save)')
|
|
86
|
+
.action(reboot);
|
|
87
|
+
device
|
|
88
|
+
.command('save-reboot')
|
|
89
|
+
.description('save data to persistant storage and reboot the device')
|
|
90
|
+
.action(saveAndReboot);
|
|
91
|
+
device
|
|
92
|
+
.command('get-net')
|
|
93
|
+
.description('get network configuration from the device')
|
|
94
|
+
.action(getNet);
|
|
95
|
+
device
|
|
96
|
+
.command('set-net')
|
|
97
|
+
.description('set network interface into static ip mode')
|
|
98
|
+
.argument('<ip>', 'the new IP address')
|
|
99
|
+
.argument('<sn>', 'the new SUBNET mask')
|
|
100
|
+
.argument('<gw>', 'the new GATEWAY address')
|
|
101
|
+
.action(setNet);
|
|
102
|
+
device
|
|
103
|
+
.command('set-dhcp')
|
|
104
|
+
.description('set network interface into DHCP mode')
|
|
105
|
+
.action(setDhcp);
|
|
106
|
+
device
|
|
107
|
+
.command('get-cloud')
|
|
108
|
+
.description('get cloud endpoint on the device')
|
|
109
|
+
.action(getCloud);
|
|
110
|
+
device
|
|
111
|
+
.command('set-cloud')
|
|
112
|
+
.description('set cloud endpoint on the device')
|
|
113
|
+
.argument('<endpoint>', 'cloud service location')
|
|
114
|
+
.action(setCloud);
|
|
115
|
+
device
|
|
116
|
+
.command('stress')
|
|
117
|
+
.description('run a stress test on a device')
|
|
118
|
+
.argument('<count>', 'how many requests to make')
|
|
119
|
+
.action(stress);
|
|
120
|
+
device
|
|
121
|
+
.command('update')
|
|
122
|
+
.description('run firmware update from file')
|
|
123
|
+
.argument('<file>', 'file to update device with')
|
|
124
|
+
.action(update);
|
|
125
|
+
device
|
|
126
|
+
.command('listen')
|
|
127
|
+
.description('listen for alerts and heartbeats')
|
|
128
|
+
.argument('<duration>', 'how long to listen')
|
|
129
|
+
.action(listen);
|
|
130
|
+
device
|
|
131
|
+
.command('concurrent')
|
|
132
|
+
.description('make a number of requests concurrently')
|
|
133
|
+
.argument('<count>', 'how many requests to make concurrently')
|
|
134
|
+
.action(concurrent);
|
|
135
|
+
const sample = program
|
|
136
|
+
.command('sample')
|
|
137
|
+
.description('manage zephyr device settings')
|
|
138
|
+
.option('-p, --port <PORT>', 'listen port for incoming device connections')
|
|
139
|
+
.option('-v, --verbose', 'print extra debug informating during request')
|
|
140
|
+
.option('-f, --first', 'perform request on first device we see (any device)');
|
|
141
|
+
sample
|
|
142
|
+
.command('get-demo')
|
|
143
|
+
.description('read the demo data from the sample')
|
|
144
|
+
.action(getDemo);
|
|
145
|
+
sample
|
|
146
|
+
.command('get-hello')
|
|
147
|
+
.description('read the hello data from the sample')
|
|
148
|
+
.action(getHello);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// Device package not available - device commands will not be registered
|
|
152
|
+
}
|
|
153
|
+
}
|
|
143
154
|
// Load plugins
|
|
144
155
|
// (await plugins()).forEach(({ plugin: _, path: __, description: ___ }) => {});
|
|
145
|
-
|
|
156
|
+
registerDeviceCommands()
|
|
157
|
+
.then(() => program.parseAsync())
|
|
158
|
+
.catch((e) => console.error(e));
|
package/dist/net.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { concat, EmptyError, finalize, firstValueFrom, lastValueFrom, map, switchMap } from 'rxjs';
|
|
2
2
|
import { Linq } from '@altronix/device';
|
|
3
|
-
import { NetIp } from '@altronix/zdk';
|
|
3
|
+
import { NetIp } from '@altronix/zdk/common';
|
|
4
4
|
import logger from './logger.js';
|
|
5
5
|
import { select, first } from './select.js';
|
|
6
6
|
export async function getNet() {
|
package/dist/plugin.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import cp from 'node:child_process';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { filter, from, lastValueFrom, map, merge, mergeMap, Observable, of, toArray } from 'rxjs';
|
|
4
|
-
import { keys } from '
|
|
4
|
+
import { keys } from '@altronix/build';
|
|
5
5
|
function npmls(g) {
|
|
6
6
|
return of(['ls', `${g ? '-g' : ''}`, '-l', '--json', '--depth 0']).pipe(mergeMap((args) => new Observable((subscriber) => {
|
|
7
7
|
const ls = cp.spawn('npm', args, { shell: true });
|
package/dist/progress.ui.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useLayoutEffect, useState } from 'react';
|
|
2
2
|
import { scan } from 'rxjs';
|
|
3
3
|
import { Box, Text } from 'ink';
|
|
4
|
-
import useDimensions from '
|
|
4
|
+
import { useStdoutDimensions as useDimensions } from '@altronix/build';
|
|
5
5
|
export default function Progress({ total, response$, onComplete }) {
|
|
6
6
|
const [cols] = useDimensions();
|
|
7
7
|
const [width, setWidth] = useState(Math.min(cols - 4, 76));
|
package/dist/select.ui.d.ts
CHANGED
package/dist/stress.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { METH_CONSTANTS } from '@altronix/zdk';
|
|
1
|
+
import { METH_CONSTANTS } from '@altronix/zdk/common';
|
|
2
2
|
import { Linq } from '@altronix/device';
|
|
3
3
|
import { EmptyError, finalize, lastValueFrom, switchMap, pipe, repeat } from 'rxjs';
|
|
4
4
|
import progress from './progress.js';
|
package/dist/update.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Linq } from '@altronix/device';
|
|
2
|
-
import { Update } from '@altronix/zdk';
|
|
2
|
+
import { Update } from '@altronix/zdk/common';
|
|
3
3
|
import { concat, defer, EmptyError, finalize, from, lastValueFrom, map, mergeScan, switchMap } from 'rxjs';
|
|
4
4
|
import fs from 'fs';
|
|
5
5
|
import logger from './logger.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@altronix/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -13,17 +13,17 @@
|
|
|
13
13
|
"dist"
|
|
14
14
|
],
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@
|
|
17
|
-
"ajv": "^8.16.0",
|
|
16
|
+
"@altronix/zdk": "^0.9.0",
|
|
18
17
|
"commander": "^10.0.1",
|
|
19
|
-
"dotenv": "^16.4.5",
|
|
20
18
|
"ink": "^4.1.0",
|
|
21
19
|
"jsonc-parser": "^3.3.1",
|
|
22
20
|
"react": "^18.2.0",
|
|
23
21
|
"rxjs": "^7.8.1",
|
|
24
22
|
"winston": "^3.13.0",
|
|
25
|
-
"@altronix/
|
|
26
|
-
|
|
23
|
+
"@altronix/build": "0.13.0"
|
|
24
|
+
},
|
|
25
|
+
"optionalDependencies": {
|
|
26
|
+
"@altronix/device": "0.9.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@sindresorhus/tsconfig": "^3.0.1",
|
package/dist/build.d.ts
DELETED
package/dist/build.js
DELETED
|
@@ -1,525 +0,0 @@
|
|
|
1
|
-
import dotenv from 'dotenv';
|
|
2
|
-
import { Ajv } from 'ajv';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import fs from 'node:fs';
|
|
5
|
-
import cp from 'node:child_process';
|
|
6
|
-
import inquirer from '@inquirer/confirm';
|
|
7
|
-
import { catchError, concat, concatMap, EMPTY, EmptyError, from, last, lastValueFrom, map, merge, mergeMap, Observable, of, share, tap, toArray } from 'rxjs';
|
|
8
|
-
import { PassThrough } from 'node:stream';
|
|
9
|
-
import { render } from 'ink';
|
|
10
|
-
import React from 'react';
|
|
11
|
-
import Ui, { BuildError } from './build.ui.js';
|
|
12
|
-
import { keys } from './keys.js';
|
|
13
|
-
const schemaBoard = {
|
|
14
|
-
type: 'object',
|
|
15
|
-
required: ['images'],
|
|
16
|
-
properties: {
|
|
17
|
-
version: { type: 'string', nullable: true },
|
|
18
|
-
soc: { type: 'string', nullable: true },
|
|
19
|
-
cpu: { type: 'string', nullable: true },
|
|
20
|
-
variant: { type: 'string', nullable: true },
|
|
21
|
-
images: {
|
|
22
|
-
type: 'object',
|
|
23
|
-
required: [],
|
|
24
|
-
additionalProperties: {
|
|
25
|
-
type: 'object',
|
|
26
|
-
properties: {
|
|
27
|
-
configs: {
|
|
28
|
-
type: 'array',
|
|
29
|
-
items: { type: 'string' },
|
|
30
|
-
nullable: true
|
|
31
|
-
},
|
|
32
|
-
overlays: {
|
|
33
|
-
type: 'array',
|
|
34
|
-
items: { type: 'string' },
|
|
35
|
-
nullable: true
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
const schemaBuild = {
|
|
43
|
-
type: 'object',
|
|
44
|
-
required: [],
|
|
45
|
-
additionalProperties: {
|
|
46
|
-
type: 'object',
|
|
47
|
-
required: ['sourceDir', 'binaryDir', 'installDir', 'boards'],
|
|
48
|
-
properties: {
|
|
49
|
-
sourceDir: { type: 'string' },
|
|
50
|
-
binaryDir: { type: 'string' },
|
|
51
|
-
installDir: { type: 'string' },
|
|
52
|
-
boards: {
|
|
53
|
-
type: 'object',
|
|
54
|
-
required: [],
|
|
55
|
-
additionalProperties: {
|
|
56
|
-
anyOf: [{ ...schemaBoard }, { type: 'array', items: schemaBoard }]
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
const schemaSeedle = {
|
|
63
|
-
type: 'object',
|
|
64
|
-
required: [],
|
|
65
|
-
additionalProperties: {
|
|
66
|
-
type: 'object',
|
|
67
|
-
required: ['installDir', 'files'],
|
|
68
|
-
properties: {
|
|
69
|
-
namespace: { type: 'string', nullable: true },
|
|
70
|
-
prefix: { type: 'string', nullable: true },
|
|
71
|
-
installDir: { type: 'string' },
|
|
72
|
-
files: { type: 'array', items: { type: 'string' } }
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
const schema = {
|
|
77
|
-
type: 'object',
|
|
78
|
-
required: ['applications', 'bootloaders', 'wasm'],
|
|
79
|
-
additionalProperties: false,
|
|
80
|
-
properties: {
|
|
81
|
-
applications: schemaBuild,
|
|
82
|
-
bootloaders: schemaBuild,
|
|
83
|
-
wasm: schemaSeedle
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
const ajv = new Ajv({ allErrors: true, verbose: true });
|
|
87
|
-
const validate = ajv.compile(schema);
|
|
88
|
-
async function stat(path) {
|
|
89
|
-
return new Promise((resolve) => fs.stat(path, (err, stat) => {
|
|
90
|
-
if (err) {
|
|
91
|
-
resolve(false);
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
resolve(stat);
|
|
95
|
-
}
|
|
96
|
-
}));
|
|
97
|
-
}
|
|
98
|
-
async function resolver(cwd) {
|
|
99
|
-
// NOTE this assumes atx-zdk is named in the west.yml file as either atx or
|
|
100
|
-
// atx-zdk. The default case is atx-zdk. Most people never rename the
|
|
101
|
-
// yaml. However, if somebody wants to rename atx-zdk repo in their
|
|
102
|
-
// workspace. We can have atx.json() pass this name in and resolve it
|
|
103
|
-
// that way
|
|
104
|
-
const project = path.resolve(cwd);
|
|
105
|
-
const workspace = path.resolve(cwd, '..');
|
|
106
|
-
const atx0 = path.resolve(cwd, '..', 'atx');
|
|
107
|
-
const atx1 = path.resolve(cwd, '..', 'atx-zdk');
|
|
108
|
-
const atx = (await stat(atx0)) ? atx0 : (await stat(atx1)) ? atx1 : project;
|
|
109
|
-
return (dir, from) => {
|
|
110
|
-
if (dir.startsWith('<workspace>')) {
|
|
111
|
-
return path.join(workspace, dir.substring(12));
|
|
112
|
-
}
|
|
113
|
-
else if (dir.startsWith('<project>')) {
|
|
114
|
-
return path.join(project, dir.substring(10));
|
|
115
|
-
}
|
|
116
|
-
else if (dir.startsWith('<atx>')) {
|
|
117
|
-
return path.join(atx, dir.substring(6));
|
|
118
|
-
}
|
|
119
|
-
else if (path.isAbsolute(dir)) {
|
|
120
|
-
return dir;
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
return path.resolve(from || cwd, dir);
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
async function parseAppVersion(v) {
|
|
128
|
-
const data = await fs.promises.readFile(v, 'ascii');
|
|
129
|
-
const reMajor = data.matchAll(/^VERSION_MAJOR = ([0-9]+)/gm).next();
|
|
130
|
-
const reMinor = data.matchAll(/^VERSION_MINOR = ([0-9]+)/gm).next();
|
|
131
|
-
const rePatch = data.matchAll(/^PATCHLEVEL = ([0-9]+)/gm).next();
|
|
132
|
-
const reTweak = data.matchAll(/^VERSION_TWEAK = ([0-9]+)/gm).next();
|
|
133
|
-
const reExtra = data.matchAll(/^EXTRAVERSION = ([\.a-zA-Z0-9-]+)/gm).next();
|
|
134
|
-
return {
|
|
135
|
-
major: reMajor.value ? parseInt(reMajor.value[1]) : 0,
|
|
136
|
-
minor: reMinor.value ? parseInt(reMinor.value[1]) : 0,
|
|
137
|
-
patch: rePatch.value ? parseInt(rePatch.value[1]) : 0,
|
|
138
|
-
tweak: reTweak.value ? parseInt(reTweak.value[1]) : 0,
|
|
139
|
-
extra: reExtra.value ? reExtra.value[1] : ''
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
function formatVersion(ver) {
|
|
143
|
-
const { major, minor, patch, tweak, extra } = ver;
|
|
144
|
-
return extra.length
|
|
145
|
-
? `${major}-${minor}-${patch}-${tweak}-${extra}`
|
|
146
|
-
: `${major}-${minor}-${patch}-${tweak}`;
|
|
147
|
-
}
|
|
148
|
-
async function westOptionsNormalize(board, config, build, cwd, verbose) {
|
|
149
|
-
const resolve = await resolver(cwd);
|
|
150
|
-
const name = build.__key;
|
|
151
|
-
const boardTarget = [board.__key, board.soc, board.cpu, board.variant]
|
|
152
|
-
.filter((item) => !!item)
|
|
153
|
-
.join('/');
|
|
154
|
-
const installDir = resolve(build.installDir);
|
|
155
|
-
const sourceDir = resolve(build.sourceDir);
|
|
156
|
-
const binaryDir = path.join(resolve(build.binaryDir), boardTarget.replaceAll('/', '-'), config.__key);
|
|
157
|
-
const versionFile = path.join(sourceDir, 'VERSION');
|
|
158
|
-
const version = formatVersion(await parseAppVersion(versionFile));
|
|
159
|
-
const confs = config.configs
|
|
160
|
-
? config.configs.map((f) => resolve(f, sourceDir))
|
|
161
|
-
: [];
|
|
162
|
-
const overlays = config.overlays
|
|
163
|
-
? config.overlays.map((f) => resolve(f, sourceDir))
|
|
164
|
-
: [];
|
|
165
|
-
return {
|
|
166
|
-
name,
|
|
167
|
-
board: boardTarget.replaceAll('/', '-'),
|
|
168
|
-
boardTarget,
|
|
169
|
-
config: config.__key,
|
|
170
|
-
cwd,
|
|
171
|
-
version,
|
|
172
|
-
sourceDir,
|
|
173
|
-
binaryDir,
|
|
174
|
-
installDir,
|
|
175
|
-
outputFile: path.join(binaryDir, 'build.log'),
|
|
176
|
-
errorFile: path.join(binaryDir, 'build.err'),
|
|
177
|
-
confs,
|
|
178
|
-
overlays,
|
|
179
|
-
verbose
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
function westItem(opts) {
|
|
183
|
-
const { board, name, config, version } = opts;
|
|
184
|
-
return {
|
|
185
|
-
kind: 'west',
|
|
186
|
-
item: `${board}-${name}-${config}-${version}`
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
function west(args) {
|
|
190
|
-
const { cwd, boardTarget, sourceDir, binaryDir, confs, overlays } = args;
|
|
191
|
-
const { item } = westItem(args);
|
|
192
|
-
const expect = path.join(binaryDir, 'zephyr', 'zephyr.bin');
|
|
193
|
-
return of([
|
|
194
|
-
`build`,
|
|
195
|
-
`-b ${boardTarget}`,
|
|
196
|
-
`-s ${sourceDir}`,
|
|
197
|
-
`-d ${binaryDir}`,
|
|
198
|
-
`--`,
|
|
199
|
-
`-DEXTRA_CONF_FILE="${[...confs].join(';')}"`,
|
|
200
|
-
`-DEXTRA_DTC_OVERLAY_FILE="${[...overlays].join(';')}"`
|
|
201
|
-
]).pipe(mergeMap((westArgs) => new Observable((subscriber) => {
|
|
202
|
-
const west = cp.spawn('west', westArgs, { cwd, shell: true });
|
|
203
|
-
const fout = fs.createWriteStream(args.outputFile);
|
|
204
|
-
const ferr = fs.createWriteStream(args.errorFile);
|
|
205
|
-
const out = new PassThrough();
|
|
206
|
-
const err = new PassThrough();
|
|
207
|
-
let error = '';
|
|
208
|
-
west.stdout.pipe(fout);
|
|
209
|
-
west.stdout.pipe(out);
|
|
210
|
-
west.stderr.pipe(ferr);
|
|
211
|
-
west.stderr.pipe(err);
|
|
212
|
-
west.on('error', (e) => {
|
|
213
|
-
fout.close();
|
|
214
|
-
ferr.close();
|
|
215
|
-
out.destroy();
|
|
216
|
-
err.destroy();
|
|
217
|
-
subscriber.next({ item, error: e.name });
|
|
218
|
-
});
|
|
219
|
-
west.on('exit', (_code) => {
|
|
220
|
-
fout.close();
|
|
221
|
-
ferr.close();
|
|
222
|
-
out.destroy();
|
|
223
|
-
err.destroy();
|
|
224
|
-
fs.stat(expect, (e) => {
|
|
225
|
-
e
|
|
226
|
-
? subscriber.next({ item, error })
|
|
227
|
-
: subscriber.next({ item, complete: true });
|
|
228
|
-
subscriber.complete();
|
|
229
|
-
});
|
|
230
|
-
});
|
|
231
|
-
out.on('data', (d) => subscriber.next({ item, output: d.toString() }));
|
|
232
|
-
err.on('data', (d) => (error += d));
|
|
233
|
-
})));
|
|
234
|
-
}
|
|
235
|
-
async function seedleOptionsNormalize(seedle, cwd, verbose) {
|
|
236
|
-
const name = seedle.__key;
|
|
237
|
-
const resolve = await resolver(cwd);
|
|
238
|
-
const types = resolve('<atx>/lib/atx/types.cddl');
|
|
239
|
-
const installDir = resolve(seedle.installDir);
|
|
240
|
-
const buildDir = path.join(installDir, name);
|
|
241
|
-
const files = [...seedle.files, types].map((file) => path.resolve(cwd, file));
|
|
242
|
-
return {
|
|
243
|
-
name: seedle.__key,
|
|
244
|
-
cwd,
|
|
245
|
-
installDir,
|
|
246
|
-
buildDir,
|
|
247
|
-
files,
|
|
248
|
-
cddl: path.join(installDir, name, `${name}.cddl`),
|
|
249
|
-
outputFile: path.join(installDir, `${name}-build.log`),
|
|
250
|
-
errorFile: path.join(installDir, `${name}-build.err`),
|
|
251
|
-
prefix: seedle.prefix || '',
|
|
252
|
-
namespace: seedle.namespace || 'altronix',
|
|
253
|
-
verbose
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
function seedle(opts) {
|
|
257
|
-
const { name, namespace, cddl, cwd, installDir } = opts;
|
|
258
|
-
const templatePath = path.resolve(cwd, '..', 'seedle-template');
|
|
259
|
-
const seedlePath = path.resolve(cwd, '..', 'seedle', 'seedle');
|
|
260
|
-
return of([
|
|
261
|
-
'generate',
|
|
262
|
-
'--force',
|
|
263
|
-
`--destination=${installDir}`,
|
|
264
|
-
`--path=${templatePath}`,
|
|
265
|
-
`--name=${name}`,
|
|
266
|
-
'--overwrite',
|
|
267
|
-
`-dnamespace=${namespace}`,
|
|
268
|
-
`-dseedle-manifest-path=${seedlePath.replace(/\\/g, '\\\\')}`,
|
|
269
|
-
`-dcddl=${cddl.replace(/\\/g, '\\\\')}`
|
|
270
|
-
]).pipe(mergeMap((seedleArgs) => new Observable((subscriber) => {
|
|
271
|
-
const wasm = cp.spawn('cargo', seedleArgs, {
|
|
272
|
-
cwd: installDir,
|
|
273
|
-
shell: true
|
|
274
|
-
});
|
|
275
|
-
const fout = fs.createWriteStream(opts.outputFile);
|
|
276
|
-
const ferr = fs.createWriteStream(opts.errorFile);
|
|
277
|
-
wasm.stdout.pipe(fout);
|
|
278
|
-
wasm.stderr.pipe(ferr);
|
|
279
|
-
wasm.on('error', (e) => {
|
|
280
|
-
subscriber.error(e);
|
|
281
|
-
fout.close();
|
|
282
|
-
ferr.close();
|
|
283
|
-
});
|
|
284
|
-
wasm.on('exit', () => {
|
|
285
|
-
fout.close();
|
|
286
|
-
ferr.close();
|
|
287
|
-
subscriber.next();
|
|
288
|
-
subscriber.complete();
|
|
289
|
-
});
|
|
290
|
-
})));
|
|
291
|
-
}
|
|
292
|
-
function cmakeItem(opts) {
|
|
293
|
-
const { name: item } = opts;
|
|
294
|
-
return { kind: 'wasm', item };
|
|
295
|
-
}
|
|
296
|
-
function cmakeConfigure(opts) {
|
|
297
|
-
const { buildDir, outputFile, errorFile } = opts;
|
|
298
|
-
const { item } = cmakeItem(opts);
|
|
299
|
-
return of([`-B${buildDir}`, `-S${buildDir}`]).pipe(mergeMap((cmakeArgs) => new Observable((subscriber) => {
|
|
300
|
-
const wasm = cp.spawn('cmake', cmakeArgs, {
|
|
301
|
-
cwd: buildDir,
|
|
302
|
-
shell: true
|
|
303
|
-
});
|
|
304
|
-
const fout = fs.createWriteStream(outputFile);
|
|
305
|
-
const ferr = fs.createWriteStream(errorFile);
|
|
306
|
-
const out = new PassThrough();
|
|
307
|
-
wasm.stdout.pipe(fout);
|
|
308
|
-
wasm.stdout.pipe(out);
|
|
309
|
-
wasm.stderr.pipe(ferr);
|
|
310
|
-
wasm.on('error', (e) => {
|
|
311
|
-
fout.close();
|
|
312
|
-
ferr.close();
|
|
313
|
-
out.destroy();
|
|
314
|
-
subscriber.error(new BuildError(item, 'wasm', e.name));
|
|
315
|
-
});
|
|
316
|
-
wasm.on('exit', () => {
|
|
317
|
-
fout.close();
|
|
318
|
-
ferr.close();
|
|
319
|
-
out.destroy();
|
|
320
|
-
subscriber.complete();
|
|
321
|
-
});
|
|
322
|
-
out.on('data', (data) => subscriber.next({ item, output: data.toString() }));
|
|
323
|
-
})));
|
|
324
|
-
}
|
|
325
|
-
function cmakeBuild(opts) {
|
|
326
|
-
const { buildDir, outputFile, errorFile } = opts;
|
|
327
|
-
const { item } = cmakeItem(opts);
|
|
328
|
-
return of([`--build`, `${buildDir}`, `--target`, ` wasm`]).pipe(mergeMap((cmakeArgs) => new Observable((subscriber) => {
|
|
329
|
-
const wasm = cp.spawn('cmake', cmakeArgs, {
|
|
330
|
-
cwd: buildDir,
|
|
331
|
-
shell: true
|
|
332
|
-
});
|
|
333
|
-
const fout = fs.createWriteStream(outputFile);
|
|
334
|
-
const ferr = fs.createWriteStream(errorFile);
|
|
335
|
-
const out = new PassThrough();
|
|
336
|
-
wasm.stdout.pipe(fout);
|
|
337
|
-
wasm.stdout.pipe(out);
|
|
338
|
-
wasm.stderr.pipe(ferr);
|
|
339
|
-
wasm.on('error', (e) => {
|
|
340
|
-
fout.close();
|
|
341
|
-
ferr.close();
|
|
342
|
-
out.destroy();
|
|
343
|
-
subscriber.error(new BuildError(item, 'wasm', e.name));
|
|
344
|
-
});
|
|
345
|
-
wasm.on('exit', () => {
|
|
346
|
-
fout.close();
|
|
347
|
-
ferr.close();
|
|
348
|
-
out.destroy();
|
|
349
|
-
subscriber.complete();
|
|
350
|
-
});
|
|
351
|
-
out.on('data', (data) => subscriber.next({ item, output: data.toString() }));
|
|
352
|
-
})));
|
|
353
|
-
}
|
|
354
|
-
function cmake(opts) {
|
|
355
|
-
const { item } = cmakeItem(opts);
|
|
356
|
-
return concat(cmakeConfigure(opts), cmakeBuild(opts), of({ item, complete: true })).pipe(catchError(of));
|
|
357
|
-
}
|
|
358
|
-
function emulateBytePages(board) {
|
|
359
|
-
return (board.startsWith('same54_xpro') ||
|
|
360
|
-
board.startsWith('netway') ||
|
|
361
|
-
board.startsWith('oa2b'));
|
|
362
|
-
}
|
|
363
|
-
function extraAppConfs(extraConfs, config) {
|
|
364
|
-
const key = process.env['ALTRONIX_RELEASE_KEY'];
|
|
365
|
-
if (!key)
|
|
366
|
-
throw new Error('missing ALTRONIX_RELEASE_KEY from environment');
|
|
367
|
-
const extraConfsData = [
|
|
368
|
-
`CONFIG_MCUBOOT_SIGNATURE_KEY_FILE="${key}"`,
|
|
369
|
-
`CONFIG_BOOTLOADER_MCUBOOT=y`,
|
|
370
|
-
`CONFIG_ATX_UPDATE_ENABLE=y`,
|
|
371
|
-
`CONFIG_ATX_CONFIG="${config}"`
|
|
372
|
-
].join('\r\n');
|
|
373
|
-
return from(fs.promises.writeFile(extraConfs, extraConfsData));
|
|
374
|
-
}
|
|
375
|
-
function extraBootConfs(board, extraConfs) {
|
|
376
|
-
const key = process.env['ALTRONIX_RELEASE_KEY'];
|
|
377
|
-
if (!key)
|
|
378
|
-
throw new Error('missing ALTRONIX_RELEASE_KEY from environment');
|
|
379
|
-
const extraConfsData = emulateBytePages(board)
|
|
380
|
-
? [`CONFIG_BOOT_SIGNATURE_KEY_FILE="${key}"`]
|
|
381
|
-
: [`CONFIG_BOOT_SIGNATURE_KEY_FILE="${key}"`];
|
|
382
|
-
return from(fs.promises.writeFile(extraConfs, extraConfsData.join('\r\n')));
|
|
383
|
-
}
|
|
384
|
-
function copy() {
|
|
385
|
-
return (obs$) => obs$.pipe(mergeMap((opts) => {
|
|
386
|
-
const { src, dst } = opts;
|
|
387
|
-
const promise = fs.promises
|
|
388
|
-
.copyFile(src, dst)
|
|
389
|
-
.then(() => opts)
|
|
390
|
-
.catch(() => ({ ...opts, err: dst }));
|
|
391
|
-
return from(promise);
|
|
392
|
-
}));
|
|
393
|
-
}
|
|
394
|
-
function concatFiles(src, dest) {
|
|
395
|
-
return from(src).pipe(concatMap((src) => from(fs.promises.readFile(src, 'ascii'))), toArray(), mergeMap((arr) => from(fs.promises.writeFile(dest, arr.join('\r\n')))));
|
|
396
|
-
}
|
|
397
|
-
function mkdir() {
|
|
398
|
-
return (obs$) => obs$.pipe(mergeMap((dir) => new Observable((subscriber) => {
|
|
399
|
-
fs.promises
|
|
400
|
-
.mkdir(dir, { recursive: true })
|
|
401
|
-
.then(() => subscriber.next())
|
|
402
|
-
.catch((e) => subscriber.error(e))
|
|
403
|
-
.finally(() => subscriber.complete());
|
|
404
|
-
})));
|
|
405
|
-
}
|
|
406
|
-
function rmdir(dir) {
|
|
407
|
-
return new Observable((subscriber) => {
|
|
408
|
-
fs.promises
|
|
409
|
-
.rm(dir, { recursive: true })
|
|
410
|
-
.then(() => subscriber.next(dir))
|
|
411
|
-
.catch((e) => subscriber.error(e))
|
|
412
|
-
.finally(() => subscriber.complete());
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
function exists(dir) {
|
|
416
|
-
return new Observable((subscriber) => {
|
|
417
|
-
fs.promises
|
|
418
|
-
.stat(dir)
|
|
419
|
-
.then(() => subscriber.next(true))
|
|
420
|
-
.catch(() => subscriber.next(false))
|
|
421
|
-
.finally(() => subscriber.complete());
|
|
422
|
-
});
|
|
423
|
-
}
|
|
424
|
-
function confirm(force) {
|
|
425
|
-
return (obs$) => force
|
|
426
|
-
? of(true)
|
|
427
|
-
: obs$.pipe(concatMap((dir) => from(inquirer({ message: `Delete ${dir}?` }))));
|
|
428
|
-
}
|
|
429
|
-
function throwIf(predicate, message) {
|
|
430
|
-
return tap((v) => {
|
|
431
|
-
if (predicate(v))
|
|
432
|
-
throw new Error(message);
|
|
433
|
-
});
|
|
434
|
-
}
|
|
435
|
-
function clean(force) {
|
|
436
|
-
return (obs$) => obs$.pipe(concatMap((dir) => exists(dir).pipe(concatMap((exists) => {
|
|
437
|
-
return exists
|
|
438
|
-
? of(dir).pipe(confirm(force), throwIf((confirm) => !confirm, 'User rejected delete'), mergeMap((_) => rmdir(dir)), map(() => dir))
|
|
439
|
-
: of(dir);
|
|
440
|
-
}))));
|
|
441
|
-
}
|
|
442
|
-
function tovoid() {
|
|
443
|
-
return (obs$) => obs$.pipe(map(() => void 0));
|
|
444
|
-
}
|
|
445
|
-
export async function build() {
|
|
446
|
-
const config = this.opts()['config'] || path.resolve('./', 'atx.json');
|
|
447
|
-
const verbose = this.optsWithGlobals()['verbose'];
|
|
448
|
-
const mBoard = new RegExp(this.opts()['matchesBoard'] || '(.*)');
|
|
449
|
-
const mApplication = new RegExp(this.opts()['matchesApplication'] || '(.*)');
|
|
450
|
-
const mConfig = new RegExp(this.opts()['matchesConfig'] || '(.*)');
|
|
451
|
-
const cwd = path.resolve(path.dirname(config));
|
|
452
|
-
const data = await fs.promises.readFile(config, 'ascii');
|
|
453
|
-
const atx = JSON.parse(data);
|
|
454
|
-
const extraAppConfFile = 'application.conf';
|
|
455
|
-
const extraBootConfFile = 'bootloader.conf';
|
|
456
|
-
if (!validate(atx))
|
|
457
|
-
throw validate.errors;
|
|
458
|
-
const env = path.resolve(cwd, '.env');
|
|
459
|
-
dotenv.config({ path: env });
|
|
460
|
-
const apps = keys(atx.applications)
|
|
461
|
-
.filter(({ __key }) => __key.match(mApplication))
|
|
462
|
-
.flatMap((app) => {
|
|
463
|
-
return keys(app.boards)
|
|
464
|
-
.filter(({ __key }) => __key.match(mBoard))
|
|
465
|
-
.flatMap((board) => {
|
|
466
|
-
return keys(board.images)
|
|
467
|
-
.filter(({ __key }) => __key.match(mConfig))
|
|
468
|
-
.map((config) => {
|
|
469
|
-
return westOptionsNormalize(board, config, app, cwd, verbose);
|
|
470
|
-
});
|
|
471
|
-
});
|
|
472
|
-
});
|
|
473
|
-
const bootloaders = keys(atx.bootloaders).flatMap((app) => {
|
|
474
|
-
return keys(app.boards)
|
|
475
|
-
.filter(({ __key }) => __key.match(mBoard))
|
|
476
|
-
.flatMap((board) => {
|
|
477
|
-
return keys(board.images).map((config) => westOptionsNormalize(board, config, app, cwd, verbose));
|
|
478
|
-
});
|
|
479
|
-
});
|
|
480
|
-
const wasm = keys(atx.wasm).map((w) => seedleOptionsNormalize(w, cwd, verbose));
|
|
481
|
-
let concurrent = this.opts()['concurrent']
|
|
482
|
-
? parseInt(this.opts()['concurrent'])
|
|
483
|
-
: Infinity;
|
|
484
|
-
let buildApps = this.opts()['application'];
|
|
485
|
-
let buildBoot = this.opts()['bootloader'];
|
|
486
|
-
let buildWasm = this.opts()['wasm'];
|
|
487
|
-
if (!(buildApps || buildBoot || buildWasm)) {
|
|
488
|
-
buildApps = buildBoot = buildWasm = true;
|
|
489
|
-
}
|
|
490
|
-
const apps$ = buildApps ? from(await Promise.all(apps)) : EMPTY;
|
|
491
|
-
const boot$ = buildBoot ? from(await Promise.all(bootloaders)) : EMPTY;
|
|
492
|
-
const wasm$ = buildWasm ? from(await Promise.all(wasm)) : EMPTY;
|
|
493
|
-
// Handle all the preliminary stuff before building
|
|
494
|
-
const ready$ = concat(merge(apps$.pipe(mergeMap(({ installDir: s, binaryDir: b }) => from([s, b]))), boot$.pipe(mergeMap(({ installDir: s, binaryDir: b }) => from([s, b]))), wasm$.pipe(map(({ installDir }) => installDir))).pipe(toArray(), mergeMap((arr) => from([...new Set(arr)])), // dedupe
|
|
495
|
-
clean(this.opts()['yes']), mkdir()), apps$.pipe(mergeMap(({ binaryDir, config }) => extraAppConfs(path.join(binaryDir, extraAppConfFile), config))), boot$.pipe(mergeMap(({ board, binaryDir }) => extraBootConfs(board, path.join(binaryDir, extraBootConfFile)))), wasm$.pipe(mergeMap(seedle)), wasm$.pipe(mergeMap(({ files, cddl: dest }) => concatFiles(files, dest)))).pipe(last(), share());
|
|
496
|
-
// Get an array of every build item.
|
|
497
|
-
const items$ = merge(apps$.pipe(map(westItem)), boot$.pipe(map(westItem)), wasm$.pipe(map(cmakeItem))).pipe(toArray());
|
|
498
|
-
// Run build commands for all bootloaders, applications and wasm concurrently
|
|
499
|
-
const build$ = merge(apps$.pipe(map(west)), boot$.pipe(map(west)), wasm$.pipe(map(cmake))).pipe(mergeMap((obs) => obs, concurrent), share());
|
|
500
|
-
// Install everything into installDir
|
|
501
|
-
const install$ = merge(apps$.pipe(map(({ name, config, version: ver, board, binaryDir, installDir: d }) => {
|
|
502
|
-
return {
|
|
503
|
-
src: path.join(binaryDir, 'zephyr', 'zephyr.signed.bin'),
|
|
504
|
-
dst: path.join(d, `${board}-${name}-${config}-${ver}.signed.bin`)
|
|
505
|
-
};
|
|
506
|
-
})), boot$.pipe(map(({ name, config, board, binaryDir, installDir: d }) => {
|
|
507
|
-
return {
|
|
508
|
-
src: path.join(binaryDir, 'zephyr', 'zephyr.bin'),
|
|
509
|
-
dst: path.join(d, `${board}-${name}-${config}.bin`)
|
|
510
|
-
};
|
|
511
|
-
}))).pipe(copy(), tovoid());
|
|
512
|
-
try {
|
|
513
|
-
await lastValueFrom(ready$);
|
|
514
|
-
const items = await lastValueFrom(items$);
|
|
515
|
-
const renderer = render(React.createElement(Ui, { items: items, "progress$": build$, onComplete: () => renderer.unmount() }));
|
|
516
|
-
await renderer.waitUntilExit();
|
|
517
|
-
renderer.cleanup();
|
|
518
|
-
return lastValueFrom(install$);
|
|
519
|
-
}
|
|
520
|
-
catch (e) {
|
|
521
|
-
if (!(e instanceof EmptyError))
|
|
522
|
-
throw e;
|
|
523
|
-
console.log('nothing to build');
|
|
524
|
-
}
|
|
525
|
-
}
|
package/dist/build.ui.d.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Observable } from 'rxjs';
|
|
3
|
-
export declare class BuildError extends Error implements BuildItem {
|
|
4
|
-
item: string;
|
|
5
|
-
kind: 'west' | 'wasm';
|
|
6
|
-
constructor(item: string, kind: 'west' | 'wasm', message: string);
|
|
7
|
-
}
|
|
8
|
-
export interface BuildItem {
|
|
9
|
-
item: string;
|
|
10
|
-
kind: 'west' | 'wasm';
|
|
11
|
-
}
|
|
12
|
-
export interface BuildProgress<K extends string = string> {
|
|
13
|
-
item: K;
|
|
14
|
-
output?: string;
|
|
15
|
-
error?: string;
|
|
16
|
-
complete?: boolean;
|
|
17
|
-
}
|
|
18
|
-
export interface Options {
|
|
19
|
-
items: BuildItem[];
|
|
20
|
-
progress$: Observable<BuildProgress>;
|
|
21
|
-
onComplete: BuildEffectCallback;
|
|
22
|
-
}
|
|
23
|
-
export default function ({ items, progress$, onComplete }: Options): React.JSX.Element;
|
|
24
|
-
interface BuildEffectCallback<E extends Error = Error> {
|
|
25
|
-
(e?: E): void;
|
|
26
|
-
}
|
|
27
|
-
export {};
|
package/dist/build.ui.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import React, { useLayoutEffect, useState } from 'react';
|
|
2
|
-
import { Box, Text } from 'ink';
|
|
3
|
-
import { scan } from 'rxjs';
|
|
4
|
-
import useStdoutDimensions from './useStdoutDimensions.js';
|
|
5
|
-
export class BuildError extends Error {
|
|
6
|
-
constructor(item, kind, message) {
|
|
7
|
-
super(message);
|
|
8
|
-
Object.defineProperty(this, "item", {
|
|
9
|
-
enumerable: true,
|
|
10
|
-
configurable: true,
|
|
11
|
-
writable: true,
|
|
12
|
-
value: item
|
|
13
|
-
});
|
|
14
|
-
Object.defineProperty(this, "kind", {
|
|
15
|
-
enumerable: true,
|
|
16
|
-
configurable: true,
|
|
17
|
-
writable: true,
|
|
18
|
-
value: kind
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
export default function ({ items, progress$, onComplete }) {
|
|
23
|
-
const [col, _rows] = useStdoutDimensions();
|
|
24
|
-
const [width, setWidth] = useState(0);
|
|
25
|
-
const progress = useBuildEffect(progress$, items.map(({ item: i }) => i), onComplete);
|
|
26
|
-
useLayoutEffect(() => {
|
|
27
|
-
const width = items.map(({ item }) => item).reduce(calculateItemWidth, 0);
|
|
28
|
-
setWidth(width);
|
|
29
|
-
}, [items]);
|
|
30
|
-
return (React.createElement(Box, { flexDirection: "column" }, items.map(({ item, kind }) => (React.createElement(Box, { key: item },
|
|
31
|
-
React.createElement(Box, { width: width, marginRight: 1 },
|
|
32
|
-
React.createElement(Text, { wrap: "truncate", bold: true }, item.padStart(width))),
|
|
33
|
-
React.createElement(Box, { width: 4, marginRight: 1 },
|
|
34
|
-
React.createElement(Text, { wrap: "truncate", bold: true, color: buildColor(kind) }, kind.toUpperCase().padStart(4))),
|
|
35
|
-
React.createElement(Box, { width: 2, marginRight: 1 }, progress[item] && React.createElement(Text, { color: "cyan" }, "=>")),
|
|
36
|
-
React.createElement(Box, { width: col - width - 4 - 2 - 1 - 1 - 1 },
|
|
37
|
-
React.createElement(Text, { wrap: "truncate", dimColor: !progressComplete(progress[item]), color: progressColor(progress[item]) }, progress[item])))))));
|
|
38
|
-
}
|
|
39
|
-
function buildColor(kind) {
|
|
40
|
-
return kind === 'west' ? 'blue' : 'magenta';
|
|
41
|
-
}
|
|
42
|
-
function progressComplete(progress) {
|
|
43
|
-
return progress === 'OK!';
|
|
44
|
-
}
|
|
45
|
-
function progressColor(progress) {
|
|
46
|
-
return !progress ||
|
|
47
|
-
progress.charAt(0) == '|' ||
|
|
48
|
-
progress.charAt(0) == '/' ||
|
|
49
|
-
progress.charAt(0) == '-' ||
|
|
50
|
-
progress.charAt(0) == '\\'
|
|
51
|
-
? 'white'
|
|
52
|
-
: progressComplete(progress)
|
|
53
|
-
? 'green'
|
|
54
|
-
: 'red';
|
|
55
|
-
}
|
|
56
|
-
function initProgress(items) {
|
|
57
|
-
return items.reduce((acc, curr) => ({ ...acc, [curr]: '' }), {});
|
|
58
|
-
}
|
|
59
|
-
function calculateItemWidth(acc, next) {
|
|
60
|
-
return next.length > acc ? next.length : acc;
|
|
61
|
-
}
|
|
62
|
-
function progressInc(progress) {
|
|
63
|
-
if (progress.charAt(0) == '|') {
|
|
64
|
-
return '/';
|
|
65
|
-
}
|
|
66
|
-
else if (progress.charAt(0) == '/') {
|
|
67
|
-
return '-';
|
|
68
|
-
}
|
|
69
|
-
else if (progress.charAt(0) == '-') {
|
|
70
|
-
return '\\';
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
return '|';
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
function progressReducer(acc, next) {
|
|
77
|
-
acc[next.item] = next.complete
|
|
78
|
-
? 'OK!'
|
|
79
|
-
: next.error
|
|
80
|
-
? next.error.replace(/\r?\n/g, '')
|
|
81
|
-
: progressInc(acc[next.item]);
|
|
82
|
-
return acc;
|
|
83
|
-
}
|
|
84
|
-
function useBuildEffect(obs$, items, cb) {
|
|
85
|
-
const [progress, setProgress] = useState(initProgress(items));
|
|
86
|
-
useLayoutEffect(() => {
|
|
87
|
-
const s = obs$.pipe(scan(progressReducer, progress)).subscribe({
|
|
88
|
-
next: (progress) => setProgress({ ...progress }),
|
|
89
|
-
complete: cb,
|
|
90
|
-
error: cb
|
|
91
|
-
});
|
|
92
|
-
return () => s.unsubscribe();
|
|
93
|
-
}, [obs$]);
|
|
94
|
-
return progress;
|
|
95
|
-
}
|
package/dist/keys.d.ts
DELETED
package/dist/keys.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export function keys(map) {
|
|
2
|
-
let ret = [];
|
|
3
|
-
Object.keys(map)
|
|
4
|
-
.filter((key) => key !== '__key')
|
|
5
|
-
.forEach((key) => {
|
|
6
|
-
if (Array.isArray(map[key])) {
|
|
7
|
-
map[key].forEach((item) => ret.push({ ...item, __key: key }));
|
|
8
|
-
}
|
|
9
|
-
else {
|
|
10
|
-
ret.push({ ...map[key], __key: key });
|
|
11
|
-
}
|
|
12
|
-
});
|
|
13
|
-
return ret;
|
|
14
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default function useStdoutDimensions(): [number, number];
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect } from 'react';
|
|
2
|
-
import { useStdout } from 'ink';
|
|
3
|
-
export default function useStdoutDimensions() {
|
|
4
|
-
const { stdout } = useStdout();
|
|
5
|
-
const [dimensions, setDimensions] = useState([
|
|
6
|
-
stdout.columns,
|
|
7
|
-
stdout.rows
|
|
8
|
-
]);
|
|
9
|
-
useEffect(() => {
|
|
10
|
-
const handler = () => setDimensions([stdout.columns, stdout.rows]);
|
|
11
|
-
stdout.on('resize', handler);
|
|
12
|
-
return () => {
|
|
13
|
-
stdout.off('resize', handler);
|
|
14
|
-
};
|
|
15
|
-
}, [stdout]);
|
|
16
|
-
return dimensions;
|
|
17
|
-
}
|