fix: maintain unix file permissions from file read to zip options (#14)

This commit is contained in:
Andrew A. Johnson 2025-06-28 19:41:10 -04:00 • committed by GitHub
commit b22675cef9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 33 additions and 6 deletions

View file

@ -1,5 +1,6 @@
import { confirm } from "@inquirer/prompts";
import { createHash } from "crypto";
import type { Zippable } from "fflate";
import { zipSync } from "fflate";
import {
existsSync,
@ -140,8 +141,9 @@ export async function packExtension({
>();
const shallowFiles: Array<{ path: string; size: number }> = [];
for (const [filePath, content] of fileEntries) {
for (const [filePath, fileData] of fileEntries) {
const relPath = relative(resolvedPath, filePath);
const content = fileData.data;
const size =
typeof content === "string"
? Buffer.byteLength(content, "utf8")
@ -184,8 +186,26 @@ export async function packExtension({
}
}
// Create zip
const zipData = zipSync(files, {
// Create zip with preserved file permissions
const zipFiles: Zippable = {};
const isUnix = process.platform !== "win32";
for (const [filePath, fileData] of Object.entries(files)) {
if (isUnix) {
// Set external file attributes to preserve Unix permissions
// The mode needs to be shifted to the upper 16 bits for ZIP format
zipFiles[filePath] = [
fileData.data,
{ os: 3, attrs: (fileData.mode & 0o777) << 16 },
];
} else {
// On Windows, use default ZIP attributes (no Unix permissions)
zipFiles[filePath] = fileData.data;
}
}
const zipData = zipSync(zipFiles, {
level: 9, // Maximum compression
mtime: new Date(),
});

View file

@ -176,15 +176,19 @@ export function getAllFiles(
return fileList;
}
interface FileWithPermissions {
data: Uint8Array;
mode: number;
}
export interface GetAllFilesResult {
files: Record<string, Uint8Array>;
files: Record<string, FileWithPermissions>;
ignoredCount: number;
}
export function getAllFilesWithCount(
dirPath: string,
baseDir: string = dirPath,
fileList: Record<string, Uint8Array> = {},
fileList: Record<string, FileWithPermissions> = {},
additionalPatterns: string[] = [],
ignoredCount = 0,
): GetAllFilesResult {
@ -213,7 +217,10 @@ export function getAllFilesWithCount(
} else {
// Use forward slashes in zip file paths
const zipPath = relativePath.split(sep).join("/");
fileList[zipPath] = readFileSync(filePath);
fileList[zipPath] = {
data: readFileSync(filePath),
mode: stat.mode,
};
}
}