From d627ce72a33edfbfcd04f89201c94b174a59183e Mon Sep 17 00:00:00 2001 From: Daniel Scalzi Date: Tue, 2 Jun 2020 23:07:59 -0400 Subject: [PATCH] Replace AdmZip with node-stream-zip. --- .vscode/launch.json | 3 +- package-lock.json | 19 +- package.json | 3 +- src/model/struct/model/module/file.struct.ts | 4 +- .../module/forgemod/forgemod113.struct.ts | 163 +++++++++++------- .../module/forgemod/forgemod17.struct.ts | 161 +++++++++-------- .../struct/model/module/library.struct.ts | 4 +- .../struct/model/module/litemod.struct.ts | 64 +++++-- .../struct/model/module/module.struct.ts | 8 +- .../forge/adapter/ForgeGradle2.resolver.ts | 23 +-- .../forge/adapter/ForgeGradle3.resolver.ts | 25 +-- src/resolver/forge/forge.resolver.ts | 21 +++ 12 files changed, 283 insertions(+), 215 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 3639121..41038fe 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -16,7 +16,8 @@ "preLaunchTask": "compile", "outFiles": [ "${workspaceFolder}/dist/**/*.js" - ] + ], + "outputCapture": "std" } ] } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1e04029..012adc7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -67,15 +67,6 @@ } } }, - "@types/adm-zip": { - "version": "0.4.33", - "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.4.33.tgz", - "integrity": "sha512-WM0DCWFLjXtddl0fu0+iN2ZF+qz8RF9RddG5OSy/S90AQz01Fu8lHn/3oTIZDxvG8gVcnBLAHMHOdBLbV6m6Mw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -210,11 +201,6 @@ "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", "dev": true }, - "adm-zip": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.14.tgz", - "integrity": "sha512-/9aQCnQHF+0IiCl0qhXoK7qs//SwYE7zX8lsr/DNk1BRAHYxeLZPL4pguwK29gUEqasYQjqPtEpDRSWEkdHn9g==" - }, "ajv": { "version": "6.12.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", @@ -1126,6 +1112,11 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "node-stream-zip": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.11.2.tgz", + "integrity": "sha512-cowCX+OyzS3tN2i4BMMFxCr/pE6cQlEMTbVCugmos0TNEJQNtcG04tR41CY8lumO1I7F5GFiLaU4WavomJthaA==" + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", diff --git a/package.json b/package.json index 0797d31..9ea427e 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ }, "homepage": "https://github.com/dscalzi/Nebula#readme", "devDependencies": { - "@types/adm-zip": "^0.4.33", "@types/fs-extra": "^9.0.1", "@types/node": "^12.12.43", "@types/triple-beam": "^1.3.1", @@ -38,12 +37,12 @@ "typescript": "^3.9.3" }, "dependencies": { - "adm-zip": "^0.4.14", "axios": "^0.19.2", "dotenv": "^8.2.0", "fs-extra": "^9.0.0", "helios-distribution-types": "^1.0.0-pre.1", "moment": "^2.26.0", + "node-stream-zip": "^1.11.2", "toml": "^3.0.0", "triple-beam": "^1.3.0", "winston": "^3.2.1", diff --git a/src/model/struct/model/module/file.struct.ts b/src/model/struct/model/module/file.struct.ts index 39b2fc5..656fac3 100644 --- a/src/model/struct/model/module/file.struct.ts +++ b/src/model/struct/model/module/file.struct.ts @@ -39,10 +39,10 @@ export class MiscFileStructure extends ModuleStructure { return acc } - protected async getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise { + protected async getModuleId(name: string, path: string): Promise { return name } - protected async getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise { + protected async getModuleName(name: string, path: string): Promise { return name } protected async getModuleUrl(name: string, path: string, stats: Stats): Promise { diff --git a/src/model/struct/model/module/forgemod/forgemod113.struct.ts b/src/model/struct/model/module/forgemod/forgemod113.struct.ts index 6775eed..4fc9742 100644 --- a/src/model/struct/model/module/forgemod/forgemod113.struct.ts +++ b/src/model/struct/model/module/forgemod/forgemod113.struct.ts @@ -1,5 +1,4 @@ -import AdmZip from 'adm-zip' -import { Stats } from 'fs-extra' +import StreamZip from 'node-stream-zip' import toml from 'toml' import { capitalize } from '../../../../../util/stringutils' import { VersionUtil } from '../../../../../util/versionutil' @@ -33,59 +32,90 @@ export class ForgeModStructure113 extends BaseForgeModStructure { return ForgeModStructure113.isForVersion(version, libraryVersion) } - protected async getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise { - const fmData = this.getForgeModMetadata(buf, name) + protected async getModuleId(name: string, path: string): Promise { + const fmData = await this.getForgeModMetadata(name, path) return this.generateMavenIdentifier(fmData.mods[0].modId, fmData.mods[0].version) } - protected async getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise { - return capitalize((this.getForgeModMetadata(buf, name)).mods[0].displayName) + protected async getModuleName(name: string, path: string): Promise { + return capitalize((await this.getForgeModMetadata(name, path)).mods[0].displayName) } - private getForgeModMetadata(buf: Buffer, name: string): ModsToml { - if (!Object.prototype.hasOwnProperty.call(this.forgeModMetadata, name)) { - const zip = new AdmZip(buf) - const zipEntries = zip.getEntries() + private getForgeModMetadata(name: string, path: string): Promise { + return new Promise((resolve, reject) => { + if (!Object.prototype.hasOwnProperty.call(this.forgeModMetadata, name)) { - // Optifine is a tweak that can be loaded as a forge mod. It does not - // appear to contain a mcmod.info class. This a special case we will - // account for. - if (name.toLowerCase().indexOf('optifine') > -1) { - // Read zip for changelog.txt - let rawChangelog - for (const entry of zipEntries) { - if (entry.entryName === 'changelog.txt') { - rawChangelog = zip.readAsText(entry) - break + const zip = new StreamZip({ + file: path, + storeEntries: true + }) + + zip.on('error', err => reject(err)) + zip.on('ready', () => { + try { + const res = this.processZip(zip, name) + zip.close() + resolve(res) + return + } catch(err) { + zip.close() + throw err } - } - if (!rawChangelog) { - throw new Error('Failed to read OptiFine changelog.') - } - const info = rawChangelog.split('\n')[0].trim() - const version = info.split(' ')[1] - this.forgeModMetadata[name] = ({ - modid: 'optifine', - name: info, - version, - mcversion: version.substring(0, version.indexOf('_')) - }) as unknown as ModsToml - return this.forgeModMetadata[name] as ModsToml + }) + + } else { + resolve(this.forgeModMetadata[name] as ModsToml) + return } - const raw = zip.readAsText('META-INF/mods.toml') + }) + } - let createDefault = false + private processZip(zip: StreamZip, name: string): ModsToml { - if (raw) { - // Assuming the main mod will be the first entry in this file. - try { - const parsed = toml.parse(raw) as ModsToml + // Optifine is a tweak that can be loaded as a forge mod. It does not + // appear to contain a mcmod.info class. This a special case we will + // account for. + if (name.toLowerCase().indexOf('optifine') > -1) { - // tslint:disable-next-line: no-invalid-template-strings - if (parsed.mods[0].version === '${file.jarVersion}') { - let version = '0.0.0' - const manifest = zip.readAsText('META-INF/MANIFEST.MF') - const keys = manifest.split('\n') + // Read zip for changelog.txt + let changelogBuf: Buffer + try { + changelogBuf = zip.entryDataSync('changelog.txt') + } catch(err) { + throw new Error('Failed to read OptiFine changelog.') + } + + const info = changelogBuf.toString().split('\n')[0].trim() + const version = info.split(' ')[1] + this.forgeModMetadata[name] = ({ + modid: 'optifine', + name: info, + version, + mcversion: version.substring(0, version.indexOf('_')) + }) as unknown as ModsToml + return this.forgeModMetadata[name] as ModsToml + } + + let raw: Buffer | undefined + try { + raw = zip.entryDataSync('META-INF/mods.toml') + } catch(err) { + // ignored + } + + let createDefault = false + + if (raw) { + // Assuming the main mod will be the first entry in this file. + try { + const parsed = toml.parse(raw.toString()) as ModsToml + + // tslint:disable-next-line: no-invalid-template-strings + if (parsed.mods[0].version === '${file.jarVersion}') { + let version = '0.0.0' + try { + const manifest = zip.entryDataSync('META-INF/MANIFEST.MF') + const keys = manifest.toString().split('\n') ForgeModStructure113.logger.debug(keys) for (const key of keys) { const match = ForgeModStructure113.IMPLEMENTATION_VERSION_REGEX.exec(key) @@ -94,36 +124,37 @@ export class ForgeModStructure113 extends BaseForgeModStructure { } } ForgeModStructure113.logger.debug(`ForgeMod ${name} contains a version wildcard, inferring ${version}`) - parsed.mods[0].version = version + } catch { + ForgeModStructure113.logger.debug(`ForgeMod ${name} contains a version wildcard yet no MANIFEST.MF.. Defaulting to ${version}`) } - - this.forgeModMetadata[name] = parsed - - } catch (err) { - ForgeModStructure113.logger.error(`ForgeMod ${name} contains an invalid mods.toml file.`) - createDefault = true + parsed.mods[0].version = version } - } else { - ForgeModStructure113.logger.error(`ForgeMod ${name} does not contain mods.toml file.`) + + this.forgeModMetadata[name] = parsed + + } catch (err) { + ForgeModStructure113.logger.error(`ForgeMod ${name} contains an invalid mods.toml file.`) createDefault = true } + } else { + ForgeModStructure113.logger.error(`ForgeMod ${name} does not contain mods.toml file.`) + createDefault = true + } - if (createDefault) { - this.forgeModMetadata[name] = ({ - modLoader: 'javafml', - loaderVersion: '', - mods: [{ - modId: name.substring(0, name.lastIndexOf('.')).toLowerCase(), - version: '0.0.0', - displayName: name, - description: '' - }] - }) - } + if (createDefault) { + this.forgeModMetadata[name] = ({ + modLoader: 'javafml', + loaderVersion: '', + mods: [{ + modId: name.substring(0, name.lastIndexOf('.')).toLowerCase(), + version: '0.0.0', + displayName: name, + description: '' + }] + }) } return this.forgeModMetadata[name] as ModsToml - } } diff --git a/src/model/struct/model/module/forgemod/forgemod17.struct.ts b/src/model/struct/model/module/forgemod/forgemod17.struct.ts index 63e4976..2b5bce2 100644 --- a/src/model/struct/model/module/forgemod/forgemod17.struct.ts +++ b/src/model/struct/model/module/forgemod/forgemod17.struct.ts @@ -1,5 +1,4 @@ -import AdmZip from 'adm-zip' -import { Stats } from 'fs-extra' +import StreamZip from 'node-stream-zip' import { capitalize } from '../../../../../util/stringutils' import { VersionUtil } from '../../../../../util/versionutil' import { McModInfo } from '../../../../forge/mcmodinfo' @@ -31,85 +30,107 @@ export class ForgeModStructure17 extends BaseForgeModStructure { return ForgeModStructure17.isForVersion(version, libraryVersion) } - protected async getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise { - const fmData = this.getForgeModMetadata(buf, name) + protected async getModuleId(name: string, path: string): Promise { + const fmData = await this.getForgeModMetadata(name, path) return this.generateMavenIdentifier(fmData.modid, fmData.version) } - protected async getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise { - return capitalize((this.getForgeModMetadata(buf, name)).name) + protected async getModuleName(name: string, path: string): Promise { + return capitalize((await this.getForgeModMetadata(name, path)).name) } - private getForgeModMetadata(buf: Buffer, name: string): McModInfo { - if (!Object.prototype.hasOwnProperty.call(this.forgeModMetadata, name)) { - const zip = new AdmZip(buf) - const zipEntries = zip.getEntries() + private getForgeModMetadata(name: string, path: string): Promise { + return new Promise((resolve, reject) => { + if (!Object.prototype.hasOwnProperty.call(this.forgeModMetadata, name)) { - // Optifine is a tweak that can be loaded as a forge mod. It does not - // appear to contain a mcmod.info class. This a special case we will - // account for. - if (name.toLowerCase().indexOf('optifine') > -1) { - // Read zip for changelog.txt - let rawChangelog - for (const entry of zipEntries) { - if (entry.entryName === 'changelog.txt') { - rawChangelog = zip.readAsText(entry) - break + const zip = new StreamZip({ + file: path, + storeEntries: true + }) + + zip.on('error', err => reject(err)) + zip.on('ready', () => { + try { + const res = this.processZip(zip, name) + zip.close() + resolve(res) + return + } catch(err) { + zip.close() + throw err } - } - if (!rawChangelog) { - throw new Error('Failed to read OptiFine changelog.') - } - const info = rawChangelog.split('\n')[0].trim() - const version = info.split(' ')[1] - this.forgeModMetadata[name] = ({ - modid: 'optifine', - name: info, - version, - mcversion: version.substring(0, version.indexOf('_')) - }) as unknown as McModInfo - return this.forgeModMetadata[name] as McModInfo - } + }) - let raw - for (const entry of zipEntries) { - if (entry.entryName === 'mcmod.info') { - raw = zip.readAsText(entry) - break - } - } - - let createDefault = false - - if (raw) { - // Assuming the main mod will be the first entry in this file. - try { - const resolved = JSON.parse(raw) as (McModInfoList | McModInfo[]) - if (Object.prototype.hasOwnProperty.call(resolved, 'modListVersion')) { - this.forgeModMetadata[name] = (resolved as McModInfoList).modList[0] - } else { - this.forgeModMetadata[name] = (resolved as McModInfo[])[0] - } - // No way to resolve this AFAIK - if(this.forgeModMetadata[name]!.version.indexOf('@') > -1 || this.forgeModMetadata[name]!.version.indexOf('$') > -1) { - // Ex. @VERSION@, ${version} - this.forgeModMetadata[name]!.version = '0.0.0' - } - } catch (err) { - ForgeModStructure17.logger.error(`ForgeMod ${name} contains an invalid mcmod.info file.`) - createDefault = true - } } else { - ForgeModStructure17.logger.error(`ForgeMod ${name} does not contain mcmod.info file.`) + resolve(this.forgeModMetadata[name] as McModInfo) + return + } + + }) + } + + private processZip(zip: StreamZip, name: string): McModInfo { + // Optifine is a tweak that can be loaded as a forge mod. It does not + // appear to contain a mcmod.info class. This a special case we will + // account for. + if (name.toLowerCase().indexOf('optifine') > -1) { + + // Read zip for changelog.txt + let changelogBuf: Buffer + try { + changelogBuf = zip.entryDataSync('changelog.txt') + } catch(err) { + throw new Error('Failed to read OptiFine changelog.') + } + + const info = changelogBuf.toString().split('\n')[0].trim() + const version = info.split(' ')[1] + this.forgeModMetadata[name] = ({ + modid: 'optifine', + name: info, + version, + mcversion: version.substring(0, version.indexOf('_')) + }) as unknown as McModInfo + return this.forgeModMetadata[name] as McModInfo + } + + let raw: Buffer | undefined + try { + raw = zip.entryDataSync('mcmod.info') + } catch(err) { + // ignored + } + + let createDefault = false + + if (raw) { + // Assuming the main mod will be the first entry in this file. + try { + const resolved = JSON.parse(raw.toString()) as (McModInfoList | McModInfo[]) + if (Object.prototype.hasOwnProperty.call(resolved, 'modListVersion')) { + this.forgeModMetadata[name] = (resolved as McModInfoList).modList[0] + } else { + this.forgeModMetadata[name] = (resolved as McModInfo[])[0] + } + // No way to resolve this AFAIK + if(this.forgeModMetadata[name]!.version.indexOf('@') > -1 || this.forgeModMetadata[name]!.version.indexOf('$') > -1) { + // Ex. @VERSION@, ${version} + this.forgeModMetadata[name]!.version = '0.0.0' + } + } catch (err) { + ForgeModStructure17.logger.error(`ForgeMod ${name} contains an invalid mcmod.info file.`) createDefault = true } + } else { + ForgeModStructure17.logger.error(`ForgeMod ${name} does not contain mcmod.info file.`) + createDefault = true + } - if (createDefault) { - this.forgeModMetadata[name] = ({ - modid: name.substring(0, name.lastIndexOf('.')).toLowerCase(), - name, - version: '0.0.0' - }) as unknown as McModInfo - } + if (createDefault) { + this.forgeModMetadata[name] = ({ + modid: name.substring(0, name.lastIndexOf('.')).toLowerCase(), + name, + version: '0.0.0' + }) as unknown as McModInfo } return this.forgeModMetadata[name] as McModInfo diff --git a/src/model/struct/model/module/library.struct.ts b/src/model/struct/model/module/library.struct.ts index 8e05899..0cfe721 100644 --- a/src/model/struct/model/module/library.struct.ts +++ b/src/model/struct/model/module/library.struct.ts @@ -34,12 +34,12 @@ export class LibraryStructure extends ModuleStructure { } // eslint-disable-next-line @typescript-eslint/no-unused-vars - protected async getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise { + protected async getModuleId(name: string, path: string): Promise { const inference = this.attemptCrudeInference(name) return this.generateMavenIdentifier(inference.name, inference.version) } // eslint-disable-next-line @typescript-eslint/no-unused-vars - protected async getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise { + protected async getModuleName(name: string, path: string): Promise { const inference = this.attemptCrudeInference(name) return inference.name } diff --git a/src/model/struct/model/module/litemod.struct.ts b/src/model/struct/model/module/litemod.struct.ts index 28940d0..df081ff 100644 --- a/src/model/struct/model/module/litemod.struct.ts +++ b/src/model/struct/model/module/litemod.struct.ts @@ -1,4 +1,4 @@ -import AdmZip from 'adm-zip' +import StreamZip from 'node-stream-zip' import { Stats } from 'fs-extra' import { Type } from 'helios-distribution-types' import { join } from 'path' @@ -19,12 +19,12 @@ export class LiteModStructure extends ModuleStructure { super(absoluteRoot, relativeRoot, 'litemods', baseUrl, Type.LiteMod) } - protected async getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise { - const liteModData = this.getLiteModMetadata(buf, name) + protected async getModuleId(name: string, path: string): Promise { + const liteModData = await this.getLiteModMetadata(name, path) return this.generateMavenIdentifier(liteModData.name, `${liteModData.version}-${liteModData.mcversion}`) } - protected async getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise { - return capitalize(this.getLiteModMetadata(buf, name).name) + protected async getModuleName(name: string, path: string): Promise { + return capitalize((await this.getLiteModMetadata(name, path)).name) } // eslint-disable-next-line @typescript-eslint/no-unused-vars protected async getModuleUrl(name: string, path: string, stats: Stats): Promise { @@ -35,27 +35,53 @@ export class LiteModStructure extends ModuleStructure { return null } - private getLiteModMetadata(buf: Buffer, name: string): LiteMod { - if (!Object.prototype.hasOwnProperty.call(this.liteModMetadata, name)) { - const zip = new AdmZip(buf) - const zipEntries = zip.getEntries() + private getLiteModMetadata(name: string, path: string): Promise { + return new Promise((resolve, reject) => { + if (!Object.prototype.hasOwnProperty.call(this.liteModMetadata, name)) { - let raw - for (const entry of zipEntries) { - if (entry.entryName === 'litemod.json') { - raw = zip.readAsText(entry) - break - } - } + const zip = new StreamZip({ + file: path, + storeEntries: true + }) + + zip.on('error', err => reject(err)) + zip.on('ready', () => { + try { + const res = this.processZip(zip, name) + zip.close() + resolve(res) + return + } catch(err) { + zip.close() + throw err + } + }) - if (raw) { - this.liteModMetadata[name] = JSON.parse(raw) as LiteMod } else { - throw new Error(`Litemod ${name} does not contain litemod.json file.`) + resolve(this.liteModMetadata[name] as LiteMod) + return } + + }) + } + + private processZip(zip: StreamZip, name: string): LiteMod { + + let raw: Buffer | undefined + try { + raw = zip.entryDataSync('litemod.json') + } catch(err) { + // ignored + } + + if (raw) { + this.liteModMetadata[name] = JSON.parse(raw.toString()) as LiteMod + } else { + throw new Error(`Litemod ${name} does not contain litemod.json file.`) } return this.liteModMetadata[name] as LiteMod + } } diff --git a/src/model/struct/model/module/module.struct.ts b/src/model/struct/model/module/module.struct.ts index 7df446f..14fb3e2 100644 --- a/src/model/struct/model/module/module.struct.ts +++ b/src/model/struct/model/module/module.struct.ts @@ -29,16 +29,16 @@ export abstract class ModuleStructure extends BaseModelStructure { return `generated.${this.type.toLowerCase()}:${name}:${version}@${TypeMetadata[this.type].defaultExtension}` } - protected async abstract getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise - protected async abstract getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise + protected async abstract getModuleId(name: string, path: string): Promise + protected async abstract getModuleName(name: string, path: string): Promise protected async abstract getModuleUrl(name: string, path: string, stats: Stats): Promise protected async abstract getModulePath(name: string, path: string, stats: Stats): Promise protected async parseModule(file: string, filePath: string, stats: Stats): Promise { const buf = await readFile(filePath) const mdl: Module = { - id: await this.getModuleId(file, filePath, stats, buf), - name: await this.getModuleName(file, filePath, stats, buf), + id: await this.getModuleId(file, filePath), + name: await this.getModuleName(file, filePath), type: this.type, required: { value: false, diff --git a/src/resolver/forge/adapter/ForgeGradle2.resolver.ts b/src/resolver/forge/adapter/ForgeGradle2.resolver.ts index 368ebd7..5c7f696 100644 --- a/src/resolver/forge/adapter/ForgeGradle2.resolver.ts +++ b/src/resolver/forge/adapter/ForgeGradle2.resolver.ts @@ -1,4 +1,3 @@ -import AdmZip from 'adm-zip' import { createHash } from 'crypto' import { copy, lstat, mkdirs, pathExists, readFile, remove } from 'fs-extra' import { Module, Type } from 'helios-distribution-types' @@ -59,24 +58,14 @@ export class ForgeGradle2Adapter extends ForgeResolver { } ForgeGradle2Adapter.logger.debug(`Beginning processing of Forge v${this.forgeVersion} (Minecraft ${this.minecraftVersion})`) - const forgeUniversalBuffer = await readFile(targetLocalPath) - const zip = new AdmZip(forgeUniversalBuffer) - const zipEntries = zip.getEntries() - - let versionManifest - - for (const entry of zipEntries) { - if (entry.entryName === 'version.json') { - versionManifest = zip.readAsText(entry) - break - } - } - - if (!versionManifest) { + let versionManifestBuf: Buffer + try { + versionManifestBuf = await this.getVersionManifestFromJar(targetLocalPath) + } catch(err) { throw new Error('Failed to find version.json in forge universal jar.') } - versionManifest = JSON.parse(versionManifest) as VersionManifestFG2 + const versionManifest = JSON.parse(versionManifestBuf.toString()) as VersionManifestFG2 const forgeModule: Module = { id: MavenUtil.mavenComponentsToIdentifier( @@ -87,7 +76,7 @@ export class ForgeGradle2Adapter extends ForgeResolver { name: 'Minecraft Forge', type: Type.ForgeHosted, artifact: this.generateArtifact( - forgeUniversalBuffer, + await readFile(targetLocalPath), await lstat(targetLocalPath), libRepo.getArtifactUrlByComponents( this.baseUrl, diff --git a/src/resolver/forge/adapter/ForgeGradle3.resolver.ts b/src/resolver/forge/adapter/ForgeGradle3.resolver.ts index 61f1920..b8e2ab7 100644 --- a/src/resolver/forge/adapter/ForgeGradle3.resolver.ts +++ b/src/resolver/forge/adapter/ForgeGradle3.resolver.ts @@ -1,4 +1,3 @@ -import AdmZip from 'adm-zip' import { ForgeResolver } from '../forge.resolver' import { MinecraftVersion } from '../../../util/MinecraftVersion' import { LoggerUtil } from '../../../util/LoggerUtil' @@ -420,29 +419,19 @@ export class ForgeGradle3Adapter extends ForgeResolver { } return null } - + private async processWithoutInstaller(installerPath: string): Promise { // Extract version.json from installer. - const forgeInstallerBuffer = await readFile(installerPath) - const zip = new AdmZip(forgeInstallerBuffer) - const zipEntries = zip.getEntries() - - let versionManifest - - for (const entry of zipEntries) { - if (entry.entryName === 'version.json') { - versionManifest = zip.readAsText(entry) - break - } - } - - if (!versionManifest) { + let versionManifestBuf: Buffer + try { + versionManifestBuf = await this.getVersionManifestFromJar(installerPath) + } catch(err) { throw new Error('Failed to find version.json in forge installer jar.') } - - versionManifest = JSON.parse(versionManifest) as VersionManifestFG3 + + const versionManifest = JSON.parse(versionManifestBuf.toString()) as VersionManifestFG3 // Save Version Manifest const versionManifestDest = this.repoStructure.getVersionRepoStruct().getVersionManifest( diff --git a/src/resolver/forge/forge.resolver.ts b/src/resolver/forge/forge.resolver.ts index 670dd48..b840e46 100644 --- a/src/resolver/forge/forge.resolver.ts +++ b/src/resolver/forge/forge.resolver.ts @@ -1,3 +1,4 @@ +import StreamZip from 'node-stream-zip' import { createHash } from 'crypto' import { Stats } from 'fs-extra' import { Artifact } from 'helios-distribution-types' @@ -81,4 +82,24 @@ export abstract class ForgeResolver extends BaseResolver { } } + protected async getVersionManifestFromJar(jarPath: string): Promise{ + return new Promise((resolve, reject) => { + const zip = new StreamZip({ + file: jarPath, + storeEntries: true + }) + zip.on('ready', () => { + try { + const data = zip.entryDataSync('version.json') + zip.close() + resolve(data) + } catch(err) { + reject(err) + } + + }) + zip.on('error', err => reject(err)) + }) + } + }