Skip to content

Commit 05d451a

Browse files
sunnylqmclaude
andcommitted
refactor: dedupe diff zip logic, correct id types to number
- diff.ts: extract createOutputZip/addBundlePatch/addFileFromZipEntry/ finishDiffZip helpers shared by diffFromPPK and diffFromPackage, removing ~110 lines of duplicated stream/patch/manifest code - types.ts: Package.id and Version.id are numbers (server uses numeric auto-increment keys); stringify at the interactive-choice boundaries Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 29c438d commit 05d451a

3 files changed

Lines changed: 89 additions & 115 deletions

File tree

‎src/diff.ts‎

Lines changed: 82 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as fs from 'fs-extra';
22
import { npm, yarn } from 'global-dirs';
33
import path from 'path';
4+
import type { Entry, ZipFile as YauzlZipFile } from 'yauzl';
45
import { ZipFile as YazlZipFile } from 'yazl';
56
import type { CommandContext } from './types';
67
import { translateOptions } from './utils';
@@ -61,14 +62,85 @@ function basename(fn: string): string | undefined {
6162
return m?.[1];
6263
}
6364

65+
function createOutputZip(output: string) {
66+
fs.ensureDirSync(path.dirname(output));
67+
const zipfile = new YazlZipFile();
68+
const writePromise = new Promise<void>((resolve, reject) => {
69+
zipfile.outputStream.on('error', reject);
70+
zipfile.outputStream.pipe(fs.createWriteStream(output)).on('close', () => {
71+
resolve(void 0);
72+
});
73+
});
74+
return { zipfile, writePromise };
75+
}
76+
77+
async function addBundlePatch(
78+
zipfile: YazlZipFile,
79+
entry: Entry,
80+
nextZipfile: YauzlZipFile,
81+
diffFn: Diff,
82+
originSource: Buffer | undefined,
83+
) {
84+
const newSource = await readEntry(entry, nextZipfile);
85+
zipfile.addBuffer(
86+
diffFn(originSource, newSource),
87+
`${entry.fileName}.patch`,
88+
zipOptionsForPatchEntry(),
89+
);
90+
}
91+
92+
async function addFileFromZipEntry(
93+
zipfile: YazlZipFile,
94+
entry: Entry,
95+
nextZipfile: YauzlZipFile,
96+
) {
97+
const entryPrefix = await readEntryPrefix(
98+
entry,
99+
nextZipfile,
100+
ZIP_ENTRY_SNIFF_BYTES,
101+
);
102+
await new Promise<void>((resolve, reject) => {
103+
nextZipfile.openReadStream(entry, (err, readStream) => {
104+
if (err) {
105+
return reject(err);
106+
}
107+
if (!readStream) {
108+
return reject(new Error(`Unable to read zip entry: ${entry.fileName}`));
109+
}
110+
zipfile.addReadStream(
111+
readStream,
112+
entry.fileName,
113+
zipOptionsForPayloadEntry(entry.fileName, entryPrefix),
114+
);
115+
readStream.on('error', reject);
116+
readStream.on('end', () => {
117+
resolve(void 0);
118+
});
119+
});
120+
});
121+
}
122+
123+
function finishDiffZip(
124+
zipfile: YazlZipFile,
125+
writePromise: Promise<void>,
126+
manifest: Record<string, unknown>,
127+
) {
128+
const diffManifest = Buffer.from(JSON.stringify(manifest));
129+
zipfile.addBuffer(
130+
diffManifest,
131+
'__diff.json',
132+
zipOptionsForManifestEntry(diffManifest.length),
133+
);
134+
zipfile.end();
135+
return writePromise;
136+
}
137+
64138
async function diffFromPPK(
65139
origin: string,
66140
next: string,
67141
output: string,
68142
diffFn: Diff,
69143
) {
70-
fs.ensureDirSync(path.dirname(output));
71-
72144
const originEntries: EntryMap = {};
73145
const originMap: CrcMap = {};
74146

@@ -93,14 +165,7 @@ async function diffFromPPK(
93165

94166
const copies: CopyMap = {};
95167

96-
const zipfile = new YazlZipFile();
97-
98-
const writePromise = new Promise<void>((resolve, reject) => {
99-
zipfile.outputStream.on('error', reject);
100-
zipfile.outputStream.pipe(fs.createWriteStream(output)).on('close', () => {
101-
resolve(void 0);
102-
});
103-
});
168+
const { zipfile, writePromise } = createOutputZip(output);
104169

105170
const addedEntry: Record<string, true> = {};
106171

@@ -128,15 +193,7 @@ async function diffFromPPK(
128193
addEntry(entry.fileName);
129194
}
130195
} else if (isPPKBundleFileName(entry.fileName)) {
131-
//console.log('Found bundle');
132-
const newSource = await readEntry(entry, nextZipfile);
133-
//console.log('Begin diff');
134-
zipfile.addBuffer(
135-
diffFn(originSource, newSource),
136-
`${entry.fileName}.patch`,
137-
zipOptionsForPatchEntry(),
138-
);
139-
//console.log('End diff');
196+
await addBundlePatch(zipfile, entry, nextZipfile, diffFn, originSource);
140197
} else {
141198
// If same file.
142199
const originEntry = originEntries[entry.fileName];
@@ -162,33 +219,7 @@ async function diffFromPPK(
162219
addEntry(basePath);
163220
}
164221

165-
const entryPrefix = await readEntryPrefix(
166-
entry,
167-
nextZipfile,
168-
ZIP_ENTRY_SNIFF_BYTES,
169-
);
170-
await new Promise<void>((resolve, reject) => {
171-
nextZipfile.openReadStream(entry, (err, readStream) => {
172-
if (err) {
173-
return reject(err);
174-
}
175-
if (!readStream) {
176-
return reject(
177-
new Error(`Unable to read zip entry: ${entry.fileName}`),
178-
);
179-
}
180-
zipfile.addReadStream(
181-
readStream,
182-
entry.fileName,
183-
zipOptionsForPayloadEntry(entry.fileName, entryPrefix),
184-
);
185-
readStream.on('error', reject);
186-
readStream.on('end', () => {
187-
//console.log('add finished');
188-
resolve(void 0);
189-
});
190-
});
191-
});
222+
await addFileFromZipEntry(zipfile, entry, nextZipfile);
192223
}
193224
});
194225

