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": {
|
||||
"@root/walk": "^1.1.0",
|
||||
"@sindresorhus/slugify": "^2.1.0",
|
||||
"address": "^1.2.0",
|
||||
"commander": "^9.4.0",
|
||||
"dedent": "^0.7.0",
|
||||
|
|
22
pnpm-lock.yaml
generated
22
pnpm-lock.yaml
generated
|
@ -2,6 +2,7 @@ lockfileVersion: 5.4
|
|||
|
||||
specifiers:
|
||||
'@root/walk': ^1.1.0
|
||||
'@sindresorhus/slugify': ^2.1.0
|
||||
'@types/dedent': ^0.7.0
|
||||
'@types/fs-extra': ^9.0.13
|
||||
'@types/lodash-es': ^4.17.6
|
||||
|
@ -44,6 +45,7 @@ specifiers:
|
|||
|
||||
dependencies:
|
||||
'@root/walk': 1.1.0
|
||||
'@sindresorhus/slugify': 2.1.0
|
||||
address: 1.2.0
|
||||
commander: 9.4.0
|
||||
dedent: 0.7.0
|
||||
|
@ -166,6 +168,22 @@ packages:
|
|||
engines: {node: '>=14.16'}
|
||||
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:
|
||||
resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==}
|
||||
engines: {node: '>=14.16'}
|
||||
|
@ -1162,6 +1180,10 @@ packages:
|
|||
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
|
||||
dev: false
|
||||
|
||||
/lodash.deburr/4.1.0:
|
||||
resolution: {integrity: sha512-m/M1U1f3ddMCs6Hq2tAsYThTBDaAKFDX3dwDo97GEYzamXi9SqUpjWi/Rrj/gf3X2n8ktwgZrlP1z6E3v/IExQ==}
|
||||
dev: false
|
||||
|
||||
/log-symbols/5.1.0:
|
||||
resolution: {integrity: sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
|
@ -7,6 +7,8 @@ import { fetchFabricMinecraftVersions, fetchFabricVersions } from "../fabricApi.
|
|||
import enquirer from "enquirer"
|
||||
import { PACK_MANIFEST_FILE_NAME, PACK_MANIFEST_FORMAT_VERSION, PackManifest } from "../files.js"
|
||||
import pathModule from "path"
|
||||
import { EXPORTS_DIRECTORY_NAME } from "../pack.js"
|
||||
import slugify from "@sindresorhus/slugify"
|
||||
|
||||
export const initCommand = new Command("init")
|
||||
.argument("<path>")
|
||||
|
@ -62,6 +64,7 @@ export const initCommand = new Command("init")
|
|||
|
||||
const file: PackManifest = {
|
||||
formatVersion: PACK_MANIFEST_FORMAT_VERSION,
|
||||
slug: slugify(answers.name),
|
||||
meta: {
|
||||
name: answers.name,
|
||||
version: "1.0.0",
|
||||
|
@ -76,7 +79,7 @@ export const initCommand = new Command("init")
|
|||
}
|
||||
|
||||
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))}`))
|
||||
})
|
||||
|
|
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 kleur from "kleur"
|
||||
import { openCommand } from "./open.js"
|
||||
import { exportCommand } from "./export.js"
|
||||
|
||||
export const modrinthCommand = new Command("modrinth")
|
||||
.alias("mr")
|
||||
.addCommand(activateCommand)
|
||||
.addCommand(exportCommand)
|
||||
.addCommand(openCommand)
|
||||
.addHelpText("afterAll", dedent`
|
||||
\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({
|
||||
formatVersion: z.literal(PACK_MANIFEST_FORMAT_VERSION),
|
||||
slug: z.string(),
|
||||
meta: z.object({
|
||||
name: 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>
|
||||
}
|
||||
|
||||
export const EXPORTS_DIRECTORY_NAME = "exports"
|
||||
|
||||
let pack: Pack
|
||||
export async function usePack(): Promise<Pack> {
|
||||
if (pack === undefined) {
|
||||
|
@ -97,7 +99,7 @@ export async function usePack(): Promise<Pack> {
|
|||
side: pathSegments[0] as Side,
|
||||
relativePath: 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)) {
|
||||
|
@ -107,6 +109,7 @@ export async function usePack(): Promise<Pack> {
|
|||
const metaFile: MetaFile = {
|
||||
...sourceFile,
|
||||
isStatic: false,
|
||||
effectivePath: sourceFile.effectivePath.parent().joinedWith(content.version.fileName),
|
||||
content,
|
||||
fetchUpdates: source?.type === "modrinth"
|
||||
? allowedReleaseChannels => fetchModrinthModUpdates(metaFile, source, allowedReleaseChannels, manifest.versions.minecraft)
|
||||
|
@ -134,7 +137,7 @@ export async function usePack(): Promise<Pack> {
|
|||
paths: {
|
||||
root: rootDirectoryPath,
|
||||
source: sourceDirectoryPath,
|
||||
exports: rootDirectoryPath.resolve("exports")
|
||||
exports: rootDirectoryPath.resolve(EXPORTS_DIRECTORY_NAME)
|
||||
},
|
||||
manifest,
|
||||
metaFiles,
|
||||
|
|
2
test-pack/.gitignore
vendored
2
test-pack/.gitignore
vendored
|
@ -1 +1 @@
|
|||
/generated/
|
||||
/exports/
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"formatVersion": 1,
|
||||
"slug": "test",
|
||||
"meta": {
|
||||
"name": "Test",
|
||||
"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