import chalk from "chalk"; import { execSync } from "child_process"; import { readdirSync } from "fs"; import fs from "fs-extra"; import path from "path"; import { PolarError } from "../../internal/core/errors"; import { ERRORS } from "../../internal/core/errors-list"; import { ARTIFACTS_DIR, assertDir, CACHE_DIR, CONTRACTS_DIR, SCHEMA_DIR, TARGET_DIR } from "../../internal/core/project-structure"; import { replaceAll } from "../../internal/util/strings"; export async function compile ( docker: boolean, sourceDir: string[], force: boolean, skipSchema: boolean ): Promise { await assertDir(CACHE_DIR); let contractDirs: string[] = []; const toml = "Cargo.toml"; // Contract(s) path given if (sourceDir.length > 0) { contractDirs = sourceDir; } else { const paths = readdirSync(CONTRACTS_DIR); // Only one contract in the contracts dir and compile in contracts dir only if (paths.includes(toml)) { contractDirs.push(CONTRACTS_DIR); } else { // Multiple contracts and each should be compiled by going inside each of them const contractNames = new Set(); for (const p of paths) { const contractPath = path.join(CONTRACTS_DIR, path.basename(p)); const val = readContractName(path.join(contractPath, toml)); // Check for similar contract names before compiling contracts. // For contract with same names raise an error. if (contractNames.has(val)) { throw new PolarError(ERRORS.GENERAL.SAME_CONTRACT_NAMES, { val }); } else { contractNames.add(readContractName(path.join(contractPath, toml))); contractDirs.push(contractPath); } } } } for (const dir of contractDirs) { compileContract(dir, docker); if (!skipSchema) { // only generate schema if this flag is not passed generateSchema(dir, docker); } const contractName = readContractName(path.join(dir, toml)); createArtifacts( TARGET_DIR, path.join(SCHEMA_DIR, contractName), path.join(ARTIFACTS_DIR, CONTRACTS_DIR), path.join(dir, "schema"), docker, skipSchema ); } } export function readContractName (tomlFilePath: string): string { const tomlFileContent: string = fs.readFileSync(tomlFilePath, 'utf-8'); return replaceAll(tomlFileContent.split('\n')[1].split("\"")[1], '-', '_'); } export function compileContract (contractDir: string, docker: boolean): void { const currDir = process.cwd(); process.chdir(contractDir); console.log(`🛠 Compiling your contract in directory: ${chalk.gray(contractDir)}`); console.log("==========================================="); // Compiles the contract and creates .wasm file alongside others try { execSync(`RUSTFLAGS='-C link-arg=-s' cargo build --release --target wasm32-unknown-unknown`, { stdio: 'inherit' }); } catch (error) { if (error instanceof Error) { throw new PolarError(ERRORS.GENERAL.RUST_COMPILE_ERROR); } else { throw error; } } process.chdir(currDir); } export function generateSchema (contractDir: string, docker: boolean): void { const currDir = process.cwd(); process.chdir(contractDir); console.log(`Creating schema for contract in directory: ${chalk.gray(contractDir)}`); // Creates schema .json files execSync(`cargo run --example schema`, { stdio: 'inherit' }); process.chdir(currDir); } export function createArtifacts ( targetDir: string, schemaDir: string, artifactsDir: string, sourceSchemaDir: string, docker: boolean, skipSchema: boolean ): void { const paths = fs.readdirSync(targetDir); // create nested dirs if not present if (!fs.existsSync(artifactsDir)) { fs.mkdirSync(artifactsDir, { recursive: true }); } if (!fs.existsSync(schemaDir)) { fs.mkdirSync(schemaDir, { recursive: true }); } for (const p of paths) { const filename = path.basename(p); if (filename.split('.')[filename.split('.').length - 1] !== "wasm") { continue; } console.log(`Copying file ${filename} from ${chalk.gray(targetDir)} to ${chalk.gray(artifactsDir)}`); const sourcePath = path.resolve(targetDir, filename); const destPath = path.resolve(artifactsDir, filename); fs.copyFileSync(sourcePath, destPath); } if (skipSchema) { // do not copy schema to artifacts as there is none return; } const schemaPaths = fs.readdirSync(sourceSchemaDir); for (const p of schemaPaths) { const filename = path.basename(p); if (filename.split('.')[filename.split('.').length - 1] !== "json") { continue; } console.log( `Copying file ${filename} from ${chalk.gray(sourceSchemaDir)} to ${chalk.gray(schemaDir)}` ); const sourcePath = path.resolve(sourceSchemaDir, filename); const destPath = path.resolve(schemaDir, filename); fs.copyFileSync(sourcePath, destPath); } }