Replace AdmZip with node-stream-zip.

This commit is contained in:
Daniel Scalzi
2020-06-02 23:07:59 -04:00
parent 0b063e4bfc
commit d627ce72a3
12 changed files with 283 additions and 215 deletions

3
.vscode/launch.json vendored
View File

@@ -16,7 +16,8 @@
"preLaunchTask": "compile", "preLaunchTask": "compile",
"outFiles": [ "outFiles": [
"${workspaceFolder}/dist/**/*.js" "${workspaceFolder}/dist/**/*.js"
] ],
"outputCapture": "std"
} }
] ]
} }

19
package-lock.json generated
View File

@@ -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": { "@types/color-name": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
@@ -210,11 +201,6 @@
"integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==",
"dev": true "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": { "ajv": {
"version": "6.12.2", "version": "6.12.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz",
@@ -1126,6 +1112,11 @@
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
"dev": true "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": { "once": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",

View File

@@ -26,7 +26,6 @@
}, },
"homepage": "https://github.com/dscalzi/Nebula#readme", "homepage": "https://github.com/dscalzi/Nebula#readme",
"devDependencies": { "devDependencies": {
"@types/adm-zip": "^0.4.33",
"@types/fs-extra": "^9.0.1", "@types/fs-extra": "^9.0.1",
"@types/node": "^12.12.43", "@types/node": "^12.12.43",
"@types/triple-beam": "^1.3.1", "@types/triple-beam": "^1.3.1",
@@ -38,12 +37,12 @@
"typescript": "^3.9.3" "typescript": "^3.9.3"
}, },
"dependencies": { "dependencies": {
"adm-zip": "^0.4.14",
"axios": "^0.19.2", "axios": "^0.19.2",
"dotenv": "^8.2.0", "dotenv": "^8.2.0",
"fs-extra": "^9.0.0", "fs-extra": "^9.0.0",
"helios-distribution-types": "^1.0.0-pre.1", "helios-distribution-types": "^1.0.0-pre.1",
"moment": "^2.26.0", "moment": "^2.26.0",
"node-stream-zip": "^1.11.2",
"toml": "^3.0.0", "toml": "^3.0.0",
"triple-beam": "^1.3.0", "triple-beam": "^1.3.0",
"winston": "^3.2.1", "winston": "^3.2.1",

View File

@@ -39,10 +39,10 @@ export class MiscFileStructure extends ModuleStructure {
return acc return acc
} }
protected async getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> { protected async getModuleId(name: string, path: string): Promise<string> {
return name return name
} }
protected async getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> { protected async getModuleName(name: string, path: string): Promise<string> {
return name return name
} }
protected async getModuleUrl(name: string, path: string, stats: Stats): Promise<string> { protected async getModuleUrl(name: string, path: string, stats: Stats): Promise<string> {

View File

@@ -1,5 +1,4 @@
import AdmZip from 'adm-zip' import StreamZip from 'node-stream-zip'
import { Stats } from 'fs-extra'
import toml from 'toml' import toml from 'toml'
import { capitalize } from '../../../../../util/stringutils' import { capitalize } from '../../../../../util/stringutils'
import { VersionUtil } from '../../../../../util/versionutil' import { VersionUtil } from '../../../../../util/versionutil'
@@ -33,59 +32,90 @@ export class ForgeModStructure113 extends BaseForgeModStructure {
return ForgeModStructure113.isForVersion(version, libraryVersion) return ForgeModStructure113.isForVersion(version, libraryVersion)
} }
protected async getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> { protected async getModuleId(name: string, path: string): Promise<string> {
const fmData = this.getForgeModMetadata(buf, name) const fmData = await this.getForgeModMetadata(name, path)
return this.generateMavenIdentifier(fmData.mods[0].modId, fmData.mods[0].version) return this.generateMavenIdentifier(fmData.mods[0].modId, fmData.mods[0].version)
} }
protected async getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> { protected async getModuleName(name: string, path: string): Promise<string> {
return capitalize((this.getForgeModMetadata(buf, name)).mods[0].displayName) return capitalize((await this.getForgeModMetadata(name, path)).mods[0].displayName)
} }
private getForgeModMetadata(buf: Buffer, name: string): ModsToml { private getForgeModMetadata(name: string, path: string): Promise<ModsToml> {
if (!Object.prototype.hasOwnProperty.call(this.forgeModMetadata, name)) { return new Promise((resolve, reject) => {
const zip = new AdmZip(buf) if (!Object.prototype.hasOwnProperty.call(this.forgeModMetadata, name)) {
const zipEntries = zip.getEntries()
// Optifine is a tweak that can be loaded as a forge mod. It does not const zip = new StreamZip({
// appear to contain a mcmod.info class. This a special case we will file: path,
// account for. storeEntries: true
if (name.toLowerCase().indexOf('optifine') > -1) { })
// Read zip for changelog.txt
let rawChangelog zip.on('error', err => reject(err))
for (const entry of zipEntries) { zip.on('ready', () => {
if (entry.entryName === 'changelog.txt') { try {
rawChangelog = zip.readAsText(entry) const res = this.processZip(zip, name)
break zip.close()
resolve(res)
return
} catch(err) {
zip.close()
throw err
} }
} })
if (!rawChangelog) {
throw new Error('Failed to read OptiFine changelog.') } else {
} resolve(this.forgeModMetadata[name] as ModsToml)
const info = rawChangelog.split('\n')[0].trim() return
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
} }
const raw = zip.readAsText('META-INF/mods.toml') })
}
let createDefault = false private processZip(zip: StreamZip, name: string): ModsToml {
if (raw) { // Optifine is a tweak that can be loaded as a forge mod. It does not
// Assuming the main mod will be the first entry in this file. // appear to contain a mcmod.info class. This a special case we will
try { // account for.
const parsed = toml.parse(raw) as ModsToml if (name.toLowerCase().indexOf('optifine') > -1) {
// tslint:disable-next-line: no-invalid-template-strings // Read zip for changelog.txt
if (parsed.mods[0].version === '${file.jarVersion}') { let changelogBuf: Buffer
let version = '0.0.0' try {
const manifest = zip.readAsText('META-INF/MANIFEST.MF') changelogBuf = zip.entryDataSync('changelog.txt')
const keys = manifest.split('\n') } 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) ForgeModStructure113.logger.debug(keys)
for (const key of keys) { for (const key of keys) {
const match = ForgeModStructure113.IMPLEMENTATION_VERSION_REGEX.exec(key) 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}`) 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}`)
} }
parsed.mods[0].version = version
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.`) this.forgeModMetadata[name] = parsed
} catch (err) {
ForgeModStructure113.logger.error(`ForgeMod ${name} contains an invalid mods.toml file.`)
createDefault = true createDefault = true
} }
} else {
ForgeModStructure113.logger.error(`ForgeMod ${name} does not contain mods.toml file.`)
createDefault = true
}
if (createDefault) { if (createDefault) {
this.forgeModMetadata[name] = ({ this.forgeModMetadata[name] = ({
modLoader: 'javafml', modLoader: 'javafml',
loaderVersion: '', loaderVersion: '',
mods: [{ mods: [{
modId: name.substring(0, name.lastIndexOf('.')).toLowerCase(), modId: name.substring(0, name.lastIndexOf('.')).toLowerCase(),
version: '0.0.0', version: '0.0.0',
displayName: name, displayName: name,
description: '' description: ''
}] }]
}) })
}
} }
return this.forgeModMetadata[name] as ModsToml return this.forgeModMetadata[name] as ModsToml
} }
} }

View File

@@ -1,5 +1,4 @@
import AdmZip from 'adm-zip' import StreamZip from 'node-stream-zip'
import { Stats } from 'fs-extra'
import { capitalize } from '../../../../../util/stringutils' import { capitalize } from '../../../../../util/stringutils'
import { VersionUtil } from '../../../../../util/versionutil' import { VersionUtil } from '../../../../../util/versionutil'
import { McModInfo } from '../../../../forge/mcmodinfo' import { McModInfo } from '../../../../forge/mcmodinfo'
@@ -31,85 +30,107 @@ export class ForgeModStructure17 extends BaseForgeModStructure {
return ForgeModStructure17.isForVersion(version, libraryVersion) return ForgeModStructure17.isForVersion(version, libraryVersion)
} }
protected async getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> { protected async getModuleId(name: string, path: string): Promise<string> {
const fmData = this.getForgeModMetadata(buf, name) const fmData = await this.getForgeModMetadata(name, path)
return this.generateMavenIdentifier(fmData.modid, fmData.version) return this.generateMavenIdentifier(fmData.modid, fmData.version)
} }
protected async getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> { protected async getModuleName(name: string, path: string): Promise<string> {
return capitalize((this.getForgeModMetadata(buf, name)).name) return capitalize((await this.getForgeModMetadata(name, path)).name)
} }
private getForgeModMetadata(buf: Buffer, name: string): McModInfo { private getForgeModMetadata(name: string, path: string): Promise<McModInfo> {
if (!Object.prototype.hasOwnProperty.call(this.forgeModMetadata, name)) { return new Promise((resolve, reject) => {
const zip = new AdmZip(buf) if (!Object.prototype.hasOwnProperty.call(this.forgeModMetadata, name)) {
const zipEntries = zip.getEntries()
// Optifine is a tweak that can be loaded as a forge mod. It does not const zip = new StreamZip({
// appear to contain a mcmod.info class. This a special case we will file: path,
// account for. storeEntries: true
if (name.toLowerCase().indexOf('optifine') > -1) { })
// Read zip for changelog.txt
let rawChangelog zip.on('error', err => reject(err))
for (const entry of zipEntries) { zip.on('ready', () => {
if (entry.entryName === 'changelog.txt') { try {
rawChangelog = zip.readAsText(entry) const res = this.processZip(zip, name)
break 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 { } 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 createDefault = true
} }
} else {
ForgeModStructure17.logger.error(`ForgeMod ${name} does not contain mcmod.info file.`)
createDefault = true
}
if (createDefault) { if (createDefault) {
this.forgeModMetadata[name] = ({ this.forgeModMetadata[name] = ({
modid: name.substring(0, name.lastIndexOf('.')).toLowerCase(), modid: name.substring(0, name.lastIndexOf('.')).toLowerCase(),
name, name,
version: '0.0.0' version: '0.0.0'
}) as unknown as McModInfo }) as unknown as McModInfo
}
} }
return this.forgeModMetadata[name] as McModInfo return this.forgeModMetadata[name] as McModInfo

View File

@@ -34,12 +34,12 @@ export class LibraryStructure extends ModuleStructure {
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
protected async getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> { protected async getModuleId(name: string, path: string): Promise<string> {
const inference = this.attemptCrudeInference(name) const inference = this.attemptCrudeInference(name)
return this.generateMavenIdentifier(inference.name, inference.version) return this.generateMavenIdentifier(inference.name, inference.version)
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
protected async getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> { protected async getModuleName(name: string, path: string): Promise<string> {
const inference = this.attemptCrudeInference(name) const inference = this.attemptCrudeInference(name)
return inference.name return inference.name
} }

View File

@@ -1,4 +1,4 @@
import AdmZip from 'adm-zip' import StreamZip from 'node-stream-zip'
import { Stats } from 'fs-extra' import { Stats } from 'fs-extra'
import { Type } from 'helios-distribution-types' import { Type } from 'helios-distribution-types'
import { join } from 'path' import { join } from 'path'
@@ -19,12 +19,12 @@ export class LiteModStructure extends ModuleStructure {
super(absoluteRoot, relativeRoot, 'litemods', baseUrl, Type.LiteMod) super(absoluteRoot, relativeRoot, 'litemods', baseUrl, Type.LiteMod)
} }
protected async getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> { protected async getModuleId(name: string, path: string): Promise<string> {
const liteModData = this.getLiteModMetadata(buf, name) const liteModData = await this.getLiteModMetadata(name, path)
return this.generateMavenIdentifier(liteModData.name, `${liteModData.version}-${liteModData.mcversion}`) return this.generateMavenIdentifier(liteModData.name, `${liteModData.version}-${liteModData.mcversion}`)
} }
protected async getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> { protected async getModuleName(name: string, path: string): Promise<string> {
return capitalize(this.getLiteModMetadata(buf, name).name) return capitalize((await this.getLiteModMetadata(name, path)).name)
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
protected async getModuleUrl(name: string, path: string, stats: Stats): Promise<string> { protected async getModuleUrl(name: string, path: string, stats: Stats): Promise<string> {
@@ -35,27 +35,53 @@ export class LiteModStructure extends ModuleStructure {
return null return null
} }
private getLiteModMetadata(buf: Buffer, name: string): LiteMod { private getLiteModMetadata(name: string, path: string): Promise<LiteMod> {
if (!Object.prototype.hasOwnProperty.call(this.liteModMetadata, name)) { return new Promise((resolve, reject) => {
const zip = new AdmZip(buf) if (!Object.prototype.hasOwnProperty.call(this.liteModMetadata, name)) {
const zipEntries = zip.getEntries()
let raw const zip = new StreamZip({
for (const entry of zipEntries) { file: path,
if (entry.entryName === 'litemod.json') { storeEntries: true
raw = zip.readAsText(entry) })
break
} 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 { } 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 return this.liteModMetadata[name] as LiteMod
} }
} }

View File

@@ -29,16 +29,16 @@ export abstract class ModuleStructure extends BaseModelStructure<Module> {
return `generated.${this.type.toLowerCase()}:${name}:${version}@${TypeMetadata[this.type].defaultExtension}` return `generated.${this.type.toLowerCase()}:${name}:${version}@${TypeMetadata[this.type].defaultExtension}`
} }
protected async abstract getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> protected async abstract getModuleId(name: string, path: string): Promise<string>
protected async abstract getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> protected async abstract getModuleName(name: string, path: string): Promise<string>
protected async abstract getModuleUrl(name: string, path: string, stats: Stats): Promise<string> protected async abstract getModuleUrl(name: string, path: string, stats: Stats): Promise<string>
protected async abstract getModulePath(name: string, path: string, stats: Stats): Promise<string | null> protected async abstract getModulePath(name: string, path: string, stats: Stats): Promise<string | null>
protected async parseModule(file: string, filePath: string, stats: Stats): Promise<Module> { protected async parseModule(file: string, filePath: string, stats: Stats): Promise<Module> {
const buf = await readFile(filePath) const buf = await readFile(filePath)
const mdl: Module = { const mdl: Module = {
id: await this.getModuleId(file, filePath, stats, buf), id: await this.getModuleId(file, filePath),
name: await this.getModuleName(file, filePath, stats, buf), name: await this.getModuleName(file, filePath),
type: this.type, type: this.type,
required: { required: {
value: false, value: false,

View File

@@ -1,4 +1,3 @@
import AdmZip from 'adm-zip'
import { createHash } from 'crypto' import { createHash } from 'crypto'
import { copy, lstat, mkdirs, pathExists, readFile, remove } from 'fs-extra' import { copy, lstat, mkdirs, pathExists, readFile, remove } from 'fs-extra'
import { Module, Type } from 'helios-distribution-types' 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})`) ForgeGradle2Adapter.logger.debug(`Beginning processing of Forge v${this.forgeVersion} (Minecraft ${this.minecraftVersion})`)
const forgeUniversalBuffer = await readFile(targetLocalPath) let versionManifestBuf: Buffer
const zip = new AdmZip(forgeUniversalBuffer) try {
const zipEntries = zip.getEntries() versionManifestBuf = await this.getVersionManifestFromJar(targetLocalPath)
} catch(err) {
let versionManifest
for (const entry of zipEntries) {
if (entry.entryName === 'version.json') {
versionManifest = zip.readAsText(entry)
break
}
}
if (!versionManifest) {
throw new Error('Failed to find version.json in forge universal jar.') 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 = { const forgeModule: Module = {
id: MavenUtil.mavenComponentsToIdentifier( id: MavenUtil.mavenComponentsToIdentifier(
@@ -87,7 +76,7 @@ export class ForgeGradle2Adapter extends ForgeResolver {
name: 'Minecraft Forge', name: 'Minecraft Forge',
type: Type.ForgeHosted, type: Type.ForgeHosted,
artifact: this.generateArtifact( artifact: this.generateArtifact(
forgeUniversalBuffer, await readFile(targetLocalPath),
await lstat(targetLocalPath), await lstat(targetLocalPath),
libRepo.getArtifactUrlByComponents( libRepo.getArtifactUrlByComponents(
this.baseUrl, this.baseUrl,

View File

@@ -1,4 +1,3 @@
import AdmZip from 'adm-zip'
import { ForgeResolver } from '../forge.resolver' import { ForgeResolver } from '../forge.resolver'
import { MinecraftVersion } from '../../../util/MinecraftVersion' import { MinecraftVersion } from '../../../util/MinecraftVersion'
import { LoggerUtil } from '../../../util/LoggerUtil' import { LoggerUtil } from '../../../util/LoggerUtil'
@@ -425,24 +424,14 @@ export class ForgeGradle3Adapter extends ForgeResolver {
// Extract version.json from installer. // Extract version.json from installer.
const forgeInstallerBuffer = await readFile(installerPath) let versionManifestBuf: Buffer
const zip = new AdmZip(forgeInstallerBuffer) try {
const zipEntries = zip.getEntries() versionManifestBuf = await this.getVersionManifestFromJar(installerPath)
} catch(err) {
let versionManifest
for (const entry of zipEntries) {
if (entry.entryName === 'version.json') {
versionManifest = zip.readAsText(entry)
break
}
}
if (!versionManifest) {
throw new Error('Failed to find version.json in forge installer jar.') 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 // Save Version Manifest
const versionManifestDest = this.repoStructure.getVersionRepoStruct().getVersionManifest( const versionManifestDest = this.repoStructure.getVersionRepoStruct().getVersionManifest(

View File

@@ -1,3 +1,4 @@
import StreamZip from 'node-stream-zip'
import { createHash } from 'crypto' import { createHash } from 'crypto'
import { Stats } from 'fs-extra' import { Stats } from 'fs-extra'
import { Artifact } from 'helios-distribution-types' import { Artifact } from 'helios-distribution-types'
@@ -81,4 +82,24 @@ export abstract class ForgeResolver extends BaseResolver {
} }
} }
protected async getVersionManifestFromJar(jarPath: string): Promise<Buffer>{
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))
})
}
} }