Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 17 additions & 1 deletion bend2/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,16 @@ function path_real(p: string): string {
return fs.existsSync(p) ? fs.realpathSync(p) : path.resolve(p);
}

// same_file compares device and inode, so links to one file agree.
function same_file(a: string, b: string): boolean {
if (!fs.existsSync(a) || !fs.existsSync(b)) {
return false;
}
const x = fs.statSync(a, { bigint: true });
const y = fs.statSync(b, { bigint: true });
return x.dev === y.dev && x.ino === y.ino;
}

function cli_emit(book: Bend.Book, out: string): void {
if (out.endsWith(".mjs")) {
fs.writeFileSync(out, Comp.js_lib(book, true));
Expand Down Expand Up @@ -572,8 +582,14 @@ async function cli_bundle(page: string, dir: string): Promise<void> {
},
};
try {
// Only the page keeps its name in the bundle (chunks and assets are hashed),
// so it is the input an -o can overwrite: refuse that, through links too.
const entry = path_real(page);
if (same_file(path.join(dir, path.basename(entry)), entry)) {
cli_fail("-o " + dir + " would overwrite the page");
}
const out = await Bun.build({
entrypoints: [page],
entrypoints: [entry],
outdir: dir,
target: "browser",
minify: true,
Expand Down
14 changes: 14 additions & 0 deletions tests/io/bundle_page_input.bend
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# A page bundled into a directory that already holds it (directly, through a
# symlink or a hard link) is refused and left intact; a symlinked page builds
# under its target's name; a missing page keeps Bun's entry error.
import Base

def Bundle.page_input() -> IO(U32):
import "./bundle_page_input.js"

def main() -> IO(Unit):
do IO<Unit>:
value : U32 <- Bundle.page_input()
IO.print(U32.show(value))

#|0
57 changes: 57 additions & 0 deletions tests/io/bundle_page_input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
function bundle_page_input() {
const fs = require("node:fs");
const path = require("node:path");
const child = require("node:child_process");
const dir = fs.mkdtempSync(path.join(process.cwd(), ".bend-page-input-"));
const html = '<script type="module">console.log(42);</script>\n';
const page = path.join(dir, "page.html");
const sub = (name) => {
fs.mkdirSync(path.join(dir, name));
return path.join(dir, name);
};
const build = (file, out) => child.spawnSync(process.execPath,
[path.resolve("bend2/main.ts"), file, "-o", out], {
encoding: "utf8", env: { ...process.env, HOME: dir },
});
const refused = (file, out) => {
const r = build(file, out);
return r.status === 1 && r.stderr.includes("would overwrite the page")
&& fs.readFileSync(page, "utf8") === html;
};
try {
fs.writeFileSync(page, html);
if (!refused(page, dir)) {
return 1;
}
const hard = sub("hard");
fs.linkSync(page, path.join(hard, "page.html"));
if (!refused(page, hard)) {
return 2;
}
const linked = sub("linked");
fs.symlinkSync(page, path.join(linked, "page.html"));
fs.symlinkSync(page, path.join(dir, "alias.html"));
if (!refused(path.join(dir, "alias.html"), linked)) {
return 3;
}
const beside = sub("beside");
fs.symlinkSync(page, path.join(beside, "alias.html"));
const ok = build(path.join(beside, "alias.html"), beside);
const js = fs.readdirSync(beside).find((f) => f.endsWith(".js"));
if (ok.status !== 0 || fs.readFileSync(page, "utf8") !== html
|| !fs.existsSync(path.join(beside, "page.html")) || js === undefined
|| child.spawnSync(process.execPath, [path.join(beside, js)],
{ encoding: "utf8" }).stdout.trim() !== "42") {
return 4;
}
const none = build(path.join(dir, "none.html"), path.join(dir, "none"));
if (none.status !== 1 || !none.stderr.includes("ModuleNotFound")) {
return 5;
}
return 0;
} finally {
fs.rmSync(dir, { recursive: true, force: true });
}
}

io_eff(CID(Bundle.page_input), bundle_page_input);