@needle-tools/engine
Version:
Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.
106 lines (101 loc) • 4.42 kB
JavaScript
import fs, { existsSync, statSync } from 'fs';
import crypto from 'crypto';
import { relative } from 'path';
import { needleLog } from '../vite/logging.js';
/** Create a file containing information about the build inside the build directory
* @param {String} buildDirectory
* @param {{log?:boolean}} [options]
*/
export function createBuildInfoFile(buildDirectory, options = undefined) {
const shouldLog = options?.log !== false;
const rel = (pathValue) => {
const value = relative(process.cwd(), pathValue).replaceAll("\\", "/");
return value?.length ? value : ".";
};
if (!buildDirectory) {
if (shouldLog) needleLog("needle-buildinfo", "Can not create build info file because \"buildDirectory\" is not defined", "warn", { dimBody: false });
return { ok: false, error: "buildDirectory is not defined" };
}
// start creating the buildinfo
const buildInfo = {
time: new Date().toISOString(),
totalsize: 0,
files: []
};
if (shouldLog) needleLog("needle-buildinfo", `Begin collecting files in \"${rel(buildDirectory)}\"`);
recursivelyCollectFiles(buildDirectory, "", buildInfo);
const buildInfoPath = `${buildDirectory}/needle.buildinfo.json`;
const totalSizeInMB = buildInfo.totalsize / 1024 / 1024;
if (shouldLog) needleLog("needle-buildinfo", `Collected ${buildInfo.files.length} files (${totalSizeInMB.toFixed(2)} MB). Writing build info to \"${rel(buildInfoPath)}\"`);
const str = JSON.stringify(buildInfo);
fs.writeFileSync(buildInfoPath, str);
if(!existsSync(buildDirectory)) {
if (shouldLog) needleLog("needle-buildinfo", `Could not write build info file to \"${rel(buildInfoPath)}\"`, "warn", { dimBody: false });
return { ok: false, error: `Could not write build info file to \"${rel(buildInfoPath)}\"` };
}
if (shouldLog) needleLog("needle-buildinfo", `Build info file successfully written to \"${rel(buildInfoPath)}\"`);
return {
ok: true,
buildDirectory: rel(buildDirectory),
buildInfoPath: rel(buildInfoPath),
fileCount: buildInfo.files.length,
totalSizeBytes: buildInfo.totalsize,
totalSizeInMB,
};
}
/**
* Collect information about the build output directory, such as total file count and size
* @param {String} buildDirectory
* @returns {import("./buildinfo").BuildInfo}
*/
export function collectBuildDirectoryStats(buildDirectory) {
if (!buildDirectory || !existsSync(buildDirectory)) {
return {
fileCount: 0,
totalSizeBytes: 0,
totalSizeInMB: 0,
};
}
const info = {
totalsize: 0,
files: [],
};
recursivelyCollectFiles(buildDirectory, "", info);
return {
fileCount: info.files.length,
totalSizeBytes: info.totalsize,
totalSizeInMB: info.totalsize / 1024 / 1024,
};
}
/** Recursively collect all files in a directory
* @param {String} directory to search
* @param {{ time?: string, files: Array<{path:string, hash:string, size:number}>, totalsize:number }} info
*/
function recursivelyCollectFiles(directory, path, info) {
const entries = fs.readdirSync(directory, { withFileTypes: true });
for (const entry of entries) {
if (entry.isDirectory()) {
// make sure we never collect files inside node_modules
if (entry.name === "node_modules") {
needleLog("needle-buildinfo", "Skipping node_modules directory at " + path, "warn", { dimBody: false });
continue;
}
const newPath = path?.length <= 0 ? entry.name : `${path}/${entry.name}`;
const newDirectory = `${directory}/${entry.name}`;
recursivelyCollectFiles(newDirectory, newPath, info);
} else {
const relpath = path?.length <= 0 ? entry.name : `${path}/${entry.name}`;
// console.log("[needle-buildinfo] - New File: " + relpath);
const filehash = crypto.createHash('sha256');
const fullpath = `${directory}/${entry.name}`;
filehash.update(fs.readFileSync(fullpath));
const stats = statSync(fullpath);
info.files.push({
path: relpath,
hash: filehash.digest('hex'),
size: stats.size
});
info.totalsize += stats.size;
}
}
}