From 4c82459cd05acea1b40f57da245f651a6b854ef1 Mon Sep 17 00:00:00 2001 From: connerdouglass Date: Wed, 10 Nov 2021 22:21:59 -0800 Subject: [PATCH] Added build command --- README.md | 10 +++ cmd/crx/build.go | 52 +++++++++++++++ cmd/crx/main.go | 44 +++++------- lib/bundler.go | 159 ++++++++++++++++++++++++++++++++++++++++++++ lib/jar_template.go | 61 +++++++++++++++++ lib/jarbuilder.go | 62 ----------------- package.json | 2 +- 7 files changed, 298 insertions(+), 92 deletions(-) create mode 100644 cmd/crx/build.go create mode 100644 lib/bundler.go create mode 100644 lib/jar_template.go delete mode 100644 lib/jarbuilder.go diff --git a/README.md b/README.md index 09a567a..5f181f9 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,13 @@ # @customrealms/cli +CustomRealms command-line tools for setting up and compiling JavaScript Minecraft plugins. +### Installation + +Install the CLI on your computer: + +```sh +npm install -g @customrealms/cli +``` + +### Start a project diff --git a/cmd/crx/build.go b/cmd/crx/build.go new file mode 100644 index 0000000..61e2455 --- /dev/null +++ b/cmd/crx/build.go @@ -0,0 +1,52 @@ +package main + +import ( + "flag" + "fmt" + "os" + "os/exec" + + "github.com/customrealms/cli/lib" +) + +const DEFAULT_MC_VERSION = "1.17.1" + +func crxBuild() { + + var projectDir string + var mcVersion string + var outputFile string + + flag.StringVar(&projectDir, "p", ".", "plugin project directory") + flag.StringVar(&mcVersion, "mc", DEFAULT_MC_VERSION, "Minecraft version number target") + flag.StringVar(&outputFile, "o", "", "output JAR file path") + + flag.CommandLine.Parse(os.Args[2:]) + + if len(outputFile) == 0 { + fmt.Println("Output JAR file is required: -o option") + os.Exit(1) + } + + // Build the local directory + cmd := exec.Command("npm", "run", "build") + cmd.Dir = projectDir + if err := cmd.Run(); err != nil { + panic(err) + } + + // Define the specification for the JAR template + jarTemplate := lib.JarTemplate{ + MCVersion: mcVersion, + } + + if err := lib.BundleJar( + projectDir, + &jarTemplate, + mcVersion, + outputFile, + ); err != nil { + panic(err) + } + +} diff --git a/cmd/crx/main.go b/cmd/crx/main.go index b798b68..d535e53 100644 --- a/cmd/crx/main.go +++ b/cmd/crx/main.go @@ -1,43 +1,29 @@ package main import ( + "fmt" "os" - "strings" - - "github.com/customrealms/cli/lib" ) -const TEMPLATE_JAR = "/Users/conner/Projects/customrealms/bukkit-runtime/target/bukkit-runtime-jar-with-dependencies.jar" -const output = "/Users/conner/Desktop/mcserver/plugins/bukkit-runtime-jar-with-dependencies.jar" +const VERSION = "0.1.0" func main() { - // Open the output file for the final JAR - file, err := os.Create(output) - if err != nil { - panic(err) - } - defer file.Close() - - // Create a reader for the plugin source code - pluginCode := strings.NewReader("setInterval(() => console.log('YOOOOOO'), 3000)") - - // Define the plugin.yml details for the plugin - pluginYml := lib.PluginYml{ - Name: "MyPlugin", - ApiVersion: "1.17", - Version: "0.0.1", - Main: "io.customrealms.MainPlugin", + // If there are no command line arguments + if len(os.Args) <= 1 { + fmt.Println("Missing command name: build, init") + os.Exit(1) } - // Produce the final JAR file - if err := lib.CreateFinalJar( - file, - TEMPLATE_JAR, - pluginCode, - &pluginYml, - ); err != nil { - panic(err) + // Get the operation string + switch os.Args[1] { + case "version": + fmt.Printf("customrealms-cli (crx) v%s\n", VERSION) + case "init": + fmt.Println("crx build ... is not yet implemented") + os.Exit(1) + case "build": + crxBuild() } } diff --git a/lib/bundler.go b/lib/bundler.go new file mode 100644 index 0000000..9f3a160 --- /dev/null +++ b/lib/bundler.go @@ -0,0 +1,159 @@ +package lib + +import ( + "archive/zip" + "bytes" + "encoding/json" + "fmt" + "io" + "os" + "path/filepath" + "strings" +) + +const JAR_MAIN_CLASS = "io.customrealms.MainPlugin" + +type PackageJSON struct { + Name string `json:"name"` + Version string `json:"version"` +} + +func mcVersionToApiVersion(mcVersion string) string { + parts := strings.Split(mcVersion, ".") + return strings.Join(parts[:2], ".") +} + +func BundleJar( + projectDir string, + jarTemplate *JarTemplate, + mcVersion string, + outputFile string, +) error { + + // Download the jar template + var jarTemplateBuf bytes.Buffer + if err := jarTemplate.Download(&jarTemplateBuf); err != nil { + return err + } + + // Make sure the directory above the output file exists + if err := os.MkdirAll(filepath.Dir(outputFile), 0777); err != nil { + return err + } + + // Open the output file for the final JAR + file, err := os.Create(outputFile) + if err != nil { + return err + } + defer file.Close() + + // Create a reader for the plugin source code + pluginCode, err := os.Open(filepath.Join(projectDir, "dist", "bundle.js")) + if err != nil { + return err + } + defer pluginCode.Close() + + // Read the package.json file + packageJsonBytes, err := os.ReadFile(filepath.Join(projectDir, "package.json")) + if err != nil { + return err + } + var packageJson PackageJSON + if err := json.Unmarshal(packageJsonBytes, &packageJson); err != nil { + return err + } + + // Define the plugin.yml details for the plugin + pluginYml := PluginYml{ + Name: packageJson.Name, + ApiVersion: mcVersionToApiVersion(mcVersion), + Version: packageJson.Version, + Main: JAR_MAIN_CLASS, + } + + // Produce the final JAR file + if err := WriteJarFile( + file, + jarTemplateBuf.Bytes(), + pluginCode, + &pluginYml, + ); err != nil { + return err + } + + fmt.Println("Wrote JAR file to: ", outputFile) + + return nil + +} + +func WriteJarFile( + writer io.Writer, + templateJarData []byte, + pluginSourceCode io.Reader, + pluginYml *PluginYml, +) error { + + fmt.Println("============================================================") + fmt.Println("Generating final JAR file for your plugin") + fmt.Println("============================================================") + + // Create the ZIP writer + zw := zip.NewWriter(writer) + defer zw.Close() + + // Create the ZIP reader from the base YML + templateJarReader := bytes.NewReader(templateJarData) + zr, err := zip.NewReader(templateJarReader, int64(len(templateJarData))) + if err != nil { + return err + } + + fmt.Println(" -> Copying template files to new JAR file") + + // Copy all the files back to the jar file + for _, f := range zr.File { + + // Skip some files + if f.Name == "plugin.js" || f.Name == "plugin.yml" { + continue + } + + // Copy the rest + if err := zw.Copy(f); err != nil { + return err + } + + } + + fmt.Println(" -> Writing bundle JS code to JAR file") + + // Write the plugin code to the jar + codeFile, err := zw.Create("plugin.js") + if err != nil { + return err + } + if _, err := io.Copy(codeFile, pluginSourceCode); err != nil { + return err + } + + fmt.Println(" -> Writing plugin.yml file to JAR file") + + // Write the plugin YML file to the jar + ymlFile, err := zw.Create("plugin.yml") + if err != nil { + return err + } + if _, err := io.Copy(ymlFile, strings.NewReader(pluginYml.String())); err != nil { + return err + } + + fmt.Println(" -> DONE") + fmt.Println() + + // We're done, no errors + return nil + +} diff --git a/lib/jar_template.go b/lib/jar_template.go new file mode 100644 index 0000000..ca5fa1b --- /dev/null +++ b/lib/jar_template.go @@ -0,0 +1,61 @@ +package lib + +import ( + "fmt" + "io" + "net/http" + "runtime" +) + +type JarTemplate struct { + Platform string + MCVersion string +} + +func (jt *JarTemplate) normalizePlatform() string { + if len(jt.Platform) > 0 { + return jt.Platform + } + if runtime.GOOS == "darwin" { + return "macos" + } + return runtime.GOOS +} + +func (jt *JarTemplate) getJarUrl() string { + return fmt.Sprintf( + "https://github.com/customrealms/bukkit-runtime/releases/latest/download/bukkit-runtime-%s-%s.jar", + jt.normalizePlatform(), + jt.MCVersion, + ) +} + +func (jt *JarTemplate) Download(writer io.Writer) error { + + fmt.Println("============================================================") + fmt.Println("Downloading JAR plugin runtime") + fmt.Println("============================================================") + + // Get the JAR url + jarUrl := jt.getJarUrl() + + // Download the JAR file + fmt.Printf(" -> %s\n", jarUrl) + res, err := http.Get(jarUrl) + if err != nil { + return err + } + defer res.Body.Close() + + // Pipe the response body to the writer + if _, err := io.Copy(writer, res.Body); err != nil { + return err + } + + fmt.Println(" -> DONE") + fmt.Println() + + // Return without error + return nil + +} diff --git a/lib/jarbuilder.go b/lib/jarbuilder.go deleted file mode 100644 index ddf85ec..0000000 --- a/lib/jarbuilder.go +++ /dev/null @@ -1,62 +0,0 @@ -package lib - -import ( - "archive/zip" - "io" - "strings" -) - -func CreateFinalJar( - writer io.Writer, - templateJar string, - pluginSourceCode io.Reader, - pluginYml *PluginYml, -) error { - - // Create the ZIP writer - zw := zip.NewWriter(writer) - defer zw.Close() - - // Create the ZIP reader from the base YML - zr, err := zip.OpenReader(templateJar) - if err != nil { - return err - } - - // Copy all the files back to the jar file - for _, f := range zr.File { - - // Skip some files - if f.Name == "plugin.js" || f.Name == "plugin.yml" { - continue - } - - // Copy the rest - if err := zw.Copy(f); err != nil { - return err - } - - } - - // Write the plugin code to the jar - codeFile, err := zw.Create("plugin.js") - if err != nil { - return err - } - if _, err := io.Copy(codeFile, pluginSourceCode); err != nil { - return err - } - - // Write the plugin YML file to the jar - ymlFile, err := zw.Create("plugin.yml") - if err != nil { - return err - } - if _, err := io.Copy(ymlFile, strings.NewReader(pluginYml.String())); err != nil { - return err - } - - // We're done, no errors - return nil - -} diff --git a/package.json b/package.json index 0e7f0ae..601a2e4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@customrealms/cli", - "version": "0.0.4", + "version": "0.1.0", "description": "", "scripts": { "postinstall": "node postinstall.js install",