Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

developing extension(part 1) #73

Merged
merged 34 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
8b7ea5c
very basic script, pick last commit and create file
technophile-04 Jul 2, 2024
a7895c1
copy all the changes from first commit to last commit
technophile-04 Jul 2, 2024
1f99e61
ignore template files from being copied
technophile-04 Jul 3, 2024
93c7e79
Merge branch 'main' into developer-extension-v0.2
technophile-04 Jul 5, 2024
2616e86
use path.sep for showing the path
technophile-04 Jul 5, 2024
4861d10
prettylogs
technophile-04 Jul 5, 2024
b79ca6e
remove first commit function
technophile-04 Jul 5, 2024
556c06c
use fs promises directly
technophile-04 Jul 5, 2024
5d7d5a0
make literal paths to constant variables
technophile-04 Jul 5, 2024
db5d78f
use create-extension-cli to store build of create-extension cli
technophile-04 Jul 5, 2024
4cb6720
don't gitignore create-extension-cli output
technophile-04 Jul 5, 2024
264a625
fix forge install creating multiple commits
technophile-04 Jul 5, 2024
a403468
ignore yarn.lock file
technophile-04 Jul 5, 2024
b8a9c53
build create-extension
technophile-04 Jul 5, 2024
961251c
create BASE_DIR and SOLIDITY_FRAMEWORKS_DIR in const and use it
technophile-04 Jul 6, 2024
ad55ab1
rename parseArguments => getProjectPath
technophile-04 Jul 6, 2024
10a808f
remove getChangedFiles function
technophile-04 Jul 6, 2024
e340ecb
skip package.json from copying
technophile-04 Jul 6, 2024
759bc27
generate create-extension inside generated dir
technophile-04 Jul 6, 2024
fc4eedd
move output in dist dir
technophile-04 Jul 7, 2024
d39304f
create output in dist/create-extension
technophile-04 Jul 7, 2024
d7436c2
move rollup config inside dev folder
technophile-04 Jul 7, 2024
de256c7
don't use .dev in rollup config
technophile-04 Jul 7, 2024
c5975c9
fix templates dir path
technophile-04 Jul 7, 2024
e535a46
fix spell of manually
technophile-04 Jul 9, 2024
f2cf80c
don't copy normal file only allow new files
technophile-04 Jul 12, 2024
4e86914
cleanup
technophile-04 Jul 12, 2024
5dee9a5
add spaces b/w continue condition
technophile-04 Jul 12, 2024
870079c
update tickmark emoji
technophile-04 Jul 12, 2024
748ba19
Merge branch 'main' into developer-extension-v0.2
carletex Jul 16, 2024
0274afe
remove unecessary shouldSkipFile abstractions
technophile-04 Jul 16, 2024
a0f0ad1
use error instead of warning while skipping core files
technophile-04 Jul 16, 2024
680ddcf
use word ignored instead of skipping for coreFiles
technophile-04 Jul 16, 2024
597040f
Merge branch 'main' into developer-extension-v0.2
technophile-04 Jul 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
"bin": "bin/create-dapp-se2.js",
"scripts": {
"build": "rollup -c rollup.config.js",
"build:dev": "yarn build && rollup -c src/dev/rollup.config.js",
"create-extension": "node dist/create-extension/create-extension.js",
"dev": "rollup -c rollup.config.js --watch",
"cli": "node bin/create-dapp-se2.js",
"lint": "eslint .",
Expand Down
170 changes: 170 additions & 0 deletions src/dev/create-extension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import arg from "arg";
import path from "path";
import fs from "fs";
import { promisify } from "util";
import { execa } from "execa";
import ncp from "ncp";
import { fileURLToPath } from "url";
import { BASE_DIR, SOLIDITY_FRAMEWORKS, SOLIDITY_FRAMEWORKS_DIR } from "../utils/consts";
import chalk from "chalk";

const EXTERNAL_EXTENSIONS_DIR = "externalExtensions";
const TARGET_EXTENSION_DIR = "extension";
const TEMPLATE_FILE_SUFFIX = ".template.mjs";
const DEPLOYED_CONTRACTS_FILE = "deployedContracts.ts";
const YARN_LOCK_FILE = "yarn.lock";
const PACKAGE_JSON_FILE = "package.json";
const NEXTJS_DIR = "nextjs";

const prettyLog = {
info: (message: string, indent = 0) => console.log(chalk.cyan(`${" ".repeat(indent)}${message}`)),
success: (message: string, indent = 0) => console.log(chalk.green(`${" ".repeat(indent)}✔︎ ${message}`)),
warning: (message: string, indent = 0) => console.log(chalk.yellow(`${" ".repeat(indent)}⚠ ${message}`)),
error: (message: string, indent = 0) => console.log(chalk.red(`${" ".repeat(indent)}✖ ${message}`)),
};

const ncpPromise = promisify(ncp);

const currentFileUrl = import.meta.url;
const templateDirectory = path.resolve(decodeURI(fileURLToPath(currentFileUrl)), "../../../templates");

const getProjectPath = (rawArgs: string[]) => {
const args = arg({}, { argv: rawArgs.slice(2) });
const projectPath = args._[0];
if (!projectPath) {
throw new Error("Project path is required");
}
return { projectPath };
};

const getChangedFilesFromFirstCommit = async (projectPath: string): Promise<string[]> => {
const { stdout: firstCommit } = await execa("git", ["rev-list", "--max-parents=0", "HEAD"], {
cwd: projectPath,
});
const { stdout } = await execa("git", ["diff", "--name-only", `${firstCommit.trim()}..HEAD`], {
cwd: projectPath,
});
return stdout.split("\n").filter(Boolean);
};

const createDirectories = async (filePath: string, projectName: string) => {
const dirPath = path.join(EXTERNAL_EXTENSIONS_DIR, projectName, TARGET_EXTENSION_DIR, path.dirname(filePath));
await fs.promises.mkdir(dirPath, { recursive: true });
};

const findTemplateFiles = async (dir: string, templates: Set<string>) => {
const files = await fs.promises.readdir(dir, { withFileTypes: true });
for (const file of files) {
const fullPath = path.join(dir, file.name);
if (file.isDirectory()) {
await findTemplateFiles(fullPath, templates);
} else if (file.name.endsWith(TEMPLATE_FILE_SUFFIX)) {
let relativePath = path.relative(templateDirectory, fullPath).replace(new RegExp(`${TEMPLATE_FILE_SUFFIX}$`), "");
const pathSegments = relativePath.split(path.sep);

// Normalize the relative path by stripping the initial parts
if (pathSegments[0] === BASE_DIR) {
relativePath = pathSegments.slice(1).join(path.sep);
} else if (pathSegments[0] === SOLIDITY_FRAMEWORKS_DIR) {
const framework = pathSegments[1];
if (Object.values(SOLIDITY_FRAMEWORKS).includes(framework as any)) {
relativePath = pathSegments.slice(2).join(path.sep);
rin-st marked this conversation as resolved.
Show resolved Hide resolved
}
}

templates.add(relativePath);
}
}
};

const copyFiles = async (files: string[], projectName: string, projectPath: string, templates: Set<string>) => {
for (const file of files) {
const pathSegmentsOfFile = file.split(path.sep);
const sourcePath = path.resolve(projectPath, file);
const destPath = path.join(EXTERNAL_EXTENSIONS_DIR, projectName, TARGET_EXTENSION_DIR, file);
const sourceFileName = path.basename(sourcePath);

if (templates.has(file)) {
prettyLog.warning(`Skipping file: ${file}`, 2);
prettyLog.info(`Please instead create/update: ${destPath}.args.mjs`, 3);
console.log("\n");
continue;
}

if (sourceFileName === DEPLOYED_CONTRACTS_FILE) {
prettyLog.warning(`Skipping file: ${file}`, 2);
prettyLog.info(`${sourceFileName} can be generated using \`yarn deploy\``, 3);
console.log("\n");
continue;
}

if (sourceFileName === YARN_LOCK_FILE) {
prettyLog.warning(`Skipping file: ${file}`, 2);
prettyLog.info(`${file} will be generated when doing \`yarn install\``, 3);
console.log("\n");
continue;
}

const isRootPackageJson = pathSegmentsOfFile.length === 1 && pathSegmentsOfFile[0] === PACKAGE_JSON_FILE;
const isNextJsPackageJson =
pathSegmentsOfFile.includes(NEXTJS_DIR) && pathSegmentsOfFile.includes(PACKAGE_JSON_FILE);
const isSolidityFrameworkPackageJson =
(pathSegmentsOfFile.includes(SOLIDITY_FRAMEWORKS.HARDHAT) ||
pathSegmentsOfFile.includes(SOLIDITY_FRAMEWORKS.FOUNDRY)) &&
pathSegmentsOfFile.includes(PACKAGE_JSON_FILE);

if (isRootPackageJson || isNextJsPackageJson || isSolidityFrameworkPackageJson) {
prettyLog.warning(`Skipping file: ${file}`, 2);
prettyLog.info(`Please manually just add new scripts or dependencies in: ${destPath}`, 3);
console.log("\n");
continue;
}

const coreFilesPath = [
path.join(templateDirectory, BASE_DIR, file),
path.join(templateDirectory, SOLIDITY_FRAMEWORKS_DIR, SOLIDITY_FRAMEWORKS.HARDHAT, file),
path.join(templateDirectory, SOLIDITY_FRAMEWORKS_DIR, SOLIDITY_FRAMEWORKS.FOUNDRY, file),
];
if (coreFilesPath.some(fs.existsSync)) {
prettyLog.error(`Ignored file: ${file}`, 2);
prettyLog.info("Only new files can be added", 3);
console.log("\n");
continue;
}

await createDirectories(file, projectName);
await ncpPromise(sourcePath, destPath);
prettyLog.success(`Copied: ${file}`, 2);
console.log("\n");
}
};

const main = async (rawArgs: string[]) => {
try {
const { projectPath } = getProjectPath(rawArgs);
const projectName = path.basename(projectPath);
const templates = new Set<string>();
await findTemplateFiles(templateDirectory, templates);

console.log("\n");
prettyLog.info(`Extension name: ${projectName}\n`);

prettyLog.info("Getting list of changed files...", 1);
const changedFiles = await getChangedFilesFromFirstCommit(projectPath);

if (changedFiles.length === 0) {
prettyLog.warning("No changed files to copy.", 1);
console.log("\n");
} else {
prettyLog.info(`Found ${changedFiles.length} changed files, processing them...`, 1);
console.log("\n");
await copyFiles(changedFiles, projectName, projectPath, templates);
}

prettyLog.info(`Files processed successfully, updated ${EXTERNAL_EXTENSIONS_DIR}/${projectName} directory.`);
} catch (err: any) {
prettyLog.error(`Error: ${err.message}`);
}
};

main(process.argv).catch(() => process.exit(1));
12 changes: 12 additions & 0 deletions src/dev/rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import typescript from "@rollup/plugin-typescript";
import autoExternal from "rollup-plugin-auto-external";

export default {
input: "src/dev/create-extension.ts",
output: {
dir: "dist/create-extension",
format: "es",
sourcemap: true,
},
plugins: [autoExternal(), typescript({ exclude: ["templates/**", "externalExtensions/**"] })],
};
3 changes: 1 addition & 2 deletions src/tasks/copy-template-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ import path from "path";
import { promisify } from "util";
import link from "../utils/link";
import { getArgumentFromExternalExtensionOption } from "../utils/external-extensions";
import { BASE_DIR, SOLIDITY_FRAMEWORKS_DIR } from "../utils/consts";

const BASE_DIR = "base";
const EXTERNAL_EXTENSION_TMP_DIR = "tmp-external-extension";
const SOLIDITY_FRAMEWORKS_DIR = "solidity-frameworks";

const copy = promisify(ncp);
let copyOrLink = copy;
Expand Down
4 changes: 3 additions & 1 deletion src/tasks/create-first-git-commit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ export async function createFirstGitCommit(targetDir: string, options: Options)
if (options.solidityFramework === SOLIDITY_FRAMEWORKS.FOUNDRY) {
const foundryWorkSpacePath = path.resolve(targetDir, "packages", SOLIDITY_FRAMEWORKS.FOUNDRY);
// forge install foundry libraries
await execa("forge", ["install", ...foundryLibraries], { cwd: foundryWorkSpacePath });
await execa("forge", ["install", ...foundryLibraries, "--no-commit"], { cwd: foundryWorkSpacePath });
await execa("git", ["add", "-A"], { cwd: targetDir });
await execa("git", ["commit", "--amend", "--no-edit"], { cwd: targetDir });
technophile-04 marked this conversation as resolved.
Show resolved Hide resolved
}
} catch (e: any) {
// cast error as ExecaError to get stderr
Expand Down
3 changes: 3 additions & 0 deletions src/utils/consts.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
export const BASE_DIR = "base";
export const SOLIDITY_FRAMEWORKS_DIR = "solidity-frameworks";

export const SOLIDITY_FRAMEWORKS = {
HARDHAT: "hardhat",
FOUNDRY: "foundry",
Expand Down
Loading