| import fs from "node:fs/promises"; |
| import path from "node:path"; |
|
|
| const pointerPrefix = "version https://git-lfs.github.com/spec/v1"; |
| const publicRoot = path.join(process.cwd(), "public"); |
| const spaceRepo = process.env.TRIWORLDBENCH_SPACE_REPO?.trim(); |
| const revision = process.env.HF_REVISION?.trim() || "main"; |
| const assetExtensions = new Set([".gif", ".jpeg", ".jpg", ".mp4", ".pdf", ".png", ".svg", ".webp"]); |
|
|
| async function collectFiles(directory) { |
| const entries = await fs.readdir(directory, { withFileTypes: true }); |
| const files = []; |
| for (const entry of entries) { |
| const entryPath = path.join(directory, entry.name); |
| if (entry.isDirectory()) { |
| files.push(...await collectFiles(entryPath)); |
| } else if (entry.isFile() && assetExtensions.has(path.extname(entry.name).toLowerCase())) { |
| files.push(entryPath); |
| } |
| } |
| return files; |
| } |
|
|
| async function isLfsPointer(filePath) { |
| const contents = await fs.readFile(filePath, "utf8").catch(() => ""); |
| return contents.startsWith(pointerPrefix); |
| } |
|
|
| function assetUrl(relativePath) { |
| const encodedRepo = spaceRepo.split("/").map(encodeURIComponent).join("/"); |
| const encodedPath = relativePath.split("/").map(encodeURIComponent).join("/"); |
| return `https://huggingface.co/spaces/${encodedRepo}/resolve/${encodeURIComponent(revision)}/public/${encodedPath}`; |
| } |
|
|
| const files = await collectFiles(publicRoot); |
| const pointerFiles = []; |
| for (const filePath of files) { |
| if (await isLfsPointer(filePath)) { |
| pointerFiles.push(filePath); |
| } |
| } |
|
|
| if (!pointerFiles.length) { |
| console.log("No Git LFS public assets need restoration."); |
| process.exit(0); |
| } |
|
|
| if (!spaceRepo || spaceRepo.split("/").length !== 2) { |
| throw new Error("TRIWORLDBENCH_SPACE_REPO is required to restore Git LFS public assets."); |
| } |
|
|
| for (const filePath of pointerFiles) { |
| const relativePath = path.relative(publicRoot, filePath).split(path.sep).join("/"); |
| const response = await fetch(assetUrl(relativePath)); |
| if (!response.ok) { |
| throw new Error(`Could not restore ${relativePath}: ${response.status} ${response.statusText}`); |
| } |
| const contents = Buffer.from(await response.arrayBuffer()); |
| if (contents.subarray(0, pointerPrefix.length).toString("utf8") === pointerPrefix) { |
| throw new Error(`Resolved asset is still a Git LFS pointer: ${relativePath}`); |
| } |
| const temporaryPath = `${filePath}.restore-${process.pid}`; |
| await fs.writeFile(temporaryPath, contents); |
| await fs.rename(temporaryPath, filePath); |
| console.log(`Restored public asset: ${relativePath}`); |
| } |
|
|