Implement modrinth export
This commit is contained in:
parent
5a1c6f47e4
commit
d40c3b82e3
11 changed files with 139 additions and 4 deletions
|
@ -20,6 +20,7 @@
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@root/walk": "^1.1.0",
|
"@root/walk": "^1.1.0",
|
||||||
|
"@sindresorhus/slugify": "^2.1.0",
|
||||||
"address": "^1.2.0",
|
"address": "^1.2.0",
|
||||||
"commander": "^9.4.0",
|
"commander": "^9.4.0",
|
||||||
"dedent": "^0.7.0",
|
"dedent": "^0.7.0",
|
||||||
|
|
22
pnpm-lock.yaml
generated
22
pnpm-lock.yaml
generated
|
@ -2,6 +2,7 @@ lockfileVersion: 5.4
|
||||||
|
|
||||||
specifiers:
|
specifiers:
|
||||||
'@root/walk': ^1.1.0
|
'@root/walk': ^1.1.0
|
||||||
|
'@sindresorhus/slugify': ^2.1.0
|
||||||
'@types/dedent': ^0.7.0
|
'@types/dedent': ^0.7.0
|
||||||
'@types/fs-extra': ^9.0.13
|
'@types/fs-extra': ^9.0.13
|
||||||
'@types/lodash-es': ^4.17.6
|
'@types/lodash-es': ^4.17.6
|
||||||
|
@ -44,6 +45,7 @@ specifiers:
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
'@root/walk': 1.1.0
|
'@root/walk': 1.1.0
|
||||||
|
'@sindresorhus/slugify': 2.1.0
|
||||||
address: 1.2.0
|
address: 1.2.0
|
||||||
commander: 9.4.0
|
commander: 9.4.0
|
||||||
dedent: 0.7.0
|
dedent: 0.7.0
|
||||||
|
@ -166,6 +168,22 @@ packages:
|
||||||
engines: {node: '>=14.16'}
|
engines: {node: '>=14.16'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@sindresorhus/slugify/2.1.0:
|
||||||
|
resolution: {integrity: sha512-gU3Gdm/V167BmUwIn8APHZ3SeeRVRUSOdXxnt7Q/JkUHLXaaTA/prYmoRumwsSitJZWUDYMzDWdWgrOdvE8IRQ==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dependencies:
|
||||||
|
'@sindresorhus/transliterate': 1.5.0
|
||||||
|
escape-string-regexp: 5.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@sindresorhus/transliterate/1.5.0:
|
||||||
|
resolution: {integrity: sha512-/sfSkoNelLq5riqNRp5uBjHIKBi1MWZk9ubRT1WiBQuTfmDf7BeQkph2DJzRB83QagMPHk2VDjuvpy0VuwyzdA==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dependencies:
|
||||||
|
escape-string-regexp: 5.0.0
|
||||||
|
lodash.deburr: 4.1.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@szmarczak/http-timer/5.0.1:
|
/@szmarczak/http-timer/5.0.1:
|
||||||
resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==}
|
resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==}
|
||||||
engines: {node: '>=14.16'}
|
engines: {node: '>=14.16'}
|
||||||
|
@ -1162,6 +1180,10 @@ packages:
|
||||||
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
|
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/lodash.deburr/4.1.0:
|
||||||
|
resolution: {integrity: sha512-m/M1U1f3ddMCs6Hq2tAsYThTBDaAKFDX3dwDo97GEYzamXi9SqUpjWi/Rrj/gf3X2n8ktwgZrlP1z6E3v/IExQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/log-symbols/5.1.0:
|
/log-symbols/5.1.0:
|
||||||
resolution: {integrity: sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==}
|
resolution: {integrity: sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
|
@ -7,6 +7,8 @@ import { fetchFabricMinecraftVersions, fetchFabricVersions } from "../fabricApi.
|
||||||
import enquirer from "enquirer"
|
import enquirer from "enquirer"
|
||||||
import { PACK_MANIFEST_FILE_NAME, PACK_MANIFEST_FORMAT_VERSION, PackManifest } from "../files.js"
|
import { PACK_MANIFEST_FILE_NAME, PACK_MANIFEST_FORMAT_VERSION, PackManifest } from "../files.js"
|
||||||
import pathModule from "path"
|
import pathModule from "path"
|
||||||
|
import { EXPORTS_DIRECTORY_NAME } from "../pack.js"
|
||||||
|
import slugify from "@sindresorhus/slugify"
|
||||||
|
|
||||||
export const initCommand = new Command("init")
|
export const initCommand = new Command("init")
|
||||||
.argument("<path>")
|
.argument("<path>")
|
||||||
|
@ -62,6 +64,7 @@ export const initCommand = new Command("init")
|
||||||
|
|
||||||
const file: PackManifest = {
|
const file: PackManifest = {
|
||||||
formatVersion: PACK_MANIFEST_FORMAT_VERSION,
|
formatVersion: PACK_MANIFEST_FORMAT_VERSION,
|
||||||
|
slug: slugify(answers.name),
|
||||||
meta: {
|
meta: {
|
||||||
name: answers.name,
|
name: answers.name,
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
|
@ -76,7 +79,7 @@ export const initCommand = new Command("init")
|
||||||
}
|
}
|
||||||
|
|
||||||
await fs.writeJson(manifestFilePath.toString(), file, { spaces: 2 })
|
await fs.writeJson(manifestFilePath.toString(), file, { spaces: 2 })
|
||||||
await fs.writeFile(path.resolve(".gitignore").toString(), "/generated/")
|
await fs.writeFile(path.resolve(".gitignore").toString(), `/${EXPORTS_DIRECTORY_NAME}/`)
|
||||||
|
|
||||||
output.println(kleur.green(`Successfully initialized pack in ${kleur.yellow(pathModule.normalize(pathString))}`))
|
output.println(kleur.green(`Successfully initialized pack in ${kleur.yellow(pathModule.normalize(pathString))}`))
|
||||||
})
|
})
|
||||||
|
|
41
src/commands/modrinth/export.ts
Normal file
41
src/commands/modrinth/export.ts
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import { Command } from "commander"
|
||||||
|
import { usePack } from "../../pack.js"
|
||||||
|
import { output } from "../../utils/output.js"
|
||||||
|
import fs from "fs-extra"
|
||||||
|
import { generateOutputDirectory } from "../../modrinth/exporting.js"
|
||||||
|
import kleur from "kleur"
|
||||||
|
import { zipDirectory } from "../../utils/zip.js"
|
||||||
|
|
||||||
|
const EXPORT_OUTPUT_DIRECTORY_NAME = "modrinth"
|
||||||
|
|
||||||
|
export const exportCommand = new Command("export")
|
||||||
|
.option("-s, --no-generate", "Skip regenerating the output directory.")
|
||||||
|
.option("-z, --no-zip", "Skip creating a zipped .mrpack file.")
|
||||||
|
.option("-c, --clean", "Remove the output directory afterwards.")
|
||||||
|
.action(async options => {
|
||||||
|
const pack = await usePack()
|
||||||
|
const outputDirectoryPath = pack.paths.exports.resolve(EXPORT_OUTPUT_DIRECTORY_NAME)
|
||||||
|
|
||||||
|
const loader = output.startLoading("Exporting")
|
||||||
|
|
||||||
|
if (options.generate) {
|
||||||
|
await output.withLoading(generateOutputDirectory(outputDirectoryPath), "Generating the output directory")
|
||||||
|
output.println(kleur.green(`Generated Modrinth pack directory.`))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.zip) {
|
||||||
|
const fileName = `${pack.manifest.slug}-${pack.manifest.meta.version}.mrpack`
|
||||||
|
if (!(await fs.pathExists(outputDirectoryPath.toString())))
|
||||||
|
output.failAndExit(`The ${kleur.yellow(EXPORT_OUTPUT_DIRECTORY_NAME)} export directory does not exist.\nRun the command without ${kleur.yellow("--no-generate")} to create it.`)
|
||||||
|
|
||||||
|
await output.withLoading(zipDirectory(outputDirectoryPath, pack.paths.exports.resolve(fileName)), `Creating ${kleur.yellow(".mrpack")} file`)
|
||||||
|
output.println(kleur.green(`Created ${kleur.yellow(fileName)}`))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.clean) {
|
||||||
|
await fs.remove(outputDirectoryPath.toString())
|
||||||
|
output.println(kleur.green(`Removed the ${kleur.yellow(EXPORT_OUTPUT_DIRECTORY_NAME)} directory.`))
|
||||||
|
}
|
||||||
|
|
||||||
|
loader.stop()
|
||||||
|
})
|
|
@ -3,10 +3,12 @@ import { activateCommand } from "./activate.js"
|
||||||
import dedent from "dedent"
|
import dedent from "dedent"
|
||||||
import kleur from "kleur"
|
import kleur from "kleur"
|
||||||
import { openCommand } from "./open.js"
|
import { openCommand } from "./open.js"
|
||||||
|
import { exportCommand } from "./export.js"
|
||||||
|
|
||||||
export const modrinthCommand = new Command("modrinth")
|
export const modrinthCommand = new Command("modrinth")
|
||||||
.alias("mr")
|
.alias("mr")
|
||||||
.addCommand(activateCommand)
|
.addCommand(activateCommand)
|
||||||
|
.addCommand(exportCommand)
|
||||||
.addCommand(openCommand)
|
.addCommand(openCommand)
|
||||||
.addHelpText("afterAll", dedent`
|
.addHelpText("afterAll", dedent`
|
||||||
\n${kleur.yellow("<code>")} may be one of the following:
|
\n${kleur.yellow("<code>")} may be one of the following:
|
||||||
|
|
|
@ -49,6 +49,7 @@ export const PACK_MANIFEST_FILE_NAME = "horizr.json"
|
||||||
|
|
||||||
export const horizrFileSchema = z.object({
|
export const horizrFileSchema = z.object({
|
||||||
formatVersion: z.literal(PACK_MANIFEST_FORMAT_VERSION),
|
formatVersion: z.literal(PACK_MANIFEST_FORMAT_VERSION),
|
||||||
|
slug: z.string(),
|
||||||
meta: z.object({
|
meta: z.object({
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
version: z.string(),
|
version: z.string(),
|
||||||
|
|
60
src/modrinth/exporting.ts
Normal file
60
src/modrinth/exporting.ts
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import { AbsolutePath } from "../utils/path.js"
|
||||||
|
import { output } from "../utils/output.js"
|
||||||
|
import fs from "fs-extra"
|
||||||
|
import { Side, usePack } from "../pack.js"
|
||||||
|
import kleur from "kleur"
|
||||||
|
|
||||||
|
const overridesDirectoryNameBySide: Record<Side, string> = {
|
||||||
|
client: "client-overrides",
|
||||||
|
server: "server-overrides",
|
||||||
|
universal: "overrides"
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateOutputDirectory(outputDirectoryPath: AbsolutePath) {
|
||||||
|
const pack = await usePack()
|
||||||
|
await fs.remove(outputDirectoryPath.toString())
|
||||||
|
await fs.mkdirp(outputDirectoryPath.toString())
|
||||||
|
|
||||||
|
await fs.writeJson(outputDirectoryPath.resolve("modrinth.index.json").toString(), {
|
||||||
|
formatVersion: 1,
|
||||||
|
game: "minecraft",
|
||||||
|
versionId: pack.manifest.meta.version,
|
||||||
|
name: pack.manifest.meta.name,
|
||||||
|
summary: pack.manifest.meta.description,
|
||||||
|
dependencies: {
|
||||||
|
minecraft: pack.manifest.versions.minecraft,
|
||||||
|
"fabric-loader": pack.manifest.versions.fabric
|
||||||
|
},
|
||||||
|
files: pack.metaFiles.map(metaFile => ({
|
||||||
|
path: metaFile.effectivePath.toString(),
|
||||||
|
hashes: {
|
||||||
|
sha1: metaFile.content.version.hashes.sha1,
|
||||||
|
sha512: metaFile.content.version.hashes.sha512
|
||||||
|
},
|
||||||
|
env: {
|
||||||
|
client: metaFile.side === "client" || metaFile.side === "universal" ? "required" : "unsupported",
|
||||||
|
server: metaFile.side === "server" || metaFile.side === "universal" ? "required" : "unsupported"
|
||||||
|
},
|
||||||
|
downloads: [
|
||||||
|
metaFile.content.version.downloadUrl
|
||||||
|
],
|
||||||
|
fileSize: metaFile.content.version.size
|
||||||
|
}))
|
||||||
|
}, { spaces: 2 })
|
||||||
|
|
||||||
|
let i = 0
|
||||||
|
for (const staticSourceFile of pack.staticSourceFiles) {
|
||||||
|
i++
|
||||||
|
const loader = output.startLoading(`Exporting static source file (${i}/${pack.staticSourceFiles.length}): ${kleur.yellow(staticSourceFile.relativePath.toString())}`)
|
||||||
|
const outputPath = outputDirectoryPath.resolve(overridesDirectoryNameBySide[staticSourceFile.side], staticSourceFile.effectivePath)
|
||||||
|
await fs.mkdirp(outputPath.parent().toString())
|
||||||
|
await fs.copy(staticSourceFile.absolutePath.toString(), outputPath.toString())
|
||||||
|
|
||||||
|
// Workaround for https://github.com/PolyMC/PolyMC/issues/1060
|
||||||
|
if (staticSourceFile.side === "client") {
|
||||||
|
await fs.mkdirp(outputDirectoryPath.resolve(overridesDirectoryNameBySide.universal, staticSourceFile.effectivePath).parent().toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
loader.stop()
|
||||||
|
}
|
||||||
|
}
|
|
@ -73,6 +73,8 @@ export interface Update {
|
||||||
apply(): Promise<void>
|
apply(): Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const EXPORTS_DIRECTORY_NAME = "exports"
|
||||||
|
|
||||||
let pack: Pack
|
let pack: Pack
|
||||||
export async function usePack(): Promise<Pack> {
|
export async function usePack(): Promise<Pack> {
|
||||||
if (pack === undefined) {
|
if (pack === undefined) {
|
||||||
|
@ -97,7 +99,7 @@ export async function usePack(): Promise<Pack> {
|
||||||
side: pathSegments[0] as Side,
|
side: pathSegments[0] as Side,
|
||||||
relativePath: relativePath,
|
relativePath: relativePath,
|
||||||
absolutePath: sourceDirectoryPath.resolve(relativePath),
|
absolutePath: sourceDirectoryPath.resolve(relativePath),
|
||||||
effectivePath: RelativePath._createDirect(pathSegments.slice(1).join("/")),
|
effectivePath: RelativePath._createDirect(pathSegments.slice(1).join("/"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (relativePath.toString().endsWith("." + META_FILE_EXTENSION)) {
|
if (relativePath.toString().endsWith("." + META_FILE_EXTENSION)) {
|
||||||
|
@ -107,6 +109,7 @@ export async function usePack(): Promise<Pack> {
|
||||||
const metaFile: MetaFile = {
|
const metaFile: MetaFile = {
|
||||||
...sourceFile,
|
...sourceFile,
|
||||||
isStatic: false,
|
isStatic: false,
|
||||||
|
effectivePath: sourceFile.effectivePath.parent().joinedWith(content.version.fileName),
|
||||||
content,
|
content,
|
||||||
fetchUpdates: source?.type === "modrinth"
|
fetchUpdates: source?.type === "modrinth"
|
||||||
? allowedReleaseChannels => fetchModrinthModUpdates(metaFile, source, allowedReleaseChannels, manifest.versions.minecraft)
|
? allowedReleaseChannels => fetchModrinthModUpdates(metaFile, source, allowedReleaseChannels, manifest.versions.minecraft)
|
||||||
|
@ -134,7 +137,7 @@ export async function usePack(): Promise<Pack> {
|
||||||
paths: {
|
paths: {
|
||||||
root: rootDirectoryPath,
|
root: rootDirectoryPath,
|
||||||
source: sourceDirectoryPath,
|
source: sourceDirectoryPath,
|
||||||
exports: rootDirectoryPath.resolve("exports")
|
exports: rootDirectoryPath.resolve(EXPORTS_DIRECTORY_NAME)
|
||||||
},
|
},
|
||||||
manifest,
|
manifest,
|
||||||
metaFiles,
|
metaFiles,
|
||||||
|
|
2
test-pack/.gitignore
vendored
2
test-pack/.gitignore
vendored
|
@ -1 +1 @@
|
||||||
/generated/
|
/exports/
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"formatVersion": 1,
|
"formatVersion": 1,
|
||||||
|
"slug": "test",
|
||||||
"meta": {
|
"meta": {
|
||||||
"name": "Test",
|
"name": "Test",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
|
1
test-pack/src/client/resourcepacks/test
Normal file
1
test-pack/src/client/resourcepacks/test
Normal file
|
@ -0,0 +1 @@
|
||||||
|
content
|
Loading…
Add table
Reference in a new issue