diff --git a/src/bin/tools/jar.ts b/src/bin/tools/jar.ts index 4964ed72..a87e9048 100644 --- a/src/bin/tools/jar.ts +++ b/src/bin/tools/jar.ts @@ -48,7 +48,7 @@ export async function jarStream({ groupId, artifactId, version, asyncPathGenerat for await (const entry of asyncPathGeneratorFn()) { if ("buffer" in entry) { zipFile.addBuffer(entry.buffer, entry.zipPath); - } else if ("fsPath" in entry && entry.fsPath.endsWith(sep)) { + } else if ("fsPath" in entry && !entry.fsPath.endsWith(sep)) { zipFile.addFile(entry.fsPath, entry.zipPath); } } diff --git a/src/bin/tools/walk.ts b/src/bin/tools/walk.ts index f7c4dee0..57c544a6 100644 --- a/src/bin/tools/walk.ts +++ b/src/bin/tools/walk.ts @@ -1,9 +1,9 @@ import { readdir } from "fs/promises"; -import { resolve } from "path"; +import { resolve, sep } from "path"; /** * Asynchronously and recursively walk a directory tree, yielding every file and directory - * found + * found. Directory paths will _always_ end with a path separator. * * @param root the starting directory * @returns AsyncGenerator @@ -12,8 +12,8 @@ export default async function* walk(root: string): AsyncGenerator = { [Symbol.asyncIterator](): AsyncIterableIterator; @@ -17,7 +22,7 @@ async function readToBuffer(stream: NodeJS.ReadableStream) { return Buffer.concat(await arrayFromAsync(stream as AsyncIterable)); } -function unzip(buffer: Buffer) { +function unzipBuffer(buffer: Buffer) { return new Promise((resolve, reject) => fromBuffer(buffer, { lazyEntries: true }, (err, zipFile) => { if (err !== null) { @@ -57,15 +62,22 @@ function readAll(zipFile: ZipFile): Promise> { } describe("jar", () => { + const coords = { artifactId: "someArtifactId", groupId: "someGroupId", version: "1.2.3" }; + + const tmpDirs: string[] = []; + + afterAll(async () => { + await Promise.all(tmpDirs.map(dir => rm(dir, { force: true, recursive: true }))); + }); + it("creates jar artifacts without error", async () => { async function* mockFiles(): ZipEntryGenerator { yield { zipPath: "foo", buffer: Buffer.from("foo") }; } - const opts = { artifactId: "someArtifactId", groupId: "someGroupId", version: "1.2.3", asyncPathGeneratorFn: mockFiles }; - const zipped = await jarStream(opts); + const zipped = await jarStream({ ...coords, asyncPathGeneratorFn: mockFiles }); const buffered = await readToBuffer(zipped.outputStream); - const unzipped = await unzip(buffered); + const unzipped = await unzipBuffer(buffered); const entries = await readAll(unzipped); assert.equal(entries.size, 3); @@ -83,4 +95,31 @@ describe("jar", () => { assert.isOk(pomProperties?.includes("someGroupId")); assert.isOk(pomProperties?.includes("someArtifactId")); }); + + it("creates a jar from _real_ files without error", async () => { + const tmp = await mkdtemp(path.join(tmpdir(), "kc-jar-test-")); + tmpDirs.push(tmp); + const rootPath = path.join(tmp, "src"); + const targetPath = path.join(tmp, "jar.jar"); + await mkdir(rootPath); + + await cp(path.dirname(__dirname), rootPath, { recursive: true }); + + await jar({ ...coords, rootPath, targetPath }); + + const buffered = await readToBuffer(createReadStream(targetPath)); + const unzipped = await unzipBuffer(buffered); + const entries = await readAll(unzipped); + const zipPaths = Array.from(entries.keys()); + + assert.isOk(entries.has("META-INF/MANIFEST.MF")); + assert.isOk(entries.has("META-INF/maven/someGroupId/someArtifactId/pom.properties")); + + for await (const fsPath of walk(rootPath)) { + if (!fsPath.endsWith(path.sep)) { + const rel = path.relative(rootPath, fsPath).replace(path.sep === "/" ? /\//g : /\\/g, "/"); + assert.isOk(zipPaths.includes(rel), `missing ${rel} (${rel}, ${zipPaths.join(", ")})`); + } + } + }); });