Completed steps up to downloading forge universal jar for 1.8-1.12.
Next step is processing the version.json and transforming it into a deliverable module.
This commit is contained in:
7
.vscode/launch.json
vendored
7
.vscode/launch.json
vendored
@@ -8,7 +8,12 @@
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Launch Program",
|
||||
"program": "${workspaceFolder}\\dist\\index.js",
|
||||
"program": "${workspaceFolder}\\src\\index.ts",
|
||||
"args": [
|
||||
"test",
|
||||
"1.12.2",
|
||||
"14.23.5.2847"
|
||||
],
|
||||
"preLaunchTask": "compile",
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/dist/**/*.js"
|
||||
|
||||
29
package-lock.json
generated
29
package-lock.json
generated
@@ -96,6 +96,14 @@
|
||||
"sprintf-js": "~1.0.2"
|
||||
}
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.19.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.1.tgz",
|
||||
"integrity": "sha512-Yl+7nfreYKaLRvAvjNPkvfjnQHJM1yLBY3zhqAwcJSwR/6ETkanUgylgtIvkvz0xJ+p/vZuNw8X7Hnb7Whsbpw==",
|
||||
"requires": {
|
||||
"follow-redirects": "1.5.10"
|
||||
}
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
@@ -195,6 +203,14 @@
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"decamelize": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||
@@ -238,6 +254,14 @@
|
||||
"path-exists": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
|
||||
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
|
||||
"requires": {
|
||||
"debug": "=3.1.0"
|
||||
}
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
|
||||
@@ -361,6 +385,11 @@
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"adm-zip": "^0.4.13",
|
||||
"axios": "^0.19.1",
|
||||
"fs-extra": "^8.1.0",
|
||||
"yargs": "^15.1.0"
|
||||
}
|
||||
|
||||
18
src/index.ts
18
src/index.ts
@@ -1,8 +1,10 @@
|
||||
/* tslint:disable:no-shadowed-variable */
|
||||
import { writeFile } from 'fs-extra'
|
||||
import { resolve as resolvePath } from 'path'
|
||||
import { URL } from 'url'
|
||||
import yargs from 'yargs'
|
||||
import { DistributionStructure } from './model/struct/model/distribution.struct'
|
||||
import { ResolverRegistry } from './resolver/ResolverRegistry'
|
||||
|
||||
function rootOption(yargs: yargs.Argv) {
|
||||
return yargs.option('root', {
|
||||
@@ -166,6 +168,21 @@ const validateCommand: yargs.CommandModule = {
|
||||
}
|
||||
}
|
||||
|
||||
const testCommand: yargs.CommandModule = {
|
||||
command: 'test <mcVer> <forgeVer>',
|
||||
describe: 'Validate a distribution.json against the spec.',
|
||||
builder: (yargs) => {
|
||||
return namePositional(yargs)
|
||||
},
|
||||
handler: async (argv) => {
|
||||
console.debug(`Invoked test with mcVer ${argv.mcVer} forgeVer ${argv.forgeVer}`)
|
||||
const resolver = ResolverRegistry.getForgeResolver('1.12.2', '14.23.5.2847', 'D:/TestRoot2', 'D:/TestRoot2')
|
||||
if (resolver != null) {
|
||||
await resolver.getModule()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Registering yargs configuration.
|
||||
// tslint:disable-next-line:no-unused-expression
|
||||
yargs
|
||||
@@ -174,6 +191,7 @@ yargs
|
||||
.command(initCommand)
|
||||
.command(generateCommand)
|
||||
.command(validateCommand)
|
||||
.command(testCommand)
|
||||
.demandCommand()
|
||||
.help()
|
||||
.argv
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { resolve } from 'path'
|
||||
import axios from 'axios'
|
||||
import { createWriteStream, mkdirs, pathExists } from 'fs-extra'
|
||||
import { dirname, resolve } from 'path'
|
||||
import { resolve as resolveURL } from 'url'
|
||||
import { MavenUtil } from '../../../util/maven'
|
||||
import { BaseFileStructure } from '../BaseFileStructure'
|
||||
|
||||
@@ -19,8 +22,36 @@ export abstract class BaseMavenRepo extends BaseFileStructure {
|
||||
|
||||
public getArtifactByComponents(group: string, artifact: string, version: string,
|
||||
classifier?: string, extension = 'jar'): string {
|
||||
throw resolve(this.containerDirectory,
|
||||
return resolve(this.containerDirectory,
|
||||
MavenUtil.mavenComponentsToString(group, artifact, version, classifier, extension))
|
||||
}
|
||||
|
||||
public async artifactExists(path: string) {
|
||||
return pathExists(path)
|
||||
}
|
||||
|
||||
public async downloadArtifact(url: string, group: string, artifact: string, version: string,
|
||||
classifier?: string, extension?: string) {
|
||||
const relative = MavenUtil.mavenComponentsToString(group, artifact, version, classifier, extension)
|
||||
const resolvedURL = resolveURL(url, relative).toString()
|
||||
console.debug(`Downloading ${resolvedURL}..`)
|
||||
const response = await axios({
|
||||
method: 'get',
|
||||
url: resolvedURL,
|
||||
responseType: 'stream'
|
||||
})
|
||||
const localPath = resolve(this.containerDirectory, relative)
|
||||
await mkdirs(dirname(localPath))
|
||||
const writer = createWriteStream(localPath)
|
||||
response.data.pipe(writer)
|
||||
// tslint:disable-next-line: no-shadowed-variable
|
||||
return new Promise((resolve, reject) => {
|
||||
writer.on('finish', () => {
|
||||
console.debug(`Completed download of ${resolvedURL}.`)
|
||||
resolve()
|
||||
})
|
||||
writer.on('error', reject)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@ import { BaseMavenRepo } from './BaseMavenRepo'
|
||||
|
||||
export class ForgeRepoStructure extends BaseMavenRepo {
|
||||
|
||||
public static readonly FORGE_GROUP = 'net.minecraftforge'
|
||||
public static readonly FORGE_ARTIFACT = 'forge'
|
||||
|
||||
constructor(
|
||||
absoluteRoot: string,
|
||||
relativeRoot: string
|
||||
@@ -10,7 +13,10 @@ export class ForgeRepoStructure extends BaseMavenRepo {
|
||||
}
|
||||
|
||||
public getLocalForge(version: string, classifier?: string) {
|
||||
this.getArtifactByComponents('net.minecraftforge', 'forge', version, classifier, 'jar')
|
||||
return this.getArtifactByComponents(
|
||||
ForgeRepoStructure.FORGE_GROUP,
|
||||
ForgeRepoStructure.FORGE_ARTIFACT,
|
||||
version, classifier, 'jar')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
23
src/resolver/ResolverRegistry.ts
Normal file
23
src/resolver/ResolverRegistry.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Forge113Adapter } from './forge/adapter/forge113.resolver'
|
||||
import { Forge18Adapter } from './forge/adapter/forge18.resolver'
|
||||
import { ForgeResolver } from './forge/forge.resolver'
|
||||
|
||||
export class ResolverRegistry {
|
||||
|
||||
public static readonly FORGE_ADAPTER_IMPL = [
|
||||
Forge18Adapter,
|
||||
Forge113Adapter
|
||||
]
|
||||
|
||||
public static getForgeResolver(
|
||||
minecraftVersion: string,
|
||||
forgeVersion: string,
|
||||
absoluteRoot: string, relativeRoot: string): ForgeResolver | undefined {
|
||||
for (const impl of ResolverRegistry.FORGE_ADAPTER_IMPL) {
|
||||
if (impl.isForVersion(minecraftVersion)) {
|
||||
return new impl(absoluteRoot, relativeRoot, minecraftVersion, forgeVersion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +1,17 @@
|
||||
import { Module } from '../model/spec/module'
|
||||
import { VersionUtil } from '../util/versionutil'
|
||||
import { Resolver } from './resolver'
|
||||
|
||||
export abstract class BaseResolver implements Resolver {
|
||||
|
||||
protected static isVersionAcceptable(version: string, acceptable: number[]): boolean {
|
||||
const versionComponents = VersionUtil.getMinecraftVersionComponents(version)
|
||||
if (versionComponents != null && versionComponents.major === 1) {
|
||||
return acceptable.find((element) => versionComponents.minor === element) != null
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
constructor(
|
||||
protected absoluteRoot: string,
|
||||
protected relativeRoot: string
|
||||
@@ -10,4 +19,6 @@ export abstract class BaseResolver implements Resolver {
|
||||
|
||||
public abstract getModule(): Promise<Module>
|
||||
|
||||
public abstract isForVersion(version: string): boolean
|
||||
|
||||
}
|
||||
|
||||
27
src/resolver/forge/adapter/forge113.resolver.ts
Normal file
27
src/resolver/forge/adapter/forge113.resolver.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Module } from '../../../model/spec/module'
|
||||
import { ForgeResolver } from '../forge.resolver'
|
||||
|
||||
export class Forge113Adapter extends ForgeResolver {
|
||||
|
||||
public static isForVersion(version: string) {
|
||||
return Forge113Adapter.isVersionAcceptable(version, [13, 14, 15])
|
||||
}
|
||||
|
||||
constructor(
|
||||
absoluteRoot: string,
|
||||
relativeRoot: string,
|
||||
minecraftVersion: string,
|
||||
forgeVersion: string
|
||||
) {
|
||||
super(absoluteRoot, relativeRoot, minecraftVersion, forgeVersion)
|
||||
}
|
||||
|
||||
public async getModule(): Promise<Module> {
|
||||
return null as unknown as Module
|
||||
}
|
||||
|
||||
public isForVersion(version: string): boolean {
|
||||
return Forge113Adapter.isForVersion(version)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,52 @@
|
||||
import { Module } from '../../../model/spec/module'
|
||||
import { ForgeRepoStructure } from '../../../model/struct/repo/forgerepo.struct'
|
||||
import { ForgeResolver } from '../forge.resolver'
|
||||
|
||||
export class Forge18Adapter extends ForgeResolver {
|
||||
|
||||
public static isForVersion(version: string) {
|
||||
return Forge18Adapter.isVersionAcceptable(version, [8, 9, 10, 11, 12])
|
||||
}
|
||||
|
||||
constructor(
|
||||
absoluteRoot: string,
|
||||
relativeRoot: string,
|
||||
minecraftVersion: string,
|
||||
forgeVersion: string
|
||||
) {
|
||||
super(absoluteRoot, relativeRoot, minecraftVersion, forgeVersion)
|
||||
}
|
||||
|
||||
public async getModule(): Promise<Module> {
|
||||
await this.getForgeByVersion()
|
||||
return null as unknown as Module
|
||||
}
|
||||
|
||||
public isForVersion(version: string) {
|
||||
return Forge18Adapter.isForVersion(version)
|
||||
}
|
||||
|
||||
public async getForgeByVersion() {
|
||||
const forgeRepo = this.repoStructure.getForgeRepoStruct()
|
||||
const artifactVersion = `${this.minecraftVersion}-${this.forgeVersion}`
|
||||
const targetLocalPath = forgeRepo.getLocalForge(artifactVersion, 'universal')
|
||||
console.debug(`Checking for forge version at ${targetLocalPath}..`)
|
||||
if (!await forgeRepo.artifactExists(targetLocalPath)) {
|
||||
console.debug(`Forge not found locally, initializing download..`)
|
||||
await forgeRepo.downloadArtifact(
|
||||
this.REMOTE_REPOSITORY,
|
||||
ForgeRepoStructure.FORGE_GROUP,
|
||||
ForgeRepoStructure.FORGE_ARTIFACT,
|
||||
artifactVersion, 'universal', 'jar')
|
||||
} else {
|
||||
console.debug('Using locally discovered forge.')
|
||||
}
|
||||
console.debug(`Beginning processing of Forge v${this.forgeVersion} (Minecraft ${this.minecraftVersion})`)
|
||||
}
|
||||
|
||||
// TODO
|
||||
// extract manifest
|
||||
// parse manifest
|
||||
// return module
|
||||
|
||||
}
|
||||
|
||||
@@ -1,33 +1,20 @@
|
||||
import { Module } from '../../model/spec/module'
|
||||
import { RepoStructure } from '../../model/struct/repo/repo.struct'
|
||||
import { BaseResolver } from '../baseresolver'
|
||||
import { Forge18Adapter } from './adapter/forge18.resolver'
|
||||
|
||||
export abstract class ForgeResolver extends BaseResolver {
|
||||
|
||||
public static getResolver(version: string) {
|
||||
return ForgeResolver.ADAPTER_LIST[version]
|
||||
}
|
||||
|
||||
// tslint:disable: object-literal-key-quotes
|
||||
private static readonly ADAPTER_LIST: {[version: string]: any} = {
|
||||
'1.8': Forge18Adapter,
|
||||
'1.9': Forge18Adapter,
|
||||
'1.10': Forge18Adapter,
|
||||
'1.11': Forge18Adapter,
|
||||
'1.12': Forge18Adapter
|
||||
}
|
||||
protected readonly REMOTE_REPOSITORY = 'https://files.minecraftforge.net/maven/'
|
||||
|
||||
protected repoStructure: RepoStructure
|
||||
|
||||
constructor(
|
||||
absoluteRoot: string,
|
||||
relativeRoot: string
|
||||
relativeRoot: string,
|
||||
protected minecraftVersion: string,
|
||||
protected forgeVersion: string
|
||||
) {
|
||||
super(absoluteRoot, relativeRoot)
|
||||
this.repoStructure = new RepoStructure(absoluteRoot, relativeRoot)
|
||||
}
|
||||
|
||||
public abstract getModule(): Promise<Module>
|
||||
|
||||
}
|
||||
|
||||
@@ -3,10 +3,11 @@ import { URL } from 'url'
|
||||
|
||||
export class MavenUtil {
|
||||
|
||||
public static readonly ID_REGEX = /(.+):(.+):([^@-]+)(?:-{1}([^@]+))?(?:@{1}(.+)$)?/
|
||||
public static readonly ID_REGEX = /(.+):(.+):([^@]+)()(?:@{1}(.+)$)?/
|
||||
public static readonly ID_REGEX_WITH_CLASSIFIER = /(.+):(.+):(?:([^@]+)(?:-([a-zA-Z]+)))(?:@{1}(.+)$)?/
|
||||
|
||||
public static isMavenIdentifier(id: string) {
|
||||
return MavenUtil.ID_REGEX.test(id)
|
||||
return MavenUtil.ID_REGEX.test(id) || MavenUtil.ID_REGEX_WITH_CLASSIFIER.test(id)
|
||||
}
|
||||
|
||||
public static mavenIdentifierToString(id: string, extension = 'jar') {
|
||||
@@ -14,12 +15,19 @@ export class MavenUtil {
|
||||
return null
|
||||
}
|
||||
|
||||
const result = MavenUtil.ID_REGEX.exec(id)
|
||||
let result
|
||||
|
||||
if (MavenUtil.ID_REGEX_WITH_CLASSIFIER.test(id)) {
|
||||
result = MavenUtil.ID_REGEX_WITH_CLASSIFIER.exec(id)
|
||||
} else {
|
||||
result = MavenUtil.ID_REGEX.exec(id)
|
||||
}
|
||||
|
||||
if (result != null) {
|
||||
const group = result[1]
|
||||
const artifact = result[2]
|
||||
const version = result[3]
|
||||
const classifier = result[4]
|
||||
const classifier = result[4] || undefined
|
||||
const ext = result[5] || extension
|
||||
|
||||
return MavenUtil.mavenComponentsToString(group, artifact, version, classifier, ext)
|
||||
@@ -27,19 +35,29 @@ export class MavenUtil {
|
||||
return null
|
||||
}
|
||||
|
||||
public static mavenComponentsToString(group: string, artifact: string,version: string,
|
||||
public static mavenComponentsToString(group: string, artifact: string, version: string,
|
||||
classifier?: string, extension = 'jar') {
|
||||
return `${group.replace(/\./g, '/')}/${artifact}/${version}/${artifact}-${version}${classifier != null ? `-${classifier}` : ''}.${extension}`
|
||||
}
|
||||
|
||||
public static mavenToUrl(id: string, extension = 'jar') {
|
||||
public static mavenIdentifierToUrl(id: string, extension = 'jar') {
|
||||
const res = MavenUtil.mavenIdentifierToString(id, extension)
|
||||
return res == null ? null : new URL(res)
|
||||
}
|
||||
|
||||
public static mavenToPath(id: string, extension = 'jar') {
|
||||
public static mavenComponentsToUrl(group: string, artifact: string, version: string,
|
||||
classifier?: string, extension = 'jar') {
|
||||
return new URL(MavenUtil.mavenComponentsToString(group, artifact, version, classifier, extension))
|
||||
}
|
||||
|
||||
public static mavenIdentifierToPath(id: string, extension = 'jar') {
|
||||
const res = MavenUtil.mavenIdentifierToString(id, extension)
|
||||
return res == null ? null : normalize(res)
|
||||
}
|
||||
|
||||
public static mavenComponentsToPath(group: string, artifact: string, version: string,
|
||||
classifier?: string, extension = 'jar') {
|
||||
return normalize(MavenUtil.mavenComponentsToString(group, artifact, version, classifier, extension))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
23
src/util/versionutil.ts
Normal file
23
src/util/versionutil.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
export class VersionUtil {
|
||||
|
||||
public static readonly MINECRAFT_VERSION_REGEX = /(\d+).(\d+).(\d+)/
|
||||
|
||||
public static isMinecraftVersion(version: string) {
|
||||
return VersionUtil.MINECRAFT_VERSION_REGEX.test(version)
|
||||
}
|
||||
|
||||
public static getMinecraftVersionComponents(version: string) {
|
||||
if (VersionUtil.isMinecraftVersion(version)) {
|
||||
const result = VersionUtil.MINECRAFT_VERSION_REGEX.exec(version)
|
||||
if (result != null) {
|
||||
return {
|
||||
major: Number(result[1]),
|
||||
minor: Number(result[2]),
|
||||
revision: Number(result[3])
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
"compilerOptions": {
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
||||
"target": "ES2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
"lib": ["ES2019"], /* Specify library files to be included in the compilation. */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||
|
||||
Reference in New Issue
Block a user