@altronix/cli 0.7.2 → 0.7.3

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/app.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ type Props = {
3
+ name: string | undefined;
4
+ };
5
+ export default function App({ name }: Props): React.JSX.Element;
6
+ export {};
package/dist/app.js ADDED
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import { Text } from 'ink';
3
+ export default function App({ name = 'Stranger' }) {
4
+ return (React.createElement(Text, null,
5
+ "Hello, ",
6
+ React.createElement(Text, { color: "green" }, name)));
7
+ }
package/dist/build.js ADDED
@@ -0,0 +1,491 @@
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 { concat, concatMap, EMPTY, 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 from "./build.ui.js";
12
+ import { keys } from "./keys.js";
13
+ const schemaBuild = {
14
+ type: "object",
15
+ required: [],
16
+ patternProperties: {
17
+ ".*": {
18
+ type: "object",
19
+ required: ["sourceDir", "binaryDir", "installDir", "boards"],
20
+ properties: {
21
+ sourceDir: { type: "string" },
22
+ binaryDir: { type: "string" },
23
+ installDir: { type: "string" },
24
+ boards: {
25
+ type: "object",
26
+ required: [],
27
+ patternProperties: {
28
+ ".*": {
29
+ type: "object",
30
+ required: [],
31
+ patternProperties: {
32
+ ".*": {
33
+ type: "object",
34
+ properties: {
35
+ configs: {
36
+ type: "array",
37
+ items: { type: "string" },
38
+ nullable: true,
39
+ },
40
+ overlays: {
41
+ type: "array",
42
+ items: { type: "string" },
43
+ nullable: true,
44
+ },
45
+ },
46
+ },
47
+ },
48
+ },
49
+ },
50
+ },
51
+ },
52
+ },
53
+ },
54
+ };
55
+ const schemaSeedle = {
56
+ type: "object",
57
+ required: [],
58
+ patternProperties: {
59
+ ".*": {
60
+ type: "object",
61
+ required: ["installDir", "files"],
62
+ properties: {
63
+ namespace: { type: "string", nullable: true },
64
+ prefix: { type: "string", nullable: true },
65
+ installDir: { type: "string" },
66
+ files: { type: "array", items: { type: "string" } },
67
+ },
68
+ },
69
+ },
70
+ };
71
+ const schema = {
72
+ type: "object",
73
+ required: ["applications", "bootloaders", "wasm"],
74
+ additionalProperties: false,
75
+ properties: {
76
+ applications: schemaBuild,
77
+ bootloaders: schemaBuild,
78
+ wasm: schemaSeedle,
79
+ },
80
+ };
81
+ const ajv = new Ajv({ allErrors: true, verbose: true });
82
+ const validate = ajv.compile(schema);
83
+ async function stat(path) {
84
+ return new Promise((resolve) => fs.stat(path, (err, stat) => {
85
+ if (err) {
86
+ resolve(false);
87
+ }
88
+ else {
89
+ resolve(stat);
90
+ }
91
+ }));
92
+ }
93
+ async function resolver(cwd) {
94
+ // NOTE this assumes atx-zdk is named in the west.yml file as either atx or
95
+ // atx-zdk. The default case is atx-zdk. Most people never rename the
96
+ // yaml. However, if somebody wants to rename atx-zdk repo in their
97
+ // workspace. We can have atx.json() pass this name in and resolve it
98
+ // that way
99
+ const project = path.resolve(cwd);
100
+ const workspace = path.resolve(cwd, "..");
101
+ const atx0 = path.resolve(cwd, "..", "atx");
102
+ const atx1 = path.resolve(cwd, "..", "atx-zdk");
103
+ const atx = (await stat(atx0)) ? atx0 : (await stat(atx1)) ? atx1 : project;
104
+ return (dir, from) => {
105
+ if (dir.startsWith("<workspace>")) {
106
+ return path.join(workspace, dir.substring(12));
107
+ }
108
+ else if (dir.startsWith("<project>")) {
109
+ return path.join(project, dir.substring(10));
110
+ }
111
+ else if (dir.startsWith("<atx>")) {
112
+ return path.join(atx, dir.substring(6));
113
+ }
114
+ else if (path.isAbsolute(dir)) {
115
+ return dir;
116
+ }
117
+ else {
118
+ return path.resolve(from || cwd, dir);
119
+ }
120
+ };
121
+ }
122
+ async function parseAppVersion(v) {
123
+ const data = await fs.promises.readFile(v, "ascii");
124
+ const reMajor = data.matchAll(/^VERSION_MAJOR = ([0-9]+)/gm).next();
125
+ const reMinor = data.matchAll(/^VERSION_MINOR = ([0-9]+)/gm).next();
126
+ const rePatch = data.matchAll(/^PATCHLEVEL = ([0-9]+)/gm).next();
127
+ const reTweak = data.matchAll(/^VERSION_TWEAK = ([0-9]+)/gm).next();
128
+ const reExtra = data.matchAll(/^EXTRAVERSION = ([.a-zA-Z-]+)/gm).next();
129
+ return {
130
+ major: reMajor.value ? parseInt(reMajor.value[1]) : 0,
131
+ minor: reMinor.value ? parseInt(reMinor.value[1]) : 0,
132
+ patch: rePatch.value ? parseInt(rePatch.value[1]) : 0,
133
+ tweak: reTweak.value ? parseInt(reTweak.value[1]) : 0,
134
+ extra: reExtra.value ? reExtra.value[1] : "",
135
+ };
136
+ }
137
+ function formatVersion(ver) {
138
+ const { major, minor, patch, tweak, extra } = ver;
139
+ return extra.length
140
+ ? `${major}-${minor}-${patch}-${tweak}-${extra}`
141
+ : `${major}-${minor}-${patch}-${tweak}`;
142
+ }
143
+ async function westOptionsNormalize(board, config, build, cwd, verbose) {
144
+ const resolve = await resolver(cwd);
145
+ const name = build.__key;
146
+ const installDir = resolve(build.installDir);
147
+ const sourceDir = resolve(build.sourceDir);
148
+ const binaryDir = path.join(resolve(build.binaryDir), board, config.__key);
149
+ const versionFile = path.join(sourceDir, "VERSION");
150
+ const version = formatVersion(await parseAppVersion(versionFile));
151
+ const confs = config.configs
152
+ ? config.configs.map((f) => resolve(f, sourceDir))
153
+ : [];
154
+ const overlays = config.overlays
155
+ ? config.overlays.map((f) => resolve(f, sourceDir))
156
+ : [];
157
+ return {
158
+ name,
159
+ board,
160
+ config: config.__key,
161
+ cwd,
162
+ version,
163
+ sourceDir,
164
+ binaryDir,
165
+ installDir,
166
+ outputFile: path.join(binaryDir, "build.log"),
167
+ errorFile: path.join(binaryDir, "build.err"),
168
+ confs,
169
+ overlays,
170
+ verbose,
171
+ };
172
+ }
173
+ function westItem(opts) {
174
+ const { board, name, config, version } = opts;
175
+ return {
176
+ kind: "west",
177
+ name: `${board}-${name}-${config}-${version}`
178
+ };
179
+ }
180
+ function west(args) {
181
+ const { cwd, board, sourceDir, binaryDir, confs, overlays } = args;
182
+ const item = westItem(args).name;
183
+ return of([
184
+ `build`,
185
+ `-b ${board}`,
186
+ `-s ${sourceDir}`,
187
+ `-d ${binaryDir}`,
188
+ `--`,
189
+ `-DEXTRA_CONF_FILE="${[...confs].join(";")}"`,
190
+ `-DEXTRA_DTC_OVERLAY_FILE="${[...overlays].join(";")}"`,
191
+ ]).pipe(mergeMap((westArgs) => new Observable((subscriber) => {
192
+ const west = cp.spawn("west", westArgs, { cwd, shell: true });
193
+ const fout = fs.createWriteStream(args.outputFile);
194
+ const ferr = fs.createWriteStream(args.errorFile);
195
+ const out = new PassThrough();
196
+ west.stdout.pipe(fout);
197
+ west.stdout.pipe(out);
198
+ west.stderr.pipe(ferr);
199
+ west.on("error", (e) => {
200
+ subscriber.error(e);
201
+ fout.close();
202
+ ferr.close();
203
+ out.destroy();
204
+ });
205
+ west.on("exit", () => {
206
+ fout.close();
207
+ ferr.close();
208
+ out.destroy();
209
+ subscriber.next({ item, complete: true });
210
+ subscriber.complete();
211
+ });
212
+ out.on("data", (data) => subscriber.next({ item, output: data.toString() }));
213
+ })));
214
+ }
215
+ async function seedleOptionsNormalize(seedle, cwd, verbose) {
216
+ const name = seedle.__key;
217
+ const resolve = await resolver(cwd);
218
+ const types = resolve("<atx>/lib/atx/types.cddl");
219
+ const installDir = resolve(seedle.installDir);
220
+ const buildDir = path.join(installDir, name);
221
+ const files = [...seedle.files, types].map((file) => path.resolve(cwd, file));
222
+ return {
223
+ name: seedle.__key,
224
+ cwd,
225
+ installDir,
226
+ buildDir,
227
+ files,
228
+ cddl: path.join(installDir, name, `${name}.cddl`),
229
+ outputFile: path.join(installDir, `${name}-build.log`),
230
+ errorFile: path.join(installDir, `${name}-build.err`),
231
+ prefix: seedle.prefix || "",
232
+ namespace: seedle.namespace || "altronix",
233
+ verbose,
234
+ };
235
+ }
236
+ function seedle(opts) {
237
+ const { name, namespace, cddl, cwd, installDir } = opts;
238
+ const templatePath = path.resolve(cwd, "..", "seedle-template");
239
+ const seedlePath = path.resolve(cwd, "..", "seedle", "seedle");
240
+ return of([
241
+ "generate",
242
+ "--force",
243
+ `--destination=${installDir}`,
244
+ `--path=${templatePath}`,
245
+ `--name=${name}`,
246
+ "--overwrite",
247
+ `-dnamespace=${namespace}`,
248
+ `-dseedle-manifest-path=${seedlePath.replace(/\\/g, "\\\\")}`,
249
+ `-dcddl=${cddl.replace(/\\/g, "\\\\")}`,
250
+ ]).pipe(mergeMap((seedleArgs) => new Observable((subscriber) => {
251
+ const wasm = cp.spawn("cargo", seedleArgs, {
252
+ cwd: installDir,
253
+ shell: true,
254
+ });
255
+ const fout = fs.createWriteStream(opts.outputFile);
256
+ const ferr = fs.createWriteStream(opts.errorFile);
257
+ wasm.stdout.pipe(fout);
258
+ wasm.stderr.pipe(ferr);
259
+ wasm.on("error", (e) => {
260
+ subscriber.error(e);
261
+ fout.close();
262
+ ferr.close();
263
+ });
264
+ wasm.on("exit", () => {
265
+ fout.close();
266
+ ferr.close();
267
+ subscriber.next();
268
+ subscriber.complete();
269
+ });
270
+ })));
271
+ }
272
+ function cmakeItem(opts) {
273
+ const { name } = opts;
274
+ return { kind: "wasm", name };
275
+ }
276
+ function cmakeConfigure(opts) {
277
+ const { buildDir, outputFile, errorFile, } = opts;
278
+ const item = cmakeItem(opts).name;
279
+ return of([`-B${buildDir}`, `-S${buildDir}`]).pipe(mergeMap((cmakeArgs) => new Observable((subscriber) => {
280
+ const wasm = cp.spawn("cmake", cmakeArgs, {
281
+ cwd: buildDir,
282
+ shell: true,
283
+ });
284
+ const fout = fs.createWriteStream(outputFile);
285
+ const ferr = fs.createWriteStream(errorFile);
286
+ const out = new PassThrough();
287
+ wasm.stdout.pipe(fout);
288
+ wasm.stdout.pipe(out);
289
+ wasm.stderr.pipe(ferr);
290
+ wasm.on("error", (e) => {
291
+ subscriber.error(e);
292
+ fout.close();
293
+ ferr.close();
294
+ out.destroy();
295
+ });
296
+ wasm.on("exit", () => {
297
+ fout.close();
298
+ ferr.close();
299
+ out.destroy();
300
+ subscriber.next({ item, complete: true });
301
+ subscriber.complete();
302
+ });
303
+ out.on("data", (data) => subscriber.next({ item, output: data.toString() }));
304
+ })));
305
+ }
306
+ function cmakeBuild(opts) {
307
+ const { buildDir, outputFile, errorFile, } = opts;
308
+ const item = cmakeItem(opts).name;
309
+ return of([`--build`, `${buildDir}`, `--target`, ` wasm`]).pipe(mergeMap((cmakeArgs) => new Observable((subscriber) => {
310
+ const wasm = cp.spawn("cmake", cmakeArgs, {
311
+ cwd: buildDir,
312
+ shell: true,
313
+ });
314
+ const fout = fs.createWriteStream(outputFile);
315
+ const ferr = fs.createWriteStream(errorFile);
316
+ const out = new PassThrough();
317
+ wasm.stdout.pipe(fout);
318
+ wasm.stdout.pipe(out);
319
+ wasm.stderr.pipe(ferr);
320
+ wasm.on("error", (e) => {
321
+ subscriber.error(e);
322
+ fout.close();
323
+ ferr.close();
324
+ out.destroy();
325
+ });
326
+ wasm.on("exit", () => {
327
+ fout.close();
328
+ ferr.close();
329
+ out.destroy();
330
+ subscriber.next({ item, complete: true });
331
+ subscriber.complete();
332
+ });
333
+ out.on("data", (data) => subscriber.next({ item, output: data.toString() }));
334
+ })));
335
+ }
336
+ function cmake(opts) {
337
+ return concat(cmakeConfigure(opts), cmakeBuild(opts));
338
+ }
339
+ function emulateBytePages(board) {
340
+ return (board.startsWith("atsame54_xpro") ||
341
+ board.startsWith("netway4e1bt") ||
342
+ board.startsWith("netway4eb") ||
343
+ board.startsWith("netway5pq") ||
344
+ board.startsWith("oa2b"));
345
+ }
346
+ function extraApplicationConfs(extraConfs) {
347
+ const key = process.env["ALTRONIX_RELEASE_KEY"];
348
+ if (!key)
349
+ throw new Error("missing ALTRONIX_RELEASE_KEY from environment");
350
+ const extraConfsData = [
351
+ `CONFIG_MCUBOOT_SIGNATURE_KEY_FILE="${key}"`,
352
+ `CONFIG_BOOTLOADER_MCUBOOT=y`,
353
+ `CONFIG_ATX_UPDATE_ENABLE=y`,
354
+ ].join("\r\n");
355
+ return from(fs.promises.writeFile(extraConfs, extraConfsData));
356
+ }
357
+ function extraBootloaderConfs(board, extraConfs) {
358
+ const key = process.env["ALTRONIX_RELEASE_KEY"];
359
+ if (!key)
360
+ throw new Error("missing ALTRONIX_RELEASE_KEY from environment");
361
+ const extraConfsData = emulateBytePages(board)
362
+ ? [
363
+ `CONFIG_BOOT_SIGNATURE_KEY_FILE="${key}"`,
364
+ `CONFIG_SOC_FLASH_SAM0_EMULATE_BYTE_PAGES=y`,
365
+ ]
366
+ : [`CONFIG_BOOT_SIGNATURE_KEY_FILE="${key}"`];
367
+ return from(fs.promises.writeFile(extraConfs, extraConfsData.join("\r\n")));
368
+ }
369
+ function copy() {
370
+ return (obs$) => obs$.pipe(mergeMap((opts) => {
371
+ const { src, dst } = opts;
372
+ return new Observable((subscriber) => {
373
+ fs.promises
374
+ .copyFile(src, dst)
375
+ .then(() => subscriber.next(opts))
376
+ .catch(() => subscriber.next({ ...opts, err: dst }))
377
+ .finally(() => subscriber.complete());
378
+ });
379
+ }));
380
+ }
381
+ function concatFiles(src, dest) {
382
+ return from(src).pipe(concatMap((src) => from(fs.promises.readFile(src, "ascii"))), toArray(), mergeMap((arr) => from(fs.promises.writeFile(dest, arr.join("\r\n")))));
383
+ }
384
+ function mkdir() {
385
+ return (obs$) => obs$.pipe(mergeMap((dir) => new Observable((subscriber) => {
386
+ fs.promises
387
+ .mkdir(dir, { recursive: true })
388
+ .then(() => subscriber.next())
389
+ .catch((e) => subscriber.error(e))
390
+ .finally(() => subscriber.complete());
391
+ })));
392
+ }
393
+ function rmdir(dir) {
394
+ return new Observable((subscriber) => {
395
+ fs.promises
396
+ .rm(dir, { recursive: true })
397
+ .then(() => subscriber.next(dir))
398
+ .catch((e) => subscriber.error(e))
399
+ .finally(() => subscriber.complete());
400
+ });
401
+ }
402
+ function exists() {
403
+ return (obs$) => obs$.pipe(mergeMap((dir) => new Observable((subscriber) => {
404
+ fs.promises
405
+ .stat(dir)
406
+ .then(() => subscriber.next(dir))
407
+ .catch(() => subscriber.next(undefined))
408
+ .finally(() => subscriber.complete());
409
+ })));
410
+ }
411
+ function confirm(force) {
412
+ return (obs$) => force
413
+ ? of(true)
414
+ : obs$.pipe(concatMap((dir) => from(inquirer({ message: `Delete ${dir}?` }))));
415
+ }
416
+ function throwIf(predicate, message) {
417
+ return tap((v) => {
418
+ if (predicate(v))
419
+ throw new Error(message);
420
+ });
421
+ }
422
+ function clean(force) {
423
+ return (obs$) => obs$.pipe(exists(), concatMap((dir) => {
424
+ return dir
425
+ ? of(dir).pipe(confirm(force), throwIf((confirm) => !confirm, "User rejected delete"), mergeMap((_) => rmdir(dir)), map(() => void 0))
426
+ : of(void 0);
427
+ }));
428
+ }
429
+ function tovoid() {
430
+ return (obs$) => obs$.pipe(map(() => void 0));
431
+ }
432
+ export async function build() {
433
+ const config = this.opts()["config"] || path.resolve("./", "atx.json");
434
+ const verbose = this.optsWithGlobals()["verbose"];
435
+ const cwd = path.resolve(path.dirname(config));
436
+ const data = await fs.promises.readFile(config, "ascii");
437
+ const atx = JSON.parse(data);
438
+ const extraAppConfFile = "application.conf";
439
+ const extraBootConfFile = "bootloader.conf";
440
+ if (!validate(atx))
441
+ throw validate.errors;
442
+ const env = path.resolve(cwd, ".env");
443
+ dotenv.config({ path: env });
444
+ const apps = keys(atx.applications).flatMap((app) => {
445
+ return keys(app.boards).flatMap((board) => {
446
+ return keys(board).map((config) => westOptionsNormalize(board.__key, config, app, cwd, verbose));
447
+ });
448
+ });
449
+ const bootloaders = keys(atx.bootloaders).flatMap((app) => {
450
+ return keys(app.boards).flatMap((board) => {
451
+ return keys(board).map((config) => westOptionsNormalize(board.__key, config, app, cwd, verbose));
452
+ });
453
+ });
454
+ const wasm = keys(atx.wasm).map((w) => seedleOptionsNormalize(w, cwd, verbose));
455
+ let concurrent = this.opts()["concurrent"]
456
+ ? parseInt(this.opts()["concurrent"])
457
+ : Infinity;
458
+ let buildApps = this.opts()["application"];
459
+ let buildBoot = this.opts()["bootloader"];
460
+ let buildWasm = this.opts()["wasm"];
461
+ if (!(buildApps || buildBoot || buildWasm)) {
462
+ buildApps = buildBoot = buildWasm = true;
463
+ }
464
+ const apps$ = buildApps ? from(await Promise.all(apps)) : EMPTY;
465
+ const boot$ = buildBoot ? from(await Promise.all(bootloaders)) : EMPTY;
466
+ const wasm$ = buildWasm ? from(await Promise.all(wasm)) : EMPTY;
467
+ // Handle all the preliminary stuff before building
468
+ 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: dir }) => dir))).pipe(mkdir()), wasm$.pipe(map(({ name, installDir }) => path.join(installDir, name)), clean(this.opts()["yes"])), apps$.pipe(mergeMap(({ binaryDir }) => extraApplicationConfs(path.join(binaryDir, extraAppConfFile)))), boot$.pipe(mergeMap(({ board, binaryDir }) => extraBootloaderConfs(board, path.join(binaryDir, extraBootConfFile)))), wasm$.pipe(mergeMap(seedle)), wasm$.pipe(mergeMap(({ files, cddl: dest }) => concatFiles(files, dest)))).pipe(last(), share());
469
+ // Get an array of every build item.
470
+ const items$ = merge(apps$.pipe(map(westItem)), boot$.pipe(map(westItem)), wasm$.pipe(map(cmakeItem))).pipe(toArray());
471
+ // Run build commands for all bootloaders, applications and wasm concurrently
472
+ const build$ = merge(apps$.pipe(map(west)), boot$.pipe(map(west)), wasm$.pipe(map(cmake))).pipe(mergeMap((obs) => obs, concurrent), share());
473
+ // Install everything into installDir
474
+ const install$ = merge(apps$.pipe(map(({ name, config, version: ver, board, binaryDir, installDir: d }) => {
475
+ return {
476
+ src: path.join(binaryDir, "zephyr", "zephyr.signed.bin"),
477
+ dst: path.join(d, `${board}-${name}-${config}-${ver}.signed.bin`),
478
+ };
479
+ })), boot$.pipe(map(({ name, config, board, binaryDir, installDir: d }) => {
480
+ return {
481
+ src: path.join(binaryDir, "zephyr", "zephyr.bin"),
482
+ dst: path.join(d, `${board}-${name}-${config}.bin`),
483
+ };
484
+ }))).pipe(copy(), tovoid());
485
+ await lastValueFrom(ready$);
486
+ const items = await lastValueFrom(items$);
487
+ const renderer = render(React.createElement(Ui, { items: items, "progress$": build$ }));
488
+ await lastValueFrom(build$);
489
+ renderer.cleanup();
490
+ return lastValueFrom(install$);
491
+ }
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { Observable } from 'rxjs';
3
+ export interface BuildItem {
4
+ name: string;
5
+ kind: "west" | "wasm";
6
+ }
7
+ export interface BuildProgress<K extends string = string> {
8
+ item: K;
9
+ output?: string;
10
+ error?: string;
11
+ complete?: boolean;
12
+ }
13
+ export interface Options {
14
+ items: BuildItem[];
15
+ progress$: Observable<BuildProgress>;
16
+ }
17
+ export default function ({ items, progress$ }: Options): React.JSX.Element;
@@ -0,0 +1,62 @@
1
+ import React, { useLayoutEffect, useState } from 'react';
2
+ import { Box, Text } from "ink";
3
+ import { scan } from 'rxjs';
4
+ export default function ({ items, progress$ }) {
5
+ const [width, setWidth] = useState(0);
6
+ const progress = useBuildEffect(progress$, items.map(({ name }) => name));
7
+ useLayoutEffect(() => {
8
+ const width = items
9
+ .map(({ name }) => name)
10
+ .reduce(calculateItemWidth, 0);
11
+ setWidth(width);
12
+ }, [items]);
13
+ return (React.createElement(Box, { flexDirection: "column" }, items.map((item) => (React.createElement(Box, { key: item.name },
14
+ React.createElement(Box, { width: width, marginRight: 2 },
15
+ React.createElement(Text, { wrap: "truncate", bold: true }, item.name.padStart(width))),
16
+ React.createElement(Box, { width: 4, marginRight: 2 },
17
+ React.createElement(Text, { wrap: "truncate", bold: true, color: buildColor(item.kind) }, item.kind.toUpperCase().padStart(4))),
18
+ React.createElement(Text, { dimColor: !progressComplete(progress[item.name]), color: progressColor(progress[item.name]) }, progress[item.name]))))));
19
+ }
20
+ function buildColor(kind) {
21
+ return kind === "west" ? "blue" : "magenta";
22
+ }
23
+ function progressComplete(progress) {
24
+ return progress === "OK!";
25
+ }
26
+ function progressColor(progress) {
27
+ return progressComplete(progress) ? "green" : "white";
28
+ }
29
+ function initProgress(items) {
30
+ return items.reduce((acc, curr) => ({ ...acc, [curr]: "" }), {});
31
+ }
32
+ function calculateItemWidth(acc, next) {
33
+ return next.length > acc ? next.length : acc;
34
+ }
35
+ function progressInc(progress) {
36
+ if (progress.charAt(0) == "|") {
37
+ return "/";
38
+ }
39
+ else if (progress.charAt(0) == "/") {
40
+ return "-";
41
+ }
42
+ else if (progress.charAt(0) == "-") {
43
+ return "\\";
44
+ }
45
+ else {
46
+ return "|";
47
+ }
48
+ }
49
+ function progressReducer(acc, next) {
50
+ acc[next.item] = next.complete ? "OK!" : progressInc(acc[next.item]);
51
+ return acc;
52
+ }
53
+ function useBuildEffect(obs$, items) {
54
+ const [progress, setProgress] = useState(initProgress(items));
55
+ useLayoutEffect(() => {
56
+ const s = obs$
57
+ .pipe(scan(progressReducer, progress))
58
+ .subscribe(progress => setProgress({ ...progress }));
59
+ return () => s.unsubscribe();
60
+ }, [obs$, items]);
61
+ return progress;
62
+ }
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+ import React from 'react';
3
+ import { render } from 'ink';
4
+ import meow from 'meow';
5
+ import App from './app.js';
6
+ const cli = meow(`
7
+ Usage
8
+ $ cli
9
+
10
+ Options
11
+ --name Your name
12
+
13
+ Examples
14
+ $ cli --name=Jane
15
+ Hello, Jane
16
+ `, {
17
+ importMeta: import.meta,
18
+ flags: {
19
+ name: {
20
+ type: 'string',
21
+ },
22
+ },
23
+ });
24
+ render(React.createElement(App, { name: cli.flags.name }));
package/dist/index.js ADDED
@@ -0,0 +1,50 @@
1
+ import { program } from "commander";
2
+ import path from "path";
3
+ import fs from "fs";
4
+ import { build } from "./build.js";
5
+ import { plugins } from "./plugin.js";
6
+ import { fileURLToPath } from "url";
7
+ // https://stackoverflow.com/questions/8817423/why-is-dirname-not-defined-in-node-repl
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+ (async function main() {
10
+ // Parse package.json to get version
11
+ const pkg = path.resolve(__dirname, "..", "package.json");
12
+ const ver = JSON.parse(await fs.promises.readFile(pkg, "ascii")).version;
13
+ // const cwd = path.resolve('./');
14
+ program
15
+ .name("atx")
16
+ .description("build atx zdk projects")
17
+ .version(ver)
18
+ .option("-VV, --verbose", "extra logging");
19
+ // Scan command
20
+ /*
21
+ const ignore = 'node_modules;target;build;.git';
22
+ program
23
+ .command('scan')
24
+ .description('scan for *.cddl files')
25
+ .option('-p, --path <PATH>', 'root directory to start scan', cwd)
26
+ .option('-m, --matches <REGEX>', 'match expression', '.*cddl$')
27
+ .option('-i, --ignores <REGEX>', 'ignore directories', ignore)
28
+ .action(seedle.scan);
29
+ */
30
+ // Build command
31
+ // TODO - detect if west is available and fail early
32
+ program
33
+ .command("build")
34
+ .description("build atx zdk application")
35
+ .option("-c, --config <CONFIG>", "workspace config file")
36
+ .option("-C, --concurrent <NUMBER>", "how many builds to run concurrently")
37
+ .option("-A, --application", "build applications")
38
+ .option("-B, --bootloader", "build bootloaders")
39
+ .option("-W, --wasm", "build wasm")
40
+ .option("-y, --yes", "answer yes automatically")
41
+ .action(build);
42
+ // Load plugins
43
+ (await plugins()).forEach(({ plugin: _, path: __, description: ___ }) => { });
44
+ try {
45
+ await program.parseAsync();
46
+ }
47
+ catch (e) {
48
+ console.error(e);
49
+ }
50
+ })();
package/dist/keys.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ export type WithKey<T> = T & {
2
+ __key: string;
3
+ };
4
+ export declare function keys<T>(map: {
5
+ [key: string]: T;
6
+ }): WithKey<T>[];
package/dist/keys.js ADDED
@@ -0,0 +1,5 @@
1
+ export function keys(map) {
2
+ return Object.keys(map)
3
+ .filter((key) => key !== "__key")
4
+ .map((key) => ({ ...map[key], __key: key }));
5
+ }
@@ -0,0 +1,7 @@
1
+ interface NpmLsResult {
2
+ plugin: string;
3
+ path: string;
4
+ description: string;
5
+ }
6
+ export declare function plugins(): Promise<NpmLsResult[]>;
7
+ export {};