From 59d78c93ba80d20e5d7c4f47b9fe24575bcdc8cd Mon Sep 17 00:00:00 2001 From: Kevin Ingersoll Date: Fri, 1 Dec 2023 13:54:55 +0000 Subject: [PATCH] feat(cli): add build command (#1990) Co-authored-by: alvarius --- .changeset/ninety-lions-double.md | 5 +++ e2e/packages/contracts/package.json | 9 +--- .../minimal/packages/contracts/package.json | 6 +-- packages/cli/src/build.ts | 44 +++++++++++++++++++ packages/cli/src/commands/build.ts | 36 +++++++++++++++ packages/cli/src/commands/index.ts | 2 + packages/cli/src/runDeploy.ts | 37 ++-------------- .../phaser/packages/contracts/package.json | 6 +-- .../react-ecs/packages/contracts/package.json | 6 +-- .../react/packages/contracts/package.json | 6 +-- .../threejs/packages/contracts/package.json | 6 +-- .../vanilla/packages/contracts/package.json | 6 +-- 12 files changed, 104 insertions(+), 65 deletions(-) create mode 100644 .changeset/ninety-lions-double.md create mode 100644 packages/cli/src/build.ts create mode 100644 packages/cli/src/commands/build.ts diff --git a/.changeset/ninety-lions-double.md b/.changeset/ninety-lions-double.md new file mode 100644 index 0000000000..f6475fa292 --- /dev/null +++ b/.changeset/ninety-lions-double.md @@ -0,0 +1,5 @@ +--- +"@latticexyz/cli": minor +--- + +Added a `mud build` command that generates table libraries, system interfaces, and typed ABIs. diff --git a/e2e/packages/contracts/package.json b/e2e/packages/contracts/package.json index 134bc3f29f..24bdde1eec 100644 --- a/e2e/packages/contracts/package.json +++ b/e2e/packages/contracts/package.json @@ -4,13 +4,8 @@ "private": true, "license": "MIT", "scripts": { - "build": "pnpm run build:mud && pnpm run build:abi && pnpm run build:abi-ts", - "build:abi": "forge build", - "build:abi-ts": "mud abi-ts", - "build:mud": "mud tablegen && mud worldgen", - "clean": "pnpm run clean:abi && pnpm run clean:mud", - "clean:abi": "forge clean", - "clean:mud": "rimraf src/codegen", + "build": "mud build", + "clean": "forge clean && rimraf src/codegen", "deploy:local": "mud deploy", "test": "mud test", "test:ci": "pnpm run test" diff --git a/examples/minimal/packages/contracts/package.json b/examples/minimal/packages/contracts/package.json index 935ba8484b..1bd8b4276b 100644 --- a/examples/minimal/packages/contracts/package.json +++ b/examples/minimal/packages/contracts/package.json @@ -4,10 +4,8 @@ "private": true, "license": "MIT", "scripts": { - "build": "pnpm run build:mud && pnpm run build:abi && pnpm run build:abi-ts", - "build:abi": "forge build", - "build:abi-ts": "mud abi-ts", - "build:mud": "rimraf src/codegen && mud tablegen && mud worldgen", + "build": "mud build", + "clean": "forge clean && rimraf src/codegen", "deploy:local": "pnpm run build && mud deploy", "deploy:testnet": "pnpm run build && mud deploy --profile=lattice-testnet", "dev": "pnpm mud dev-contracts", diff --git a/packages/cli/src/build.ts b/packages/cli/src/build.ts new file mode 100644 index 0000000000..879bc1bdc3 --- /dev/null +++ b/packages/cli/src/build.ts @@ -0,0 +1,44 @@ +import { existsSync, readFileSync, writeFileSync } from "node:fs"; +import path from "node:path"; +import { tablegen } from "@latticexyz/store/codegen"; +import { worldgen } from "@latticexyz/world/node"; +import { StoreConfig } from "@latticexyz/store"; +import { WorldConfig } from "@latticexyz/world"; +import { forge, getForgeConfig, getRemappings } from "@latticexyz/common/foundry"; +import { getExistingContracts } from "./utils/getExistingContracts"; +import { debug as parentDebug } from "./debug"; +import { execa } from "execa"; + +const debug = parentDebug.extend("runDeploy"); + +type BuildOptions = { + foundryProfile?: string; + srcDir: string; + config: StoreConfig & WorldConfig; +}; + +export async function build({ + config, + srcDir, + foundryProfile = process.env.FOUNDRY_PROFILE, +}: BuildOptions): Promise { + const outPath = path.join(srcDir, config.codegenDirectory); + const remappings = await getRemappings(foundryProfile); + await Promise.all([tablegen(config, outPath, remappings), worldgen(config, getExistingContracts(srcDir), outPath)]); + + // TODO remove when https://github.com/foundry-rs/foundry/issues/6241 is resolved + const forgeConfig = await getForgeConfig(foundryProfile); + if (forgeConfig.cache) { + const cacheFilePath = path.join(forgeConfig.cache_path, "solidity-files-cache.json"); + if (existsSync(cacheFilePath)) { + debug("Unsetting cached content hash of IWorld.sol to force it to regenerate"); + const solidityFilesCache = JSON.parse(readFileSync(cacheFilePath, "utf8")); + const worldInterfacePath = path.join(outPath, "world", "IWorld.sol"); + solidityFilesCache["files"][worldInterfacePath]["contentHash"] = ""; + writeFileSync(cacheFilePath, JSON.stringify(solidityFilesCache, null, 2)); + } + } + + await forge(["build"], { profile: foundryProfile }); + await execa("mud", ["abi-ts"], { stdio: "inherit" }); +} diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts new file mode 100644 index 0000000000..4faec86ff9 --- /dev/null +++ b/packages/cli/src/commands/build.ts @@ -0,0 +1,36 @@ +import type { CommandModule } from "yargs"; +import { loadConfig } from "@latticexyz/config/node"; +import { StoreConfig } from "@latticexyz/store"; +import { WorldConfig } from "@latticexyz/world"; + +import { getSrcDirectory } from "@latticexyz/common/foundry"; +import { build } from "../build"; + +type Options = { + configPath?: string; + profile?: string; +}; + +const commandModule: CommandModule = { + command: "build", + + describe: "Build contracts and generate MUD artifacts (table libraries, world interface, ABI)", + + builder(yargs) { + return yargs.options({ + configPath: { type: "string", desc: "Path to the config file" }, + profile: { type: "string", desc: "The foundry profile to use" }, + }); + }, + + async handler({ configPath, profile }) { + const config = (await loadConfig(configPath)) as StoreConfig & WorldConfig; + const srcDir = await getSrcDirectory(); + + await build({ config, srcDir, foundryProfile: profile }); + + process.exit(0); + }, +}; + +export default commandModule; diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index 2ebded6aef..b00bf65dc0 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -3,6 +3,7 @@ import { CommandModule } from "yargs"; import gasReport from "@latticexyz/gas-report"; import abiTs from "@latticexyz/abi-ts"; +import build from "./build"; import devnode from "./devnode"; import faucet from "./faucet"; import hello from "./hello"; @@ -16,6 +17,7 @@ import devContracts from "./dev-contracts"; // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Each command has different options export const commands: CommandModule[] = [ + build, deploy, devnode, faucet, diff --git a/packages/cli/src/runDeploy.ts b/packages/cli/src/runDeploy.ts index 36689081b3..639f10195d 100644 --- a/packages/cli/src/runDeploy.ts +++ b/packages/cli/src/runDeploy.ts @@ -7,27 +7,14 @@ import { privateKeyToAccount } from "viem/accounts"; import { loadConfig } from "@latticexyz/config/node"; import { StoreConfig } from "@latticexyz/store"; import { WorldConfig } from "@latticexyz/world"; -import { - forge, - getForgeConfig, - getOutDirectory, - getRemappings, - getRpcUrl, - getSrcDirectory, -} from "@latticexyz/common/foundry"; +import { getOutDirectory, getRpcUrl, getSrcDirectory } from "@latticexyz/common/foundry"; import chalk from "chalk"; -import { execa } from "execa"; import { MUDError } from "@latticexyz/common/errors"; import { resolveConfig } from "./deploy/resolveConfig"; import { getChainId } from "viem/actions"; import { postDeploy } from "./utils/utils/postDeploy"; import { WorldDeploy } from "./deploy/common"; -import { tablegen } from "@latticexyz/store/codegen"; -import { worldgen } from "@latticexyz/world/node"; -import { getExistingContracts } from "./utils/getExistingContracts"; -import { debug as parentDebug } from "./debug"; - -const debug = parentDebug.extend("runDeploy"); +import { build } from "./build"; export const deployOptions = { configPath: { type: "string", desc: "Path to the config file" }, @@ -60,7 +47,6 @@ export async function runDeploy(opts: DeployOptions): Promise { const srcDir = opts.srcDir ?? (await getSrcDirectory(profile)); const outDir = await getOutDirectory(profile); - const remappings = await getRemappings(); const rpc = opts.rpc ?? (await getRpcUrl(profile)); console.log( @@ -71,24 +57,7 @@ export async function runDeploy(opts: DeployOptions): Promise { // Run build if (!opts.skipBuild) { - const outPath = path.join(srcDir, config.codegenDirectory); - await Promise.all([tablegen(config, outPath, remappings), worldgen(config, getExistingContracts(srcDir), outPath)]); - - // TODO remove when https://github.com/foundry-rs/foundry/issues/6241 is resolved - const forgeConfig = await getForgeConfig(profile); - if (forgeConfig.cache) { - const cacheFilePath = path.join(forgeConfig.cache_path, "solidity-files-cache.json"); - if (existsSync(cacheFilePath)) { - debug("Unsetting cached content hash of IWorld.sol to force it to regenerate"); - const solidityFilesCache = JSON.parse(readFileSync(cacheFilePath, "utf8")); - const worldInterfacePath = path.join(outPath, "world", "IWorld.sol"); - solidityFilesCache["files"][worldInterfacePath]["contentHash"] = ""; - writeFileSync(cacheFilePath, JSON.stringify(solidityFilesCache, null, 2)); - } - } - - await forge(["build"], { profile }); - await execa("mud", ["abi-ts"], { stdio: "inherit" }); + await build({ config, srcDir, foundryProfile: profile }); } const privateKey = process.env.PRIVATE_KEY as Hex; diff --git a/templates/phaser/packages/contracts/package.json b/templates/phaser/packages/contracts/package.json index 87e0fa2db6..aa7c055744 100644 --- a/templates/phaser/packages/contracts/package.json +++ b/templates/phaser/packages/contracts/package.json @@ -4,10 +4,8 @@ "private": true, "license": "MIT", "scripts": { - "build": "pnpm run build:mud && pnpm run build:abi && pnpm run build:abi-ts", - "build:abi": "forge build", - "build:abi-ts": "mud abi-ts", - "build:mud": "rimraf src/codegen && mud tablegen && mud worldgen", + "build": "mud build", + "clean": "forge clean && rimraf src/codegen", "deploy:local": "pnpm run build && mud deploy", "deploy:testnet": "pnpm run build && mud deploy --profile=lattice-testnet", "dev": "pnpm mud dev-contracts", diff --git a/templates/react-ecs/packages/contracts/package.json b/templates/react-ecs/packages/contracts/package.json index 87e0fa2db6..aa7c055744 100644 --- a/templates/react-ecs/packages/contracts/package.json +++ b/templates/react-ecs/packages/contracts/package.json @@ -4,10 +4,8 @@ "private": true, "license": "MIT", "scripts": { - "build": "pnpm run build:mud && pnpm run build:abi && pnpm run build:abi-ts", - "build:abi": "forge build", - "build:abi-ts": "mud abi-ts", - "build:mud": "rimraf src/codegen && mud tablegen && mud worldgen", + "build": "mud build", + "clean": "forge clean && rimraf src/codegen", "deploy:local": "pnpm run build && mud deploy", "deploy:testnet": "pnpm run build && mud deploy --profile=lattice-testnet", "dev": "pnpm mud dev-contracts", diff --git a/templates/react/packages/contracts/package.json b/templates/react/packages/contracts/package.json index 87e0fa2db6..aa7c055744 100644 --- a/templates/react/packages/contracts/package.json +++ b/templates/react/packages/contracts/package.json @@ -4,10 +4,8 @@ "private": true, "license": "MIT", "scripts": { - "build": "pnpm run build:mud && pnpm run build:abi && pnpm run build:abi-ts", - "build:abi": "forge build", - "build:abi-ts": "mud abi-ts", - "build:mud": "rimraf src/codegen && mud tablegen && mud worldgen", + "build": "mud build", + "clean": "forge clean && rimraf src/codegen", "deploy:local": "pnpm run build && mud deploy", "deploy:testnet": "pnpm run build && mud deploy --profile=lattice-testnet", "dev": "pnpm mud dev-contracts", diff --git a/templates/threejs/packages/contracts/package.json b/templates/threejs/packages/contracts/package.json index 028d1ccc55..eaf3a8b0b8 100644 --- a/templates/threejs/packages/contracts/package.json +++ b/templates/threejs/packages/contracts/package.json @@ -4,10 +4,8 @@ "private": true, "license": "MIT", "scripts": { - "build": "pnpm run build:mud && pnpm run build:abi && pnpm run build:abi-ts", - "build:abi": "forge build", - "build:abi-ts": "mud abi-ts", - "build:mud": "rimraf src/codegen && mud tablegen && mud worldgen", + "build": "mud build", + "clean": "forge clean && rimraf src/codegen", "deploy:local": "pnpm run build && mud deploy", "deploy:testnet": "pnpm run build && mud deploy --profile=lattice-testnet", "dev": "pnpm mud dev-contracts", diff --git a/templates/vanilla/packages/contracts/package.json b/templates/vanilla/packages/contracts/package.json index 87e0fa2db6..aa7c055744 100644 --- a/templates/vanilla/packages/contracts/package.json +++ b/templates/vanilla/packages/contracts/package.json @@ -4,10 +4,8 @@ "private": true, "license": "MIT", "scripts": { - "build": "pnpm run build:mud && pnpm run build:abi && pnpm run build:abi-ts", - "build:abi": "forge build", - "build:abi-ts": "mud abi-ts", - "build:mud": "rimraf src/codegen && mud tablegen && mud worldgen", + "build": "mud build", + "clean": "forge clean && rimraf src/codegen", "deploy:local": "pnpm run build && mud deploy", "deploy:testnet": "pnpm run build && mud deploy --profile=lattice-testnet", "dev": "pnpm mud dev-contracts",