First pass at Claritas implementation.
The resolution logic was reworked so that Claritas only needs to be invoked once per supported type, ie only once for ForgeMod and LiteMod resolutions per server. The resolver now uses identifies module candidates and collects them. Claritas is invoked and the resulting metadata is stored. The module resolution then proceeds with all of this data available. Toggleable module logic was also reworked to first accumulate all candidates and then process. This required the resolution function to optionally take a preprocess and postprocess callback to perform the necessary cleanup and transformations. The minor rework was necessary because spawning child process is expensive, and we should only do it as often as we must to keep the application performant. Claritas resolution also supports exceptions defined by the structure class. This is to facilitate handling of special cases (ex. Optifine).
This commit is contained in:
@@ -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<void> {
|
||||
return PackXZExtractWrapper.execute('-packxz', paths)
|
||||
}
|
||||
|
||||
public static extract(paths: string[]): Promise<void> {
|
||||
return PackXZExtractWrapper.execute('-xz', paths)
|
||||
}
|
||||
|
||||
public static unpack(paths: string[]): Promise<void> {
|
||||
return PackXZExtractWrapper.execute('-pack', paths)
|
||||
}
|
||||
|
||||
private static execute(command: string, paths: string[]): Promise<void> {
|
||||
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)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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}!`)
|
||||
|
||||
32
src/util/java/ClaritasWrapper.ts
Normal file
32
src/util/java/ClaritasWrapper.ts
Normal file
@@ -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<ClaritasResult> {
|
||||
|
||||
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<ClaritasResult> {
|
||||
return super.executeJar(
|
||||
'--absoluteJarPaths', absoluteJarPaths.join(','),
|
||||
'--libraryType', libraryType,
|
||||
'--mcVersion', mcVersion.toString()
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
48
src/util/java/JarExecutor.ts
Normal file
48
src/util/java/JarExecutor.ts
Normal file
@@ -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<T> {
|
||||
|
||||
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<T> {
|
||||
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)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
30
src/util/java/PackXZExtractWrapper.ts
Normal file
30
src/util/java/PackXZExtractWrapper.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { join } from 'path'
|
||||
import { JarExecutor } from './JarExecutor'
|
||||
|
||||
export class PackXZExtractWrapper extends JarExecutor<void> {
|
||||
|
||||
constructor() {
|
||||
super('PackXZExtract')
|
||||
}
|
||||
|
||||
protected getJarPath(): string {
|
||||
return join(process.cwd(), 'libraries', 'java', 'PackXZExtract.jar')
|
||||
}
|
||||
|
||||
protected execute(command: string, paths: string[]): Promise<void> {
|
||||
return super.executeJar(command, paths.join(','))
|
||||
}
|
||||
|
||||
public extractUnpack(paths: string[]): Promise<void> {
|
||||
return this.execute('-packxz', paths)
|
||||
}
|
||||
|
||||
public extract(paths: string[]): Promise<void> {
|
||||
return this.execute('-xz', paths)
|
||||
}
|
||||
|
||||
public unpack(paths: string[]): Promise<void> {
|
||||
return this.execute('-pack', paths)
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user