diff --git a/libraries/java/Claritas.jar b/libraries/java/Claritas.jar new file mode 100644 index 0000000..a86fb5b Binary files /dev/null and b/libraries/java/Claritas.jar differ diff --git a/package-lock.json b/package-lock.json index 2d5aa5f..ed3ca54 100644 --- a/package-lock.json +++ b/package-lock.json @@ -67,15 +67,6 @@ } } }, - "@babel/runtime-corejs3": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.10.4.tgz", - "integrity": "sha512-BFlgP2SoLO9HJX9WBwN67gHWMBhDX/eDz64Jajd6mR/UAUzqrNMm99d4qHnVaKscAElZoFiPv+JpR/Siud5lXw==", - "requires": { - "core-js-pure": "^3.0.0", - "regenerator-runtime": "^0.13.4" - } - }, "@dabh/diagnostics": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", @@ -113,9 +104,9 @@ "dev": true }, "@types/node": { - "version": "12.12.47", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.47.tgz", - "integrity": "sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A==", + "version": "12.12.50", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.50.tgz", + "integrity": "sha512-5ImO01Fb8YsEOYpV+aeyGYztcYcjGsBvN4D7G5r1ef2cuQOpymjWNQi5V0rKHE6PC2ru3HkoUr/Br2/8GUA84w==", "dev": true }, "@types/triple-beam": { @@ -140,12 +131,12 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.5.0.tgz", - "integrity": "sha512-m4erZ8AkSjoIUOf8s4k2V1xdL2c1Vy0D3dN6/jC9d7+nEqjY3gxXCkgi3gW/GAxPaA4hV8biaCoTVdQmfAeTCQ==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.6.1.tgz", + "integrity": "sha512-06lfjo76naNeOMDl+mWG9Fh/a0UHKLGhin+mGaIw72FUMbMGBkdi/FEJmgEDzh4eE73KIYzHWvOCYJ0ak7nrJQ==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "3.5.0", + "@typescript-eslint/experimental-utils": "3.6.1", "debug": "^4.1.1", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", @@ -171,45 +162,45 @@ } }, "@typescript-eslint/experimental-utils": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.5.0.tgz", - "integrity": "sha512-zGNOrVi5Wz0jcjUnFZ6QUD0MCox5hBuVwemGCew2qJzUX5xPoyR+0EzS5qD5qQXL/vnQ8Eu+nv03tpeFRwLrDg==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.6.1.tgz", + "integrity": "sha512-oS+hihzQE5M84ewXrTlVx7eTgc52eu+sVmG7ayLfOhyZmJ8Unvf3osyFQNADHP26yoThFfbxcibbO0d2FjnYhg==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/types": "3.5.0", - "@typescript-eslint/typescript-estree": "3.5.0", + "@typescript-eslint/types": "3.6.1", + "@typescript-eslint/typescript-estree": "3.6.1", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" } }, "@typescript-eslint/parser": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.5.0.tgz", - "integrity": "sha512-sU07VbYB70WZHtgOjH/qfAp1+OwaWgrvD1Km1VXqRpcVxt971PMTU7gJtlrCje0M+Sdz7xKAbtiyIu+Y6QdnVA==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.6.1.tgz", + "integrity": "sha512-SLihQU8RMe77YJ/jGTqOt0lMq7k3hlPVfp7v/cxMnXA9T0bQYoMDfTsNgHXpwSJM1Iq2aAJ8WqekxUwGv5F67Q==", "dev": true, "requires": { "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "3.5.0", - "@typescript-eslint/types": "3.5.0", - "@typescript-eslint/typescript-estree": "3.5.0", + "@typescript-eslint/experimental-utils": "3.6.1", + "@typescript-eslint/types": "3.6.1", + "@typescript-eslint/typescript-estree": "3.6.1", "eslint-visitor-keys": "^1.1.0" } }, "@typescript-eslint/types": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.5.0.tgz", - "integrity": "sha512-Dreqb5idi66VVs1QkbAwVeDmdJG+sDtofJtKwKCZXIaBsINuCN7Jv5eDIHrS0hFMMiOvPH9UuOs4splW0iZe4Q==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.6.1.tgz", + "integrity": "sha512-NPxd5yXG63gx57WDTW1rp0cF3XlNuuFFB5G+Kc48zZ+51ZnQn9yjDEsjTPQ+aWM+V+Z0I4kuTFKjKvgcT1F7xQ==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.5.0.tgz", - "integrity": "sha512-Na71ezI6QP5WVR4EHxwcBJgYiD+Sre9BZO5iJK2QhrmRPo/42+b0no/HZIrdD1sjghzlYv7t+7Jis05M1uMxQg==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.6.1.tgz", + "integrity": "sha512-G4XRe/ZbCZkL1fy09DPN3U0mR6SayIv1zSeBNquRFRk7CnVLgkC2ZPj8llEMJg5Y8dJ3T76SvTGtceytniaztQ==", "dev": true, "requires": { - "@typescript-eslint/types": "3.5.0", - "@typescript-eslint/visitor-keys": "3.5.0", + "@typescript-eslint/types": "3.6.1", + "@typescript-eslint/visitor-keys": "3.6.1", "debug": "^4.1.1", "glob": "^7.1.6", "is-glob": "^4.0.1", @@ -236,9 +227,9 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.5.0.tgz", - "integrity": "sha512-7cTp9rcX2sz9Z+zua9MCOX4cqp5rYyFD5o8LlbSpXrMTXoRdngTtotRZEkm8+FNMHPWYFhitFK+qt/brK8BVJQ==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.6.1.tgz", + "integrity": "sha512-qC8Olwz5ZyMTZrh4Wl3K4U6tfms0R/mzU4/5W3XeUZptVraGVmbptJbn6h2Ey6Rb3hOs3zWoAUebZk8t47KGiQ==", "dev": true, "requires": { "eslint-visitor-keys": "^1.1.0" @@ -451,11 +442,6 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "core-js-pure": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.5.tgz", - "integrity": "sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==" - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -481,12 +467,9 @@ } }, "decamelize": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-3.2.0.tgz", - "integrity": "sha512-4TgkVUsmmu7oCSyGBm5FvfMoACuoh9EOidm7V5/J2X2djAwwt57qb3F2KMP2ITqODTCSwb+YRV+0Zqrv18k/hw==", - "requires": { - "xregexp": "^4.2.4" - } + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, "deep-is": { "version": "0.1.3", @@ -976,9 +959,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", "dev": true }, "logform": { @@ -1156,11 +1139,6 @@ "util-deprecate": "^1.0.1" } }, - "regenerator-runtime": { - "version": "0.13.5", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", - "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==" - }, "regexpp": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", @@ -1559,26 +1537,18 @@ "mkdirp": "^0.5.1" } }, - "xregexp": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.3.0.tgz", - "integrity": "sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g==", - "requires": { - "@babel/runtime-corejs3": "^7.8.3" - } - }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" }, "yargs": { - "version": "15.4.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.0.tgz", - "integrity": "sha512-D3fRFnZwLWp8jVAAhPZBsmeIHY8tTsb8ItV9KaAaopmC6wde2u6Yw29JBIZHXw14kgkRnYmDgmQU4FVMDlIsWw==", + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "requires": { "cliui": "^6.0.0", - "decamelize": "^3.2.0", + "decamelize": "^1.2.0", "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", @@ -1597,13 +1567,6 @@ "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" - }, - "dependencies": { - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - } } } } diff --git a/package.json b/package.json index 97cd39e..2927e24 100644 --- a/package.json +++ b/package.json @@ -27,11 +27,11 @@ "homepage": "https://github.com/dscalzi/Nebula#readme", "devDependencies": { "@types/fs-extra": "^9.0.1", - "@types/node": "^12.12.47", + "@types/node": "^12.12.50", "@types/triple-beam": "^1.3.1", "@types/yargs": "^15.0.5", - "@typescript-eslint/eslint-plugin": "^3.5.0", - "@typescript-eslint/parser": "^3.5.0", + "@typescript-eslint/eslint-plugin": "^3.6.1", + "@typescript-eslint/parser": "^3.6.1", "eslint": "^7.4.0", "rimraf": "^3.0.2", "typescript": "^3.9.6" @@ -46,6 +46,6 @@ "toml": "^3.0.0", "triple-beam": "^1.3.0", "winston": "^3.3.3", - "yargs": "^15.4.0" + "yargs": "^15.4.1" } } diff --git a/src/model/claritas/ClaritasLibraryType.ts b/src/model/claritas/ClaritasLibraryType.ts new file mode 100644 index 0000000..14b5e3e --- /dev/null +++ b/src/model/claritas/ClaritasLibraryType.ts @@ -0,0 +1,6 @@ +export enum LibraryType { + + FORGE = 'FORGE', + LITELOADER = 'LITELOADER' + +} \ No newline at end of file diff --git a/src/model/claritas/ClaritasResult.ts b/src/model/claritas/ClaritasResult.ts new file mode 100644 index 0000000..a431e1c --- /dev/null +++ b/src/model/claritas/ClaritasResult.ts @@ -0,0 +1,26 @@ +export interface ClaritasModuleMetadata { + + /** + * Present on ForgeMods + */ + id?: string + /** + * Always Present + */ + group: string + /** + * Possibly present on ForgeMods 1.12- + */ + version?: string + /** + * Possibly present on ForgeMods 1.12- + */ + name?: string + +} + +export interface ClaritasResult { + + [jarPath: string]: ClaritasModuleMetadata | undefined + +} \ No newline at end of file diff --git a/src/model/struct/BaseFileStructure.ts b/src/model/struct/BaseFileStructure.ts index ffc8746..4a9ba25 100644 --- a/src/model/struct/BaseFileStructure.ts +++ b/src/model/struct/BaseFileStructure.ts @@ -1,9 +1,12 @@ import { mkdirs } from 'fs-extra' import { join, resolve } from 'path' import { FileStructure } from './FileStructure' +import { Logger } from 'winston' +import { LoggerUtil } from '../../util/LoggerUtil' export abstract class BaseFileStructure implements FileStructure { + protected logger: Logger protected containerDirectory: string constructor( @@ -13,10 +16,13 @@ export abstract class BaseFileStructure implements FileStructure { ) { this.relativeRoot = join(relativeRoot, structRoot) this.containerDirectory = resolve(absoluteRoot, structRoot) + this.logger = LoggerUtil.getLogger(this.getLoggerName()) } public async init(): Promise { mkdirs(this.containerDirectory) } + public abstract getLoggerName(): string + } diff --git a/src/model/struct/model/module/file.struct.ts b/src/model/struct/model/module/file.struct.ts index 656fac3..01bf008 100644 --- a/src/model/struct/model/module/file.struct.ts +++ b/src/model/struct/model/module/file.struct.ts @@ -5,15 +5,21 @@ import { resolve as resolveURL } from 'url' import { ModuleStructure } from './module.struct' import { readdir, stat } from 'fs-extra' import { join, resolve, sep } from 'path' +import { MinecraftVersion } from '../../../../util/MinecraftVersion' export class MiscFileStructure extends ModuleStructure { constructor( absoluteRoot: string, relativeRoot: string, - baseUrl: string + baseUrl: string, + minecraftVersion: MinecraftVersion ) { - super(absoluteRoot, relativeRoot, 'files', baseUrl, Type.File) + super(absoluteRoot, relativeRoot, 'files', baseUrl, minecraftVersion, Type.File) + } + + public getLoggerName(): string { + return 'MiscFileStructure' } public async getSpecModel(): Promise { diff --git a/src/model/struct/model/module/forgemod.struct.ts b/src/model/struct/model/module/forgemod.struct.ts index 8e1f2b3..aa0d214 100644 --- a/src/model/struct/model/module/forgemod.struct.ts +++ b/src/model/struct/model/module/forgemod.struct.ts @@ -5,6 +5,8 @@ import { resolve } from 'url' import { VersionSegmented } from '../../../../util/VersionSegmented' import { MinecraftVersion } from '../../../../util/MinecraftVersion' import { ToggleableModuleStructure } from './toggleablemodule.struct' +import { LibraryType } from '../../../claritas/ClaritasLibraryType' +import { ClaritasException } from './module.struct' export abstract class BaseForgeModStructure extends ToggleableModuleStructure implements VersionSegmented { @@ -13,9 +15,10 @@ export abstract class BaseForgeModStructure extends ToggleableModuleStructure im constructor( absoluteRoot: string, relativeRoot: string, - baseUrl: string + baseUrl: string, + minecraftVersion: MinecraftVersion ) { - super(absoluteRoot, relativeRoot, 'forgemods', baseUrl, Type.ForgeMod) + super(absoluteRoot, relativeRoot, 'forgemods', baseUrl, minecraftVersion, Type.ForgeMod) } public abstract isForVersion(version: MinecraftVersion, libraryVersion: string): boolean @@ -29,4 +32,21 @@ export abstract class BaseForgeModStructure extends ToggleableModuleStructure im return null } + protected getClaritasExceptions(): ClaritasException[] { + return [{ + exceptionName: 'optifine', + proxyMetadata: { + group: 'net.optifine' + } + }] + } + + protected getClaritasType(): LibraryType { + return LibraryType.FORGE + } + + protected discernResult(claritasValue: string | undefined, crudeInference: string): string { + return (claritasValue == null || claritasValue == '') ? crudeInference : claritasValue + } + } diff --git a/src/model/struct/model/module/forgemod/forgemod113.struct.ts b/src/model/struct/model/module/forgemod/forgemod113.struct.ts index ff7186d..c73d0fe 100644 --- a/src/model/struct/model/module/forgemod/forgemod113.struct.ts +++ b/src/model/struct/model/module/forgemod/forgemod113.struct.ts @@ -5,12 +5,9 @@ import { VersionUtil } from '../../../../../util/versionutil' import { ModsToml } from '../../../../forge/modstoml' import { BaseForgeModStructure } from '../forgemod.struct' import { MinecraftVersion } from '../../../../../util/MinecraftVersion' -import { LoggerUtil } from '../../../../../util/LoggerUtil' export class ForgeModStructure113 extends BaseForgeModStructure { - private static readonly logger = LoggerUtil.getLogger('ForgeModStructure (1.13)') - public static readonly IMPLEMENTATION_VERSION_REGEX = /^Implementation-Version: (.+)[\r\n]/ // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -23,18 +20,23 @@ export class ForgeModStructure113 extends BaseForgeModStructure { constructor( absoluteRoot: string, relativeRoot: string, - baseUrl: string + baseUrl: string, + minecraftVersion: MinecraftVersion ) { - super(absoluteRoot, relativeRoot, baseUrl) + super(absoluteRoot, relativeRoot, baseUrl, minecraftVersion) } public isForVersion(version: MinecraftVersion, libraryVersion: string): boolean { return ForgeModStructure113.isForVersion(version, libraryVersion) } + public getLoggerName(): string { + return 'ForgeModStructure (1.13)' + } + 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) + return this.generateMavenIdentifier(this.getClaritasGroup(path), fmData.mods[0].modId, fmData.mods[0].version) } protected async getModuleName(name: string, path: string): Promise { return capitalize((await this.getForgeModMetadata(name, path)).mods[0].displayName) @@ -52,7 +54,7 @@ export class ForgeModStructure113 extends BaseForgeModStructure { zip.on('error', err => reject(err)) zip.on('ready', () => { try { - const res = this.processZip(zip, name) + const res = this.processZip(zip, name, path) zip.close() resolve(res) return @@ -71,7 +73,7 @@ export class ForgeModStructure113 extends BaseForgeModStructure { }) } - private processZip(zip: StreamZip, name: string): ModsToml { + private processZip(zip: StreamZip, name: string, path: string): 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 @@ -116,12 +118,21 @@ export class ForgeModStructure113 extends BaseForgeModStructure { const parsed = toml.parse(raw.toString()) as ModsToml this.forgeModMetadata[name] = parsed } catch (err) { - ForgeModStructure113.logger.error(`ForgeMod ${name} contains an invalid mods.toml file.`) + this.logger.error(`ForgeMod ${name} contains an invalid mods.toml file.`) } } else { - ForgeModStructure113.logger.error(`ForgeMod ${name} does not contain mods.toml file.`) + this.logger.error(`ForgeMod ${name} does not contain mods.toml file.`) } + const cRes = this.claritasResult?.[path] + + if(cRes == null) { + this.logger.error(`Claritas failed to yield metadata for ForgeMod ${name}!`) + this.logger.error('Is this mod malformated or does Claritas need an update?') + } + + const claritasId = cRes?.id + const crudeInference = this.attemptCrudeInference(name) if(this.forgeModMetadata[name] != null) { @@ -130,7 +141,7 @@ export class ForgeModStructure113 extends BaseForgeModStructure { for(const entry of x.mods) { if(entry.modId === this.EXAMPLE_MOD_ID) { - entry.modId = crudeInference.name.toLowerCase() + entry.modId = this.discernResult(claritasId, crudeInference.name.toLowerCase()) entry.displayName = crudeInference.name } @@ -139,16 +150,16 @@ export class ForgeModStructure113 extends BaseForgeModStructure { try { const manifest = zip.entryDataSync('META-INF/MANIFEST.MF') const keys = manifest.toString().split('\n') - ForgeModStructure113.logger.debug(keys) + this.logger.debug(keys) for (const key of keys) { const match = ForgeModStructure113.IMPLEMENTATION_VERSION_REGEX.exec(key) if (match != null) { version = match[1] } } - ForgeModStructure113.logger.debug(`ForgeMod ${name} contains a version wildcard, inferring ${version}`) + this.logger.debug(`ForgeMod ${name} contains a version wildcard, inferring ${version}`) } catch { - ForgeModStructure113.logger.debug(`ForgeMod ${name} contains a version wildcard yet no MANIFEST.MF.. Defaulting to ${version}`) + this.logger.debug(`ForgeMod ${name} contains a version wildcard yet no MANIFEST.MF.. Defaulting to ${version}`) } entry.version = version } @@ -159,7 +170,7 @@ export class ForgeModStructure113 extends BaseForgeModStructure { modLoader: 'javafml', loaderVersion: '', mods: [{ - modId: crudeInference.name.toLowerCase(), + modId: this.discernResult(claritasId, crudeInference.name.toLowerCase()), version: crudeInference.version, displayName: crudeInference.name, description: '' diff --git a/src/model/struct/model/module/forgemod/forgemod17.struct.ts b/src/model/struct/model/module/forgemod/forgemod17.struct.ts index 2694f4e..d512de6 100644 --- a/src/model/struct/model/module/forgemod/forgemod17.struct.ts +++ b/src/model/struct/model/module/forgemod/forgemod17.struct.ts @@ -5,12 +5,9 @@ import { McModInfo } from '../../../../forge/mcmodinfo' import { McModInfoList } from '../../../../forge/mcmodinfolist' import { BaseForgeModStructure } from '../forgemod.struct' import { MinecraftVersion } from '../../../../../util/MinecraftVersion' -import { LoggerUtil } from '../../../../../util/LoggerUtil' export class ForgeModStructure17 extends BaseForgeModStructure { - private static readonly logger = LoggerUtil.getLogger('ForgeModStructure (1.7)') - // eslint-disable-next-line @typescript-eslint/no-unused-vars public static isForVersion(version: MinecraftVersion, libraryVersion: string): boolean { return VersionUtil.isVersionAcceptable(version, [7, 8, 9, 10, 11, 12]) @@ -21,18 +18,23 @@ export class ForgeModStructure17 extends BaseForgeModStructure { constructor( absoluteRoot: string, relativeRoot: string, - baseUrl: string + baseUrl: string, + minecraftVersion: MinecraftVersion ) { - super(absoluteRoot, relativeRoot, baseUrl) + super(absoluteRoot, relativeRoot, baseUrl, minecraftVersion) } public isForVersion(version: MinecraftVersion, libraryVersion: string): boolean { return ForgeModStructure17.isForVersion(version, libraryVersion) } + public getLoggerName(): string { + return 'ForgeModStructure (1.7)' + } + protected async getModuleId(name: string, path: string): Promise { const fmData = await this.getForgeModMetadata(name, path) - return this.generateMavenIdentifier(fmData.modid, fmData.version) + return this.generateMavenIdentifier(this.getClaritasGroup(path), fmData.modid, fmData.version) } protected async getModuleName(name: string, path: string): Promise { return capitalize((await this.getForgeModMetadata(name, path)).name) @@ -50,7 +52,7 @@ export class ForgeModStructure17 extends BaseForgeModStructure { zip.on('error', err => reject(err)) zip.on('ready', () => { try { - const res = this.processZip(zip, name) + const res = this.processZip(zip, name, path) zip.close() resolve(res) return @@ -69,7 +71,7 @@ export class ForgeModStructure17 extends BaseForgeModStructure { }) } - private processZip(zip: StreamZip, name: string): McModInfo { + private processZip(zip: StreamZip, name: string, path: 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. @@ -113,38 +115,50 @@ export class ForgeModStructure17 extends BaseForgeModStructure { } } catch (err) { - ForgeModStructure17.logger.error(`ForgeMod ${name} contains an invalid mcmod.info file.`) + this.logger.error(`ForgeMod ${name} contains an invalid mcmod.info file.`) } } else { - ForgeModStructure17.logger.error(`ForgeMod ${name} does not contain mcmod.info file.`) + this.logger.error(`ForgeMod ${name} does not contain mcmod.info file.`) } + const cRes = this.claritasResult[path] + + if(cRes == null) { + this.logger.error(`Claritas failed to yield metadata for ForgeMod ${name}!`) + this.logger.error('Is this mod malformated or does Claritas need an update?') + } + + const claritasId = cRes?.id + const claritasVersion = cRes?.version + const claritasName = cRes?.name + + // Validate const crudeInference = this.attemptCrudeInference(name) if(this.forgeModMetadata[name] != null) { const x = this.forgeModMetadata[name]! if(x.modid == null || x.modid === '' || x.modid === this.EXAMPLE_MOD_ID) { - x.modid = crudeInference.name.toLowerCase() - x.name = crudeInference.name + x.modid = this.discernResult(claritasId, crudeInference.name.toLowerCase()) + x.name = this.discernResult(claritasName, crudeInference.name) } // Ex. @VERSION@, ${version} if(this.forgeModMetadata[name]!.version != null) { const isVersionWildcard = this.forgeModMetadata[name]!.version.indexOf('@') > -1 || this.forgeModMetadata[name]!.version.indexOf('$') > -1 if(isVersionWildcard) { - x.version = crudeInference.version + x.version = this.discernResult(claritasVersion, crudeInference.version) } } else { - x.version = crudeInference.version + x.version = this.discernResult(claritasVersion, crudeInference.version) } } else { this.forgeModMetadata[name] = ({ - modid: crudeInference.name.toLowerCase(), - name: crudeInference.name, - version: crudeInference.version + modid: this.discernResult(claritasId, crudeInference.name.toLowerCase()), + name: this.discernResult(claritasName, crudeInference.name), + version: this.discernResult(claritasVersion, crudeInference.version) }) as McModInfo } diff --git a/src/model/struct/model/module/library.struct.ts b/src/model/struct/model/module/library.struct.ts index c02327c..fdecf3f 100644 --- a/src/model/struct/model/module/library.struct.ts +++ b/src/model/struct/model/module/library.struct.ts @@ -3,23 +3,29 @@ import { Type, TypeMetadata } from 'helios-distribution-types' import { Stats } from 'fs-extra' import { join } from 'path' import { resolve } from 'url' +import { MinecraftVersion } from '../../../../util/MinecraftVersion' export class LibraryStructure extends ModuleStructure { constructor( absoluteRoot: string, relativeRoot: string, - baseUrl: string + baseUrl: string, + minecraftVersion: MinecraftVersion ) { - super(absoluteRoot, relativeRoot, 'libraries', baseUrl, Type.Library, (name: string) => { + super(absoluteRoot, relativeRoot, 'libraries', baseUrl, minecraftVersion, Type.Library, (name: string) => { return name.toLowerCase().endsWith(TypeMetadata[this.type].defaultExtension!) }) } + public getLoggerName(): string { + return 'LibraryStructure' + } + // eslint-disable-next-line @typescript-eslint/no-unused-vars protected async getModuleId(name: string, path: string): Promise { const inference = this.attemptCrudeInference(name) - return this.generateMavenIdentifier(inference.name, inference.version) + return this.generateMavenIdentifier(this.getDefaultGroup(), inference.name, inference.version) } // eslint-disable-next-line @typescript-eslint/no-unused-vars protected async getModuleName(name: string, path: string): Promise { diff --git a/src/model/struct/model/module/litemod.struct.ts b/src/model/struct/model/module/litemod.struct.ts index 1c88a5d..932b3bd 100644 --- a/src/model/struct/model/module/litemod.struct.ts +++ b/src/model/struct/model/module/litemod.struct.ts @@ -6,6 +6,8 @@ import { resolve } from 'url' import { capitalize } from '../../../../util/stringutils' import { LiteMod } from '../../../liteloader/litemod' import { ToggleableModuleStructure } from './toggleablemodule.struct' +import { MinecraftVersion } from '../../../../util/MinecraftVersion' +import { LibraryType } from '../../../claritas/ClaritasLibraryType' export class LiteModStructure extends ToggleableModuleStructure { @@ -14,14 +16,19 @@ export class LiteModStructure extends ToggleableModuleStructure { constructor( absoluteRoot: string, relativeRoot: string, - baseUrl: string + baseUrl: string, + minecraftVersion: MinecraftVersion ) { - super(absoluteRoot, relativeRoot, 'litemods', baseUrl, Type.LiteMod) + super(absoluteRoot, relativeRoot, 'litemods', baseUrl, minecraftVersion, Type.LiteMod) + } + + public getLoggerName(): string { + return 'LiteModStructure' } protected async getModuleId(name: string, path: string): Promise { const liteModData = await this.getLiteModMetadata(name, path) - return this.generateMavenIdentifier(liteModData.name, `${liteModData.version}-${liteModData.mcversion}`) + return this.generateMavenIdentifier(this.getClaritasGroup(path), liteModData.name, `${liteModData.version}-${liteModData.mcversion}`) } protected async getModuleName(name: string, path: string): Promise { return capitalize((await this.getLiteModMetadata(name, path)).name) @@ -35,6 +42,10 @@ export class LiteModStructure extends ToggleableModuleStructure { return null } + protected getClaritasType(): LibraryType { + return LibraryType.LITELOADER + } + private getLiteModMetadata(name: string, path: string): Promise { return new Promise((resolve, reject) => { if (!Object.prototype.hasOwnProperty.call(this.liteModMetadata, name)) { diff --git a/src/model/struct/model/module/module.struct.ts b/src/model/struct/model/module/module.struct.ts index 8e1f940..f383cc4 100644 --- a/src/model/struct/model/module/module.struct.ts +++ b/src/model/struct/model/module/module.struct.ts @@ -3,17 +3,35 @@ import { lstat, pathExists, readdir, readFile, Stats } from 'fs-extra' import { Module, Type, TypeMetadata } from 'helios-distribution-types' import { resolve } from 'path' import { BaseModelStructure } from '../basemodel.struct' +import { LibraryType } from '../../../claritas/ClaritasLibraryType' +import { ClaritasResult, ClaritasModuleMetadata } from '../../../claritas/ClaritasResult' +import { ClaritasWrapper } from '../../../../util/java/ClaritasWrapper' +import { MinecraftVersion } from '../../../../util/MinecraftVersion' + +export interface ModuleCandidate { + file: string + filePath: string + stats: Stats +} + +export interface ClaritasException { + exceptionName: string + proxyMetadata: ClaritasModuleMetadata +} export abstract class ModuleStructure extends BaseModelStructure { private readonly crudeRegex = /(.+?)-(.+).[jJ][aA][rR]/ protected readonly DEFAULT_VERSION = '0.0.0' + protected claritasResult!: ClaritasResult + constructor( absoluteRoot: string, relativeRoot: string, structRoot: string, baseUrl: string, + protected minecraftVersion: MinecraftVersion, protected type: Type, protected filter?: ((name: string, path: string, stats: Stats) => boolean) ) { @@ -22,14 +40,18 @@ export abstract class ModuleStructure extends BaseModelStructure { public async getSpecModel(): Promise { if (this.resolvedModels == null) { - this.resolvedModels = await this._doModuleRetrieval(this.containerDirectory) + this.resolvedModels = await this._doModuleRetrieval(await this._doModuleDiscovery(this.containerDirectory)) } return this.resolvedModels } - protected generateMavenIdentifier(name: string, version: string): string { - return `generated.${this.type.toLowerCase()}:${name}:${version}@${TypeMetadata[this.type].defaultExtension}` + protected getDefaultGroup(): string { + return `generated.${this.type.toLowerCase()}` + } + + protected generateMavenIdentifier(group: string, id: string, version: string): string { + return `${group}:${id}:${version}@${TypeMetadata[this.type].defaultExtension}` } protected attemptCrudeInference(name: string): { name: string, version: string } { @@ -47,6 +69,18 @@ export abstract class ModuleStructure extends BaseModelStructure { } } + protected getClaritasGroup(path: string): string { + return this.claritasResult[path]?.group || this.getDefaultGroup() + } + + protected getClaritasExceptions(): ClaritasException[] { + return [] + } + + protected getClaritasType(): LibraryType | null { + return null + } + 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 @@ -71,9 +105,9 @@ export abstract class ModuleStructure extends BaseModelStructure { return mdl } - protected async _doModuleRetrieval(scanDirectory: string): Promise { + protected async _doModuleDiscovery(scanDirectory: string): Promise { - const accumulator: Module[] = [] + const moduleCandidates: ModuleCandidate[] = [] if (await pathExists(scanDirectory)) { const files = await readdir(scanDirectory) @@ -82,13 +116,63 @@ export abstract class ModuleStructure extends BaseModelStructure { const stats = await lstat(filePath) if (stats.isFile()) { if(this.filter == null || this.filter(file, filePath, stats)) { - accumulator.push(await this.parseModule(file, filePath, stats)) + moduleCandidates.push({file, filePath, stats}) } - } } } + return moduleCandidates + + } + + protected async _doModuleRetrieval(moduleCandidates: ModuleCandidate[], options?: { + preProcess?: (candidate: ModuleCandidate) => void + postProcess?: (module: Module) => void + }): Promise { + + const accumulator: Module[] = [] + + if(moduleCandidates.length > 0) { + + // Invoke Claritas + if(this.getClaritasType() != null) { + const claritasExecutor = new ClaritasWrapper() + + let claritasCandidates = moduleCandidates + const exceptionCandidates: [ModuleCandidate, ClaritasException][] = [] + for(const exception of this.getClaritasExceptions()) { + const exceptionCandidate = moduleCandidates.find((value) => value.file.toLowerCase().indexOf(exception.exceptionName) > -1) + if(exceptionCandidate != null) { + exceptionCandidates.push([exceptionCandidate, exception]) + claritasCandidates = claritasCandidates.filter((value) => value.file.toLowerCase().indexOf(exception.exceptionName) === -1) + } + } + + this.claritasResult = await claritasExecutor.execute( + this.getClaritasType()!, + this.minecraftVersion, + claritasCandidates.map(entry => entry.filePath) + ) + if(this.claritasResult == null) { + this.logger.error('Failed to process Claritas result!') + } else { + for(const [candidate, exception] of exceptionCandidates) { + this.claritasResult[candidate.filePath] = exception.proxyMetadata + } + } + } + + // Process Modules + for(const candidate of moduleCandidates) { + options?.preProcess?.(candidate) + const mdl = await this.parseModule(candidate.file, candidate.filePath, candidate.stats) + options?.postProcess?.(mdl) + accumulator.push(mdl) + } + + } + return accumulator } diff --git a/src/model/struct/model/module/toggleablemodule.struct.ts b/src/model/struct/model/module/toggleablemodule.struct.ts index 169f8e2..967a906 100644 --- a/src/model/struct/model/module/toggleablemodule.struct.ts +++ b/src/model/struct/model/module/toggleablemodule.struct.ts @@ -1,7 +1,8 @@ -import { ModuleStructure } from './module.struct' +import { ModuleStructure, ModuleCandidate } from './module.struct' import { Type, Module } from 'helios-distribution-types' import { Stats, mkdirs } from 'fs-extra' import { resolve } from 'path' +import { MinecraftVersion } from '../../../../util/MinecraftVersion' export enum ToggleableNamespace { @@ -11,6 +12,10 @@ export enum ToggleableNamespace { } +export interface ToggleableModuleCandidate extends ModuleCandidate { + namespace: ToggleableNamespace +} + export abstract class ToggleableModuleStructure extends ModuleStructure { private activeNamespace: string | undefined @@ -20,10 +25,11 @@ export abstract class ToggleableModuleStructure extends ModuleStructure { relativeRoot: string, structRoot: string, baseUrl: string, - protected type: Type, - protected filter?: ((name: string, path: string, stats: Stats) => boolean) + minecraftVersion: MinecraftVersion, + type: Type, + filter?: ((name: string, path: string, stats: Stats) => boolean) ) { - super(absoluteRoot, relativeRoot, structRoot, baseUrl, type, filter) + super(absoluteRoot, relativeRoot, structRoot, baseUrl, minecraftVersion, type, filter) } public async init(): Promise { @@ -36,13 +42,21 @@ export abstract class ToggleableModuleStructure extends ModuleStructure { public async getSpecModel(): Promise { if (this.resolvedModels == null) { - this.resolvedModels = [] + const moduleCandidates: ToggleableModuleCandidate[] = [] for(const value of Object.values(ToggleableNamespace)) { - this.activeNamespace = value - const models = await this._doModuleRetrieval(resolve(this.containerDirectory, value)) - models.forEach(this.getNamespaceMapper(value)) - this.resolvedModels = this.resolvedModels.concat(models) + moduleCandidates.push(...(await super._doModuleDiscovery(resolve(this.containerDirectory, value))).map(val => ({...val, namespace: value}))) } + + this.resolvedModels = await this._doModuleRetrieval(moduleCandidates, { + preProcess: (candidate) => { + this.activeNamespace = (candidate as ToggleableModuleCandidate).namespace + }, + postProcess: (module) => { + this.getNamespaceMapper(this.activeNamespace as ToggleableNamespace)(module) + } + }) + + // Cleanup this.activeNamespace = undefined } diff --git a/src/model/struct/model/server.struct.ts b/src/model/struct/model/server.struct.ts index 65df93d..6344269 100644 --- a/src/model/struct/model/server.struct.ts +++ b/src/model/struct/model/server.struct.ts @@ -9,12 +9,9 @@ import { MiscFileStructure } from './module/file.struct' import { LiteModStructure } from './module/litemod.struct' import { LibraryStructure } from './module/library.struct' import { MinecraftVersion } from '../../../util/MinecraftVersion' -import { LoggerUtil } from '../../../util/LoggerUtil' export class ServerStructure extends BaseModelStructure { - private static readonly logger = LoggerUtil.getLogger('ServerStructure') - private readonly ID_REGEX = /(.+-(.+)$)/ private readonly SERVER_META_FILE = 'servermeta.json' @@ -25,6 +22,10 @@ export class ServerStructure extends BaseModelStructure { super(absoluteRoot, '', 'servers', baseUrl) } + public getLoggerName(): string { + return 'ServerStructure' + } + public async getSpecModel(): Promise { if (this.resolvedModels == null) { this.resolvedModels = await this._doSeverRetrieval() @@ -45,7 +46,7 @@ export class ServerStructure extends BaseModelStructure { const relativeServerRoot = join(this.relativeRoot, effectiveId) if (await pathExists(absoluteServerRoot)) { - ServerStructure.logger.error('Server already exists! Aborting.') + this.logger.error('Server already exists! Aborting.') return } @@ -66,7 +67,7 @@ export class ServerStructure extends BaseModelStructure { } if (options.liteloaderVersion != null) { - const lms = new LiteModStructure(absoluteServerRoot, relativeServerRoot, this.baseUrl) + const lms = new LiteModStructure(absoluteServerRoot, relativeServerRoot, this.baseUrl, minecraftVersion) await lms.init() serverMetaOpts.liteloaderVersion = options.liteloaderVersion } @@ -74,10 +75,10 @@ export class ServerStructure extends BaseModelStructure { const serverMeta: ServerMeta = getDefaultServerMeta(id, minecraftVersion.toString(), serverMetaOpts) await writeFile(resolvePath(absoluteServerRoot, this.SERVER_META_FILE), JSON.stringify(serverMeta, null, 2)) - const libS = new LibraryStructure(absoluteServerRoot, relativeServerRoot, this.baseUrl) + const libS = new LibraryStructure(absoluteServerRoot, relativeServerRoot, this.baseUrl, minecraftVersion) await libS.init() - const mfs = new MiscFileStructure(absoluteServerRoot, relativeServerRoot, this.baseUrl) + const mfs = new MiscFileStructure(absoluteServerRoot, relativeServerRoot, this.baseUrl, minecraftVersion) await mfs.init() } @@ -93,8 +94,8 @@ export class ServerStructure extends BaseModelStructure { const match = this.ID_REGEX.exec(file) if (match == null) { - ServerStructure.logger.warn(`Server directory ${file} does not match the defined standard.`) - ServerStructure.logger.warn('All server ids must end with - (ex. -1.12.2)') + this.logger.warn(`Server directory ${file} does not match the defined standard.`) + this.logger.warn('All server ids must end with - (ex. -1.12.2)') continue } @@ -110,7 +111,7 @@ export class ServerStructure extends BaseModelStructure { } if (!iconUrl) { - ServerStructure.logger.warn(`No icon file found for server ${file}.`) + this.logger.warn(`No icon file found for server ${file}.`) } // Read server meta @@ -146,16 +147,16 @@ export class ServerStructure extends BaseModelStructure { if(serverMeta.liteloader) { - const liteModStruct = new LiteModStructure(absoluteServerRoot, relativeServerRoot, this.baseUrl) + const liteModStruct = new LiteModStructure(absoluteServerRoot, relativeServerRoot, this.baseUrl, minecraftVersion) const liteModModules = await liteModStruct.getSpecModel() modules.push(...liteModModules) } - const libraryStruct = new LibraryStructure(absoluteServerRoot, relativeServerRoot, this.baseUrl) + const libraryStruct = new LibraryStructure(absoluteServerRoot, relativeServerRoot, this.baseUrl, minecraftVersion) const libraryModules = await libraryStruct.getSpecModel() modules.push(...libraryModules) - const fileStruct = new MiscFileStructure(absoluteServerRoot, relativeServerRoot, this.baseUrl) + const fileStruct = new MiscFileStructure(absoluteServerRoot, relativeServerRoot, this.baseUrl, minecraftVersion) const fileModules = await fileStruct.getSpecModel() modules.push(...fileModules) @@ -174,7 +175,7 @@ export class ServerStructure extends BaseModelStructure { }) } else { - ServerStructure.logger.warn(`Path ${file} in server directory is not a directory!`) + this.logger.warn(`Path ${file} in server directory is not a directory!`) } } return accumulator diff --git a/src/model/struct/repo/librepo.struct.ts b/src/model/struct/repo/librepo.struct.ts index 3ededb9..0163ea4 100644 --- a/src/model/struct/repo/librepo.struct.ts +++ b/src/model/struct/repo/librepo.struct.ts @@ -18,6 +18,10 @@ export class LibRepoStructure extends BaseMavenRepo { super(absoluteRoot, relativeRoot, 'lib') } + public getLoggerName(): string { + return 'LibRepoStructure' + } + public getLocalForge(version: string, classifier?: string): string { return this.getArtifactByComponents( LibRepoStructure.FORGE_GROUP, diff --git a/src/model/struct/repo/repo.struct.ts b/src/model/struct/repo/repo.struct.ts index 8182d6f..38db8f1 100644 --- a/src/model/struct/repo/repo.struct.ts +++ b/src/model/struct/repo/repo.struct.ts @@ -17,6 +17,10 @@ export class RepoStructure extends BaseFileStructure { this.versionRepoStruct = new VersionRepoStructure(this.containerDirectory, this.relativeRoot) } + public getLoggerName(): string { + return 'RepoStructure' + } + public async init(): Promise { super.init() await this.libRepoStruct.init() diff --git a/src/model/struct/repo/versionrepo.struct.ts b/src/model/struct/repo/versionrepo.struct.ts index 039dd04..c4436f1 100644 --- a/src/model/struct/repo/versionrepo.struct.ts +++ b/src/model/struct/repo/versionrepo.struct.ts @@ -12,6 +12,10 @@ export class VersionRepoStructure extends BaseFileStructure { super(absoluteRoot, relativeRoot, 'versions') } + public getLoggerName(): string { + return 'VersionRepoStructure' + } + public getFileName(minecraftVersion: MinecraftVersion, forgeVersion: string): string { return `${minecraftVersion}-forge-${forgeVersion}` } diff --git a/src/resolver/forge/adapter/ForgeGradle2.resolver.ts b/src/resolver/forge/adapter/ForgeGradle2.resolver.ts index 5c7f696..ad73be4 100644 --- a/src/resolver/forge/adapter/ForgeGradle2.resolver.ts +++ b/src/resolver/forge/adapter/ForgeGradle2.resolver.ts @@ -5,7 +5,7 @@ import { basename, join } from 'path' import { VersionManifestFG2 } from '../../../model/forge/VersionManifestFG2' import { LibRepoStructure } from '../../../model/struct/repo/librepo.struct' import { MavenUtil } from '../../../util/maven' -import { PackXZExtractWrapper } from '../../../util/PackXZExtractWrapper' +import { PackXZExtractWrapper } from '../../../util/java/PackXZExtractWrapper' import { VersionUtil } from '../../../util/versionutil' import { ForgeResolver } from '../forge.resolver' import { MinecraftVersion } from '../../../util/MinecraftVersion' @@ -227,7 +227,8 @@ export class ForgeGradle2Adapter extends ForgeResolver { } ForgeGradle2Adapter.logger.debug('Spawning PackXZExtract.') - await PackXZExtractWrapper.extractUnpack(files) + const packXZExecutor = new PackXZExtractWrapper() + await packXZExecutor.extractUnpack(files) ForgeGradle2Adapter.logger.debug('All files extracted, calculating hashes..') for (const entry of processingQueue) { diff --git a/src/resolver/forge/adapter/ForgeGradle3.resolver.ts b/src/resolver/forge/adapter/ForgeGradle3.resolver.ts index 01f66e1..e567e22 100644 --- a/src/resolver/forge/adapter/ForgeGradle3.resolver.ts +++ b/src/resolver/forge/adapter/ForgeGradle3.resolver.ts @@ -7,7 +7,7 @@ import { LibRepoStructure } from '../../../model/struct/repo/librepo.struct' import { pathExists, remove, mkdirs, copy, writeFile, readFile, lstat, move, writeJson } from 'fs-extra' import { join, basename, dirname } from 'path' import { spawn } from 'child_process' -import { JavaUtil } from '../../../util/javautil' +import { JavaUtil } from '../../../util/java/javautil' import { VersionManifestFG3 } from '../../../model/forge/VersionManifestFG3' import { MavenUtil } from '../../../util/maven' import { createHash } from 'crypto' diff --git a/src/util/PackXZExtractWrapper.ts b/src/util/PackXZExtractWrapper.ts deleted file mode 100644 index fd50e55..0000000 --- a/src/util/PackXZExtractWrapper.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { spawn } from 'child_process' -import { join } from 'path' -import { JavaUtil } from './javautil' -import { LoggerUtil } from './LoggerUtil' - -export class PackXZExtractWrapper { - - private static readonly logger = LoggerUtil.getLogger('PackXZExtract') - - public static getPackXZExtract(): string { - return join(process.cwd(), 'libraries', 'java', 'PackXZExtract.jar') - } - - public static extractUnpack(paths: string[]): Promise { - return PackXZExtractWrapper.execute('-packxz', paths) - } - - public static extract(paths: string[]): Promise { - return PackXZExtractWrapper.execute('-xz', paths) - } - - public static unpack(paths: string[]): Promise { - return PackXZExtractWrapper.execute('-pack', paths) - } - - private static execute(command: string, paths: string[]): Promise { - return new Promise((resolve, reject) => { - const child = spawn(JavaUtil.getJavaExecutable(), [ - '-jar', - PackXZExtractWrapper.getPackXZExtract(), - command, - paths.join(',') - ]) - child.stdout.on('data', (data) => PackXZExtractWrapper.logger.info(data.toString('utf8').trim())) - child.stderr.on('data', (data) => PackXZExtractWrapper.logger.error(data.toString('utf8').trim())) - child.on('close', code => { - PackXZExtractWrapper.logger.info('Exited with code', code) - resolve() - }) - child.on('error', (err) => { - PackXZExtractWrapper.logger.info('Error during process execution', err) - reject(err) - }) - }) - } - -} diff --git a/src/util/VersionSegmentedRegistry.ts b/src/util/VersionSegmentedRegistry.ts index b016970..95d27d5 100644 --- a/src/util/VersionSegmentedRegistry.ts +++ b/src/util/VersionSegmentedRegistry.ts @@ -42,7 +42,7 @@ export class VersionSegmentedRegistry { ): BaseForgeModStructure { for (const impl of VersionSegmentedRegistry.FORGEMOD_STRUCT_IML) { if (impl.isForVersion(minecraftVersion, forgeVersion)) { - return new impl(absoluteRoot, relativeRoot, baseUrl) + return new impl(absoluteRoot, relativeRoot, baseUrl, minecraftVersion) } } throw new Error(`No forge mod structure found for Minecraft ${minecraftVersion}!`) diff --git a/src/util/java/ClaritasWrapper.ts b/src/util/java/ClaritasWrapper.ts new file mode 100644 index 0000000..6c97e9d --- /dev/null +++ b/src/util/java/ClaritasWrapper.ts @@ -0,0 +1,32 @@ +import { JarExecutor } from './JarExecutor' +import { join } from 'path' +import { ClaritasResult } from '../../model/claritas/ClaritasResult' +import { MinecraftVersion } from '../MinecraftVersion' +import { LibraryType } from '../../model/claritas/ClaritasLibraryType' + +export class ClaritasWrapper extends JarExecutor { + + constructor() { + super('Claritas') + this.stdoutListeners.push((data) => { + const clean = data.toString('utf8').trim() as string + const spike = 'results::' + if(clean.startsWith(spike)) { + this.lastExecutionResult = JSON.parse(clean.substr(spike.length)) as ClaritasResult + } + }) + } + + protected getJarPath(): string { + return join(process.cwd(), 'libraries', 'java', 'Claritas.jar') + } + + public execute(libraryType: LibraryType, mcVersion: MinecraftVersion, absoluteJarPaths: string[]): Promise { + return super.executeJar( + '--absoluteJarPaths', absoluteJarPaths.join(','), + '--libraryType', libraryType, + '--mcVersion', mcVersion.toString() + ) + } + +} \ No newline at end of file diff --git a/src/util/java/JarExecutor.ts b/src/util/java/JarExecutor.ts new file mode 100644 index 0000000..24454b5 --- /dev/null +++ b/src/util/java/JarExecutor.ts @@ -0,0 +1,48 @@ +import { JavaUtil } from './javautil' +import { Logger } from 'winston' +import { spawn } from 'child_process' +import { LoggerUtil } from '../LoggerUtil' + +export abstract class JarExecutor { + + protected readonly logger: Logger + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + protected stdoutListeners: ((chunk: any) => void)[] = [] + // eslint-disable-next-line @typescript-eslint/no-explicit-any + protected stderrListeners: ((chunk: any) => void)[] = [] + + protected lastExecutionResult!: T + + protected constructor(loggerName: string) { + this.logger = LoggerUtil.getLogger(loggerName) + } + + protected abstract getJarPath(): string + + protected executeJar(...args: string[]): Promise { + this.lastExecutionResult = undefined! + return new Promise((resolve, reject) => { + const child = spawn(JavaUtil.getJavaExecutable(), [ + '-jar', + this.getJarPath(), + ...args + ]) + child.stdout.on('data', (data) => this.logger.info(data.toString('utf8').trim())) + this.stdoutListeners.forEach(l => child.stdout.on('data', l)) + + child.stderr.on('data', (data) => this.logger.error(data.toString('utf8').trim())) + this.stderrListeners.forEach(l => child.stderr.on('data', l)) + + child.on('close', code => { + this.logger.info('Exited with code', code) + resolve(this.lastExecutionResult) + }) + child.on('error', (err) => { + this.logger.info('Error during process execution', err) + reject(err) + }) + }) + } + +} \ No newline at end of file diff --git a/src/util/java/PackXZExtractWrapper.ts b/src/util/java/PackXZExtractWrapper.ts new file mode 100644 index 0000000..5fb3b83 --- /dev/null +++ b/src/util/java/PackXZExtractWrapper.ts @@ -0,0 +1,30 @@ +import { join } from 'path' +import { JarExecutor } from './JarExecutor' + +export class PackXZExtractWrapper extends JarExecutor { + + constructor() { + super('PackXZExtract') + } + + protected getJarPath(): string { + return join(process.cwd(), 'libraries', 'java', 'PackXZExtract.jar') + } + + protected execute(command: string, paths: string[]): Promise { + return super.executeJar(command, paths.join(',')) + } + + public extractUnpack(paths: string[]): Promise { + return this.execute('-packxz', paths) + } + + public extract(paths: string[]): Promise { + return this.execute('-xz', paths) + } + + public unpack(paths: string[]): Promise { + return this.execute('-pack', paths) + } + +} diff --git a/src/util/javautil.ts b/src/util/java/javautil.ts similarity index 100% rename from src/util/javautil.ts rename to src/util/java/javautil.ts