@cartesi/cli 1.5.0 → 2.0.0-alpha.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/baseCommand.d.ts +2 -0
- package/dist/baseCommand.d.ts.map +1 -1
- package/dist/baseCommand.js +10 -5
- package/dist/builder/directory.d.ts +3 -0
- package/dist/builder/directory.d.ts.map +1 -0
- package/dist/builder/directory.js +37 -0
- package/dist/builder/docker.d.ts +10 -0
- package/dist/builder/docker.d.ts.map +1 -0
- package/dist/builder/docker.js +103 -0
- package/dist/builder/empty.d.ts +3 -0
- package/dist/builder/empty.d.ts.map +1 -0
- package/dist/builder/empty.js +21 -0
- package/dist/builder/index.d.ts +6 -0
- package/dist/builder/index.d.ts.map +1 -0
- package/dist/builder/index.js +5 -0
- package/dist/builder/none.d.ts +3 -0
- package/dist/builder/none.d.ts.map +1 -0
- package/dist/builder/none.js +11 -0
- package/dist/builder/tar.d.ts +3 -0
- package/dist/builder/tar.d.ts.map +1 -0
- package/dist/builder/tar.js +30 -0
- package/dist/commands/build.d.ts +3 -15
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +53 -194
- package/dist/commands/shell.d.ts +2 -1
- package/dist/commands/shell.d.ts.map +1 -1
- package/dist/commands/shell.js +41 -41
- package/dist/config.d.ts +102 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +378 -0
- package/dist/contracts.d.ts +492 -1038
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +223 -498
- package/dist/exec/cartesi-machine.d.ts +9 -0
- package/dist/exec/cartesi-machine.d.ts.map +1 -0
- package/dist/exec/cartesi-machine.js +20 -0
- package/dist/exec/crane.d.ts +15 -0
- package/dist/exec/crane.d.ts.map +1 -0
- package/dist/exec/crane.js +17 -0
- package/dist/exec/genext2fs.d.ts +28 -0
- package/dist/exec/genext2fs.d.ts.map +1 -0
- package/dist/exec/genext2fs.js +44 -0
- package/dist/exec/index.d.ts +5 -0
- package/dist/exec/index.d.ts.map +1 -0
- package/dist/exec/index.js +4 -0
- package/dist/exec/mksquashfs.d.ts +21 -0
- package/dist/exec/mksquashfs.d.ts.map +1 -0
- package/dist/exec/mksquashfs.js +45 -0
- package/dist/exec/util.d.ts +36 -0
- package/dist/exec/util.d.ts.map +1 -0
- package/dist/exec/util.js +78 -0
- package/dist/machine.d.ts +6 -0
- package/dist/machine.d.ts.map +1 -0
- package/dist/machine.js +80 -0
- package/dist/node/docker-compose-anvil.yaml +4 -3
- package/dist/node/docker-compose-bundler.yaml +1 -1
- package/dist/node/docker-compose-paymaster.yaml +1 -1
- package/oclif.manifest.json +32 -95
- package/package.json +7 -7
- package/dist/commands/send/dapp-address.d.ts +0 -9
- package/dist/commands/send/dapp-address.d.ts.map +0 -1
- package/dist/commands/send/dapp-address.js +0 -20
package/dist/baseCommand.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Command, Interfaces } from "@oclif/core";
|
|
2
2
|
import { Address, Hash } from "viem";
|
|
3
|
+
import { Config } from "./config.js";
|
|
3
4
|
export type Flags<T extends typeof Command> = Interfaces.InferredFlags<(typeof BaseCommand)["baseFlags"] & T["flags"]>;
|
|
4
5
|
export type Args<T extends typeof Command> = Interfaces.InferredArgs<T["args"]>;
|
|
5
6
|
export type AddressBook = Record<string, Address>;
|
|
@@ -8,6 +9,7 @@ export declare abstract class BaseCommand<T extends typeof Command> extends Comm
|
|
|
8
9
|
protected args: Args<T>;
|
|
9
10
|
protected getServiceState(projectName: string, serviceName: string): Promise<string | undefined>;
|
|
10
11
|
protected getContextPath(...paths: string[]): string;
|
|
12
|
+
protected getApplicationConfig(configPath: string): Config;
|
|
11
13
|
protected getMachineHash(): Hash | undefined;
|
|
12
14
|
protected logPrompt({ title, value }: {
|
|
13
15
|
title: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"baseCommand.d.ts","sourceRoot":"","sources":["../src/baseCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAKlD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAsB,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"baseCommand.d.ts","sourceRoot":"","sources":["../src/baseCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAKlD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAsB,MAAM,MAAM,CAAC;AAEzD,OAAO,EAAE,MAAM,EAAS,MAAM,aAAa,CAAC;AAiB5C,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,OAAO,OAAO,IAAI,UAAU,CAAC,aAAa,CAClE,CAAC,OAAO,WAAW,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CACjD,CAAC;AACF,MAAM,MAAM,IAAI,CAAC,CAAC,SAAS,OAAO,OAAO,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAChF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAElD,8BAAsB,WAAW,CAAC,CAAC,SAAS,OAAO,OAAO,CAAE,SAAQ,OAAO;IACvE,SAAS,CAAC,KAAK,EAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3B,SAAS,CAAC,IAAI,EAAG,IAAI,CAAC,CAAC,CAAC,CAAC;cAET,eAAe,CAC3B,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAe9B,SAAS,CAAC,cAAc,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM;IAIpD,SAAS,CAAC,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAM1D,SAAS,CAAC,cAAc,IAAI,IAAI,GAAG,SAAS;IAY5C,SAAS,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;cAItD,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC;cAKzC,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC;IAiCzC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAYrC"}
|
package/dist/baseCommand.js
CHANGED
|
@@ -4,7 +4,8 @@ import { execa } from "execa";
|
|
|
4
4
|
import fs from "fs";
|
|
5
5
|
import path from "path";
|
|
6
6
|
import { getAddress, isHash } from "viem";
|
|
7
|
-
import {
|
|
7
|
+
import { parse } from "./config.js";
|
|
8
|
+
import { applicationFactoryAddress, authorityFactoryAddress, erc1155BatchPortalAddress, erc1155SinglePortalAddress, erc20PortalAddress, erc721PortalAddress, etherPortalAddress, inputBoxAddress, selfHostedApplicationFactoryAddress, testMultiTokenAddress, testNftAddress, testTokenAddress, } from "./contracts.js";
|
|
8
9
|
export class BaseCommand extends Command {
|
|
9
10
|
async getServiceState(projectName, serviceName) {
|
|
10
11
|
// get service information
|
|
@@ -23,6 +24,11 @@ export class BaseCommand extends Command {
|
|
|
23
24
|
getContextPath(...paths) {
|
|
24
25
|
return path.join(".cartesi", ...paths);
|
|
25
26
|
}
|
|
27
|
+
getApplicationConfig(configPath) {
|
|
28
|
+
return fs.existsSync(configPath)
|
|
29
|
+
? parse(fs.readFileSync(configPath).toString())
|
|
30
|
+
: parse("");
|
|
31
|
+
}
|
|
26
32
|
getMachineHash() {
|
|
27
33
|
// read hash of the cartesi machine snapshot, if one exists
|
|
28
34
|
const hashPath = this.getContextPath("image", "hash");
|
|
@@ -45,10 +51,9 @@ export class BaseCommand extends Command {
|
|
|
45
51
|
const applicationAddress = await this.getApplicationAddress();
|
|
46
52
|
// build rollups contracts address book
|
|
47
53
|
const contracts = {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
DAppAddressRelay: dAppAddressRelayAddress,
|
|
54
|
+
Application: applicationAddress,
|
|
55
|
+
ApplicationFactory: applicationFactoryAddress,
|
|
56
|
+
AuthorityFactory: authorityFactoryAddress,
|
|
52
57
|
EntryPointV06: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
|
|
53
58
|
EntryPointV07: "0x0000000071727De22E5E9d8BAf0edAc6f37da032",
|
|
54
59
|
ERC1155BatchPortal: erc1155BatchPortalAddress,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory.d.ts","sourceRoot":"","sources":["../../src/builder/directory.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAGpD,eAAO,MAAM,KAAK,SACR,MAAM,SACL,oBAAoB,YACjB,MAAM,eACH,MAAM,KACpB,OAAO,CAAC,IAAI,CAkCd,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { genext2fs, mksquashfs } from "../exec/index.js";
|
|
4
|
+
export const build = async (name, drive, sdkImage, destination) => {
|
|
5
|
+
const filename = `${name}.${drive.format}`;
|
|
6
|
+
// copy directory to destination
|
|
7
|
+
const dest = path.join(destination, name);
|
|
8
|
+
await fs.mkdirp(dest);
|
|
9
|
+
await fs.copy(drive.directory, dest);
|
|
10
|
+
try {
|
|
11
|
+
switch (drive.format) {
|
|
12
|
+
case "ext2": {
|
|
13
|
+
await genext2fs.fromDirectory({
|
|
14
|
+
extraSize: drive.extraSize,
|
|
15
|
+
input: name,
|
|
16
|
+
output: filename,
|
|
17
|
+
cwd: destination,
|
|
18
|
+
image: sdkImage,
|
|
19
|
+
});
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
case "sqfs": {
|
|
23
|
+
await mksquashfs.fromDirectory({
|
|
24
|
+
input: name,
|
|
25
|
+
output: filename,
|
|
26
|
+
cwd: destination,
|
|
27
|
+
image: sdkImage,
|
|
28
|
+
});
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
// delete copied
|
|
35
|
+
await fs.remove(dest);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { DockerDriveConfig } from "../config.js";
|
|
2
|
+
type ImageInfo = {
|
|
3
|
+
cmd: string[];
|
|
4
|
+
entrypoint: string[];
|
|
5
|
+
env: string[];
|
|
6
|
+
workdir: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const build: (name: string, drive: DockerDriveConfig, sdkImage: string, destination: string) => Promise<ImageInfo | undefined>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=docker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["../../src/builder/docker.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAQjD,KAAK,SAAS,GAAG;IACb,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACnB,CAAC;AA6DF,eAAO,MAAM,KAAK,SACR,MAAM,SACL,iBAAiB,YACd,MAAM,eACH,MAAM,KACpB,OAAO,CAAC,SAAS,GAAG,SAAS,CAsD/B,CAAC"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { execa } from "execa";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import tmp from "tmp";
|
|
5
|
+
import { crane, genext2fs, mksquashfs } from "../exec/index.js";
|
|
6
|
+
/**
|
|
7
|
+
* Build Docker image (linux/riscv64). Returns image id.
|
|
8
|
+
*/
|
|
9
|
+
const buildImage = async (options) => {
|
|
10
|
+
const { context, dockerfile, tags, target } = options;
|
|
11
|
+
const buildResult = tmp.tmpNameSync();
|
|
12
|
+
const args = [
|
|
13
|
+
"buildx",
|
|
14
|
+
"build",
|
|
15
|
+
"--file",
|
|
16
|
+
dockerfile,
|
|
17
|
+
"--load",
|
|
18
|
+
"--iidfile",
|
|
19
|
+
buildResult,
|
|
20
|
+
context,
|
|
21
|
+
];
|
|
22
|
+
// set tags for the image built
|
|
23
|
+
args.push(...tags.map((tag) => ["--tag", tag]).flat());
|
|
24
|
+
if (target) {
|
|
25
|
+
args.push("--target", target);
|
|
26
|
+
}
|
|
27
|
+
await execa("docker", args, { stdio: "inherit" });
|
|
28
|
+
return fs.readFileSync(buildResult, "utf8");
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Query the image using docker image inspect
|
|
32
|
+
* @param image image id or name
|
|
33
|
+
* @returns Information about the image
|
|
34
|
+
*/
|
|
35
|
+
const getImageInfo = async (image) => {
|
|
36
|
+
const { stdout: jsonStr } = await execa("docker", [
|
|
37
|
+
"image",
|
|
38
|
+
"inspect",
|
|
39
|
+
image,
|
|
40
|
+
]);
|
|
41
|
+
// parse image info from docker inspect output
|
|
42
|
+
const [imageInfo] = JSON.parse(jsonStr);
|
|
43
|
+
// validate image architecture (must be riscv64)
|
|
44
|
+
if (imageInfo["Architecture"] !== "riscv64") {
|
|
45
|
+
throw new Error(`Invalid image Architecture: ${imageInfo["Architecture"]}. Expected riscv64`);
|
|
46
|
+
}
|
|
47
|
+
const info = {
|
|
48
|
+
cmd: imageInfo["Config"]["Cmd"] ?? [],
|
|
49
|
+
entrypoint: imageInfo["Config"]["Entrypoint"] ?? [],
|
|
50
|
+
env: imageInfo["Config"]["Env"] || [],
|
|
51
|
+
workdir: imageInfo["Config"]["WorkingDir"],
|
|
52
|
+
};
|
|
53
|
+
return info;
|
|
54
|
+
};
|
|
55
|
+
export const build = async (name, drive, sdkImage, destination) => {
|
|
56
|
+
const { format } = drive;
|
|
57
|
+
const ocitar = `${name}.oci.tar`;
|
|
58
|
+
const tar = `${name}.tar`;
|
|
59
|
+
const filename = `${name}.${format}`;
|
|
60
|
+
// use pre-existing image or build docker image
|
|
61
|
+
const image = drive.image || (await buildImage(drive));
|
|
62
|
+
// get image info
|
|
63
|
+
const imageInfo = await getImageInfo(image);
|
|
64
|
+
try {
|
|
65
|
+
// create OCI Docker tarball from Docker image
|
|
66
|
+
await execa("docker", ["image", "save", image, "-o", ocitar], {
|
|
67
|
+
cwd: destination,
|
|
68
|
+
});
|
|
69
|
+
// create rootfs tar from OCI tar
|
|
70
|
+
await crane.exportImage({
|
|
71
|
+
stdin: fs.openSync(path.join(destination, ocitar), "r"),
|
|
72
|
+
stdout: fs.openSync(path.join(destination, tar), "w"),
|
|
73
|
+
image: sdkImage,
|
|
74
|
+
});
|
|
75
|
+
switch (format) {
|
|
76
|
+
case "ext2": {
|
|
77
|
+
await genext2fs.fromTar({
|
|
78
|
+
extraSize: drive.extraSize,
|
|
79
|
+
input: tar,
|
|
80
|
+
output: filename,
|
|
81
|
+
cwd: destination,
|
|
82
|
+
image: sdkImage,
|
|
83
|
+
});
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
case "sqfs": {
|
|
87
|
+
await mksquashfs.fromTar({
|
|
88
|
+
input: path.join(destination, tar),
|
|
89
|
+
output: filename,
|
|
90
|
+
cwd: destination,
|
|
91
|
+
image: sdkImage,
|
|
92
|
+
});
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
// delete intermediate files
|
|
99
|
+
await fs.remove(path.join(destination, ocitar));
|
|
100
|
+
await fs.remove(path.join(destination, tar));
|
|
101
|
+
}
|
|
102
|
+
return imageInfo;
|
|
103
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"empty.d.ts","sourceRoot":"","sources":["../../src/builder/empty.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGhD,eAAO,MAAM,KAAK,SACR,MAAM,SACL,gBAAgB,YACb,MAAM,eACH,MAAM,KACpB,OAAO,CAAC,IAAI,CAoBd,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { genext2fs } from "../exec/index.js";
|
|
4
|
+
export const build = async (name, drive, sdkImage, destination) => {
|
|
5
|
+
const filename = `${name}.${drive.format}`;
|
|
6
|
+
switch (drive.format) {
|
|
7
|
+
case "ext2": {
|
|
8
|
+
await genext2fs.empty({
|
|
9
|
+
output: filename,
|
|
10
|
+
size: drive.size,
|
|
11
|
+
cwd: destination,
|
|
12
|
+
image: sdkImage,
|
|
13
|
+
});
|
|
14
|
+
break;
|
|
15
|
+
}
|
|
16
|
+
case "raw": {
|
|
17
|
+
await fs.writeFile(path.join(destination, filename), Buffer.alloc(drive.size));
|
|
18
|
+
break;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { build as buildDirectory } from "./directory.js";
|
|
2
|
+
export { build as buildDocker } from "./docker.js";
|
|
3
|
+
export { build as buildEmpty } from "./empty.js";
|
|
4
|
+
export { build as buildNone } from "./none.js";
|
|
5
|
+
export { build as buildTar } from "./tar.js";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/builder/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,KAAK,IAAI,WAAW,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,KAAK,IAAI,UAAU,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,KAAK,IAAI,QAAQ,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"none.d.ts","sourceRoot":"","sources":["../../src/builder/none.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAkB,MAAM,cAAc,CAAC;AAEnE,eAAO,MAAM,KAAK,SACR,MAAM,SACL,mBAAmB,eACb,MAAM,KACpB,OAAO,CAAC,IAAI,CAQd,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { getDriveFormat } from "../config.js";
|
|
4
|
+
export const build = async (name, drive, destination) => {
|
|
5
|
+
// no need to build, drive already exists
|
|
6
|
+
const src = drive.filename;
|
|
7
|
+
const format = getDriveFormat(src);
|
|
8
|
+
const filename = path.join(destination, `${name}.${format}`);
|
|
9
|
+
// just copy it
|
|
10
|
+
await fs.copyFile(src, filename);
|
|
11
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tar.d.ts","sourceRoot":"","sources":["../../src/builder/tar.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9C,eAAO,MAAM,KAAK,SACR,MAAM,SACL,cAAc,YACX,MAAM,eACH,MAAM,KACpB,OAAO,CAAC,IAAI,CA4Bd,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { genext2fs, mksquashfs } from "../exec/index.js";
|
|
4
|
+
export const build = async (name, drive, sdkImage, destination) => {
|
|
5
|
+
const tar = `${name}.tar`;
|
|
6
|
+
const filename = `${name}.${drive.format}`;
|
|
7
|
+
// copy input tar to destination directory (with drive name)
|
|
8
|
+
await fs.copy(drive.filename, path.join(destination, tar));
|
|
9
|
+
switch (drive.format) {
|
|
10
|
+
case "ext2": {
|
|
11
|
+
await genext2fs.fromTar({
|
|
12
|
+
extraSize: drive.extraSize,
|
|
13
|
+
input: tar,
|
|
14
|
+
output: filename,
|
|
15
|
+
cwd: destination,
|
|
16
|
+
image: sdkImage,
|
|
17
|
+
});
|
|
18
|
+
break;
|
|
19
|
+
}
|
|
20
|
+
case "sqfs": {
|
|
21
|
+
await mksquashfs.fromTar({
|
|
22
|
+
input: path.join(destination, tar),
|
|
23
|
+
output: filename,
|
|
24
|
+
cwd: destination,
|
|
25
|
+
image: sdkImage,
|
|
26
|
+
});
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
package/dist/commands/build.d.ts
CHANGED
|
@@ -1,24 +1,12 @@
|
|
|
1
1
|
import { BaseCommand } from "../baseCommand.js";
|
|
2
|
-
export default class
|
|
2
|
+
export default class Build extends BaseCommand<typeof Build> {
|
|
3
3
|
static summary: string;
|
|
4
4
|
static description: string;
|
|
5
5
|
static examples: string[];
|
|
6
|
-
static args: {};
|
|
7
6
|
static flags: {
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
config: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
8
|
+
"drives-only": import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
10
9
|
};
|
|
11
|
-
/**
|
|
12
|
-
* Build DApp image (linux/riscv64). Returns image id.
|
|
13
|
-
* @param directory path of context containing Dockerfile
|
|
14
|
-
*/
|
|
15
|
-
private buildImage;
|
|
16
|
-
private getImageInfo;
|
|
17
|
-
private createTarball;
|
|
18
|
-
private sdkRun;
|
|
19
|
-
private static createRootfsTarCommand;
|
|
20
|
-
private static createExt2Command;
|
|
21
|
-
private static createMachineSnapshotCommand;
|
|
22
10
|
run(): Promise<void>;
|
|
23
11
|
}
|
|
24
12
|
//# sourceMappingURL=build.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAoChD,MAAM,CAAC,OAAO,OAAO,KAAM,SAAQ,WAAW,CAAC,OAAO,KAAK,CAAC;IACxD,MAAM,CAAC,OAAO,SAAwB;IAEtC,MAAM,CAAC,WAAW,SAC+E;IAEjG,MAAM,CAAC,QAAQ,WAA2C;IAE1D,MAAM,CAAC,KAAK;;;MAUV;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA2CpC"}
|
package/dist/commands/build.js
CHANGED
|
@@ -1,214 +1,73 @@
|
|
|
1
1
|
import { Flags } from "@oclif/core";
|
|
2
|
-
import bytes from "bytes";
|
|
3
|
-
import { execa } from "execa";
|
|
4
2
|
import fs from "fs-extra";
|
|
5
|
-
import
|
|
3
|
+
import path from "path";
|
|
6
4
|
import tmp from "tmp";
|
|
7
5
|
import { BaseCommand } from "../baseCommand.js";
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const CARTESI_LABEL_SDK_NAME = `${CARTESI_LABEL_PREFIX}.sdk_name`;
|
|
15
|
-
const CARTESI_DEFAULT_SDK_VERSION = "0.9.0";
|
|
16
|
-
class BuildApplication extends BaseCommand {
|
|
17
|
-
/**
|
|
18
|
-
* Build DApp image (linux/riscv64). Returns image id.
|
|
19
|
-
* @param directory path of context containing Dockerfile
|
|
20
|
-
*/
|
|
21
|
-
async buildImage(options) {
|
|
22
|
-
const buildResult = tmp.tmpNameSync();
|
|
23
|
-
this.debug(`building docker image and writing result to ${buildResult}`);
|
|
24
|
-
const args = ["buildx", "build", "--load", "--iidfile", buildResult];
|
|
25
|
-
if (options.target) {
|
|
26
|
-
args.push("--target", options.target);
|
|
6
|
+
import { buildDirectory, buildDocker, buildEmpty, buildNone, buildTar, } from "../builder/index.js";
|
|
7
|
+
import { bootMachine } from "../machine.js";
|
|
8
|
+
const buildDrive = async (name, drive, sdkImage, destination) => {
|
|
9
|
+
switch (drive.builder) {
|
|
10
|
+
case "directory": {
|
|
11
|
+
return buildDirectory(name, drive, sdkImage, destination);
|
|
27
12
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
async getImageInfo(image) {
|
|
32
|
-
const { stdout: jsonStr } = await execa("docker", [
|
|
33
|
-
"image",
|
|
34
|
-
"inspect",
|
|
35
|
-
image,
|
|
36
|
-
]);
|
|
37
|
-
// parse image info from docker inspect output
|
|
38
|
-
const [imageInfo] = JSON.parse(jsonStr);
|
|
39
|
-
// validate image architecture (must be riscv64)
|
|
40
|
-
if (imageInfo["Architecture"] !== "riscv64") {
|
|
41
|
-
throw new Error(`Invalid image Architecture: ${imageInfo["Architecture"]}. Expected riscv64`);
|
|
42
|
-
}
|
|
43
|
-
const labels = imageInfo["Config"]["Labels"] || {};
|
|
44
|
-
const info = {
|
|
45
|
-
cmd: imageInfo["Config"]["Cmd"] ?? [],
|
|
46
|
-
dataSize: labels[CARTESI_LABEL_DATA_SIZE] ?? "10Mb",
|
|
47
|
-
entrypoint: imageInfo["Config"]["Entrypoint"] ?? [],
|
|
48
|
-
env: imageInfo["Config"]["Env"] || [],
|
|
49
|
-
ramSize: labels[CARTESI_LABEL_RAM_SIZE] ?? CARTESI_DEFAULT_RAM_SIZE,
|
|
50
|
-
sdkName: labels[CARTESI_LABEL_SDK_NAME] ?? "cartesi/sdk",
|
|
51
|
-
sdkVersion: labels[CARTESI_LABEL_SDK_VERSION] ??
|
|
52
|
-
CARTESI_DEFAULT_SDK_VERSION,
|
|
53
|
-
workdir: imageInfo["Config"]["WorkingDir"],
|
|
54
|
-
};
|
|
55
|
-
if (!info.entrypoint && !info.cmd) {
|
|
56
|
-
throw new Error("Undefined image ENTRYPOINT or CMD");
|
|
13
|
+
case "docker": {
|
|
14
|
+
return buildDocker(name, drive, sdkImage, destination);
|
|
57
15
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
this.warn("sdk version is not a valid semver");
|
|
16
|
+
case "empty": {
|
|
17
|
+
return buildEmpty(name, drive, sdkImage, destination);
|
|
61
18
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
throw new Error(`Unsupported sdk version: ${info.sdkVersion} (used) < ${CARTESI_DEFAULT_SDK_VERSION} (minimum).
|
|
65
|
-
Update your application Dockerfile using one of the templates at https://github.com/cartesi/application-templates/tree/${DEFAULT_TEMPLATES_BRANCH}
|
|
66
|
-
`);
|
|
19
|
+
case "tar": {
|
|
20
|
+
return buildTar(name, drive, sdkImage, destination);
|
|
67
21
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
this.warn(`Undefined ${CARTESI_LABEL_SDK_VERSION} label, defaulting to ${CARTESI_DEFAULT_SDK_VERSION}`);
|
|
71
|
-
info.ramSize ||
|
|
72
|
-
this.warn(`Undefined ${CARTESI_LABEL_RAM_SIZE} label, defaulting to ${CARTESI_DEFAULT_RAM_SIZE}`);
|
|
73
|
-
// validate data size value
|
|
74
|
-
if (bytes(info.dataSize) === null) {
|
|
75
|
-
throw new Error(`Invalid ${CARTESI_LABEL_DATA_SIZE} value: ${info.dataSize}`);
|
|
22
|
+
case "none": {
|
|
23
|
+
return buildNone(name, drive, destination);
|
|
76
24
|
}
|
|
77
|
-
// XXX: validate other values
|
|
78
|
-
return info;
|
|
79
|
-
}
|
|
80
|
-
// saves the OCI Image to a tarball
|
|
81
|
-
async createTarball(image, outputFilePath) {
|
|
82
|
-
// create docker tarball from app image
|
|
83
|
-
await execa("docker", ["image", "save", image, "-o", outputFilePath]);
|
|
84
|
-
}
|
|
85
|
-
// this wraps the call to the sdk image with a one-shot approach
|
|
86
|
-
// the (inputPath, outputPath) signature will mount the input as a volume and copy the output with docker cp
|
|
87
|
-
async sdkRun(sdkImage, cmd, inputPath, outputPath) {
|
|
88
|
-
const { stdout: cid } = await execa("docker", [
|
|
89
|
-
"container",
|
|
90
|
-
"create",
|
|
91
|
-
"--volume",
|
|
92
|
-
`./${inputPath}:/tmp/input`,
|
|
93
|
-
sdkImage,
|
|
94
|
-
...cmd,
|
|
95
|
-
]);
|
|
96
|
-
await execa("docker", ["container", "start", "-a", cid], {
|
|
97
|
-
stdio: "inherit",
|
|
98
|
-
});
|
|
99
|
-
await execa("docker", [
|
|
100
|
-
"container",
|
|
101
|
-
"cp",
|
|
102
|
-
`${cid}:/tmp/output`,
|
|
103
|
-
outputPath,
|
|
104
|
-
]);
|
|
105
|
-
await execa("docker", ["container", "stop", cid]);
|
|
106
|
-
await execa("docker", ["container", "rm", cid]);
|
|
107
|
-
}
|
|
108
|
-
// returns the command to create rootfs tarball from an OCI Image tarball
|
|
109
|
-
static createRootfsTarCommand() {
|
|
110
|
-
const cmd = [
|
|
111
|
-
"cat",
|
|
112
|
-
"/tmp/input",
|
|
113
|
-
"|",
|
|
114
|
-
"crane",
|
|
115
|
-
"export",
|
|
116
|
-
"-", // OCI Image from stdin
|
|
117
|
-
"-", // rootfs tarball to stdout
|
|
118
|
-
"|",
|
|
119
|
-
"bsdtar",
|
|
120
|
-
"-cf",
|
|
121
|
-
"/tmp/output",
|
|
122
|
-
"--format=gnutar",
|
|
123
|
-
"@/dev/stdin", // rootfs tarball from stdin
|
|
124
|
-
];
|
|
125
|
-
return ["/usr/bin/env", "bash", "-c", cmd.join(" ")];
|
|
126
|
-
}
|
|
127
|
-
// returns the command to create ext2 from a rootfs
|
|
128
|
-
static createExt2Command(extraBytes) {
|
|
129
|
-
const blockSize = 4096;
|
|
130
|
-
const extraBlocks = Math.ceil(extraBytes / blockSize);
|
|
131
|
-
const extraSize = `+${extraBlocks}`;
|
|
132
|
-
return [
|
|
133
|
-
"xgenext2fs",
|
|
134
|
-
"--tarball",
|
|
135
|
-
"/tmp/input",
|
|
136
|
-
"--block-size",
|
|
137
|
-
blockSize.toString(),
|
|
138
|
-
"--faketime",
|
|
139
|
-
"-r",
|
|
140
|
-
extraSize,
|
|
141
|
-
"/tmp/output",
|
|
142
|
-
];
|
|
143
|
-
}
|
|
144
|
-
static createMachineSnapshotCommand(info) {
|
|
145
|
-
const ramSize = info.ramSize;
|
|
146
|
-
const driveLabel = "root"; // XXX: does this need to be customizable?
|
|
147
|
-
// list of environment variables of docker image
|
|
148
|
-
const envs = info.env.map((variable) => `--env=${variable}`);
|
|
149
|
-
// ENTRYPOINT and CMD as a space separated string
|
|
150
|
-
const entrypoint = [...info.entrypoint, ...info.cmd].join(" ");
|
|
151
|
-
// command to change working directory if WORKDIR is defined
|
|
152
|
-
const cwd = info.workdir ? `--workdir=${info.workdir}` : "";
|
|
153
|
-
return [
|
|
154
|
-
"create_machine_snapshot",
|
|
155
|
-
`--ram-length=${ramSize}`,
|
|
156
|
-
`--drive-label=${driveLabel}`,
|
|
157
|
-
`--drive-filename=/tmp/input`,
|
|
158
|
-
`--output=/tmp/output`,
|
|
159
|
-
cwd,
|
|
160
|
-
...envs,
|
|
161
|
-
`--entrypoint=${entrypoint}`,
|
|
162
|
-
];
|
|
163
25
|
}
|
|
26
|
+
};
|
|
27
|
+
class Build extends BaseCommand {
|
|
164
28
|
async run() {
|
|
165
|
-
const { flags } = await this.parse(
|
|
166
|
-
const snapshotPath = this.getContextPath("image");
|
|
167
|
-
const tarPath = this.getContextPath("image.tar");
|
|
168
|
-
const gnuTarPath = this.getContextPath("image.gnutar");
|
|
169
|
-
const ext2Path = this.getContextPath("image.ext2");
|
|
29
|
+
const { flags } = await this.parse(Build);
|
|
170
30
|
// clean up temp files we create along the process
|
|
171
31
|
tmp.setGracefulCleanup();
|
|
172
|
-
//
|
|
173
|
-
const
|
|
32
|
+
// get application configuration from 'cartesi.toml'
|
|
33
|
+
const config = this.getApplicationConfig(flags.config);
|
|
34
|
+
// destination directory for image and intermediate files
|
|
35
|
+
const destination = path.resolve(this.getContextPath());
|
|
174
36
|
// prepare context directory
|
|
175
|
-
await fs.emptyDir(
|
|
176
|
-
//
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
await this.sdkRun(sdkImage, BuildApplication.createExt2Command(bytes.parse(imageInfo.dataSize)), gnuTarPath, ext2Path);
|
|
187
|
-
// create machine snapshot
|
|
188
|
-
await this.sdkRun(sdkImage, BuildApplication.createMachineSnapshotCommand(imageInfo), ext2Path, snapshotPath);
|
|
189
|
-
await fs.chmod(snapshotPath, 0o755);
|
|
190
|
-
}
|
|
191
|
-
finally {
|
|
192
|
-
await fs.remove(gnuTarPath);
|
|
193
|
-
await fs.remove(tarPath);
|
|
37
|
+
await fs.emptyDir(destination); // XXX: make it less error prone
|
|
38
|
+
// start build of all drives simultaneously
|
|
39
|
+
const results = Object.entries(config.drives).reduce((acc, [name, drive]) => {
|
|
40
|
+
acc[name] = buildDrive(name, drive, config.sdk, destination);
|
|
41
|
+
return acc;
|
|
42
|
+
}, {});
|
|
43
|
+
// await for all drives to be built
|
|
44
|
+
await Promise.all(Object.values(results));
|
|
45
|
+
if (flags["drives-only"]) {
|
|
46
|
+
// only build drives, so quit here
|
|
47
|
+
return;
|
|
194
48
|
}
|
|
49
|
+
// get image info of root drive
|
|
50
|
+
const root = await results["root"];
|
|
51
|
+
const imageInfo = root || undefined;
|
|
52
|
+
// path of machine snapshot
|
|
53
|
+
const snapshotPath = this.getContextPath("image");
|
|
54
|
+
// create machine snapshot
|
|
55
|
+
await bootMachine(config, imageInfo, destination);
|
|
56
|
+
await fs.chmod(snapshotPath, 0o755);
|
|
195
57
|
}
|
|
196
58
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
"from-image": Flags.string({
|
|
206
|
-
summary: "skip docker build and start from this image.",
|
|
207
|
-
description: "if the build process of the application Dockerfile needs more control the developer can build the image using the `docker build` command, and then start the build process of the Cartesi machine starting from that image.",
|
|
59
|
+
Build.summary = "Build application.";
|
|
60
|
+
Build.description = "Build application by building Cartesi machine drives, configuring a machine and booting it";
|
|
61
|
+
Build.examples = ["<%= config.bin %> <%= command.id %>"];
|
|
62
|
+
Build.flags = {
|
|
63
|
+
config: Flags.file({
|
|
64
|
+
char: "c",
|
|
65
|
+
default: "cartesi.toml",
|
|
66
|
+
summary: "path to the configuration file",
|
|
208
67
|
}),
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
68
|
+
"drives-only": Flags.boolean({
|
|
69
|
+
default: false,
|
|
70
|
+
summary: "only build drives",
|
|
212
71
|
}),
|
|
213
72
|
};
|
|
214
|
-
export default
|
|
73
|
+
export default Build;
|