@@ -201,15 +232,7 @@ async function diffFromPPK(
201232
}
202233
}
203234

204-
//console.log({copies, deletes});
205-
const diffManifest = Buffer.from(JSON.stringify({ copies, deletes }));
206-
zipfile.addBuffer(
207-
diffManifest,
208-
'__diff.json',
209-
zipOptionsForManifestEntry(diffManifest.length),
210-
);
211-
zipfile.end();
212-
await writePromise;
235+
await finishDiffZip(zipfile, writePromise, { copies, deletes });
213236
}
214237

215238
async function diffFromPackage(
@@ -220,8 +243,6 @@ async function diffFromPackage(
220243
originBundleName: string,
221244
transformPackagePath: (v: string) => string | undefined = (v: string) => v,
222245
) {
223-
fs.ensureDirSync(path.dirname(output));
224-
225246
const originEntries: Record<string, number> = {};
226247
const originMap: CrcMap = {};
227248

@@ -259,29 +280,14 @@ async function diffFromPackage(
259280

260281
const copies: CopyMap = {};
261282

262-
const zipfile = new YazlZipFile();
263-
264-
const writePromise = new Promise<void>((resolve, reject) => {
265-
zipfile.outputStream.on('error', reject);
266-
zipfile.outputStream.pipe(fs.createWriteStream(output)).on('close', () => {
267-
resolve(void 0);
268-
});
269-
});
283+
const { zipfile, writePromise } = createOutputZip(output);
270284

271285
await enumZipEntries(next, async (entry, nextZipfile) => {
272286
if (/\/$/.test(entry.fileName)) {
273287
// Directory
274288
zipfile.addEmptyDirectory(entry.fileName);
275289
} else if (isPPKBundleFileName(entry.fileName)) {
276-
//console.log('Found bundle');
277-
const newSource = await readEntry(entry, nextZipfile);
278-
//console.log('Begin diff');
279-
zipfile.addBuffer(
280-
diffFn(originSource, newSource),
281-
`${entry.fileName}.patch`,
282-
zipOptionsForPatchEntry(),
283-
);
284-
//console.log('End diff');
290+
await addBundlePatch(zipfile, entry, nextZipfile, diffFn, originSource);
285291
} else {
286292
// If same file.
287293
if (originEntries[entry.fileName] === entry.crc32) {
@@ -299,44 +305,11 @@ async function diffFromPackage(
299305
return;
300306
}
301307

302-
const entryPrefix = await readEntryPrefix(
303-
entry,
304-
nextZipfile,
305-
ZIP_ENTRY_SNIFF_BYTES,
306-
);
307-
await new Promise<void>((resolve, reject) => {
308-
nextZipfile.openReadStream(entry, (err, readStream) => {
309-
if (err) {
310-
return reject(err);
311-
}
312-
if (!readStream) {
313-
return reject(
314-
new Error(`Unable to read zip entry: ${entry.fileName}`),
315-
);
316-
}
317-
zipfile.addReadStream(
318-
readStream,
319-
entry.fileName,
320-
zipOptionsForPayloadEntry(entry.fileName, entryPrefix),
321-
);
322-
readStream.on('error', reject);
323-
readStream.on('end', () => {
324-
//console.log('add finished');
325-
resolve(void 0);
326-
});
327-
});
328-
});
308+
await addFileFromZipEntry(zipfile, entry, nextZipfile);
329309
}
330310
});
331311

332-
const diffManifest = Buffer.from(JSON.stringify({ copies, copiesCrc }));
333-
zipfile.addBuffer(
334-
diffManifest,
335-
'__diff.json',
336-
zipOptionsForManifestEntry(diffManifest.length),
337-
);
338-
zipfile.end();
339-
await writePromise;
312+
await finishDiffZip(zipfile, writePromise, { copies, copiesCrc });
340313
}
341314

342315
type DiffCommandOptions = {

‎src/types.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ export interface Session {
1010
export type Platform = 'ios' | 'android' | 'harmony';
1111

1212
export interface Package {
13-
id: string;
13+
// server-side ids are numeric (auto-increment primary keys)
14+
id: number;
1415
name: string;
1516
version?: string;
1617
status?: string;
@@ -22,7 +23,7 @@ export interface Package {
2223
}
2324

2425
export interface Version {
25-
id: string;
26+
id: number;
2627
hash: string;
2728
name: string;
2829
packages?: Package[];

‎src/versions.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ export const versionCommands = {
563563
if (nonInteractive) {
564564
throw new Error(t('versionIdRequired'));
565565
}
566-
versionId = (await chooseVersion(String(appId))).id;
566+
versionId = String((await chooseVersion(String(appId))).id);
567567
}
568568
if (versionId === 'null') {
569569
versionId = null;
@@ -640,7 +640,7 @@ export const versionCommands = {
640640
if (nonInteractive) {
641641
throw new Error(t('packageIdRequired'));
642642
}
643-
pkgId = (await choosePackage(String(appId))).id;
643+
pkgId = String((await choosePackage(String(appId))).id);
644644
}
645645

646646
if (!pkgId) {
@@ -693,7 +693,7 @@ export const versionCommands = {
693693
if (nonInteractive) {
694694
throw new Error(t('versionIdRequired'));
695695
}
696-
versionId = (await chooseVersion(String(appId))).id;
696+
versionId = String((await chooseVersion(String(appId))).id);
697697
}
698698

699699
const updateParams: Record<string, string> = {};
@@ -721,7 +721,7 @@ export const versionCommands = {
721721
if (nonInteractive) {
722722
throw new Error(t('versionIdRequired'));
723723
}
724-
versionIds = [(await chooseVersion(String(appId))).id];
724+
versionIds = [String((await chooseVersion(String(appId))).id)];
725725
}
726726

727727
try {

0 commit comments

Comments
 (0)