farjs-app
Advanced tools
| /** | ||
| * @import { FileListItem } from "@farjs/filelist/api/FileListItem.mjs" | ||
| * @import StreamReader from "@farjs/filelist/util/StreamReader.mjs" | ||
| */ | ||
| import SubProcess from "@farjs/filelist/util/SubProcess.mjs"; | ||
| import ZipEntry from "./ZipEntry.mjs"; | ||
| class ZipApi { | ||
| /** | ||
| * @param {string} zipFile | ||
| * @param {string} parent | ||
| * @param {Set<string>} items | ||
| * @param {() => void} onNextItem | ||
| * @returns {Promise<void>} | ||
| */ | ||
| static async addToZip(zipFile, parent, items, onNextItem) { | ||
| const subProcess = await SubProcess.wrap( | ||
| SubProcess.spawn("zip", ["-r", zipFile, ...items], { | ||
| cwd: parent, | ||
| windowsHide: true, | ||
| }), | ||
| ); | ||
| await subProcess.stdout.readAllLines((line) => { | ||
| if (line.includes("adding: ")) { | ||
| onNextItem(); | ||
| } | ||
| }); | ||
| const error = await subProcess.exitP; | ||
| if (error && error.exitCode !== 0) { | ||
| throw error; | ||
| } | ||
| } | ||
| /** | ||
| * @param {string} zipPath | ||
| * @returns {Promise<Map<string, readonly FileListItem[]>>} | ||
| */ | ||
| static async readZip(zipPath) { | ||
| /** @type {(reader: StreamReader, result: Buffer[]) => Promise<readonly Buffer[]>} */ | ||
| async function loop(reader, result) { | ||
| const content = await reader.readNextBytes(64 * 1024); | ||
| if (content) { | ||
| result.push(content); | ||
| return loop(reader, result); | ||
| } | ||
| return result; | ||
| } | ||
| const subProcess = await SubProcess.wrap( | ||
| SubProcess.spawn("unzip", ["-ZT", zipPath], { | ||
| windowsHide: true, | ||
| }), | ||
| ); | ||
| const chunks = await loop(subProcess.stdout, []); | ||
| const output = Buffer.concat(chunks).toString(); | ||
| const error = await subProcess.exitP; | ||
| if (error && (error.exitCode !== 1 || !output.includes("Empty zipfile."))) { | ||
| throw error; | ||
| } | ||
| return ZipEntry.groupByParent(ZipEntry.fromUnzipCommand(output)); | ||
| } | ||
| } | ||
| export default ZipApi; |
@@ -75,2 +75,45 @@ /** | ||
| /** | ||
| * @param {readonly ZipEntry[]} entries | ||
| * @returns {Map<string, readonly FileListItem[]>} | ||
| */ | ||
| ZipEntry.groupByParent = (entries) => { | ||
| /** @type {Set<string>} */ | ||
| const processedDirs = new Set(); | ||
| /** @type {Map<string, FileListItem[]>} */ | ||
| const entriesByParent = new Map(); | ||
| /** @type {(entry: ZipEntry) => void} */ | ||
| function ensureDirs(entry) { | ||
| while (true) { | ||
| const values = entriesByParent.get(entry.parent) ?? []; | ||
| if (entry.name === "" || values.find((_) => _.name === entry.name)) { | ||
| return; | ||
| } | ||
| values.push(entry); | ||
| entriesByParent.set(entry.parent, values); | ||
| if (processedDirs.has(entry.parent)) { | ||
| return; | ||
| } | ||
| processedDirs.add(entry.parent); | ||
| const [parent, name] = (() => { | ||
| const lastSlash = entry.parent.lastIndexOf("/"); | ||
| return lastSlash !== -1 | ||
| ? [ | ||
| entry.parent.substring(0, lastSlash), | ||
| entry.parent.substring(lastSlash + 1), | ||
| ] | ||
| : ["", entry.parent]; | ||
| })(); | ||
| entry = ZipEntry(parent, name, true, 0, entry.mtimeMs, "drw-r--r--"); | ||
| } | ||
| } | ||
| entries.forEach(ensureDirs); | ||
| return entriesByParent; | ||
| }; | ||
| /** @type {() => RegExp} */ | ||
@@ -77,0 +120,0 @@ const itemRegex = lazyFn( |
+2
-2
| { | ||
| "author": "viktor-podzigun", | ||
| "name": "farjs-app", | ||
| "version": "0.19.5", | ||
| "version": "0.19.6", | ||
| "repository": { | ||
@@ -77,3 +77,3 @@ "type": "git", | ||
| "@farjs/better-sqlite3-migrate": "^3.0.0", | ||
| "@farjs/filelist": "0.8.1", | ||
| "@farjs/filelist": "0.8.2", | ||
| "@farjs/ui": "0.9.1", | ||
@@ -80,0 +80,0 @@ "iconv-lite": "0.6.3" |
Sorry, the diff of this file is too big to display
87
1.16%785852
-3.87%24466
-3.8%+ Added
- Removed
Updated