From 4ef43dfbecc79283d038d939f94671966802039e Mon Sep 17 00:00:00 2001 From: NeeEoo Date: Wed, 10 Apr 2024 15:57:19 +0200 Subject: [PATCH] Improved the Command Line Util --- .github/workflows/linux.yml | 2 +- .github/workflows/macos.yml | 2 +- .github/workflows/windows.yml | 2 +- commandline/ArgParser.hx | 81 ++++++++++++++++++++++++++ commandline/Main.hx | 97 ++++++++++++++++++++++++------- commandline/commands/Compiler.hx | 4 +- commandline/commands/Optimizer.hx | 31 ++++++++++ commandline/commands/Update.hx | 20 ++++++- 8 files changed, 210 insertions(+), 29 deletions(-) create mode 100644 commandline/ArgParser.hx create mode 100644 commandline/commands/Optimizer.hx diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 76adeded..758cd50f 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -31,7 +31,7 @@ jobs: sudo apt-get install libvlc-dev libvlccore-dev - name: Installing/Updating libraries run: | - haxe -cp commandline -D analyzer-optimize --run Main setup + haxe -cp commandline -D analyzer-optimize --run Main setup -s - name: Building the game run: | haxelib run lime build linux diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index e6646418..9ae13a76 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -28,7 +28,7 @@ jobs: cache-build-mac - name: Installing/Updating libraries run: | - haxe -cp commandline -D analyzer-optimize --run Main setup + haxe -cp commandline -D analyzer-optimize --run Main setup -s - name: Building the game run: | haxelib run lime build mac diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index d89c1687..3ec71f90 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -28,7 +28,7 @@ jobs: cache-build-windows - name: Installing/Updating libraries run: | - haxe -cp commandline -D analyzer-optimize --run Main setup + haxe -cp commandline -D analyzer-optimize --run Main setup -s --no-vscheck - name: Building the game run: | haxelib run lime build windows diff --git a/commandline/ArgParser.hx b/commandline/ArgParser.hx new file mode 100644 index 00000000..61ff15b8 --- /dev/null +++ b/commandline/ArgParser.hx @@ -0,0 +1,81 @@ +package; + +using StringTools; + +class ArgParser { + public static function parse(args:Array, ?renameMap:Map = null):ArgParser { + return new ArgParser(args, renameMap); + } + + private function new(args:Array, ?renameMap:Map) { + if (renameMap == null) { + renameMap = new Map(); + } + function rename(name:String) { + return renameMap.exists(name) ? renameMap.get(name) : name; + } + this.args = args; + + this.options = new Map(); + var copy = args.copy(); + var i = 0; + while(copy.length > 0) { + var arg = copy.shift(); + // this parses the -NAME=VALUE + if (arg.startsWith("-")) { + var key = arg.substr(1); + var isLongKey = key.startsWith("-"); + if (isLongKey) { + key = key.substr(1); + } + var split = key.split("="); + var longName = split.shift(); + if(!isLongKey) { + // Allow -ABC to be parsed as -A -B -C + // Values will only work for the last one + while(longName.length > 1) { + var name = rename(longName.charAt(0)); + options.set(name, null); + longName = longName.substr(1); + } + + longName = longName.charAt(0); + // Parse the last option with value support + } + + var name = rename(longName); + var value = (split.length > 0) ? split.join("=") : null; + options.set(name, value); + + args.splice(i, 1); + i--; + } + + i++; + } + } + + /** + * Options are arguments that start with a "-", if they are followed by an "=" they are a key/value pair. + * otherwise they are stored as a key with an null value. + **/ + public var options(default, null):Map; + public var args(default, null):Array; + + public var length(get, never):Int; + inline function get_length():Int { + return args.length; + } + + public function get(index:Int):String { + return args[index]; + } + + public function existsOption(name:String):Bool { + return options.exists(name); + } + + public function getOption(name:String):String { + return options.get(name); + } +} \ No newline at end of file diff --git a/commandline/Main.hx b/commandline/Main.hx index 6d628cf3..8c2f9301 100644 --- a/commandline/Main.hx +++ b/commandline/Main.hx @@ -5,57 +5,108 @@ import commands.*; class Main { public static var commands:Array = []; + public static var curCommand:Command; + public static function initCommands() { commands = [ { names: ["setup"], doc: "Setups (or updates) all libraries required for the engine.", func: Update.main, - dDoc: "This command runs through all libraries in libs.xml, and install them.\nIf they're already installed, they will be updated." + dDoc: [ + "Usage: setup", + "", + "This command runs through all libraries in libs.xml, and install them.", + "If they're already installed, they will be updated.", + "", + "--all : Reinstall all libraries.", + "--no-vscheck : Don't check if Visual Studio is installed.", + "-s | --silent | --silent-progress : Don't show download progress." + ].join("\n") }, { names: ["help", null], doc: "Shows help. Pass a command name to get additional help.", func: help, - dDoc: "Usage: help \n\nFor example, use \"cne help test\" to get additional help on the test command." + dDoc: [ + "Usage: help ", + "", + "For example, use \"cne help test\" to get additional help on the test command." + ].join("\n") }, { names: ["test"], doc: "Creates a non final test build, then runs it.", func: Compiler.test, - dDoc: "Usage: test \n" + - "\nThis will create a quick debug build binded to the source then run it, which means:" + - "\n- The assets WON'T be copied over - Assets will be read from the game's source." + - "\n- This build WON'T be ready for release - Running anywhere else than in the bin folder will result in a crash from missing assets" + - "\n- This build will also use the mods folder from the source directory." + - "\n\nIf you want a full build which contains all assets, run \"cne release\" or \"cne test-release\"" + - "\nAdditional arguments will be sent to the lime compiler." + dDoc: [ + "Usage: test ", + "", + "This will create a quick debug build binded to the source then run it, which means:", + "- The assets WON'T be copied over - Assets will be read from the game's source.", + "- This build WON'T be ready for release - Running anywhere else than in the bin folder will result in a crash from missing assets", + "- This build will also use the mods folder from the source directory.", + "", + "If you want a full build which contains all assets, run \"cne release\" or \"cne test-release\"", + "Additional arguments will be sent to the lime compiler.", + "", + "-debug : Builds a debug build." + ].join("\n") }, { names: ["build"], doc: "Creates a non final test build, without running it.", func: Compiler.build, - dDoc: "Usage: build \n" + - "\nThis will create a quick debug build binded to the source then run it, which means:" + - "\n- The assets WON'T be copied over - Assets will be read from the game's source." + - "\n- This build WON'T be ready for release - Running anywhere else than in the bin folder will result in a crash from missing assets" + - "\n- This build will also use the mods folder from the source directory." + - "\n\nIf you want a full build which contains all assets, run \"cne release\" or \"cne test-release\"" + - "\nAdditional arguments will be sent to the lime compiler." + dDoc: [ + "Usage: build ", + "", + "This will create a quick debug build binded to the source then run it, which means:", + "- The assets WON'T be copied over - Assets will be read from the game's source.", + "- This build WON'T be ready for release - Running anywhere else than in the bin folder will result in a crash from missing assets", + "- This build will also use the mods folder from the source directory.", + "", + "If you want a full build which contains all assets, run \"cne release\" or \"cne test-release\"", + "Additional arguments will be sent to the lime compiler.", + "", + "-debug : Builds a debug build." + ].join("\n") }, { names: ["release"], doc: "Creates a final non debug build, containing all assets.", func: Compiler.release, - dDoc: "Usage: release \n" + - "\nThis will create a final ready-for-release build, which means this build will be able to be release on websites such as GameBanana without worrying about source-dependant stuff." + dDoc: [ + "Usage: release ", + "", + "This will create and run a final ready-for-release build,", + "which means this build will be able to be release on websites such as GameBanana without worrying about source-dependant stuff.", + "Additional arguments will be sent to the lime compiler." + ].join("\n") }, { names: ["test-release"], doc: "Creates a final non debug build, containing all assets.", func: Compiler.testRelease, - dDoc: "Usage: release \n" + - "\nThis will create and run a final ready-for-release build, which means this build will be able to be release on websites such as GameBanana without worrying about source-dependant stuff." + dDoc: [ + "Usage: test-release ", + "", + "This will create and run a final ready-for-release build,", + "which means this build will be able to be release on websites such as GameBanana without worrying about source-dependant stuff.", + "Additional arguments will be sent to the lime compiler." + ].join("\n") + }, + { + names: ["optimize"], + doc: "Optimizes a JSON file.", + func: Optimizer.main, + dDoc: [ + "Usage: optimize ", + "", + "This will optimize a JSON file, which means it will remove all unnecessary spacing from the file.", + "WARNING: Order might be lost.", + "WARNING: Comments arent supported.", + "", + "-O | --no-old : No Old file will be created.", + ].join("\n") } ]; } @@ -66,8 +117,12 @@ class Main { var commandName = args.shift(); if (commandName != null) commandName = commandName.toLowerCase(); + else + commandName = "help"; + for(c in commands) { if (c.names.contains(commandName)) { + curCommand = c; c.func(args); return; } @@ -90,7 +145,7 @@ class Main { return; } - Sys.println('${matchingCommand.names.join(", ")}'); + Sys.println('Command: ${matchingCommand.names.filter(v->v != null).join(", ")}'); Sys.println("---"); Sys.println(matchingCommand.dDoc); diff --git a/commandline/commands/Compiler.hx b/commandline/commands/Compiler.hx index fe64c198..6d09f5aa 100644 --- a/commandline/commands/Compiler.hx +++ b/commandline/commands/Compiler.hx @@ -2,10 +2,10 @@ package commands; class Compiler { public static function test(args:Array) { - __build(args, ["test", getBuildTarget(), "-D", "TEST_BUILD"]); + __build(args, ["test", getBuildTarget(), "-DTEST_BUILD"]); } public static function build(args:Array) { - __build(args, ["build", getBuildTarget(), "-D", "TEST_BUILD"]); + __build(args, ["build", getBuildTarget(), "-DTEST_BUILD"]); } public static function release(args:Array) { __build(args, ["build", getBuildTarget()]); diff --git a/commandline/commands/Optimizer.hx b/commandline/commands/Optimizer.hx new file mode 100644 index 00000000..b82d9182 --- /dev/null +++ b/commandline/commands/Optimizer.hx @@ -0,0 +1,31 @@ +package commands; + +import sys.io.File; + +class Optimizer { + public static function main(args:Array) { + var args = ArgParser.parse(args); + var saveOld = args.existsOption("no-old"); + + if(args.length == 0) { + Sys.println(Main.curCommand.dDoc); + return; + } + + var filename = args.get(0); + + var data = File.getContent(filename); + var json = null; + try { + json = haxe.Json.parse(data); + } catch(e:Dynamic) { + Sys.println("Error parsing JSON file."); + Sys.println(e); + return; + } + + if(saveOld) + File.saveContent(filename + ".old", data); + File.saveContent(filename, haxe.Json.stringify(json)); + } +} \ No newline at end of file diff --git a/commandline/commands/Update.hx b/commandline/commands/Update.hx index 6ac0f0f3..269b2035 100644 --- a/commandline/commands/Update.hx +++ b/commandline/commands/Update.hx @@ -10,10 +10,20 @@ class Update { public static function main(args:Array) { prettyPrint("Preparing installation..."); + var args = ArgParser.parse(args, ["S" => "silent-progress", "silent" => "silent-progress"]); + var CHECK_VSTUDIO = !args.existsOption("no-vscheck"); + var REINSTALL_ALL = args.existsOption("all"); + var SILENT = args.existsOption("silent-progress"); + // to prevent messing with currently installed libs if (!FileSystem.exists('.haxelib')) FileSystem.createDirectory('.haxelib'); + if (REINSTALL_ALL) { + FileSystem.deleteDirectory('.haxelib'); + FileSystem.createDirectory('.haxelib'); + } + var libs:Array = []; var libsXML:Access = new Access(Xml.parse(File.getContent('./libs.xml')).firstElement()); @@ -33,15 +43,19 @@ class Update { libs.push(lib); } + var commandSuffix = " --always"; + if (SILENT) commandSuffix += " --silent"; + for(lib in libs) { var globalism:Null = lib.global == "true" ? "--global" : null; + var globalSuffix = globalism != null ? ' $globalism' : ''; switch(lib.type) { case "lib": prettyPrint((lib.global == "true" ? "Globally installing" : "Locally installing") + ' "${lib.name}"...'); - Sys.command('haxelib install ${lib.name} ${lib.version != null ? " " + lib.version : " "}${globalism != null ? ' $globalism' : ''} --always'); + Sys.command('haxelib install ${lib.name} ${lib.version != null ? " " + lib.version : " "}$globalSuffix$commandSuffix'); case "git": prettyPrint((lib.global == "true" ? "Globally installing" : "Locally installing") + ' "${lib.name}" from git url "${lib.url}"'); - Sys.command('haxelib git ${lib.name} ${lib.url}${lib.ref != null ? ' ${lib.ref}' : ''}${globalism != null ? ' $globalism' : ''} --always'); + Sys.command('haxelib git ${lib.name} ${lib.url}${lib.ref != null ? ' ${lib.ref}' : ''}$globalSuffix$commandSuffix'); default: prettyPrint('Cannot resolve library of type "${lib.type}"'); } @@ -73,7 +87,7 @@ class Update { } // vswhere.exe its used to find any visual studio related installations on the system, including full visual studio ide installations, visual studio build tools installations, and other related components - Nex - if (Compiler.getBuildTarget().toLowerCase() == "windows" && new Process('"C:/Program Files (x86)/Microsoft Visual Studio/Installer/vswhere.exe" -property catalog_productDisplayVersion').exitCode(true) == 1) { + if (CHECK_VSTUDIO && Compiler.getBuildTarget().toLowerCase() == "windows" && new Process('"C:/Program Files (x86)/Microsoft Visual Studio/Installer/vswhere.exe" -property catalog_productDisplayVersion').exitCode(true) == 1) { prettyPrint("Installing Microsoft Visual Studio Community (Dependency)"); // thanks to @crowplexus for these two lines! - Nex