diff --git a/v-next/core/src/global-dir.ts b/v-next/core/src/global-dir.ts index d5e189810f..f385a009ce 100644 --- a/v-next/core/src/global-dir.ts +++ b/v-next/core/src/global-dir.ts @@ -1,7 +1,7 @@ import { ensureDir } from "@ignored/hardhat-vnext-utils/fs"; /** - * Returns the path to the hardhat configuration directory. + * Returns the path to the hardhat configuration directory. * * @returns The path to the hardhat configuration directory. */ @@ -11,6 +11,17 @@ export async function getConfigDir(): Promise { return config; } +/** + * Returns the path to the hardhat cache directory. + * + * @returns The path to the hardhat cache directory. + */ +export async function getCacheDir(): Promise { + const { cache } = await generatePaths(); + await ensureDir(cache); + return cache; +} + async function generatePaths(packageName = "hardhat") { const { default: envPaths } = await import("env-paths"); return envPaths(packageName); diff --git a/v-next/core/src/internal/hre.ts b/v-next/core/src/internal/hre.ts index b6ae2c0193..d321837155 100644 --- a/v-next/core/src/internal/hre.ts +++ b/v-next/core/src/internal/hre.ts @@ -196,6 +196,8 @@ async function resolveUserConfig( tasks: config.tasks ?? [], paths: { root: projectRoot, + cache: config.paths?.cache ?? "", // TODO: resolve cache path + artifacts: config.paths?.artifacts ?? "", // TODO: resolve artifacts path }, }; diff --git a/v-next/core/src/types/config.ts b/v-next/core/src/types/config.ts index dce20bc624..b0e16b540a 100644 --- a/v-next/core/src/types/config.ts +++ b/v-next/core/src/types/config.ts @@ -52,8 +52,11 @@ export interface HardhatUserConfig { /** * The different paths that conform a Hardhat project. */ -// eslint-disable-next-line @typescript-eslint/no-empty-interface -- TODO: add the paths -export interface ProjectPathsUserConfig {} +export interface ProjectPathsUserConfig { + root?: string; + cache?: string; + artifacts?: string; +} /** * The resolved Hardhat configuration. @@ -64,4 +67,6 @@ export interface HardhatConfig { export interface ProjectPathsConfig { root: string; + cache: string; + artifacts: string; } diff --git a/v-next/core/test/internal/configuration-variables/configuration-variables.ts b/v-next/core/test/internal/configuration-variables/configuration-variables.ts index 081fa9e3b9..77d95e0d60 100644 --- a/v-next/core/test/internal/configuration-variables/configuration-variables.ts +++ b/v-next/core/test/internal/configuration-variables/configuration-variables.ts @@ -26,6 +26,8 @@ describe("ResolvedConfigurationVariable", () => { plugins: [], paths: { root: projectRoot, + cache: "", + artifacts: "", }, }, hooks: hookManager, diff --git a/v-next/core/test/internal/hook-manager.ts b/v-next/core/test/internal/hook-manager.ts index 826ba02103..3bc72974c9 100644 --- a/v-next/core/test/internal/hook-manager.ts +++ b/v-next/core/test/internal/hook-manager.ts @@ -103,6 +103,8 @@ describe("HookManager", () => { plugins: [], paths: { root: projectRoot, + cache: "", + artifacts: "", }, }, hooks: hookManager, @@ -171,6 +173,8 @@ describe("HookManager", () => { tasks: [], paths: { root: projectRoot, + cache: "", + artifacts: "", }, }; @@ -224,6 +228,8 @@ describe("HookManager", () => { tasks: [], paths: { root: projectRoot, + cache: "", + artifacts: "", }, }; @@ -327,6 +333,8 @@ describe("HookManager", () => { plugins: [], paths: { root: projectRoot, + cache: "", + artifacts: "", }, }, hooks: hookManager, @@ -345,6 +353,8 @@ describe("HookManager", () => { tasks: [], paths: { root: projectRoot, + cache: "", + artifacts: "", }, }; @@ -429,6 +439,8 @@ describe("HookManager", () => { tasks: [], paths: { root: projectRoot, + cache: "", + artifacts: "", }, }; @@ -550,6 +562,8 @@ describe("HookManager", () => { plugins: [], paths: { root: projectRoot, + cache: "", + artifacts: "", }, }, hooks: hookManager, @@ -642,6 +656,8 @@ describe("HookManager", () => { tasks: [], paths: { root: projectRoot, + cache: "", + artifacts: "", }, }; @@ -684,6 +700,8 @@ describe("HookManager", () => { plugins: [], paths: { root: projectRoot, + cache: "", + artifacts: "", }, }, hooks: hookManager, @@ -700,6 +718,8 @@ describe("HookManager", () => { tasks: [], paths: { root: projectRoot, + cache: "", + artifacts: "", }, }; @@ -718,6 +738,8 @@ describe("HookManager", () => { tasks: [], paths: { root: projectRoot, + cache: "", + artifacts: "", }, }; @@ -801,6 +823,8 @@ describe("HookManager", () => { tasks: [], paths: { root: projectRoot, + cache: "", + artifacts: "", }, }; @@ -843,6 +867,8 @@ describe("HookManager", () => { plugins: [], paths: { root: projectRoot, + cache: "", + artifacts: "", }, }, hooks: hookManager, @@ -1002,6 +1028,8 @@ function buildMockHardhatRuntimeEnvironment( plugins: [], paths: { root: projectRoot, + cache: "", + artifacts: "", }, }, tasks: mockTaskManager, diff --git a/v-next/core/test/internal/user-interruptions/user-interruptions-manager.ts b/v-next/core/test/internal/user-interruptions/user-interruptions-manager.ts index 29b5edefc7..c438702bbe 100644 --- a/v-next/core/test/internal/user-interruptions/user-interruptions-manager.ts +++ b/v-next/core/test/internal/user-interruptions/user-interruptions-manager.ts @@ -30,6 +30,8 @@ describe("UserInterruptionManager", () => { plugins: [], paths: { root: projectRoot, + cache: "", + artifacts: "", }, }, globalOptions: {}, @@ -74,6 +76,8 @@ describe("UserInterruptionManager", () => { plugins: [], paths: { root: projectRoot, + cache: "", + artifacts: "", }, }, globalOptions: {}, @@ -120,6 +124,8 @@ describe("UserInterruptionManager", () => { plugins: [], paths: { root: projectRoot, + cache: "", + artifacts: "", }, }, globalOptions: {}, diff --git a/v-next/hardhat/src/internal/builtin-plugins/clean/index.ts b/v-next/hardhat/src/internal/builtin-plugins/clean/index.ts new file mode 100644 index 0000000000..e178b72c05 --- /dev/null +++ b/v-next/hardhat/src/internal/builtin-plugins/clean/index.ts @@ -0,0 +1,18 @@ +import type { HardhatPlugin } from "@ignored/hardhat-vnext-core/types/plugins"; + +import { task } from "@ignored/hardhat-vnext-core/config"; + +const hardhatPlugin: HardhatPlugin = { + id: "clean", + tasks: [ + task("clean", "Clears the cache and deletes all artifacts") + .addFlag({ + name: "global", + description: "Clear the global cache", + }) + .setAction(import.meta.resolve("./task-action.js")) + .build(), + ], +}; + +export default hardhatPlugin; diff --git a/v-next/hardhat/src/internal/builtin-plugins/clean/task-action.ts b/v-next/hardhat/src/internal/builtin-plugins/clean/task-action.ts new file mode 100644 index 0000000000..2a945112fb --- /dev/null +++ b/v-next/hardhat/src/internal/builtin-plugins/clean/task-action.ts @@ -0,0 +1,23 @@ +import type { NewTaskActionFunction } from "@ignored/hardhat-vnext-core/types/tasks"; + +import { getCacheDir } from "@ignored/hardhat-vnext-core/global-dir"; +import { emptyDir, remove } from "@ignored/hardhat-vnext-utils/fs"; + +interface CleanActionArguments { + global: boolean; +} + +const cleanAction: NewTaskActionFunction = async ( + { global }, + { config }, +) => { + if (global) { + const globalCacheDir = await getCacheDir(); + await emptyDir(globalCacheDir); + } + + await emptyDir(config.paths.cache); + await remove(config.paths.artifacts); +}; + +export default cleanAction; diff --git a/v-next/hardhat/src/internal/builtin-plugins/index.ts b/v-next/hardhat/src/internal/builtin-plugins/index.ts index ee40508234..d8a7773f4b 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/index.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/index.ts @@ -1,11 +1,13 @@ import type { HardhatPlugin } from "@ignored/hardhat-vnext-core/types/plugins"; +import clean from "./clean/index.js"; import hardhatFoo from "./hardhat-foo/index.js"; import run from "./run/index.js"; // Note: When importing a plugin, you have to export its types, so that its // type extensions, if any, also get loaded. +export type * from "./clean/index.js"; export type * from "./hardhat-foo/index.js"; export type * from "./run/index.js"; -export const builtinPlugins: HardhatPlugin[] = [hardhatFoo, run]; +export const builtinPlugins: HardhatPlugin[] = [clean, hardhatFoo, run]; diff --git a/v-next/hardhat/test/internal/builtin-plugins/clean/task-action.ts b/v-next/hardhat/test/internal/builtin-plugins/clean/task-action.ts new file mode 100644 index 0000000000..8ef0324283 --- /dev/null +++ b/v-next/hardhat/test/internal/builtin-plugins/clean/task-action.ts @@ -0,0 +1,118 @@ +import type { HardhatRuntimeEnvironment } from "@ignored/hardhat-vnext-core/types/hre"; + +import assert from "node:assert/strict"; +import path from "node:path"; +import { before, beforeEach, describe, it } from "node:test"; + +import { getCacheDir } from "@ignored/hardhat-vnext-core/global-dir"; +import { + exists, + mkdir, + readdir, + remove, + writeUtf8File, +} from "@ignored/hardhat-vnext-utils/fs"; + +import { createHardhatRuntimeEnvironment } from "../../../../src/hre.js"; +import cleanAction from "../../../../src/internal/builtin-plugins/clean/task-action.js"; +import { useFixtureProject } from "../../../helpers/project.js"; + +let hre: HardhatRuntimeEnvironment; +let globalCacheDir: string; +let cacheDir: string; +let artifactsDir: string; + +function assertCleanBehavior(global: boolean) { + it("should clean the cache and artifacts directories", async () => { + await cleanAction({ global }, hre); + + // If the cache dir exists, it should be empty + if (await exists(cacheDir)) { + const cacheContents = await readdir(cacheDir); + assert.ok(cacheContents.length === 0, "Cache dir is not empty"); + } + + // The artifacts dir should not exist + assert.ok(!(await exists(artifactsDir)), "Artifacts dir exists"); + + // If the global cache dir exists, it should be empty if the global flag is + // true, and not empty otherwise + if (await exists(globalCacheDir)) { + const globalCacheContents = await readdir(globalCacheDir); + if (global) { + assert.ok( + globalCacheContents.length === 0, + "Global cache dir is not empty", + ); + } else { + assert.ok( + globalCacheContents.length > 0, + "Global cache dir is empty when it shouldn't be", + ); + } + } + }); +} + +describe("clean/task-action", () => { + describe("cleanAction", () => { + useFixtureProject("loaded-config"); + + before(async function () { + globalCacheDir = await getCacheDir(); + cacheDir = path.join(process.cwd(), "cache"); + artifactsDir = path.join(process.cwd(), "artifacts"); + hre = await createHardhatRuntimeEnvironment({ + // TODO remove this once cache and artifacts are resolved in the config + paths: { cache: cacheDir, artifacts: artifactsDir }, + }); + }); + + describe("when cache and artifact dirs don't exist", async () => { + beforeEach(async () => { + await remove(globalCacheDir); + await remove(cacheDir); + await remove(artifactsDir); + }); + + assertCleanBehavior(true); + }); + + describe("when cache and artifact are empty dirs", async () => { + beforeEach(async () => { + await remove(globalCacheDir); + await remove(cacheDir); + await remove(artifactsDir); + await getCacheDir(); // Calling this recreates the cache dir + await mkdir(cacheDir); + await mkdir(artifactsDir); + }); + + assertCleanBehavior(true); + }); + + describe("when cache and artifact dirs aren't empty", async () => { + beforeEach(async () => { + await remove(globalCacheDir); + await remove(cacheDir); + await remove(artifactsDir); + await getCacheDir(); // Calling this recreates the cache dir + await writeUtf8File(path.join(globalCacheDir, "a"), ""); + await writeUtf8File(path.join(cacheDir, "a"), ""); + await writeUtf8File(path.join(artifactsDir, "a"), ""); + }); + + assertCleanBehavior(true); + }); + + describe("when global flag is false", async () => { + beforeEach(async () => { + await remove(globalCacheDir); + await getCacheDir(); // Calling this recreates the cache dir + await writeUtf8File(path.join(globalCacheDir, "a"), ""); + }); + + assertCleanBehavior(false); + }); + }); +}); diff --git a/v-next/hardhat/test/internal/builtin-plugins/run/task-action.ts b/v-next/hardhat/test/internal/builtin-plugins/run/task-action.ts index 2da9b968a4..85caa2ef25 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/run/task-action.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/run/task-action.ts @@ -9,7 +9,7 @@ import { createHardhatRuntimeEnvironment } from "../../../../src/hre.js"; import runScriptWithHardhat from "../../../../src/internal/builtin-plugins/run/task-action.js"; import { useFixtureProject } from "../../../helpers/project.js"; -describe("runScriptWithHardhat", function () { +describe("run/task-action", function () { let hre: HardhatRuntimeEnvironment; before(async function () { diff --git a/v-next/hardhat/test/internal/cli/main.ts b/v-next/hardhat/test/internal/cli/main.ts index 6523860faf..64036921ad 100644 --- a/v-next/hardhat/test/internal/cli/main.ts +++ b/v-next/hardhat/test/internal/cli/main.ts @@ -222,6 +222,7 @@ Usage: hardhat [GLOBAL OPTIONS] [SUBTASK] [TASK OPTIONS] [--] [TASK ARGUM AVAILABLE TASKS: + clean Clears the cache and deletes all artifacts example Example task run Runs a user-defined script after compiling the project task A task that uses arg1