spawnSync cannot start the pnpm .cmd shim without a shell, so the bump step's lockfile refresh failed with ENOENT on Windows after rewriting every manifest. Resolve pnpm to a JavaScript entry executed by the current Node: the run-script's npm_execpath when present, otherwise the workspace's own pnpm dependency (located on disk because pnpm's manifest does not export its bin entry). GNU tar parses the colon in an absolute Windows path as a remote-host separator and aborts, so the tarball readers now run tar in the tarball's directory and pass only its file name.
55 lines
2.1 KiB
TypeScript
55 lines
2.1 KiB
TypeScript
/**
|
|
* Reading packed npm tarballs and the order file that accompanies them.
|
|
*
|
|
* The release steps after pack treat a directory of tarballs as the unit of
|
|
* work, so they read what a tarball declares rather than what the checkout
|
|
* currently says.
|
|
*/
|
|
|
|
import { readFileSync } from 'node:fs'
|
|
import { basename, dirname, join } from 'node:path'
|
|
import { capture } from './process.ts'
|
|
|
|
/** Name of the file recording the order in which a packed family uploads. */
|
|
export const PUBLISH_ORDER_FILE = 'publish-order.txt'
|
|
|
|
/** What a packed tarball calls itself. */
|
|
export interface PackedIdentity {
|
|
/** Package name from the packed manifest. */
|
|
readonly name: string
|
|
/** Package version from the packed manifest. */
|
|
readonly version: string
|
|
}
|
|
|
|
/**
|
|
* List a tarball's members.
|
|
* @param tarball - absolute tarball path.
|
|
* @returns Every path inside the archive.
|
|
*/
|
|
export function tarballFiles(tarball: string): string[] {
|
|
// GNU tar reads the colon in a Windows drive path as a remote-host separator, so tar runs beside the tarball.
|
|
return capture('tar', ['-tzf', basename(tarball)], { cwd: dirname(tarball) }).split(/\r?\n/u).filter(line => line !== '')
|
|
}
|
|
|
|
/**
|
|
* Read a packed tarball's own manifest.
|
|
* @param tarball - absolute tarball path.
|
|
* @returns The name and version the tarball declares.
|
|
*/
|
|
export function packedIdentity(tarball: string): PackedIdentity {
|
|
const manifest: unknown = JSON.parse(capture('tar', ['-xOzf', basename(tarball), 'package/package.json'], { cwd: dirname(tarball) }))
|
|
if (manifest === null || typeof manifest !== 'object') throw new Error(`${tarball} has no manifest`)
|
|
const { name, version } = manifest as Record<string, unknown>
|
|
if (typeof name !== 'string' || typeof version !== 'string') throw new Error(`${tarball} manifest lacks name/version`)
|
|
return { name, version }
|
|
}
|
|
|
|
/**
|
|
* Read a packed directory's upload order.
|
|
* @param directory - absolute path of a pack output directory.
|
|
* @returns Tarball filenames in upload order.
|
|
*/
|
|
export function readPublishOrder(directory: string): string[] {
|
|
return readFileSync(join(directory, PUBLISH_ORDER_FILE), 'utf8').split('\n').filter(line => line !== '')
|
|
}
|