Skip to content

Commit

Permalink
feat: add ability to create cpio archives
Browse files Browse the repository at this point in the history
  • Loading branch information
JakeChampion committed Jan 3, 2025
1 parent 92a3f82 commit 73a2c4a
Show file tree
Hide file tree
Showing 17 changed files with 1,777 additions and 12 deletions.
1 change: 1 addition & 0 deletions packages/zip-it-and-ship-it/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@netlify/serverless-functions-api": "^1.31.1",
"@vercel/nft": "0.27.7",
"archiver": "^7.0.0",
"bl": "^6.0.18",
"common-path-prefix": "^3.0.0",
"cp-file": "^10.0.0",
"es-module-lexer": "^1.0.0",
Expand Down
57 changes: 57 additions & 0 deletions packages/zip-it-and-ship-it/src/archive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,74 @@ import { Writable } from 'stream'

import archiver, { Archiver } from 'archiver'

import { CPIOPacker } from './cpio-stream.js'
import { ObjectValues } from './types/utils.js'

export { Archiver as ZipArchive } from 'archiver'

export const ARCHIVE_FORMAT = {
CPIO: 'cpio',
NONE: 'none',
ZIP: 'zip',
} as const

export type ArchiveFormat = ObjectValues<typeof ARCHIVE_FORMAT>

// Start cpio archive for files
export const startCpio = function (destPath: string): { archive: CPIOPacker; output: Writable } {
const output = createWriteStream(destPath)
const archive = new CPIOPacker()

archive.pipe(output)

return { archive, output }
}

// Add new file to cpio
export const addCpioFile = function (
archive: CPIOPacker,
file: string,
name: string,
stat?: Stats,
content?: Buffer | string,
): void {
if (stat?.isSymbolicLink()) {
const linkContent = readlinkSync(file)

archive.entry({ name: name, linkname: linkContent, mode: stat.mode, type: 'symlink' })
} else {
archive.entry(
{
type: 'file',
name,
mode: stat?.mode,
// Ensure sha256 stability regardless of mtime
mtime: new Date(0),
dev: stat?.dev,
ino: stat?.ino,
nlink: stat?.nlink,
uid: stat?.uid,
gid: stat?.gid,
rdev: stat?.rdev,
size: stat?.size,
},
content,
)
}
}

// End cpioing files
export const endCpio = async function (archive: CPIOPacker, output: Writable): Promise<void> {
const result = new Promise<void>((resolve, reject) => {
output.on('error', (error) => reject(error))
output.on('finish', () => resolve())
})

archive.finalize()

return result
}

// Start zipping files
export const startZip = function (destPath: string): { archive: Archiver; output: Writable } {
const output = createWriteStream(destPath)
Expand Down
15 changes: 10 additions & 5 deletions packages/zip-it-and-ship-it/src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import yargs from 'yargs'
import { hideBin } from 'yargs/helpers'

import { ARCHIVE_FORMAT } from './archive.js'
import { zipFunctions } from './main.js'
import { cpioFunctions, zipFunctions } from './main.js'

const packJson = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'))

Expand All @@ -22,10 +22,15 @@ const runCli = async function () {

try {
global.ZISI_CLI = true
// @ts-expect-error TODO: `options` is not getting the right types.
const zipped = await zipFunctions(srcFolder, destFolder, options)

console.log(JSON.stringify(zipped, null, 2))
let archive
if (options['archive-format'] === 'cpio') {
// @ts-expect-error TODO: `options` is not getting the right types.
archive = await cpioFunctions(srcFolder, destFolder, options)
} else {
// @ts-expect-error TODO: `options` is not getting the right types.
archive = await zipFunctions(srcFolder, destFolder, options)
}
console.log(JSON.stringify(archive, null, 2))
} catch (error) {
console.error(error.toString())
exit(1)
Expand Down
1 change: 1 addition & 0 deletions packages/zip-it-and-ship-it/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const functionConfig = z.object({
rustTargetDirectory: z.string().optional().catch(undefined),
schedule: z.string().optional().catch(undefined),
timeout: z.number().optional().catch(undefined),
cpioGo: z.boolean().optional().catch(undefined),
zipGo: z.boolean().optional().catch(undefined),

// Temporary configuration property, only meant to be used by the deploy
Expand Down
Loading

0 comments on commit 73a2c4a

Please sign in to comment.