From 05ca0f878e3fa741495ba706904a771477837055 Mon Sep 17 00:00:00 2001 From: Cervator Date: Fri, 3 Jul 2020 20:51:36 -0500 Subject: [PATCH 1/9] feat: GooeyCLI - replacement utility scripting system based on PicoCLI. Still a proof of concept, with a limited amount of old functionality converted to showcase the new approach. Relies on a groovyw tweak, renames the scripts, and lets PicoCLI worry about all the CLI structuring --- config/groovy/BaseCommand.groovy | 17 + config/groovy/Get.groovy | 37 ++ config/groovy/GitOptions.groovy | 12 + config/groovy/GooeyCLI.groovy | 36 ++ config/groovy/Init.groovy | 27 ++ config/groovy/ItemCommand.groovy | 14 + config/groovy/ManagedItem.groovy | 143 +++++++ config/groovy/ManagedModule.groovy | 46 +++ config/groovy/PropHelper.groovy | 30 ++ config/groovy/Recurse.groovy | 30 ++ config/groovy/Update.groovy | 27 ++ config/groovy/common.groovy | 589 ----------------------------- config/groovy/facade.groovy | 49 --- config/groovy/lib.groovy | 43 --- config/groovy/meta.groovy | 47 --- config/groovy/module.groovy | 107 ------ config/groovy/util.groovy | 349 ----------------- gradle/wrapper/groovy-wrapper.jar | Bin 5280 -> 5243 bytes groovyw => gw | 4 +- groovyw.bat => gw.bat | 4 +- 20 files changed, 423 insertions(+), 1188 deletions(-) create mode 100644 config/groovy/BaseCommand.groovy create mode 100644 config/groovy/Get.groovy create mode 100644 config/groovy/GitOptions.groovy create mode 100644 config/groovy/GooeyCLI.groovy create mode 100644 config/groovy/Init.groovy create mode 100644 config/groovy/ItemCommand.groovy create mode 100644 config/groovy/ManagedItem.groovy create mode 100644 config/groovy/ManagedModule.groovy create mode 100644 config/groovy/PropHelper.groovy create mode 100644 config/groovy/Recurse.groovy create mode 100644 config/groovy/Update.groovy delete mode 100644 config/groovy/common.groovy delete mode 100644 config/groovy/facade.groovy delete mode 100644 config/groovy/lib.groovy delete mode 100644 config/groovy/meta.groovy delete mode 100644 config/groovy/module.groovy delete mode 100644 config/groovy/util.groovy rename groovyw => gw (97%) mode change 100755 => 100644 rename groovyw.bat => gw.bat (93%) diff --git a/config/groovy/BaseCommand.groovy b/config/groovy/BaseCommand.groovy new file mode 100644 index 00000000000..c6c6a3f5f42 --- /dev/null +++ b/config/groovy/BaseCommand.groovy @@ -0,0 +1,17 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +import picocli.CommandLine.Command + +/** + * Simple super class for commands with global style options + */ +@Command( + synopsisHeading = "%n@|green Usage:|@%n%n", + descriptionHeading = "%n@|green Description:|@%n%n", + parameterListHeading = "%n@|green Parameters:|@%n%n", + optionListHeading = "%n@|green Options:|@%n%n", + commandListHeading = "%n@|green Commands:|@%n%n") +class BaseCommand { + +} \ No newline at end of file diff --git a/config/groovy/Get.groovy b/config/groovy/Get.groovy new file mode 100644 index 00000000000..1ee3155bf1b --- /dev/null +++ b/config/groovy/Get.groovy @@ -0,0 +1,37 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +import picocli.CommandLine.ParentCommand +import picocli.CommandLine.Command +import picocli.CommandLine.Mixin // Actually in use, annotation below may show syntax error due to Groovy's annotation by the same name. Works fine +import picocli.CommandLine.Parameters + +/** + * Sub-sub-command that works on item-oriented sub-commands. + * Mixes-in GitOptions to vary the origin if indicated by the user + * Distinct from the sibling command add-remote which does *not* mix in GitOptions since the command itself involves git remote + */ +@Command(name = "get", description = "Gets one or more items directly") +class Get extends BaseCommand implements Runnable { + + /** Reference to the parent item command so we can figure out what type it is */ + @ParentCommand + ItemCommand parent + + /** Mix in a variety of supported Git extras */ + @Mixin + GitOptions gitOptions + + @Parameters(paramLabel = "items", arity = "1", description = "Target item(s) to get") + List items + + void run() { + println "Going to get $items! And from origin: " + gitOptions.origin + + // The parent should be a ManagedItem. Make an instace including the possible git origin option + ManagedItem mi = parent.getManager(gitOptions.origin) + + // Having prepared an instance of the logic class we call it to actually retrieve stuff + mi.retrieve(items, false) + } +} diff --git a/config/groovy/GitOptions.groovy b/config/groovy/GitOptions.groovy new file mode 100644 index 00000000000..66974259ad8 --- /dev/null +++ b/config/groovy/GitOptions.groovy @@ -0,0 +1,12 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +import picocli.CommandLine.Option + +/** + * A mix-in meant to supply some general Git-related options + */ +class GitOptions { + @Option(names = [ "-o", "--origin"], description = "Which Git origin (account) to target") + String origin +} diff --git a/config/groovy/GooeyCLI.groovy b/config/groovy/GooeyCLI.groovy new file mode 100644 index 00000000000..d41253e1d35 --- /dev/null +++ b/config/groovy/GooeyCLI.groovy @@ -0,0 +1,36 @@ +// Grab the Groovy extensions for PicoCLI - in IntelliJ Alt-ENTER on a `@Grab` to register contents for syntax highlighting +@Grab('info.picocli:picocli-groovy:4.3.2') +// TODO: Actually exists inside the Gradle Wrapper - gradle-6.4.1\lib\groovy-all-1.3-2.5.10.jar\groovyjarjarpicocli\ + +// TODO: Unsure if this helps or should be included - don't really need this since we execute via Groovy Wrapper anyway +@GrabExclude('org.codehaus.groovy:groovy-all') + +// Needed for colors to work on Windows, along with a mode toggle at the start and end of execution in main +@Grab('org.fusesource.jansi:jansi:1.18') // TODO: Exists at 1.17 inside the Gradle Wrapper lib - can use that one? +import org.fusesource.jansi.AnsiConsole + +import picocli.CommandLine +import picocli.CommandLine.Command +import picocli.CommandLine.HelpCommand + +// If using local groovy files the subcommands section may highlight as bad syntax in IntelliJ - that's OK +@Command(name = "gw", + synopsisSubcommandLabel = "COMMAND", // Default is [COMMAND] indicating optional, but sub command here is required + subcommands = [ + HelpCommand.class, // Adds standard help options (help as a subcommand, -h, and --help) + Module.class, + Init.class], // Note that these Groovy classes *must* start with a capital letter for some reason + description = "Utility system for interacting with a Terasology developer workspace") +class GooeyCLI extends BaseCommand { + static void main(String[] args) { + AnsiConsole.systemInstall() // enable colors on Windows - TODO: Test on not-so-Windows systems, should those not run this? + CommandLine cmd = new CommandLine(new GooeyCLI()) + if (args.length == 0) { + cmd.usage(System.out) + } + else { + cmd.execute(args) + } + AnsiConsole.systemUninstall() // cleanup when done + } +} diff --git a/config/groovy/Init.groovy b/config/groovy/Init.groovy new file mode 100644 index 00000000000..f4cc3b2e311 --- /dev/null +++ b/config/groovy/Init.groovy @@ -0,0 +1,27 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +import picocli.CommandLine.Command +import picocli.CommandLine.Help.Ansi +import picocli.CommandLine.Mixin // Is in use, IDE may think the Groovy-supplied is in use below and mark this unused +import picocli.CommandLine.Parameters + +@Command(name = "init", description = "Initializes a workspace with some useful things") +class Init extends BaseCommand implements Runnable { + + /** The name of the distro, if given. Optional parameter (the arity = 0..1 bit) */ + @Parameters(paramLabel = "distro", arity = "0..1", defaultValue = "sample", description = "Target module distro to prepare locally") + String distro + + /** Mix in a variety of supported Git extras */ + @Mixin + GitOptions gitOptions + + void run() { + String str = Ansi.AUTO.string("@|bold,green,underline Time to initialize $distro !|@") + System.out.println(str) + println "Do we have a Git origin override? " + gitOptions.origin + println "Can has desired global prop? " + PropHelper.getGlobalProp("alternativeGithubHome") + // Call logic elsewhere + } +} diff --git a/config/groovy/ItemCommand.groovy b/config/groovy/ItemCommand.groovy new file mode 100644 index 00000000000..508ece26825 --- /dev/null +++ b/config/groovy/ItemCommand.groovy @@ -0,0 +1,14 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +/** + * Simple command type class that indicates the command deals with "items" - nested Git roots representing application elements + */ +abstract class ItemCommand extends BaseCommand { + /** + * Return a manager class for interacting with the specific type of item + * @param optionGitOrigin if the user indicated an alternative Git origin it will be used to vary some URLs + * @return the instantiated item type manager class + */ + abstract ManagedItem getManager(String optionGitOrigin) +} \ No newline at end of file diff --git a/config/groovy/ManagedItem.groovy b/config/groovy/ManagedItem.groovy new file mode 100644 index 00000000000..63e9f1a532d --- /dev/null +++ b/config/groovy/ManagedItem.groovy @@ -0,0 +1,143 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +@GrabResolver(name = 'jcenter', root = 'http://jcenter.bintray.com/') +@Grab(group = 'org.ajoberstar', module = 'grgit', version = '1.9.3') +import org.ajoberstar.grgit.Grgit + +/** + * Utility class for dealing with items managed in a developer workspace. + * + * Primarily assists with the retrieval, creation, and updating of nested Git roots representing application elements. + */ +abstract class ManagedItem { + + /** For keeping a list of items retrieved so far (retrieval calls may be recursive) */ + def itemsRetrieved = [] + + /** The default name of a git remote we might want to work on or keep handy */ + String defaultRemote = "origin" // TODO: Consider always naming remotes after their origin / account name? + + String displayName + abstract String getDisplayName() + + File targetDirectory + abstract File getTargetDirectory() + + String githubTargetHome + abstract String getDefaultItemGitOrigin() + + ManagedItem() { + displayName = getDisplayName() + targetDirectory = getTargetDirectory() + githubTargetHome = calculateGitOrigin(null) + } + + ManagedItem(String optionGitOrigin) { + displayName = getDisplayName() + targetDirectory = getTargetDirectory() + githubTargetHome = calculateGitOrigin(optionGitOrigin) + } + + String calculateGitOrigin(String optionOrigin) { + // If the user indicated a target Git origin via option parameter then use that (primary choice) + if (optionOrigin != null) { + println "We have an option set for Git origin so using that: " + optionOrigin + return optionOrigin + } + + // Alternatively if the user has a global override set for Git origin then use that (secondary choice) + String altOrigin = PropHelper.getGlobalProp("alternativeGithubHome") + if (altOrigin != null) { + println "There was no option set but we have a global proper override for Git origin: " + altOrigin + return altOrigin + } + + // And finally if neither override is set fall back on the default defined by the item type + println "No option nor global override set for Git origin so using default for the type: " + getDefaultItemGitOrigin() + return getDefaultItemGitOrigin() + } + + // TODO: Likely everything below should just delegate to more specific classes to keep things tidy + // TODO: That would allow these methods to later just figure out exact required operations then delegate + // TODO: Should make it easier to hide the logic of (for instance) different Git adapters behind the next step + + /** + * Tests a URL via a HEAD request (no body) to see if it is valid + * @param url the URL to test + * @return boolean indicating whether the URL is valid (code 200) or not + */ + boolean isUrlValid(String url) { + def code = new URL(url).openConnection().with { + requestMethod = 'HEAD' + connect() + responseCode + } + return code.toString() == "200" + } + + /** + * Primary entry point for retrieving items, kicks off recursively if needed. + * @param items the items we want to retrieve + * @param recurse whether to also retrieve dependencies of the desired items (only really for modules ...) + */ + def retrieve(List items, boolean recurse) { + println "Now inside retrieve, user (recursively? $recurse) wants: $items" + for (String itemName : items) { + println "Starting retrieval for $displayName $itemName, are we recursing? $recurse" + println "Retrieved so far: $itemsRetrieved" + retrieveItem(itemName, recurse) + } + } + + /** + * Retrieves a single item via Git Clone. Considers whether it exists locally first or if it has already been retrieved this execution. + * @param itemName the target item to retrieve + * @param recurse whether to also retrieve its dependencies (if so then recurse back into retrieve) + */ + def retrieveItem(String itemName, boolean recurse) { + File itemDir = new File(targetDirectory, itemName) + println "Request to retrieve $displayName $itemName would store it at $itemDir - exists? " + itemDir.exists() + if (itemDir.exists()) { + println "That $displayName already had an existing directory locally. If something is wrong with it please delete and try again" + itemsRetrieved << itemName + } else if (itemsRetrieved.contains(itemName)) { + println "We already retrieved $itemName - skipping" + } else { + itemsRetrieved << itemName + def targetUrl = "https://github.com/${githubTargetHome}/${itemName}" + if (!isUrlValid(targetUrl)) { + println "Can't retrieve $displayName from $targetUrl - URL appears invalid. Typo? Not created yet?" + return + } + println "Retrieving $displayName $itemName from $targetUrl" + if (githubTargetHome != getDefaultItemGitOrigin()) { + println "Doing a retrieve from a custom remote: $githubTargetHome - will name it as such plus add the ${getDefaultItemGitOrigin()} remote as '$defaultRemote'" + Grgit.clone dir: itemDir, uri: targetUrl, remote: githubTargetHome + println "Primary clone operation complete, about to add the '$defaultRemote' remote for the ${getDefaultItemGitOrigin()} org address" + //addRemote(itemName, defaultRemote, "https://github.com/${getDefaultItemGitOrigin()}/${itemName}") //TODO: Add me :p + } else { + println "Cloning $targetUrl to $itemDir" + Grgit.clone dir: itemDir, uri: targetUrl + } +/* + // This step allows the item type to check the newly cloned item and add in extra template stuff - TODO? + //itemTypeScript.copyInTemplateFiles(itemDir) + + // Handle also retrieving dependencies if the item type cares about that + if (recurse) { + def foundDependencies = itemTypeScript.findDependencies(itemDir) + if (foundDependencies.length == 0) { + println "The $itemType $itemName did not appear to have any dependencies we need to worry about" + } else { + println "The $itemType $itemName has the following $itemType dependencies we care about: $foundDependencies" + String[] uniqueDependencies = foundDependencies - itemsRetrieved + println "After removing dupes already retrieved we have the remaining dependencies left: $uniqueDependencies" + if (uniqueDependencies.length > 0) { + retrieve(uniqueDependencies, true) + } + } + }*/ + } + } +} diff --git a/config/groovy/ManagedModule.groovy b/config/groovy/ManagedModule.groovy new file mode 100644 index 00000000000..28ae39ec26a --- /dev/null +++ b/config/groovy/ManagedModule.groovy @@ -0,0 +1,46 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +class ManagedModule extends ManagedItem { + ManagedModule() { + super() + } + + ManagedModule(String optionGitOrigin) { + super(optionGitOrigin) + } + + @Override + String getDisplayName() { + return "module" + } + + @Override + File getTargetDirectory() { + return new File("modules") + } + + @Override + String getDefaultItemGitOrigin() { + return "Terasology" + } + + /** + * Copies in a fresh copy of build.gradle for all modules (in case changes are made and need to be propagated) + */ + void refreshGradle() { + targetDirectory.eachDir() { dir -> + File targetDir = new File(targetDirectory, dir.name) + + // Copy in the template build.gradle for modules + if (!new File(targetDir, "module.txt").exists()) { + println "$targetDir has no module.txt, it must not want a fresh build.gradle" + return + } + println "In refreshGradle for module $targetDir - copying in a fresh build.gradle" + File targetBuildGradle = new File(targetDir, 'build.gradle') + targetBuildGradle.delete() + targetBuildGradle << new File('templates/build.gradle').text + } + } +} diff --git a/config/groovy/PropHelper.groovy b/config/groovy/PropHelper.groovy new file mode 100644 index 00000000000..4e81417c372 --- /dev/null +++ b/config/groovy/PropHelper.groovy @@ -0,0 +1,30 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +/** + * Convenience class for pulling properties out of a 'gradle.properties' if present, for various overrides + * // TODO: YAML variant that can be added for more complex use cases? + */ +class PropHelper { + + static String getGlobalProp(String key) { + Properties extraProps = new Properties() + File gradlePropsFile = new File("gradle.properties") + if (gradlePropsFile.exists()) { + gradlePropsFile.withInputStream { + extraProps.load(it) + } + //println "Found a 'gradle.properties' file, loaded in global overrides: " + extraProps + + if (extraProps.containsKey(key)) { + println "Returning found global prop for $key" + return extraProps.get(key) + } + println "Didn't find a global prop for key $key" + + } else { + println "No 'gradle.properties' file found, not supplying global overrides" + } + return null + } +} diff --git a/config/groovy/Recurse.groovy b/config/groovy/Recurse.groovy new file mode 100644 index 00000000000..8e74d2da0b1 --- /dev/null +++ b/config/groovy/Recurse.groovy @@ -0,0 +1,30 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +import picocli.CommandLine.ParentCommand +import picocli.CommandLine.Command +import picocli.CommandLine.Mixin +import picocli.CommandLine.Parameters + +// Sub-sub-command that works on item-oriented sub-commands +// Would mix-in GitOptions to vary the origin if indicated by the user +// Distinct from the sibling command add-remote which does *not* mix in GitOptions +@Command(name = "recurse", + description = "Gets one or more items and all their dependencies") +class Recurse extends BaseCommand implements Runnable { + + @ParentCommand + ItemCommand parent + + /** Mix in a variety of supported Git extras */ + @Mixin + GitOptions gitOptions + + @Parameters(paramLabel = "items", arity = "1", description = "Target item(s) to get, including their dependencies") + List items + + void run() { + println "Going to recurse $items! And from origin: " + gitOptions.origin + println "Command parent is: " + parent.getItemType() + } +} diff --git a/config/groovy/Update.groovy b/config/groovy/Update.groovy new file mode 100644 index 00000000000..678ad1bd23e --- /dev/null +++ b/config/groovy/Update.groovy @@ -0,0 +1,27 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +import picocli.CommandLine.ParentCommand +import picocli.CommandLine.Command +import picocli.CommandLine.Mixin +import picocli.CommandLine.Parameters + +@Command(name = "update", + description = "Updates one or more items directly") +class Update extends BaseCommand implements Runnable { + + @ParentCommand + ItemCommand parent + + /** Mix in a variety of supported Git extras */ + @Mixin + GitOptions gitOptions + + @Parameters(paramLabel = "items", arity = "1", description = "Target item(s) to update") + List items + + void run() { + println "Going to update $items! And from origin: " + gitOptions.origin + println "Command parent is: " + parent.getItemType() + } +} diff --git a/config/groovy/common.groovy b/config/groovy/common.groovy deleted file mode 100644 index b215c318d02..00000000000 --- a/config/groovy/common.groovy +++ /dev/null @@ -1,589 +0,0 @@ -import groovy.json.JsonSlurper - -@Grab(group = 'org.slf4j', module = 'slf4j-api', version = '1.6.1') -@Grab(group = 'org.slf4j', module = 'slf4j-nop', version = '1.6.1') - -@GrabResolver(name = 'jcenter', root = 'http://jcenter.bintray.com/') -@Grab(group = 'org.ajoberstar', module = 'grgit', version = '1.9.3') -import org.ajoberstar.grgit.Grgit -import org.ajoberstar.grgit.exception.GrgitException -import org.ajoberstar.grgit.Remote -import org.eclipse.jgit.errors.RepositoryNotFoundException - -import static Ansi.* - -class common { - - /** For preparing an instance of the target item type utility class we want to work with */ - GroovyObject itemTypeScript - - /** The official default GitHub home (org/user) for the type */ - def githubDefaultHome - - /** The actual target GitHub home (org/user) for the type, as potentially requested by the user */ - def githubTargetHome - - /** The target directory for the type */ - File targetDirectory - - /** The clean human readable name for the type */ - def itemType - - /** Things we don't want to retrieve/update as they live in the main MovingBlocks/Terasology repo */ - def excludedItems - - /** For keeping a list of items retrieved so far */ - def itemsRetrieved = [] - - /** The default name of a git remote we might want to work on or keep handy */ - String defaultRemote = "origin" - - /** Should we cache the list of remote items */ - boolean itemListCached = false - - /** For keeping a list of remote items that can be retrieved */ - String[] cachedItemList - - /** - * Initialize defaults to match the target item type - * @param type the type to be initialized - */ - def initialize(String type) { - // Look for a gradle.properties to check for a variety of override configuration - Properties properties = new Properties() - File gradlePropsFile = new File("gradle.properties") - if (gradlePropsFile.exists()) { - gradlePropsFile.withInputStream { - properties.load(it) - } - } - - File itemTypeScriptFile = new File("config/groovy/${type}.groovy") - Class targetClass = new GroovyClassLoader(getClass().getClassLoader()).parseClass(itemTypeScriptFile) - itemTypeScript = (GroovyObject) targetClass.newInstance() - - excludedItems = itemTypeScript.excludedItems - githubDefaultHome = itemTypeScript.getGithubDefaultHome(properties) - githubTargetHome = githubDefaultHome - targetDirectory = itemTypeScript.targetDirectory - itemType = itemTypeScript.itemType - } - - /** - * Accepts input from the user, showing a descriptive prompt. - * @param prompt the prompt to show the user - */ - def getUserString(String prompt) { - println('\n*** ' + prompt + '\n') - def reader = new BufferedReader(new InputStreamReader(System.in)) - return reader.readLine() - } - - /** - * Tests a URL via a HEAD request (no body) to see if it is valid - * @param url the URL to test - * @return boolean indicating whether the URL is valid (code 200) or not - */ - boolean isUrlValid(String url) { - def code = new URL(url).openConnection().with { - requestMethod = 'HEAD' - connect() - responseCode - } - return code.toString() == "200" - } - - /** - * Primary entry point for retrieving items, kicks off recursively if needed. - * @param items the items we want to retrieve - * @param recurse whether to also retrieve dependencies of the desired items (only really for modules ...) - */ - def retrieve(String[] items, boolean recurse) { - println "Now inside retrieve, user (recursively? $recurse) wants: $items" - for (String itemName : items) { - println "Starting retrieval for $itemType $itemName, are we recursing? $recurse" - println "Retrieved so far: $itemsRetrieved" - retrieveItem(itemName, recurse) - } - } - - /** - * Retrieves a single item via Git Clone. Considers whether it exists locally first or if it has already been retrieved this execution. - * @param itemName the target item to retrieve - * @param recurse whether to also retrieve its dependencies (if so then recurse back into retrieve) - */ - def retrieveItem(String itemName, boolean recurse) { - File targetDir = new File(targetDirectory, itemName) - println "Request to retrieve $itemType $itemName would store it at $targetDir - exists? " + targetDir.exists() - if (targetDir.exists()) { - println "That $itemType already had an existing directory locally. If something is wrong with it please delete and try again" - itemsRetrieved << itemName - } else if (itemsRetrieved.contains(itemName)) { - println "We already retrieved $itemName - skipping" - } else { - itemsRetrieved << itemName - def targetUrl = "https://github.com/${githubTargetHome}/${itemName}" - if (!isUrlValid(targetUrl)) { - println "Can't retrieve $itemType from $targetUrl - URL appears invalid. Typo? Not created yet?" - return - } - println "Retrieving $itemType $itemName from $targetUrl" - if (githubTargetHome != githubDefaultHome) { - println "Doing a retrieve from a custom remote: $githubTargetHome - will name it as such plus add the $githubDefaultHome remote as '$defaultRemote'" - Grgit.clone dir: targetDir, uri: targetUrl, remote: githubTargetHome - println "Primary clone operation complete, about to add the '$defaultRemote' remote for the $githubDefaultHome org address" - addRemote(itemName, defaultRemote, "https://github.com/${githubDefaultHome}/${itemName}") - } else { - Grgit.clone dir: targetDir, uri: targetUrl - } - - // This step allows the item type to check the newly cloned item and add in extra template stuff - itemTypeScript.copyInTemplateFiles(targetDir) - - // Handle also retrieving dependencies if the item type cares about that - if (recurse) { - def foundDependencies = itemTypeScript.findDependencies(targetDir) - if (foundDependencies.length == 0) { - println "The $itemType $itemName did not appear to have any dependencies we need to worry about" - } else { - println "The $itemType $itemName has the following $itemType dependencies we care about: $foundDependencies" - String[] uniqueDependencies = foundDependencies - itemsRetrieved - println "After removing dupes already retrieved we have the remaining dependencies left: $uniqueDependencies" - if (uniqueDependencies.length > 0) { - retrieve(uniqueDependencies, true) - } - } - } - } - } - - /** - * Creates a new item with the given name and adds the necessary .gitignore file plus more if the itemType desires - * @param itemName the name of the item to be created - */ - def createItem(String itemName) { - File targetDir = new File(targetDirectory, itemName) - if (targetDir.exists()) { - println "Target directory already exists. Aborting." - return - } - println "Creating target directory" - targetDir.mkdir() - - // For now everything gets the same .gitignore, but beyond that defer to the itemType for specifics - println "Creating .gitignore" - File gitignore = new File(targetDir, ".gitignore") - def gitignoreText = new File("templates/.gitignore").text - gitignore << gitignoreText - - itemTypeScript.copyInTemplateFiles(targetDir) - - Grgit.init dir: targetDir, bare: false - addRemote(itemName, defaultRemote, "https://github.com/${githubDefaultHome}/${itemName}.git") - } - - /** - * Check if an item was updated within the provided time limit - * @param file the item's FETCH_HEAD file in the .git directory - * @param timeLimit the time limit for considering something recently updated, for example: use(groovy.time.TimeCategory){ 10.minute } - */ - def isRecentlyUpdated(File file, def timeLimit){ - Date lastUpdate = new Date(file.lastModified()) - def recentlyUpdated = use(groovy.time.TimeCategory){ - def timeElapsedSinceUpdate = new Date() - lastUpdate - if (timeElapsedSinceUpdate < timeLimit){ - return true - } else { - return false - } - } - } - - /** - * Update a given item. - * @param itemName the name of the item to update - */ - def updateItem(String itemName, boolean skipRecentUpdates = false) { - File targetDir = new File(targetDirectory, itemName) - if (!Character.isLetterOrDigit(itemName.charAt(0))){ - println color ("Skipping update for $itemName: starts with non-alphanumeric symbol", Ansi.YELLOW) - return - } - if (!targetDir.exists()) { - println color("$itemType \"$itemName\" not found", Ansi.RED) - return - } - try { - def itemGit = Grgit.open(dir: targetDir) - - // Do a check for the default remote before we attempt to update - def remotes = itemGit.remote.list() - def targetUrl = remotes.find { - it.name == defaultRemote - }?.url - if (targetUrl == null || !isUrlValid(targetUrl)) { - println color("While updating $itemName found its '$defaultRemote' remote invalid or its URL unresponsive: $targetUrl", Ansi.RED) - return - } - - // At this point we should have a valid remote to pull from. If local repo is clean then pull! - def clean = itemGit.status().clean - def branchName = itemGit.branch.getCurrent().fullName - - print "$itemType '$itemName' [$branchName]: " - - if (!clean) { - println color("uncommitted changes. Skipping.", Ansi.YELLOW) - } else { - println color("updating $itemType $itemName", Ansi.GREEN) - - File targetDirFetchHead = new File("$targetDir/.git/FETCH_HEAD") - if (targetDirFetchHead.exists()){ - // If the FETCH_HEAD has been modified within time limit and -skip-recently-updated flag was passed, skip updating - def timeLimit = use(groovy.time.TimeCategory){ 10.minute } - if (skipRecentUpdates && isRecentlyUpdated(targetDirFetchHead, timeLimit)){ - println color("Skipping update for $itemName: updated within last $timeLimit", Ansi.YELLOW) - return - } - // Always update modified time for FETCH_HEAD if it exists - targetDirFetchHead.setLastModified(new Date().getTime()) - } - - try { - def current_sha = itemGit.log(maxCommits: 1).find().getAbbreviatedId(8) - itemGit.pull remote: defaultRemote - def post_update_sha = itemGit.log(maxCommits: 1).find().getAbbreviatedId(8) - - if (current_sha != post_update_sha){ - // TODO this can be probably converted to do one composite diff of the full update - // once this PR is merged for grgit: https://github.com/ajoberstar/grgit/pull/318 - println color("Updating $current_sha..$post_update_sha", Ansi.GREEN) - def commits = itemGit.log {range(current_sha, post_update_sha)} - for (commit in commits){ - println("----${commit.getAbbreviatedId(8)}----") - def diff = itemGit.show(commit: commit.id) - print("added: ${diff.added.size()}, ") - print("copied: ${diff.copied.size()}, ") - print("modified: ${diff.modified.size()}, ") - print("removed: ${diff.removed.size()}, ") - println("renamed: ${diff.renamed.size()}") - } - print("\n") - } else { - println color ("No changes found", Ansi.YELLOW) - } - } catch (GrgitException exception) { - println color("Unable to update $itemName, Skipping: ${exception.getMessage()}", Ansi.RED) - } - } - } catch (RepositoryNotFoundException exception) { - println color("Skipping update for $itemName: no repository found (probably engine module)", Ansi.LIGHT_YELLOW) - } - } - - /** - * List all existing Git remotes for a given item. - * @param itemName the item to list remotes for - */ - def listRemotes(String itemName) { - if (!new File(targetDirectory, itemName).exists()) { - println "$itemType '$itemName' not found. Typo? Or run 'groovyw $itemType get $itemName' first" - return - } - def remoteGit = Grgit.open(dir: "${targetDirectory}/${itemName}") - def remote = remoteGit.remote.list() - def index = 1 - for (Remote item : remote) { - println(index + " " + item.name + " (" + item.url + ")") - index++ - } - } - - /** - * Add new Git remotes for the given items, all using the same remote name. - * @param items the items to add remotes for - * @param name the name to use for all the Git remotes - */ - def addRemotes(String[] items, String name) { - for (String item : items) { - addRemote(item, name) - } - } - - /** - * Add a new Git remote for the given item, deducing a standard URL to the repo. - * @param itemName the item to add the remote for - * @param remoteName the name to give the new remote - */ - def addRemote(String itemName, String remoteName) { - addRemote(itemName, remoteName, "https://github.com/$remoteName/$itemName" + ".git") - } - - /** - * Add a new Git remote for the given item. - * @param itemName the item to add the remote for - * @param remoteName the name to give the new remote - * @param URL address to the remote Git repo - */ - def addRemote(String itemName, String remoteName, String url) { - File targetModule = new File(targetDirectory, itemName) - if (!targetModule.exists()) { - println "$itemType '$itemName' not found. Typo? Or run 'groovyw $itemType get $itemName' first" - return - } - def remoteGit = Grgit.open(dir: "${targetDirectory}/${itemName}") - def remote = remoteGit.remote.list() - def check = remote.find { - it.name == "$remoteName" - } - if (!check) { - remoteGit.remote.add(name: "$remoteName", url: "$url") - if (isUrlValid(url)) { - println "Successfully added remote '$remoteName' for '$itemName' - doing a 'git fetch'" - remoteGit.fetch remote: remoteName - } else { - println "Added the remote '$remoteName' for $itemType '$itemName' - but the URL $url failed a test lookup. Typo? Not created yet?" - } - } else { - println "Remote already exists, fetching latest" - remoteGit.fetch remote: remoteName - } - } - - /** - * Considers given arguments for the presence of a custom remote, setting that up right if found, tidying up the arguments. - * @param arguments the args passed into the script - * @return the adjusted arguments without any found custom remote details and the commmand name itself (get or recurse) - */ - def processCustomRemote(String[] arguments) { - def remoteArg = arguments.findLastIndexOf { - it == "-remote" - } - if (remoteArg != -1) { - if (arguments.length == (remoteArg + 1)) { - githubTargetHome = getUserString('Enter name for the git remote (no spaces)') - arguments = arguments.dropRight(1) - } else { - githubTargetHome = arguments[remoteArg + 1] - arguments = arguments.dropRight(2) - } - } - return arguments.drop(1) - } - - /** - * Retrieves all the available items for the target type in the form of a list. - * @return a String[] containing the names of items available for download. - */ - String[] retrieveAvailableItems() { - if (itemListCached) { - return cachedItemList - } - - // TODO: We need better ways to display the result especially when it contains a lot of items - // However, in some cases heavy filtering could still mean that very few items will actually display ... - // Another consideration is if we should be more specific in the API request, like only retrieving name + description - def githubHomeApiUrl = "https://api.github.com/users/$githubTargetHome/repos?per_page=99" - //Note: 99 instead of 100 - see TODO below .. - - if (!isUrlValid(githubHomeApiUrl)) { - println "Deduced GitHub API URL $githubHomeApiUrl seems inaccessible." - return [] - } - - // Make a temporary map of found repos (possible items) and the associated repo description (for filter options) - def mappedPossibleItems = [:] - def currentPageUrl = githubHomeApiUrl - def slurper = new JsonSlurper() - while (currentPageUrl) { - //println "currentPageUrl: $currentPageUrl" - new URL(currentPageUrl).openConnection().with { connection -> - connection.content.withReader { reader -> - slurper.parseText(reader.text).each { item -> - mappedPossibleItems.put(item.name, item.description) - //println "Want to get item " + item.name - } - } - currentPageUrl = getLink(connection, "next") - // TODO: This comparison is vulnerable to a page request size of "100" or anything that starts with a 1, but just using 99 above .. - if (currentPageUrl.contains("page=1")) { - //println "The pagination warped back to page 1, we're done!" - currentPageUrl = null - } - } - } - - String[] items = itemTypeScript.filterItemsFromApi(mappedPossibleItems) - - return items; - } - - /** - * Retrieves all the available items for the target type in the form of a list that match the specified regex. - * - * Forming the regex: - * "\Q" starts an explicit quote (which includes all reserved characters as well) - * "\E" ends an explicit quote - * "\w*" is equivalent to "*" - it selects anything that has the same characters - * (in the range of a-z, A-Z or 1-9) as before and after the asterisk - * "." is equivalent to "?" - it selects anything that has the rest of the pattern but any - * character in the "?" symbol's position - * So, "\Q\E\w*\Q\E", selects anything that starts with INPUT_PART1 - * and ends with INPUT_PART2 - This regex expression is equivalent to the input argument - * "INPUT_PART1*INPUT_PART2" - * - * @return a String[] containing the names of items available for download. - * @param regex the regex that the retrieved items should match - */ - String[] retrieveAvailableItemsWithRegexMatch(String regex) { - ArrayList selectedItems = new ArrayList() - String[] itemList = retrieveAvailableItems() - for (String item : itemList) { - if (item.matches(regex)) { - selectedItems.add(item) - } - } - - return ((String[]) selectedItems.toArray()); - } - - /** - * Retrieves all the available items for the target type in the form of a list that match the specified regex. - * - * @param wildcardPattern the wildcard pattern that the retrieved items should match - * @return a String[] containing the names of items available for download. - */ - String[] retrieveAvalibleItemsWithWildcardMatch(String wildcardPattern) { - String regex = ("\\Q" + wildcardPattern.replace("*", "\\E\\w*\\Q").replace("?", "\\E.\\Q") + "\\E") - return retrieveAvailableItemsWithRegexMatch(regex); - } - - /** - * Retrieves link from HTTP headers (RFC 5988). - * @param connection connection to retrieve link from - * @param relation relation type of requested link - * @return link with the requested relation type - */ - private static String getLink(URLConnection connection, String relation) { - def links = connection.getHeaderField("Link") - def linkMatcher = links =~ /<(.*)>;\s*rel="${relation}"/ - linkMatcher.find() ? linkMatcher.group(1) : null - } - - /** - * Retrieves all the downloaded items in the form of a list. - * @return a String[] containing the names of downloaded items. - */ - String[] retrieveLocalItems() { - def localItems = [] - targetDirectory.eachDir() { dir -> - String itemName = dir.getName() - // Don't consider excluded items - if (!(excludedItems.contains(itemName))) { - localItems << itemName - } - } - return localItems - } - - void cacheItemList() { - if (!itemListCached) { - cachedItemList = retrieveAvailableItems() - } - itemListCached = true - } - - void unCacheItemList() { - itemListCached = false - } - - void writeDependencyDotFileForModule(File dependencyFile, File module) { - if (module.name.contains(".")) { - println "\"" + module.name + "\" is not a valid source (non-jar) module - skipping" - } else if (itemsRetrieved.contains(module.name)) { - println "Module \"" + module.name + "\" was already handled - skipping" - } else if (!module.exists()) { - println "Module \"" + module.name + "\" is not locally available - skipping" - itemsRetrieved << module.name - } else { - def foundDependencies = itemTypeScript.findDependencies(module, false) - if (foundDependencies.length == 0) { - // if no other dependencies exist, depend on engine - dependencyFile.append(" \"" + module.name + "\" -> \"engine\"\n") - itemsRetrieved << module.name - } else { - // add each of $foundDependencies as item -> foundDependency lines - for (dependency in foundDependencies) { - dependencyFile.append(" \"" + module.name + "\" -> \"$dependency\"\n") - } - itemsRetrieved << module.name - - // find dependencies to progress with - String[] uniqueDependencies = foundDependencies - itemsRetrieved - if (uniqueDependencies.length > 0) { - for (dependency in uniqueDependencies) { - writeDependencyDotFileForModule(dependencyFile, new File("modules/$dependency")) - } - } - } - } - } - - def refreshGradle() { - def localItems = [] - targetDirectory.eachDir() { dir -> - String itemName = dir.getName() - // Don't consider excluded items - if (!(excludedItems.contains(itemName))) { - localItems << itemName - } else { - println "Skipping $dir as it is in the exclude list" - } - } - - for (String item : localItems) { - itemTypeScript.refreshGradle(new File(targetDirectory, item)) - } - } -} - -/** - * Small ANSI coloring utility. - * @see https://gist.github.com/tvinke/db4d21dfdbdae49e6f92dcf1ca6120de - * @see http://www.bluesock.org/~willg/dev/ansi.html - * @see https://gist.github.com/dainkaplan/4651352 - */ -class Ansi { - - static final String NORMAL = "\u001B[0m" - - static final String BOLD = "\u001B[1m" - static final String ITALIC = "\u001B[3m" - static final String UNDERLINE = "\u001B[4m" - static final String BLINK = "\u001B[5m" - static final String RAPID_BLINK = "\u001B[6m" - static final String REVERSE_VIDEO = "\u001B[7m" - static final String INVISIBLE_TEXT = "\u001B[8m" - - static final String BLACK = "\u001B[30m" - static final String RED = "\u001B[31m" - static final String GREEN = "\u001B[32m" - static final String YELLOW = "\u001B[33m" - static final String BLUE = "\u001B[34m" - static final String MAGENTA = "\u001B[35m" - static final String CYAN = "\u001B[36m" - static final String WHITE = "\u001B[37m" - - static final String DARK_GRAY = "\u001B[1;30m" - static final String LIGHT_RED = "\u001B[1;31m" - static final String LIGHT_GREEN = "\u001B[1;32m" - static final String LIGHT_YELLOW = "\u001B[1;33m" - static final String LIGHT_BLUE = "\u001B[1;34m" - static final String LIGHT_PURPLE = "\u001B[1;35m" - static final String LIGHT_CYAN = "\u001B[1;36m" - - static String color(String text, String ansiValue) { - ansiValue + text + NORMAL - } - -} diff --git a/config/groovy/facade.groovy b/config/groovy/facade.groovy deleted file mode 100644 index 78915196ef1..00000000000 --- a/config/groovy/facade.groovy +++ /dev/null @@ -1,49 +0,0 @@ - -class facade { - - def excludedItems = ["PC", "TeraEd"] - - def getGithubDefaultHome(Properties properties) { - return properties.alternativeGithubHome ?: "MovingBlocks" - } - - File targetDirectory = new File("facades") - def itemType = "facade" - - // Facades currently do not care about dependencies - String[] findDependencies(File targetDir) { - return [] - } - - def copyInTemplateFiles(File targetDir) { - println "In copyInTemplateFiles for facade $targetDir.name - reviewing Gradle needs" - File targetBuildGradle = new File(targetDir, 'build.gradle') - if (!targetBuildGradle.exists()) { - targetBuildGradle << new File('templates/facades.gradle').text - } - } - - /** - * Filters the given items based on this item type's preferences - * @param possibleItems A map of repos (possible items) and their descriptions (potential filter data) - * @return A list containing only the items this type cares about - */ - List filterItemsFromApi(Map possibleItems) { - List itemList = [] - - // Facades only includes repos found to have a particular string snippet in their description - itemList = possibleItems.findAll { - it.value?.contains("Automation category: Terasology Facade") - }.collect {it.key} - - return itemList - } - - def refreshGradle(File targetDir) { - // Copy in the template build.gradle for facades - println "In refreshGradle for facade $targetDir - copying in a fresh build.gradle" - File targetBuildGradle = new File(targetDir, 'build.gradle') - targetBuildGradle.delete() - targetBuildGradle << new File('templates/facades.gradle').text - } -} diff --git a/config/groovy/lib.groovy b/config/groovy/lib.groovy deleted file mode 100644 index d3a1ebc9d89..00000000000 --- a/config/groovy/lib.groovy +++ /dev/null @@ -1,43 +0,0 @@ - -class lib { - - def excludedItems = [] - - def getGithubDefaultHome(Properties properties) { - return properties.alternativeGithubHome ?: "MovingBlocks" - } - - File targetDirectory = new File("libs") - def itemType = "library" - - // Libs currently do not care about dependencies - String[] findDependencies(File targetDir) { - return [] - } - - // TODO: Libs don't copy anything in yet .. they might be too unique. Some may Gradle stuff but not all (like the Index) - def copyInTemplateFiles(File targetDir) { - - } - - /** - * Filters the given items based on this item type's preferences - * @param possibleItems A map of repos (possible items) and their descriptions (potential filter data) - * @return A list containing only the items this type cares about - */ - List filterItemsFromApi(Map possibleItems) { - List itemList = [] - - // Libs only includes repos found to have a particular string snippet in their description - // TODO: Consideration for libraries - generic vs project specific? TeraMath could be used in DestSol etc ... - itemList = possibleItems.findAll { - it.value?.contains("Automation category: Terasology Library") - }.collect {it.key} - - return itemList - } - - def refreshGradle(File targetDir) { - println "Skipping refreshGradle for lib $targetDir- they vary too much to use any Gradle templates" - } -} diff --git a/config/groovy/meta.groovy b/config/groovy/meta.groovy deleted file mode 100644 index a550c72b52c..00000000000 --- a/config/groovy/meta.groovy +++ /dev/null @@ -1,47 +0,0 @@ - -class meta { - - def excludedItems = ["metaterasology.github.io"] - - def getGithubDefaultHome(Properties properties) { - // Note how metas use a different override property - since same name as the paired module they cannot live in same org - return properties.alternativeGithubMetaHome ?: "MetaTerasology" - } - - File targetDirectory = new File("metas") - def itemType = "meta" - - // Meta modules currently do not care about dependencies - String[] findDependencies(File targetDir) { - return [] - } - - def copyInTemplateFiles(File targetDir) { - println "In copyInTemplateFiles for meta $targetDir.name - reviewing readme template" - File targetReadme = new File(targetDir, 'README.md') - if (!targetReadme.exists()) { - def readmeText = new File('templates/metaREADME.markdown').text - targetReadme << readmeText.replaceAll('MODULENAME', targetDir.name) - } - } - - /** - * Filters the given items based on this item type's preferences - * @param possibleItems A map of repos (possible items) and their descriptions (potential filter data) - * @return A list containing only the items this type cares about - */ - List filterItemsFromApi(Map possibleItems) { - List itemList = [] - - // Meta modules just consider the item name and excludes those in a specific list - itemList = possibleItems.findAll { - !excludedItems.contains (it.key) - }.collect {it.key} - - return itemList - } - - def refreshGradle(File targetDir) { - println "Skipping refreshGradle for meta module $targetDir - they don't Gradle" - } -} diff --git a/config/groovy/module.groovy b/config/groovy/module.groovy deleted file mode 100644 index d69f149b1e3..00000000000 --- a/config/groovy/module.groovy +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2020 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import groovy.json.JsonSlurper - -class module { - def excludedItems = ["engine", "Index", "out", "build"] - - def getGithubDefaultHome(Properties properties) { - return properties.alternativeGithubHome ?: "Terasology" - } - - File targetDirectory = new File("modules") - def itemType = "module" - - String[] findDependencies(File targetDir, boolean respectExcludedItems = true) { - def foundDependencies = readModuleDependencies(new File(targetDir, "module.txt"), respectExcludedItems) - println "Looked for dependencies, found: " + foundDependencies - return foundDependencies - } - - /** - * Reads a given module info file to figure out which if any dependencies it has. Filters out any already retrieved. - * This method is only for modules. - * @param targetModuleInfo the target file to check (a module.txt file or similar) - * @return a String[] containing the next level of dependencies, if any - */ - String[] readModuleDependencies(File targetModuleInfo, boolean respectExcludedItems = true) { - def qualifiedDependencies = [] - if (!targetModuleInfo.exists()) { - println "The module info file did not appear to exist - can't calculate dependencies" - return qualifiedDependencies - } - def slurper = new JsonSlurper() - def moduleConfig = slurper.parseText(targetModuleInfo.text) - for (dependency in moduleConfig.dependencies) { - if (respectExcludedItems && excludedItems.contains(dependency.id)) { - println "Skipping listed dependency $dependency.id as it is in the exclude list (shipped with primary project)" - } else { - println "Accepting listed dependency $dependency.id" - qualifiedDependencies << dependency.id - } - } - return qualifiedDependencies - } - - def copyInTemplateFiles(File targetDir) { - // Copy in the template build.gradle for modules - println "In copyInTemplateFiles for module $targetDir.name - copying in a build.gradle then next checking for module.txt" - File targetBuildGradle = new File(targetDir, 'build.gradle') - targetBuildGradle.delete() - targetBuildGradle << new File('templates/build.gradle').text - - // Copy in the template module.txt for modules (if one doesn't exist yet) - File moduleManifest = new File(targetDir, 'module.txt') - if (!moduleManifest.exists()) { - def moduleText = new File("templates/module.txt").text - - moduleManifest << moduleText.replaceAll('MODULENAME', targetDir.name) - println "WARNING: the module ${targetDir.name} did not have a module.txt! One was created, please review and submit to GitHub" - } - - // TODO: Copy in a module readme template soon - // TODO : Add in the logback.groovy from engine\src\test\resources\logback.groovy ? Local dev only, Jenkins will use the one inside engine-tests.jar. Also add to .gitignore - } - - /** - * Filters the given items based on this item type's preferences - * @param possibleItems A map of repos (possible items) and their descriptions (potential filter data) - * @return A list containing only the items this type cares about - */ - List filterItemsFromApi(Map possibleItems) { - List itemList = [] - - // Modules just consider the item name and excludes those in a specific list - itemList = possibleItems.findAll { - !excludedItems.contains(it.key) - }.collect { it.key } - - return itemList - } - - def refreshGradle(File targetDir) { - // Copy in the template build.gradle for modules - if (!new File(targetDir, "module.txt").exists()) { - println "$targetDir has no module.txt, it must not want a fresh build.gradle" - return - } - println "In refreshGradle for module $targetDir - copying in a fresh build.gradle" - File targetBuildGradle = new File(targetDir, 'build.gradle') - targetBuildGradle.delete() - targetBuildGradle << new File('templates/build.gradle').text - } -} diff --git a/config/groovy/util.groovy b/config/groovy/util.groovy deleted file mode 100644 index 4f692a185bc..00000000000 --- a/config/groovy/util.groovy +++ /dev/null @@ -1,349 +0,0 @@ -// Create an instance of the common script to operate on -File sourceFile = new File("config/groovy/common.groovy") -Class sourceClass = new GroovyClassLoader(getClass().getClassLoader()).parseClass(sourceFile) -GroovyObject common = (GroovyObject) sourceClass.newInstance() - -// User didn't enter a type (example: `groovyw`) -if (args.length == 0) { - println "You need to supply some parameters! See 'groovyw usage' for details" - return -} - -// If the user literally requested usage text then print it! -if (args[0] == "usage") { - printUsage() - return -} - -// User entered a type that doesn't correspond to a script (example: `groovyw fish`) -if (!new File("config/groovy/" + args[0] + ".groovy").exists()) { - println "That type '" + args[0] + "' did not correspond to a defined utility type script. Typo? See 'groovyw usage'" - return -} - -// User didn't enter a sub-command (example: `groovyw module`) -if (args.length == 1) { - println "You need to supply a sub-command as well as a type of object to act on. See 'groovyw usage' for details" - return -} - -// Initialize the type target to load in things specific to that type -common.initialize(args[0]) -itemType = common.itemType - -// At this point we have the type script loaded, so don't need that arg anymore -String[] cleanerArgs = args.drop(1) - -excludedItems = common.excludedItems -targetDirectory = common.targetDirectory - -def recurse = false -switch (cleanerArgs[0]) { - case "recurse": - recurse = true - println "We're retrieving recursively (all the things depended on too)" -// We just fall through here to the get logic after setting a boolean -//noinspection GroovyFallthrough - case "get": - println "Preparing to get $itemType" - //println "cleanerArgs is $cleanerArgs" - if (cleanerArgs.length == 1) { - def itemString = common.getUserString("Enter what to get - separate multiple with spaces, CapiTaliZation MatterS): ") - println "User wants: $itemString" - String[] itemList = itemString.split("\\s+") - common.retrieve itemList, recurse - } else { - // Note: processCustomRemote also drops one of the array elements from cleanerArgs - cleanerArgs = common.processCustomRemote(cleanerArgs) - ArrayList selectedItems = new ArrayList() - - for (String arg : cleanerArgs) { - //println "Checking arg $arg" - if (!arg.contains('*') && !arg.contains('?')) { - println "Got into the non-wilcard option to fetch a fully specified item for $arg" - selectedItems.add(arg) - } else { - println "Got into the wildcard option to fetch something matching a pattern for $arg, may need to cache first" - common.cacheItemList() - selectedItems.addAll(common.retrieveAvalibleItemsWithWildcardMatch(arg)); - } - } - common.unCacheItemList() - - common.retrieve(((String[]) selectedItems.toArray()), recurse) - } - break - case "get-all": - println "Preparing to get all modules" - ArrayList selectedItems = new ArrayList() - common.cacheItemList() - selectedItems.addAll(common.retrieveAvalibleItemsWithWildcardMatch("*")); - common.unCacheItemList() - common.retrieve(((String[]) selectedItems.toArray()), recurse) - break - case "create": - println "We're doing a create" - String name - if (cleanerArgs.length > 2) { - println "Received more than one argument. Aborting." - break - } else if (cleanerArgs.length == 2) { - // User already submitted the name of what they want to create - name = cleanerArgs[1] - } else { - // User hasn't entered a name yet so request it - name = getUserString("Enter $itemType name: ") - } - println "User wants to create a $itemType named: $name" - common.createItem(name) - println "Created $itemType named $name" - break - - case "update": - println "We're updating $itemType" - String[] itemList - if (cleanerArgs.length == 1) { - def itemString = common.getUserString("Enter what to update - separate multiple with spaces, CapiTaliZation MatterS): ") - itemList = itemString.split("\\s+") - } else { - itemList = cleanerArgs.drop(1) - } - println "List of items to update: $itemList" - for (String item : itemList) { - common.updateItem(item) - } - break - - case "update-all": - println "We're updating every $itemType" - println "List of local entries: ${common.retrieveLocalItems()}" - def skipRecentlyUpdated = cleanerArgs.contains("-skip-recently-updated") - for (item in common.retrieveLocalItems()) { - common.updateItem(item, skipRecentlyUpdated) - } - break - - case "add-remote": - if (cleanerArgs.length == 3) { - itemName = cleanerArgs[1] - remoteName = cleanerArgs[2] - println "Adding git remote for $itemType $itemName" - common.addRemote(itemName, remoteName) - } else if (cleanerArgs.length == 4) { - itemName = cleanerArgs[1] - remoteName = cleanerArgs[2] - url = cleanerArgs[3] - println "Adding git remote for $itemType $itemName" - common.addRemote(itemName, remoteName, url) - } else { - println "Incorrect syntax" - println "Usage: 'groovyw ${itemType} add-remote [${itemType} name] [remote name]' - adds a git remote 'name' to the stated ${itemType} with default URL." - println " 'groovyw ${itemType} add-remote [${itemType} name] [remote name] [url]' - adds a git remote 'name' to the stated ${itemType} with the given URL." - } - break - - case "list-remotes": - if (cleanerArgs.length == 2) { - itemName = cleanerArgs[1] - println "Listing git remotes for $itemType $itemName" - common.listRemotes(itemName) - } else { - println "Incorrect syntax" - println "Usage: 'groovyw ${itemType} list-remotes [${itemType} name]' - lists all git remotes for that ${itemType}" - } - break - - case "list": - String[] availableItems = common.retrieveAvailableItems() - String[] localItems = common.retrieveLocalItems() - String[] downloadableItems = availableItems.minus(localItems) - - ListFormat listFormat = determineListFormat(cleanerArgs) - - if (cleanerArgs.contains("--local")) { - printListItems(localItems, listFormat) - } else { - println "The following items are available for download:" - if (availableItems.size() == 0) { - println "No items available for download." - } else if (downloadableItems.size() == 0) { - println "All items are already downloaded." - } else { - printListItems(downloadableItems, listFormat) - } - println "\nThe following items are already downloaded:" - if (localItems.size() == 0) { - println "No items downloaded." - } else { - printListItems(localItems, listFormat) - } - } - break - - case "refresh": - println "We're refreshing Gradle for every $itemType" - common.refreshGradle() - break - - case "createDependencyDotFile": - if (itemType != "module") { - println "Dependency dot file can only be created for modules" - break - } - String source = "" - if (cleanerArgs.length == 1 || cleanerArgs[1] == "*") { - // getting dependency dot file for all modules - source = "all" - } else if (cleanerArgs.length > 2) { - println "Please enter only one module or none to create a dependency dot file showing all modules" - } else if (cleanerArgs[1].contains('*') || cleanerArgs[1].contains('?')) { - println "Please enter a fully specified item instead of " + cleanerArgs[1] + " - CapiTaliZation MatterS" - } else { - // getting dependency dot file for specified module only - source = cleanerArgs[1] - } - - if (source != "") { - def dependencyFile = new File("dependency.dot") - dependencyFile.write "digraph moduleDependencies {\n" - if (source == "all") { - println "Creating the dependency dot file for all modules as \"dependencies.dot\"" - def modules = new File("modules") - modules.eachFile { - common.writeDependencyDotFileForModule(dependencyFile, it) - } - } else { - println "Creating the dependency dot file for module \"$source\" as \"dependencies.dot\"" - common.writeDependencyDotFileForModule(dependencyFile, new File("modules/$source")) - } - dependencyFile.append("}") - } - - break - - // Makes sure a workspace has one or more modules matching user input, most useful for grabbing whole "module distros" - case "init": - // TODO: Move most this code into module.groovy, leave an error here if you use it for something else - if (cleanerArgs.length == 1) { - println "[init] Checkout default module distribution" - String[] targetMods = ["CoreSampleGameplay"] - common.retrieve(targetMods, false) - } else if (cleanerArgs.length == 2) { - def targetModuleDistro = cleanerArgs[1] - println "[init] Checkout module distribution: '$targetModuleDistro'" - def targetDistroURL = "https://raw.githubusercontent.com/Terasology/Index/master/distros/" + targetModuleDistro + "/gradle.properties" - if (!common.isUrlValid(targetDistroURL)) { - println "[init] Invalid distribution name: '$targetModuleDistro'" - println "[init] See https://github.com/Terasology/Index/tree/master/distros for available distributions" - break - } - String distroContent = new URL(targetDistroURL).text - String moduleSnippet = "extraModules=" - int someIndex = distroContent.indexOf(moduleSnippet) - if (someIndex != -1) { - moduleLine = distroContent.substring((someIndex + moduleSnippet.length()), distroContent.indexOf("\n", someIndex)) - common.retrieve(moduleLine.split(","), false) - } else { - println "[init] ERROR: Distribution does not contain key: '$moduleSnippet'" - } - } else { - println "[init] Too many arguments! Usage: 'grooyw module init [distribution]'" - println "[init] See `groovyw usage` for more information." - } - - break - - default: - println "UNRECOGNIZED COMMAND '" + cleanerArgs[0] + "' - please try again or use 'groovyw usage' for help" -} - -enum ListFormat { - DEFAULT, SIMPLE, CONDENSED -} - -; - -private ListFormat determineListFormat(String[] args) { - for (listFormat in ListFormat.values()) { - if (args.contains("-${listFormat.name().toLowerCase()}-list-format")) - return listFormat; - } - return ListFormat.DEFAULT; -} - -private void printListItems(String[] items, ListFormat listFormat) { - def final DEFAULT_FORMAT_CONDENSATION_THRESHOLD = 50 - switch (listFormat) { - case ListFormat.SIMPLE: printListItemsSimple(items); break; - case ListFormat.CONDENSED: printListItemsCondensed(items); break; - default: items.size() < DEFAULT_FORMAT_CONDENSATION_THRESHOLD ? - printListItemsSimple(items) : - printListItemsCondensed(items) - } -} - -private void printListItemsSimple(String[] items) { - for (item in items.sort()) { - println "$item" - } -} - -private void printListItemsCondensed(String[] items) { - for (group in items.groupBy { it[0].toUpperCase() }) { - println "--" + group.key + ": " + group.value.sort().join(", ") - } -} - -/** - * Simply prints usage information. - */ -def printUsage() { - - println(""" - Utility script for interacting with Terasology. General syntax: - groovyw (type) (sub-command) - - 'type' may be module,meta,lib or facade. - - Available sub-commands: - - 'init' - retrieves a given module distro, or a default sample source module (modules only) - - 'get' - retrieves one or more items in source form (separate with spaces) - - 'get-all' - retrieves all modules that can be found on the configured remote locations - - 'recurse' - retrieves the given item(s) *and* their dependencies in source form (really only for modules) - - 'list' - lists items that are available for download or downloaded already. - - 'create' - creates a new item of the given type. - - 'update' - updates an item (git pulls latest from current origin, if workspace is clean - - 'update-all' - updates all local items of the given type. - - 'add-remote (item) (name)' - adds a remote (name) to (item) with the default URL. - - 'add-remote (item) (name) (URL)' - adds a remote with the given URL - - 'list-remotes (item)' - lists all remotes for (item) - - 'refresh' - replaces the Gradle build file for all items of the given type from the latest template - - 'createDependencyDotFile' - creates a dot file recursively listing dependencies of given locally available module, can be visualized with e.g. graphviz - - Available flags: - '-remote [someRemote]' to clone from an alternative remote, also adding the upstream org (like MovingBlocks) repo as 'origin' - Note: 'get' + 'recurse' only. This will override an alternativeGithubHome set via gradle.properties. - '-simple-list-format' to print one item per row for the 'list' sub-command, even for large numbers of items - '-condensed-list-format' to group items by starting letter for the 'list' sub-command (default with many items) - '-skip-recently-updated' (Only for update-all) to skip updating modules that have already been updated within 10 minutes - - Example: 'groovyw module init iota' - retrieves all the modules in the Iota module distro from GitHub. - Example: 'groovyw module get Sample -remote jellysnake' - would retrieve Sample from jellysnake's Sample repo on GitHub. - Example: 'groovyw module get-all' - would retrieve all the modules in the Terasology organisation on GitHub. - Example: 'groovyw module get Sa??l*' - would retrieve all the modules in the Terasology organisation on GitHub" - that start with \"Sa\", have any two characters after that, then an \"l\" and then end with anything else." - This should retrieve the Sample repository from the Terasology organisation on GitHub. - - *NOTE*: On UNIX platforms (MacOS and Linux), the wildcard arguments must be escaped with single quotes e.g. groovyw module get '*'. - - Example: 'groovyw module recurse GooeysQuests Sample' - would retrieve those modules plus their dependencies as source - Example: 'groovyw lib list' - would list library projects compatible with being embedded in a Terasology workspace - Example: 'groovyw module createDependencyDotFile JoshariasSurvival' - would create a dot file with JS' dependencies and all their dependencies - if locally available - - *NOTE*: Item names are case sensitive. If you add items then `gradlew idea` or similar may be needed to refresh your IDE - - If you omit further arguments beyond the sub-command you'll be prompted for details - - For advanced usage see project documentation. For instance you can provide an alternative GitHub home - A gradle.properties file (one exists under '/templates' in an engine workspace) can provide such overrides - """.stripIndent()) -} diff --git a/gradle/wrapper/groovy-wrapper.jar b/gradle/wrapper/groovy-wrapper.jar index 7fadbd5150cc523b5104c87aabab138320b42805..e2944390d1355cc6033ea8711b26448f19093e27 100644 GIT binary patch delta 2139 zcmV-h2&DI*Df=i5P)h>@3IG5I2mm~o13Z}Hk%J)vJecE=rzitFnB$SsFbzDI z<51pum5;Fp003r_4*@-Ye-vjOeuh0}GfbMW9LXZb0!gzQk}OteWrGN$K!O{pSqLsz zak4wv3`}O$+1UWrTCdit-u0kb>y6b~i^m3u5YJR=z5X13P<-CmO|qNpLTx^uyvO%? zzwh%s-q~0Gd-FDcz4(`cJ(!S@4IvkTt{{QQ5b_~Rg<#0Ipx`2ZOfgI=Xn`eGb_fNr zd4C9wjG~Og3f94uQBp92OM-P-#uWt}_<)SZ6h!dBFc15PSbbE+$3pnHf+z8mg01*O z2%i-6Pbv5`J|p941zq^8;CxQT=N0r|LJVIB;frGal2H6|2+xT5D>A++<7*Ov2Mo(_ z4@&UG;^PwhLv~Jom(Z3nEd69@dO~+jX%i+X;gp@#%yG>z#J)=OyHiF{LLy~5`9$8) za;BcRbT@H&ELFpzf?sp;Jav5oKY4ED&cpUJ!MLy9Z>p9Yld5g! z>dcd|sUFKKg+)9!ti0QS-h-5HC2-k`qgufe^CI_{jH663<_f(ydO52XT*J1QP+ylI zPa0P4gvN`19f{ow-PQc~N^d1P7F{NeYUZTvOzSyvmky>_XwuR0)4Jt~Txoz+uvnVN z8FWgmfR?Uq1C#Wl2Bt;NWMr7q6535|dLpNFRWH@GN5Z~0a;>wx3A4j*X(Cuk+AcX+ zT?k9q-aJ>#&5WoVGEg!GDozUDRD1{DYRa)MiPTc@0)D)B(JGe0o1f6!GCE!@72AS% zu^m5u<@Az@pW$T{*YR^!-?G`UlI0rH`cjfec*0uX2q}weTW~FT$Y)I_FmD#P9ZQbT;FE zv9TG}jD3-9WPj~3m71$Nrb>#hCb2U9o%i zym1A8!ouqkJu5z6Ug2%DtVkmXea(Tcnh~9pbLB;EFku z5LKwTD*$Z}w+4VNJvSR0xlhyru6=rcY=q~=>K?k0!TSC_Qk6`tl1zE;zDTZOQOoNq zD{0Ar-lmUKgIESdja!U&|2@*XuJ4Ff*R>a6Q@n4g;u*u8YI1!(fgzsaiOBe~iof7* zD&B)fCG1?5uB3A!E)e_f6(oeZC@-E2;GQf>5f-NA^~21t3ADH zuTn0NW^A};w$NmF)K&jT{pg(JH&TAZMfn?|mAc zf%x-75}y?u-@;vjv&1>jI}7PL7i;(f0|pC4-S*xZQsX>oUG@I986z^nGET^Uc!!LXI8@@W_Be-O{@=lRv@{UHlBE9*kMq}x(EQ12COtwP zzdkG3ByFOWOpY^$NT#oU7Mqj)h=2D@;)61_FdTtbuyqbwGvRH4YD6=XNZ-KrSw!a} zf!ohwi^t!w%A^VO2aOPa`@G=X&)>8_3~LEh zC;Awgeu9}G$a^Tcmy-LCC1o)fS%zQ?X~IYUmw31CgnA^tQVGNQCKyvA9f z*sJ(E{>tC*k5`lDLzH=f`SQg708mQ<1PTBE2nYZ?nB%i735*E?JecE?yApN-JecE? zG!riaJecE?W)n68JecE?pA$X}JecE9-g=dfu?GMEW|Qg@R0BMiM4S RPze{4iWCqAhY|n)008WI6$JnQ delta 2188 zcmV;72y^%QD4;0~P)h>@3IG5I2mk`GzL5=c0|KzVk%J)v0Ov{^@xSl`gm-pjTe793)X(FY z+3%kB`{tX`%m2N01HeA~OToR!%E(2aM=+sa5AqRAMqos6M#fox1tzA%U@2&Ttza5& z7lRW)K~UTXiZW(o3@C`=oQ(4dX7LWedZ&zcDcFoBWjv*z4eyT9caCY}CMnUhoz=_}nq!FXGBM~*8U+cd zwC&_mc}L5cdg`2`O;77i>ab(mGqVG>?G{{;Ml{39xSHeYPM?HOK`bS-Cr+o&Xfs;M z)U13e<2r_w@AD~!ojPQgdY_1@VT#&=rdFV{J1Z1C63r=pfgQcgGi_@*-H{OUH7wmt9Uo0su&5B!oIJg@)QFRQ{XGxaQv~CV>bR*| zbWEx?ovt!Z#>Q$aXQ!9&Y+b##{>}rGZzOQpvm@HHC+21DDH(@YXRH-Q@$mVqKJ6N| zRgm!|3G#%0Vdai!+}J?kcId9-?(`GSm zSlnFbOp&Kd!lpWfCgaO0F5xRGzAA>j_?nEbtM~@Ksp4DsHY>w-)>AZk{9r|lD!zlu z+>)q%0=TMnRD2iD5x*7kBjaay7-W1;#rN^NiXVtwwXE=uO*-~DQDQ27h#xI&xQwZY z>IIsATS3V?Q-!85t~BGvoPMI>r}&wQ66SacSImwUE!UXRmy1Qh1A}(a%*8F+jhj3Q zt{!(M_4tv8M&m54_^v`9S@A+KI~iw*Fl5`Ajd$!Sbo9u$s^aIkCW4ul(0>~{al?uq z_NtAB7_>276ao0QRQv+hW!zA)fL}`3dg}^*SMe+STDbkqQWh(!YoKVD%%Y0l;zgEO zw~9p}{1Sf0?68E$`Mp?o|6hGlLPrhx+L9GntiXB0s*+f0c&&Ne&CC{DeX6<-CX%Zg z&~hJapvt3~c7Zk;wOlS!oSt^{LP4kT&53l4qwJxwGjZGYctXL;_`|CbJtdwyuW&b7R#cjV zuKGZi&4{MU*}wc7OrFId7U4SKS9yrQ|zd2;!h>?kYfQmnG9{B-7p#K@?Y^pyl<|mA)K6XWjd(MlQpm4Oq-~_if6% zsx^rV+O?NpQ@rO_;iTbC*4aL9%Lu)AA~OD{;!pUSipTIa2|HG#{c=vFy&IZ;MXpU~ zUbE))H?{I5;~xw=ZQEyy(}Zr=vUJBgN1^~;sq|j9=O33L&0^mxwEK!R3bCG|cu>7I zrtk9By2-WNK|TR8hAZAI|76>FRr^`GaO%ooJ5SlY5Pv~P;swHSAHPzZCC;JFIY?Ky zScm-_!ya)H?&GNX0=OR!aOUZMKrf}JEd3iY6w(&M*RgIa&>0PMMT2t)WyXS?(QsE( z_ST`!Xr#P8I**32?yFErSU(4~Hz@UnuA(s(Ea8q=Fxpf?b8k2nj@}u(j_6n*+L9@u zwO5YG5(yi|0=xOW@nkHxh~u%)A~p%dO_wo5rBEzfLhLg7%d~yMP%o)}3%wDcu)R{D zwYPx^4W2^8qs1Z%SGdRXcoOg7@1=fNxKN%iafi?G4ReLx7x<*Q3Hbo^JYITp-dm8!<1^m>v4dz2k{Kv zfP?fvT+5h?)k7HY^00`1LE2tNKbP<@4k3WUkMebc9~QmU(O)i*5^*Gdf0z%vHqauzevGy74T3?)LaQR`^{j?7-d< zc9zioLT^||iJadP3(uirff1a*6VM26z)Q|O{P_$1Qe97|HlvHF=_Z^h!n}u)`zW~| zSyGmgk!1=pI7avw|1$6nj#FClRzC1zb&|9IE$8tT(t@;q3S;~adC)f_@E_doL3Mg7 zQG08%BAQ+K#5vS|3~)|%%_A{3hh%37ozdMKO6V$~`y!gVqCF*~EMF{`^SQP*ODgXep7YTd`0|KzVla>;80|KzV zlMfRw0|KzVlR* Date: Sat, 4 Jul 2020 15:09:45 -0500 Subject: [PATCH 2/9] chore: Minor cleanup, plus bring back the module file Git thought was being deleted rather than replaced --- config/groovy/BaseCommand.groovy | 2 +- config/groovy/Get.groovy | 3 ++- config/groovy/GooeyCLI.groovy | 3 +++ config/groovy/Init.groovy | 3 ++- config/groovy/ItemCommand.groovy | 2 +- config/groovy/Module.groovy | 28 ++++++++++++++++++++++++++++ 6 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 config/groovy/Module.groovy diff --git a/config/groovy/BaseCommand.groovy b/config/groovy/BaseCommand.groovy index c6c6a3f5f42..c3d5998b685 100644 --- a/config/groovy/BaseCommand.groovy +++ b/config/groovy/BaseCommand.groovy @@ -14,4 +14,4 @@ import picocli.CommandLine.Command commandListHeading = "%n@|green Commands:|@%n%n") class BaseCommand { -} \ No newline at end of file +} diff --git a/config/groovy/Get.groovy b/config/groovy/Get.groovy index 1ee3155bf1b..c9e52fa985b 100644 --- a/config/groovy/Get.groovy +++ b/config/groovy/Get.groovy @@ -3,7 +3,8 @@ import picocli.CommandLine.ParentCommand import picocli.CommandLine.Command -import picocli.CommandLine.Mixin // Actually in use, annotation below may show syntax error due to Groovy's annotation by the same name. Works fine +// Actually in use, annotation below may show syntax error due to Groovy's annotation by the same name. Works fine +import picocli.CommandLine.Mixin import picocli.CommandLine.Parameters /** diff --git a/config/groovy/GooeyCLI.groovy b/config/groovy/GooeyCLI.groovy index d41253e1d35..5df43f14718 100644 --- a/config/groovy/GooeyCLI.groovy +++ b/config/groovy/GooeyCLI.groovy @@ -1,3 +1,6 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + // Grab the Groovy extensions for PicoCLI - in IntelliJ Alt-ENTER on a `@Grab` to register contents for syntax highlighting @Grab('info.picocli:picocli-groovy:4.3.2') // TODO: Actually exists inside the Gradle Wrapper - gradle-6.4.1\lib\groovy-all-1.3-2.5.10.jar\groovyjarjarpicocli\ diff --git a/config/groovy/Init.groovy b/config/groovy/Init.groovy index f4cc3b2e311..9608059a578 100644 --- a/config/groovy/Init.groovy +++ b/config/groovy/Init.groovy @@ -3,7 +3,8 @@ import picocli.CommandLine.Command import picocli.CommandLine.Help.Ansi -import picocli.CommandLine.Mixin // Is in use, IDE may think the Groovy-supplied is in use below and mark this unused +// Is in use, IDE may think the Groovy-supplied is in use below and mark this unused +import picocli.CommandLine.Mixin import picocli.CommandLine.Parameters @Command(name = "init", description = "Initializes a workspace with some useful things") diff --git a/config/groovy/ItemCommand.groovy b/config/groovy/ItemCommand.groovy index 508ece26825..df020f83307 100644 --- a/config/groovy/ItemCommand.groovy +++ b/config/groovy/ItemCommand.groovy @@ -11,4 +11,4 @@ abstract class ItemCommand extends BaseCommand { * @return the instantiated item type manager class */ abstract ManagedItem getManager(String optionGitOrigin) -} \ No newline at end of file +} diff --git a/config/groovy/Module.groovy b/config/groovy/Module.groovy new file mode 100644 index 00000000000..2b6074453f7 --- /dev/null +++ b/config/groovy/Module.groovy @@ -0,0 +1,28 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +import picocli.CommandLine.Command +import picocli.CommandLine.HelpCommand + +// If using local groovy files the subcommands section may highlight as bad syntax in IntelliJ - that's OK +@Command(name = "module", + synopsisSubcommandLabel = "COMMAND", // Default is [COMMAND] indicating optional, but sub command here is required + subcommands = [ + HelpCommand.class, // Adds standard help options (help as a subcommand, -h, and --help) + Recurse.class, + Update.class, + Get.class], // Note that these Groovy classes *must* start with a capital letter for some reason + description = "Sub command for interacting with modules") +class Module extends ItemCommand { + @Override + ManagedItem getManager(String optionGitOrigin) { + return new ManagedModule(optionGitOrigin) + } + + // This is an example of a subcommand via method - used here so we can directly hit ManagedModule for something module-specific + // If in an external Refresh.groovy it _could_ specify ManagedModule, but it then could be added later to a non-module and break + @Command(name = "refresh", description = "Refreshes all build.gradle files in module directories") + void refresh() { + new ManagedModule().refreshGradle() + } +} From 4a9dc6447a7f2f31df04c23e6216380298bdf76e Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 5 Jul 2020 20:35:35 -0700 Subject: [PATCH 3/9] move CLI and added into package --- config/groovy/{ => org/terasology/cli}/BaseCommand.groovy | 1 + config/groovy/{ => org/terasology/cli}/Get.groovy | 2 +- config/groovy/{ => org/terasology/cli}/GitOptions.groovy | 2 +- config/groovy/{ => org/terasology/cli}/GooeyCLI.groovy | 1 + config/groovy/{ => org/terasology/cli}/Init.groovy | 2 +- config/groovy/{ => org/terasology/cli}/ItemCommand.groovy | 2 +- config/groovy/{ => org/terasology/cli}/ManagedItem.groovy | 2 +- config/groovy/{ => org/terasology/cli}/ManagedModule.groovy | 2 +- config/groovy/{ => org/terasology/cli}/Module.groovy | 1 + config/groovy/{ => org/terasology/cli}/PropHelper.groovy | 2 +- config/groovy/{ => org/terasology/cli}/Recurse.groovy | 2 +- config/groovy/{ => org/terasology/cli}/Update.groovy | 2 +- gw | 4 ++-- 13 files changed, 14 insertions(+), 11 deletions(-) rename config/groovy/{ => org/terasology/cli}/BaseCommand.groovy (94%) rename config/groovy/{ => org/terasology/cli}/Get.groovy (98%) rename config/groovy/{ => org/terasology/cli}/GitOptions.groovy (91%) rename config/groovy/{ => org/terasology/cli}/GooeyCLI.groovy (98%) rename config/groovy/{ => org/terasology/cli}/Init.groovy (97%) rename config/groovy/{ => org/terasology/cli}/ItemCommand.groovy (95%) rename config/groovy/{ => org/terasology/cli}/ManagedItem.groovy (99%) rename config/groovy/{ => org/terasology/cli}/ManagedModule.groovy (97%) rename config/groovy/{ => org/terasology/cli}/Module.groovy (98%) rename config/groovy/{ => org/terasology/cli}/PropHelper.groovy (97%) rename config/groovy/{ => org/terasology/cli}/Recurse.groovy (97%) rename config/groovy/{ => org/terasology/cli}/Update.groovy (96%) mode change 100644 => 100755 gw diff --git a/config/groovy/BaseCommand.groovy b/config/groovy/org/terasology/cli/BaseCommand.groovy similarity index 94% rename from config/groovy/BaseCommand.groovy rename to config/groovy/org/terasology/cli/BaseCommand.groovy index c3d5998b685..ec3e9d3db4f 100644 --- a/config/groovy/BaseCommand.groovy +++ b/config/groovy/org/terasology/cli/BaseCommand.groovy @@ -1,5 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 +package org.terasology.cli; import picocli.CommandLine.Command diff --git a/config/groovy/Get.groovy b/config/groovy/org/terasology/cli/Get.groovy similarity index 98% rename from config/groovy/Get.groovy rename to config/groovy/org/terasology/cli/Get.groovy index c9e52fa985b..cb24dca0fff 100644 --- a/config/groovy/Get.groovy +++ b/config/groovy/org/terasology/cli/Get.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 - +package org.terasology.cli; import picocli.CommandLine.ParentCommand import picocli.CommandLine.Command // Actually in use, annotation below may show syntax error due to Groovy's annotation by the same name. Works fine diff --git a/config/groovy/GitOptions.groovy b/config/groovy/org/terasology/cli/GitOptions.groovy similarity index 91% rename from config/groovy/GitOptions.groovy rename to config/groovy/org/terasology/cli/GitOptions.groovy index 66974259ad8..032005f1ce7 100644 --- a/config/groovy/GitOptions.groovy +++ b/config/groovy/org/terasology/cli/GitOptions.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 - +package org.terasology.cli; import picocli.CommandLine.Option /** diff --git a/config/groovy/GooeyCLI.groovy b/config/groovy/org/terasology/cli/GooeyCLI.groovy similarity index 98% rename from config/groovy/GooeyCLI.groovy rename to config/groovy/org/terasology/cli/GooeyCLI.groovy index 5df43f14718..217c61739f7 100644 --- a/config/groovy/GooeyCLI.groovy +++ b/config/groovy/org/terasology/cli/GooeyCLI.groovy @@ -1,5 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 +package org.terasology.cli // Grab the Groovy extensions for PicoCLI - in IntelliJ Alt-ENTER on a `@Grab` to register contents for syntax highlighting @Grab('info.picocli:picocli-groovy:4.3.2') diff --git a/config/groovy/Init.groovy b/config/groovy/org/terasology/cli/Init.groovy similarity index 97% rename from config/groovy/Init.groovy rename to config/groovy/org/terasology/cli/Init.groovy index 9608059a578..64e4d818ebc 100644 --- a/config/groovy/Init.groovy +++ b/config/groovy/org/terasology/cli/Init.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 - +package org.terasology.cli; import picocli.CommandLine.Command import picocli.CommandLine.Help.Ansi // Is in use, IDE may think the Groovy-supplied is in use below and mark this unused diff --git a/config/groovy/ItemCommand.groovy b/config/groovy/org/terasology/cli/ItemCommand.groovy similarity index 95% rename from config/groovy/ItemCommand.groovy rename to config/groovy/org/terasology/cli/ItemCommand.groovy index df020f83307..b59b065c706 100644 --- a/config/groovy/ItemCommand.groovy +++ b/config/groovy/org/terasology/cli/ItemCommand.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 - +package org.terasology.cli; /** * Simple command type class that indicates the command deals with "items" - nested Git roots representing application elements */ diff --git a/config/groovy/ManagedItem.groovy b/config/groovy/org/terasology/cli/ManagedItem.groovy similarity index 99% rename from config/groovy/ManagedItem.groovy rename to config/groovy/org/terasology/cli/ManagedItem.groovy index 63e9f1a532d..f18b4903db2 100644 --- a/config/groovy/ManagedItem.groovy +++ b/config/groovy/org/terasology/cli/ManagedItem.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 - +package org.terasology.cli; @GrabResolver(name = 'jcenter', root = 'http://jcenter.bintray.com/') @Grab(group = 'org.ajoberstar', module = 'grgit', version = '1.9.3') import org.ajoberstar.grgit.Grgit diff --git a/config/groovy/ManagedModule.groovy b/config/groovy/org/terasology/cli/ManagedModule.groovy similarity index 97% rename from config/groovy/ManagedModule.groovy rename to config/groovy/org/terasology/cli/ManagedModule.groovy index 28ae39ec26a..96a91d303c4 100644 --- a/config/groovy/ManagedModule.groovy +++ b/config/groovy/org/terasology/cli/ManagedModule.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 - +package org.terasology.cli; class ManagedModule extends ManagedItem { ManagedModule() { super() diff --git a/config/groovy/Module.groovy b/config/groovy/org/terasology/cli/Module.groovy similarity index 98% rename from config/groovy/Module.groovy rename to config/groovy/org/terasology/cli/Module.groovy index 2b6074453f7..eb94dd5ea69 100644 --- a/config/groovy/Module.groovy +++ b/config/groovy/org/terasology/cli/Module.groovy @@ -1,5 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 +package org.terasology.cli; import picocli.CommandLine.Command import picocli.CommandLine.HelpCommand diff --git a/config/groovy/PropHelper.groovy b/config/groovy/org/terasology/cli/PropHelper.groovy similarity index 97% rename from config/groovy/PropHelper.groovy rename to config/groovy/org/terasology/cli/PropHelper.groovy index 4e81417c372..d9e9673f91e 100644 --- a/config/groovy/PropHelper.groovy +++ b/config/groovy/org/terasology/cli/PropHelper.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 - +package org.terasology.cli; /** * Convenience class for pulling properties out of a 'gradle.properties' if present, for various overrides * // TODO: YAML variant that can be added for more complex use cases? diff --git a/config/groovy/Recurse.groovy b/config/groovy/org/terasology/cli/Recurse.groovy similarity index 97% rename from config/groovy/Recurse.groovy rename to config/groovy/org/terasology/cli/Recurse.groovy index 8e74d2da0b1..1ef07fcef8d 100644 --- a/config/groovy/Recurse.groovy +++ b/config/groovy/org/terasology/cli/Recurse.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 - +package org.terasology.cli; import picocli.CommandLine.ParentCommand import picocli.CommandLine.Command import picocli.CommandLine.Mixin diff --git a/config/groovy/Update.groovy b/config/groovy/org/terasology/cli/Update.groovy similarity index 96% rename from config/groovy/Update.groovy rename to config/groovy/org/terasology/cli/Update.groovy index 678ad1bd23e..0882556c0d0 100644 --- a/config/groovy/Update.groovy +++ b/config/groovy/org/terasology/cli/Update.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 - +package org.terasology.cli; import picocli.CommandLine.ParentCommand import picocli.CommandLine.Command import picocli.CommandLine.Mixin diff --git a/gw b/gw old mode 100644 new mode 100755 index a6aeccf8413..64d2d76c8c7 --- a/gw +++ b/gw @@ -130,7 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -180,6 +180,6 @@ save () { APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GroovyWrapperMain config/groovy/GooeyCLI.groovy "$APP_ARGS" +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GroovyWrapperMain config/groovy/org/terasology/cli/GooeyCLI.groovy "$APP_ARGS" exec "$JAVACMD" "$@" From d9e2e189c419239a7766420345baf1662bab9dd1 Mon Sep 17 00:00:00 2001 From: Cervator Date: Sun, 5 Jul 2020 22:59:08 -0500 Subject: [PATCH 4/9] chore: fix path on Windows, avoid some warning about logging itself --- config/groovy/org/terasology/cli/GooeyCLI.groovy | 3 +++ gw.bat | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/config/groovy/org/terasology/cli/GooeyCLI.groovy b/config/groovy/org/terasology/cli/GooeyCLI.groovy index 217c61739f7..118f009a4ac 100644 --- a/config/groovy/org/terasology/cli/GooeyCLI.groovy +++ b/config/groovy/org/terasology/cli/GooeyCLI.groovy @@ -2,6 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.cli +// Avoid some ugly warnings about logging itself - see http://www.slf4j.org/codes.html#StaticLoggerBinder +@Grab(group = 'org.slf4j', module = 'slf4j-nop', version = '1.6.1') + // Grab the Groovy extensions for PicoCLI - in IntelliJ Alt-ENTER on a `@Grab` to register contents for syntax highlighting @Grab('info.picocli:picocli-groovy:4.3.2') // TODO: Actually exists inside the Gradle Wrapper - gradle-6.4.1\lib\groovy-all-1.3-2.5.10.jar\groovyjarjarpicocli\ diff --git a/gw.bat b/gw.bat index 31b36676fef..c2a63b7bd46 100644 --- a/gw.bat +++ b/gw.bat @@ -112,7 +112,7 @@ set CLASSPATH=%APP_HOME%gradle\wrapper\gradle-wrapper.jar;%APP_HOME%gradle\wrapp @rem Execute Groovy via the Gradle Wrapper -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -cp "%CLASSPATH%" org.gradle.wrapper.GroovyWrapperMain config/groovy/GooeyCLI.groovy %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -cp "%CLASSPATH%" org.gradle.wrapper.GroovyWrapperMain config/groovy/org/terasology/cli/GooeyCLI.groovy %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell From fc46d278bf36e4bd7c1a3c61b629082b320ccf91 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 6 Jul 2020 12:29:17 -0700 Subject: [PATCH 5/9] add sourceset for cli config --- config/cli/build.gradle | 25 +++++++++++++++++++ .../org/terasology/cli/BaseCommand.groovy | 2 +- .../groovy/org/terasology/cli/Get.groovy | 2 +- .../org/terasology/cli/GitOptions.groovy | 2 +- .../groovy/org/terasology/cli/GooeyCLI.groovy | 12 ++++----- .../groovy/org/terasology/cli/Init.groovy | 2 +- .../org/terasology/cli/ItemCommand.groovy | 2 +- .../org/terasology/cli/ManagedItem.groovy | 4 +-- .../org/terasology/cli/ManagedModule.groovy | 2 +- .../groovy/org/terasology/cli/Module.groovy | 4 +-- .../org/terasology/cli/PropHelper.groovy | 2 +- .../groovy/org/terasology/cli/Recurse.groovy | 2 +- .../groovy/org/terasology/cli/Update.groovy | 2 +- gw | 4 +-- gw.bat | 5 ++-- settings.gradle | 2 +- 16 files changed, 49 insertions(+), 25 deletions(-) create mode 100644 config/cli/build.gradle rename config/{ => cli}/groovy/org/terasology/cli/BaseCommand.groovy (94%) rename config/{ => cli}/groovy/org/terasology/cli/Get.groovy (98%) rename config/{ => cli}/groovy/org/terasology/cli/GitOptions.groovy (91%) rename config/{ => cli}/groovy/org/terasology/cli/GooeyCLI.groovy (77%) rename config/{ => cli}/groovy/org/terasology/cli/Init.groovy (97%) rename config/{ => cli}/groovy/org/terasology/cli/ItemCommand.groovy (95%) rename config/{ => cli}/groovy/org/terasology/cli/ManagedItem.groovy (99%) rename config/{ => cli}/groovy/org/terasology/cli/ManagedModule.groovy (97%) rename config/{ => cli}/groovy/org/terasology/cli/Module.groovy (89%) rename config/{ => cli}/groovy/org/terasology/cli/PropHelper.groovy (97%) rename config/{ => cli}/groovy/org/terasology/cli/Recurse.groovy (97%) rename config/{ => cli}/groovy/org/terasology/cli/Update.groovy (96%) diff --git a/config/cli/build.gradle b/config/cli/build.gradle new file mode 100644 index 00000000000..36890fdfeb8 --- /dev/null +++ b/config/cli/build.gradle @@ -0,0 +1,25 @@ + + +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 +apply plugin: 'groovy' + + +group 'org.terasology' + +repositories { + mavenCentral() +} + +dependencies { + compile 'org.codehaus.groovy:groovy-all:2.5.4' + compile 'org.apache.ivy:ivy:2.4.0' +} + +sourceSets { + main { + groovy { + srcDir 'groovy' + } + } +} diff --git a/config/groovy/org/terasology/cli/BaseCommand.groovy b/config/cli/groovy/org/terasology/cli/BaseCommand.groovy similarity index 94% rename from config/groovy/org/terasology/cli/BaseCommand.groovy rename to config/cli/groovy/org/terasology/cli/BaseCommand.groovy index ec3e9d3db4f..b11375cfb59 100644 --- a/config/groovy/org/terasology/cli/BaseCommand.groovy +++ b/config/cli/groovy/org/terasology/cli/BaseCommand.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli; +package org.terasology.cli import picocli.CommandLine.Command diff --git a/config/groovy/org/terasology/cli/Get.groovy b/config/cli/groovy/org/terasology/cli/Get.groovy similarity index 98% rename from config/groovy/org/terasology/cli/Get.groovy rename to config/cli/groovy/org/terasology/cli/Get.groovy index cb24dca0fff..4d13d37278c 100644 --- a/config/groovy/org/terasology/cli/Get.groovy +++ b/config/cli/groovy/org/terasology/cli/Get.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli; +package org.terasology.cli import picocli.CommandLine.ParentCommand import picocli.CommandLine.Command // Actually in use, annotation below may show syntax error due to Groovy's annotation by the same name. Works fine diff --git a/config/groovy/org/terasology/cli/GitOptions.groovy b/config/cli/groovy/org/terasology/cli/GitOptions.groovy similarity index 91% rename from config/groovy/org/terasology/cli/GitOptions.groovy rename to config/cli/groovy/org/terasology/cli/GitOptions.groovy index 032005f1ce7..6dd4bce7747 100644 --- a/config/groovy/org/terasology/cli/GitOptions.groovy +++ b/config/cli/groovy/org/terasology/cli/GitOptions.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli; +package org.terasology.cli import picocli.CommandLine.Option /** diff --git a/config/groovy/org/terasology/cli/GooeyCLI.groovy b/config/cli/groovy/org/terasology/cli/GooeyCLI.groovy similarity index 77% rename from config/groovy/org/terasology/cli/GooeyCLI.groovy rename to config/cli/groovy/org/terasology/cli/GooeyCLI.groovy index 118f009a4ac..508063c58a1 100644 --- a/config/groovy/org/terasology/cli/GooeyCLI.groovy +++ b/config/cli/groovy/org/terasology/cli/GooeyCLI.groovy @@ -22,12 +22,12 @@ import picocli.CommandLine.HelpCommand // If using local groovy files the subcommands section may highlight as bad syntax in IntelliJ - that's OK @Command(name = "gw", - synopsisSubcommandLabel = "COMMAND", // Default is [COMMAND] indicating optional, but sub command here is required - subcommands = [ - HelpCommand.class, // Adds standard help options (help as a subcommand, -h, and --help) - Module.class, - Init.class], // Note that these Groovy classes *must* start with a capital letter for some reason - description = "Utility system for interacting with a Terasology developer workspace") +// synopsisSubcommandLabel = "COMMAND", // Default is [COMMAND] indicating optional, but sub command here is required + subcommands = [ + HelpCommand.class, // Adds standard help options (help as a subcommand, -h, and --help) + Module.class, + Init.class], // Note that these Groovy classes *must* start with a capital letter for some reason + description = "Utility system for interacting with a Terasology developer workspace") class GooeyCLI extends BaseCommand { static void main(String[] args) { AnsiConsole.systemInstall() // enable colors on Windows - TODO: Test on not-so-Windows systems, should those not run this? diff --git a/config/groovy/org/terasology/cli/Init.groovy b/config/cli/groovy/org/terasology/cli/Init.groovy similarity index 97% rename from config/groovy/org/terasology/cli/Init.groovy rename to config/cli/groovy/org/terasology/cli/Init.groovy index 64e4d818ebc..e216b185276 100644 --- a/config/groovy/org/terasology/cli/Init.groovy +++ b/config/cli/groovy/org/terasology/cli/Init.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli; +package org.terasology.cli import picocli.CommandLine.Command import picocli.CommandLine.Help.Ansi // Is in use, IDE may think the Groovy-supplied is in use below and mark this unused diff --git a/config/groovy/org/terasology/cli/ItemCommand.groovy b/config/cli/groovy/org/terasology/cli/ItemCommand.groovy similarity index 95% rename from config/groovy/org/terasology/cli/ItemCommand.groovy rename to config/cli/groovy/org/terasology/cli/ItemCommand.groovy index b59b065c706..d7e802c6613 100644 --- a/config/groovy/org/terasology/cli/ItemCommand.groovy +++ b/config/cli/groovy/org/terasology/cli/ItemCommand.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli; +package org.terasology.cli /** * Simple command type class that indicates the command deals with "items" - nested Git roots representing application elements */ diff --git a/config/groovy/org/terasology/cli/ManagedItem.groovy b/config/cli/groovy/org/terasology/cli/ManagedItem.groovy similarity index 99% rename from config/groovy/org/terasology/cli/ManagedItem.groovy rename to config/cli/groovy/org/terasology/cli/ManagedItem.groovy index f18b4903db2..0f7120e4d42 100644 --- a/config/groovy/org/terasology/cli/ManagedItem.groovy +++ b/config/cli/groovy/org/terasology/cli/ManagedItem.groovy @@ -1,9 +1,9 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli; +package org.terasology.cli @GrabResolver(name = 'jcenter', root = 'http://jcenter.bintray.com/') @Grab(group = 'org.ajoberstar', module = 'grgit', version = '1.9.3') -import org.ajoberstar.grgit.Grgit + /** * Utility class for dealing with items managed in a developer workspace. diff --git a/config/groovy/org/terasology/cli/ManagedModule.groovy b/config/cli/groovy/org/terasology/cli/ManagedModule.groovy similarity index 97% rename from config/groovy/org/terasology/cli/ManagedModule.groovy rename to config/cli/groovy/org/terasology/cli/ManagedModule.groovy index 96a91d303c4..bf5b35091b9 100644 --- a/config/groovy/org/terasology/cli/ManagedModule.groovy +++ b/config/cli/groovy/org/terasology/cli/ManagedModule.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli; +package org.terasology.cli class ManagedModule extends ManagedItem { ManagedModule() { super() diff --git a/config/groovy/org/terasology/cli/Module.groovy b/config/cli/groovy/org/terasology/cli/Module.groovy similarity index 89% rename from config/groovy/org/terasology/cli/Module.groovy rename to config/cli/groovy/org/terasology/cli/Module.groovy index eb94dd5ea69..06a81e8b8f7 100644 --- a/config/groovy/org/terasology/cli/Module.groovy +++ b/config/cli/groovy/org/terasology/cli/Module.groovy @@ -1,13 +1,13 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli; +package org.terasology.cli import picocli.CommandLine.Command import picocli.CommandLine.HelpCommand // If using local groovy files the subcommands section may highlight as bad syntax in IntelliJ - that's OK @Command(name = "module", - synopsisSubcommandLabel = "COMMAND", // Default is [COMMAND] indicating optional, but sub command here is required +// synopsisSubcommandLabel = "COMMAND", // Default is [COMMAND] indicating optional, but sub command here is required subcommands = [ HelpCommand.class, // Adds standard help options (help as a subcommand, -h, and --help) Recurse.class, diff --git a/config/groovy/org/terasology/cli/PropHelper.groovy b/config/cli/groovy/org/terasology/cli/PropHelper.groovy similarity index 97% rename from config/groovy/org/terasology/cli/PropHelper.groovy rename to config/cli/groovy/org/terasology/cli/PropHelper.groovy index d9e9673f91e..a36da4df2c7 100644 --- a/config/groovy/org/terasology/cli/PropHelper.groovy +++ b/config/cli/groovy/org/terasology/cli/PropHelper.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli; +package org.terasology.cli /** * Convenience class for pulling properties out of a 'gradle.properties' if present, for various overrides * // TODO: YAML variant that can be added for more complex use cases? diff --git a/config/groovy/org/terasology/cli/Recurse.groovy b/config/cli/groovy/org/terasology/cli/Recurse.groovy similarity index 97% rename from config/groovy/org/terasology/cli/Recurse.groovy rename to config/cli/groovy/org/terasology/cli/Recurse.groovy index 1ef07fcef8d..cb54cef4dab 100644 --- a/config/groovy/org/terasology/cli/Recurse.groovy +++ b/config/cli/groovy/org/terasology/cli/Recurse.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli; +package org.terasology.cli import picocli.CommandLine.ParentCommand import picocli.CommandLine.Command import picocli.CommandLine.Mixin diff --git a/config/groovy/org/terasology/cli/Update.groovy b/config/cli/groovy/org/terasology/cli/Update.groovy similarity index 96% rename from config/groovy/org/terasology/cli/Update.groovy rename to config/cli/groovy/org/terasology/cli/Update.groovy index 0882556c0d0..1dd6dca1b7a 100644 --- a/config/groovy/org/terasology/cli/Update.groovy +++ b/config/cli/groovy/org/terasology/cli/Update.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli; +package org.terasology.cli import picocli.CommandLine.ParentCommand import picocli.CommandLine.Command import picocli.CommandLine.Mixin diff --git a/gw b/gw index 64d2d76c8c7..fa46702a032 100755 --- a/gw +++ b/gw @@ -80,7 +80,7 @@ case "`uname`" in ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar:$APP_HOME/gradle/wrapper/groovy-wrapper.jar:$APP_HOME/config/groovy/ +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar:$APP_HOME/gradle/wrapper/groovy-wrapper.jar:$APP_HOME/config/cli/groovy # Determine the Java command to use to start the JVM. @@ -180,6 +180,6 @@ save () { APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GroovyWrapperMain config/groovy/org/terasology/cli/GooeyCLI.groovy "$APP_ARGS" +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GroovyWrapperMain config/cli/groovy/org/terasology/cli/GooeyCLI.groovy "$APP_ARGS" exec "$JAVACMD" "$@" diff --git a/gw.bat b/gw.bat index c2a63b7bd46..17717679851 100644 --- a/gw.bat +++ b/gw.bat @@ -107,12 +107,11 @@ SET CMD_LINE_ARGS=%CMD_LINE_ARGS:~1% :execute @rem Setup the command line - -set CLASSPATH=%APP_HOME%gradle\wrapper\gradle-wrapper.jar;%APP_HOME%gradle\wrapper\groovy-wrapper.jar;%APP_HOME%config\groovy\; +set CLASSPATH=%APP_HOME%gradle\wrapper\gradle-wrapper.jar;%APP_HOME%gradle\wrapper\groovy-wrapper.jar;%APP_HOME%config\cli\groovy\; @rem Execute Groovy via the Gradle Wrapper -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -cp "%CLASSPATH%" org.gradle.wrapper.GroovyWrapperMain config/groovy/org/terasology/cli/GooeyCLI.groovy %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -cp "%CLASSPATH%" org.gradle.wrapper.GroovyWrapperMain config/cli/groovy/org/terasology/cli/GooeyCLI.groovy %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell diff --git a/settings.gradle b/settings.gradle index 08786bbb491..321bd43ac24 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,7 +2,7 @@ import groovy.io.FileType rootProject.name = 'Terasology' -include 'engine', 'engine-tests', 'facades', 'metas', 'libs', 'modules' +include 'engine', 'engine-tests', 'facades', 'metas', 'libs', 'modules', ':config:cli' // Handy little snippet found online that'll "fake" having nested settings.gradle files under /modules, /libs, etc rootDir.eachDir { possibleSubprojectDir -> From c5ed6d3866d346a9ee58dc32a16e3ba5d1d12d1d Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 6 Jul 2020 13:14:35 -0700 Subject: [PATCH 6/9] correct synopsisSubcommandLabel --- .idea/discord.xml | 6 ++++++ config/cli/build.gradle | 5 +++-- config/cli/groovy/org/terasology/cli/GooeyCLI.groovy | 2 +- config/cli/groovy/org/terasology/cli/Module.groovy | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 .idea/discord.xml diff --git a/.idea/discord.xml b/.idea/discord.xml new file mode 100644 index 00000000000..90797455974 --- /dev/null +++ b/.idea/discord.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/config/cli/build.gradle b/config/cli/build.gradle index 36890fdfeb8..54bc9deac75 100644 --- a/config/cli/build.gradle +++ b/config/cli/build.gradle @@ -12,8 +12,9 @@ repositories { } dependencies { - compile 'org.codehaus.groovy:groovy-all:2.5.4' - compile 'org.apache.ivy:ivy:2.4.0' + compile 'org.codehaus.groovy:groovy-all:3.0.4' + compile 'info.picocli:picocli-groovy:4.3.2' + compile 'org.fusesource.jansi:jansi:1.18' } sourceSets { diff --git a/config/cli/groovy/org/terasology/cli/GooeyCLI.groovy b/config/cli/groovy/org/terasology/cli/GooeyCLI.groovy index 508063c58a1..89b44e78892 100644 --- a/config/cli/groovy/org/terasology/cli/GooeyCLI.groovy +++ b/config/cli/groovy/org/terasology/cli/GooeyCLI.groovy @@ -22,7 +22,7 @@ import picocli.CommandLine.HelpCommand // If using local groovy files the subcommands section may highlight as bad syntax in IntelliJ - that's OK @Command(name = "gw", -// synopsisSubcommandLabel = "COMMAND", // Default is [COMMAND] indicating optional, but sub command here is required + synopsisSubcommandLabel = "COMMAND", // Default is [COMMAND] indicating optional, but sub command here is required subcommands = [ HelpCommand.class, // Adds standard help options (help as a subcommand, -h, and --help) Module.class, diff --git a/config/cli/groovy/org/terasology/cli/Module.groovy b/config/cli/groovy/org/terasology/cli/Module.groovy index 06a81e8b8f7..b161ee99aa8 100644 --- a/config/cli/groovy/org/terasology/cli/Module.groovy +++ b/config/cli/groovy/org/terasology/cli/Module.groovy @@ -7,7 +7,7 @@ import picocli.CommandLine.HelpCommand // If using local groovy files the subcommands section may highlight as bad syntax in IntelliJ - that's OK @Command(name = "module", -// synopsisSubcommandLabel = "COMMAND", // Default is [COMMAND] indicating optional, but sub command here is required + synopsisSubcommandLabel = "COMMAND", // Default is [COMMAND] indicating optional, but sub command here is required subcommands = [ HelpCommand.class, // Adds standard help options (help as a subcommand, -h, and --help) Recurse.class, From 53662ac93738a71c843c4622bddca5004eb33b2d Mon Sep 17 00:00:00 2001 From: Cervator Date: Thu, 9 Jul 2020 23:23:05 -0500 Subject: [PATCH 7/9] chore: adjust the Gradle-based GooeyCLI setup * Moves it to a maybe more sensible place in the gradle directory where the wrapper lives, this seems kinda related * Standardizes the source path so we don't need to explicitly configure it * Drops the Groovy dependency (in Gradle) down to match what's currently in the Gradle Wrapper (although it would still get fetched and used separately for any sort of GooeyCLI *build* process) --- config/cli/build.gradle | 26 -------------- gradle/gooeycli/build.gradle | 35 +++++++++++++++++++ .../org/terasology/cli/BaseCommand.groovy | 0 .../groovy/org/terasology/cli/Get.groovy | 0 .../org/terasology/cli/GitOptions.groovy | 0 .../groovy/org/terasology/cli/GooeyCLI.groovy | 0 .../groovy/org/terasology/cli/Init.groovy | 0 .../org/terasology/cli/ItemCommand.groovy | 0 .../org/terasology/cli/ManagedItem.groovy | 2 +- .../org/terasology/cli/ManagedModule.groovy | 0 .../groovy/org/terasology/cli/Module.groovy | 0 .../org/terasology/cli/PropHelper.groovy | 0 .../groovy/org/terasology/cli/Recurse.groovy | 0 .../groovy/org/terasology/cli/Update.groovy | 0 gw | 5 ++- gw.bat | 4 +-- settings.gradle | 2 +- 17 files changed, 41 insertions(+), 33 deletions(-) delete mode 100644 config/cli/build.gradle create mode 100644 gradle/gooeycli/build.gradle rename {config/cli => gradle/gooeycli/src/main}/groovy/org/terasology/cli/BaseCommand.groovy (100%) rename {config/cli => gradle/gooeycli/src/main}/groovy/org/terasology/cli/Get.groovy (100%) rename {config/cli => gradle/gooeycli/src/main}/groovy/org/terasology/cli/GitOptions.groovy (100%) rename {config/cli => gradle/gooeycli/src/main}/groovy/org/terasology/cli/GooeyCLI.groovy (100%) rename {config/cli => gradle/gooeycli/src/main}/groovy/org/terasology/cli/Init.groovy (100%) rename {config/cli => gradle/gooeycli/src/main}/groovy/org/terasology/cli/ItemCommand.groovy (100%) rename {config/cli => gradle/gooeycli/src/main}/groovy/org/terasology/cli/ManagedItem.groovy (99%) rename {config/cli => gradle/gooeycli/src/main}/groovy/org/terasology/cli/ManagedModule.groovy (100%) rename {config/cli => gradle/gooeycli/src/main}/groovy/org/terasology/cli/Module.groovy (100%) rename {config/cli => gradle/gooeycli/src/main}/groovy/org/terasology/cli/PropHelper.groovy (100%) rename {config/cli => gradle/gooeycli/src/main}/groovy/org/terasology/cli/Recurse.groovy (100%) rename {config/cli => gradle/gooeycli/src/main}/groovy/org/terasology/cli/Update.groovy (100%) diff --git a/config/cli/build.gradle b/config/cli/build.gradle deleted file mode 100644 index 54bc9deac75..00000000000 --- a/config/cli/build.gradle +++ /dev/null @@ -1,26 +0,0 @@ - - -// Copyright 2020 The Terasology Foundation -// SPDX-License-Identifier: Apache-2.0 -apply plugin: 'groovy' - - -group 'org.terasology' - -repositories { - mavenCentral() -} - -dependencies { - compile 'org.codehaus.groovy:groovy-all:3.0.4' - compile 'info.picocli:picocli-groovy:4.3.2' - compile 'org.fusesource.jansi:jansi:1.18' -} - -sourceSets { - main { - groovy { - srcDir 'groovy' - } - } -} diff --git a/gradle/gooeycli/build.gradle b/gradle/gooeycli/build.gradle new file mode 100644 index 00000000000..483f952531a --- /dev/null +++ b/gradle/gooeycli/build.gradle @@ -0,0 +1,35 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 +apply plugin: 'groovy' + +group 'org.terasology.cli' + +repositories { + jcenter() +} + +dependencies { + compile 'org.codehaus.groovy:groovy-all:2.5.10' + compile 'info.picocli:picocli-groovy:4.3.2' + compile 'org.fusesource.jansi:jansi:1.18' + compile 'org.ajoberstar:grgit:1.9.3' +} + +// Ugly hack to allow Gradle and @Grab to get along. See https://github.com/gradle/gradle/issues/1031 - not sure if worth it? +compileGroovy { + // Create temp file. + File temp = File.createTempFile("config", ".groovy"); + + // Delete temp file when program exits. + temp.deleteOnExit(); + + // Write to temp file + BufferedWriter out = new BufferedWriter(new FileWriter(temp)); + out.write("""\ + withConfig(configuration) { + configuration.setDisabledGlobalASTTransformations(['groovy.grape.GrabAnnotationTransformation'] as Set) + } + """.stripIndent()); + out.close(); + groovyOptions.configurationScript = temp +} diff --git a/config/cli/groovy/org/terasology/cli/BaseCommand.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/BaseCommand.groovy similarity index 100% rename from config/cli/groovy/org/terasology/cli/BaseCommand.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/BaseCommand.groovy diff --git a/config/cli/groovy/org/terasology/cli/Get.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/Get.groovy similarity index 100% rename from config/cli/groovy/org/terasology/cli/Get.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/Get.groovy diff --git a/config/cli/groovy/org/terasology/cli/GitOptions.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/GitOptions.groovy similarity index 100% rename from config/cli/groovy/org/terasology/cli/GitOptions.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/GitOptions.groovy diff --git a/config/cli/groovy/org/terasology/cli/GooeyCLI.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/GooeyCLI.groovy similarity index 100% rename from config/cli/groovy/org/terasology/cli/GooeyCLI.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/GooeyCLI.groovy diff --git a/config/cli/groovy/org/terasology/cli/Init.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/Init.groovy similarity index 100% rename from config/cli/groovy/org/terasology/cli/Init.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/Init.groovy diff --git a/config/cli/groovy/org/terasology/cli/ItemCommand.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/ItemCommand.groovy similarity index 100% rename from config/cli/groovy/org/terasology/cli/ItemCommand.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/ItemCommand.groovy diff --git a/config/cli/groovy/org/terasology/cli/ManagedItem.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/ManagedItem.groovy similarity index 99% rename from config/cli/groovy/org/terasology/cli/ManagedItem.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/ManagedItem.groovy index 0f7120e4d42..132a6eb2eb7 100644 --- a/config/cli/groovy/org/terasology/cli/ManagedItem.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/ManagedItem.groovy @@ -3,7 +3,7 @@ package org.terasology.cli @GrabResolver(name = 'jcenter', root = 'http://jcenter.bintray.com/') @Grab(group = 'org.ajoberstar', module = 'grgit', version = '1.9.3') - +import org.ajoberstar.grgit.Grgit /** * Utility class for dealing with items managed in a developer workspace. diff --git a/config/cli/groovy/org/terasology/cli/ManagedModule.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/ManagedModule.groovy similarity index 100% rename from config/cli/groovy/org/terasology/cli/ManagedModule.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/ManagedModule.groovy diff --git a/config/cli/groovy/org/terasology/cli/Module.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/Module.groovy similarity index 100% rename from config/cli/groovy/org/terasology/cli/Module.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/Module.groovy diff --git a/config/cli/groovy/org/terasology/cli/PropHelper.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/PropHelper.groovy similarity index 100% rename from config/cli/groovy/org/terasology/cli/PropHelper.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/PropHelper.groovy diff --git a/config/cli/groovy/org/terasology/cli/Recurse.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/Recurse.groovy similarity index 100% rename from config/cli/groovy/org/terasology/cli/Recurse.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/Recurse.groovy diff --git a/config/cli/groovy/org/terasology/cli/Update.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/Update.groovy similarity index 100% rename from config/cli/groovy/org/terasology/cli/Update.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/Update.groovy diff --git a/gw b/gw index fa46702a032..9c7ccb1a995 100755 --- a/gw +++ b/gw @@ -80,8 +80,7 @@ case "`uname`" in ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar:$APP_HOME/gradle/wrapper/groovy-wrapper.jar:$APP_HOME/config/cli/groovy - +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar:$APP_HOME/gradle/wrapper/groovy-wrapper.jar:$APP_HOME/gradle/gooeycli/src/main/groovy # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then @@ -180,6 +179,6 @@ save () { APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GroovyWrapperMain config/cli/groovy/org/terasology/cli/GooeyCLI.groovy "$APP_ARGS" +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GroovyWrapperMain gradle/gooeycli/src/main/groovy/org/terasology/cli/GooeyCLI.groovy "$APP_ARGS" exec "$JAVACMD" "$@" diff --git a/gw.bat b/gw.bat index 17717679851..ff37fb11e55 100644 --- a/gw.bat +++ b/gw.bat @@ -107,11 +107,11 @@ SET CMD_LINE_ARGS=%CMD_LINE_ARGS:~1% :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%gradle\wrapper\gradle-wrapper.jar;%APP_HOME%gradle\wrapper\groovy-wrapper.jar;%APP_HOME%config\cli\groovy\; +set CLASSPATH=%APP_HOME%gradle\wrapper\gradle-wrapper.jar;%APP_HOME%gradle\wrapper\groovy-wrapper.jar;%APP_HOME%gradle\gooeycli\src\main\groovy; @rem Execute Groovy via the Gradle Wrapper -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -cp "%CLASSPATH%" org.gradle.wrapper.GroovyWrapperMain config/cli/groovy/org/terasology/cli/GooeyCLI.groovy %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -cp "%CLASSPATH%" org.gradle.wrapper.GroovyWrapperMain gradle/gooeycli/src/main/groovy/org/terasology/cli/GooeyCLI.groovy %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell diff --git a/settings.gradle b/settings.gradle index 321bd43ac24..1ab64317563 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,7 +2,7 @@ import groovy.io.FileType rootProject.name = 'Terasology' -include 'engine', 'engine-tests', 'facades', 'metas', 'libs', 'modules', ':config:cli' +include 'engine', 'engine-tests', 'facades', 'metas', 'libs', 'modules', ':gradle:gooeycli' // Handy little snippet found online that'll "fake" having nested settings.gradle files under /modules, /libs, etc rootDir.eachDir { possibleSubprojectDir -> From 85433d5e3f0f9d513be07d849753f0c5433c5bd3 Mon Sep 17 00:00:00 2001 From: Cervator Date: Fri, 10 Jul 2020 16:17:53 -0500 Subject: [PATCH 8/9] chore: rename stuff, add package structure, tweak some comments, more recurse logic --- gradle/gooeycli/build.gradle | 4 ++ .../groovy/org/terasology/cli/GooeyCLI.groovy | 12 ++-- .../BaseCommandType.groovy} | 4 +- .../GetCommand.groovy} | 9 ++- .../InitCommand.groovy} | 7 ++- .../ItemCommandType.groovy} | 7 ++- .../ModuleCommand.groovy} | 14 +++-- .../RecurseCommand.groovy} | 8 ++- .../UpdateCommand.groovy} | 8 ++- .../cli/{ => helpers}/PropHelper.groovy | 2 +- .../cli/managers/DependencyProvider.groovy | 11 ++++ .../cli/{ => managers}/ManagedItem.groovy | 59 +++++++++++++------ .../cli/{ => managers}/ManagedModule.groovy | 14 ++++- .../cli/{ => options}/GitOptions.groovy | 2 +- .../org/terasology/cli/scm/ScmGet.groovy | 11 ++++ 15 files changed, 125 insertions(+), 47 deletions(-) rename gradle/gooeycli/src/main/groovy/org/terasology/cli/{BaseCommand.groovy => commands/BaseCommandType.groovy} (89%) rename gradle/gooeycli/src/main/groovy/org/terasology/cli/{Get.groovy => commands/GetCommand.groovy} (86%) rename gradle/gooeycli/src/main/groovy/org/terasology/cli/{Init.groovy => commands/InitCommand.groovy} (85%) rename gradle/gooeycli/src/main/groovy/org/terasology/cli/{ItemCommand.groovy => commands/ItemCommandType.groovy} (79%) rename gradle/gooeycli/src/main/groovy/org/terasology/cli/{Module.groovy => commands/ModuleCommand.groovy} (68%) rename gradle/gooeycli/src/main/groovy/org/terasology/cli/{Recurse.groovy => commands/RecurseCommand.groovy} (84%) rename gradle/gooeycli/src/main/groovy/org/terasology/cli/{Update.groovy => commands/UpdateCommand.groovy} (80%) rename gradle/gooeycli/src/main/groovy/org/terasology/cli/{ => helpers}/PropHelper.groovy (96%) create mode 100644 gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/DependencyProvider.groovy rename gradle/gooeycli/src/main/groovy/org/terasology/cli/{ => managers}/ManagedItem.groovy (75%) rename gradle/gooeycli/src/main/groovy/org/terasology/cli/{ => managers}/ManagedModule.groovy (80%) rename gradle/gooeycli/src/main/groovy/org/terasology/cli/{ => options}/GitOptions.groovy (90%) create mode 100644 gradle/gooeycli/src/main/groovy/org/terasology/cli/scm/ScmGet.groovy diff --git a/gradle/gooeycli/build.gradle b/gradle/gooeycli/build.gradle index 483f952531a..4e6d07e632c 100644 --- a/gradle/gooeycli/build.gradle +++ b/gradle/gooeycli/build.gradle @@ -8,10 +8,14 @@ repositories { jcenter() } +// Important note: These need to be in sync with the @Grab entries in the Groovy scripts if both have to work dependencies { + // These are potentially available inside the Gradle/Groovy jar files already present compile 'org.codehaus.groovy:groovy-all:2.5.10' compile 'info.picocli:picocli-groovy:4.3.2' compile 'org.fusesource.jansi:jansi:1.18' + + // Have to rely on these via 3rd party jars compile 'org.ajoberstar:grgit:1.9.3' } diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/GooeyCLI.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/GooeyCLI.groovy index 89b44e78892..a6d3964b0a5 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/GooeyCLI.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/GooeyCLI.groovy @@ -15,20 +15,22 @@ package org.terasology.cli // Needed for colors to work on Windows, along with a mode toggle at the start and end of execution in main @Grab('org.fusesource.jansi:jansi:1.18') // TODO: Exists at 1.17 inside the Gradle Wrapper lib - can use that one? import org.fusesource.jansi.AnsiConsole - +import org.terasology.cli.commands.BaseCommandType +import org.terasology.cli.commands.InitCommand +import org.terasology.cli.commands.ModuleCommand import picocli.CommandLine import picocli.CommandLine.Command import picocli.CommandLine.HelpCommand -// If using local groovy files the subcommands section may highlight as bad syntax in IntelliJ - that's OK +// If using local groovy files without Gradle the subcommands section may highlight as bad syntax in IntelliJ - that's OK @Command(name = "gw", synopsisSubcommandLabel = "COMMAND", // Default is [COMMAND] indicating optional, but sub command here is required subcommands = [ HelpCommand.class, // Adds standard help options (help as a subcommand, -h, and --help) - Module.class, - Init.class], // Note that these Groovy classes *must* start with a capital letter for some reason + ModuleCommand.class, + InitCommand.class], // Note that these Groovy classes *must* start with a capital letter for some reason description = "Utility system for interacting with a Terasology developer workspace") -class GooeyCLI extends BaseCommand { +class GooeyCLI extends BaseCommandType { static void main(String[] args) { AnsiConsole.systemInstall() // enable colors on Windows - TODO: Test on not-so-Windows systems, should those not run this? CommandLine cmd = new CommandLine(new GooeyCLI()) diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/BaseCommand.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/BaseCommandType.groovy similarity index 89% rename from gradle/gooeycli/src/main/groovy/org/terasology/cli/BaseCommand.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/BaseCommandType.groovy index b11375cfb59..aa62a3e5041 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/BaseCommand.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/BaseCommandType.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli +package org.terasology.cli.commands import picocli.CommandLine.Command @@ -13,6 +13,6 @@ import picocli.CommandLine.Command parameterListHeading = "%n@|green Parameters:|@%n%n", optionListHeading = "%n@|green Options:|@%n%n", commandListHeading = "%n@|green Commands:|@%n%n") -class BaseCommand { +class BaseCommandType { } diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/Get.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/GetCommand.groovy similarity index 86% rename from gradle/gooeycli/src/main/groovy/org/terasology/cli/Get.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/GetCommand.groovy index 4d13d37278c..5d4ea7c3e4c 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/Get.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/GetCommand.groovy @@ -1,6 +1,9 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli +package org.terasology.cli.commands + +import org.terasology.cli.options.GitOptions +import org.terasology.cli.managers.ManagedItem import picocli.CommandLine.ParentCommand import picocli.CommandLine.Command // Actually in use, annotation below may show syntax error due to Groovy's annotation by the same name. Works fine @@ -13,11 +16,11 @@ import picocli.CommandLine.Parameters * Distinct from the sibling command add-remote which does *not* mix in GitOptions since the command itself involves git remote */ @Command(name = "get", description = "Gets one or more items directly") -class Get extends BaseCommand implements Runnable { +class GetCommand extends BaseCommandType implements Runnable { /** Reference to the parent item command so we can figure out what type it is */ @ParentCommand - ItemCommand parent + ItemCommandType parent /** Mix in a variety of supported Git extras */ @Mixin diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/Init.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/InitCommand.groovy similarity index 85% rename from gradle/gooeycli/src/main/groovy/org/terasology/cli/Init.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/InitCommand.groovy index e216b185276..309daa86f06 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/Init.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/InitCommand.groovy @@ -1,6 +1,9 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli +package org.terasology.cli.commands + +import org.terasology.cli.options.GitOptions +import org.terasology.cli.helpers.PropHelper import picocli.CommandLine.Command import picocli.CommandLine.Help.Ansi // Is in use, IDE may think the Groovy-supplied is in use below and mark this unused @@ -8,7 +11,7 @@ import picocli.CommandLine.Mixin import picocli.CommandLine.Parameters @Command(name = "init", description = "Initializes a workspace with some useful things") -class Init extends BaseCommand implements Runnable { +class InitCommand extends BaseCommandType implements Runnable { /** The name of the distro, if given. Optional parameter (the arity = 0..1 bit) */ @Parameters(paramLabel = "distro", arity = "0..1", defaultValue = "sample", description = "Target module distro to prepare locally") diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/ItemCommand.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/ItemCommandType.groovy similarity index 79% rename from gradle/gooeycli/src/main/groovy/org/terasology/cli/ItemCommand.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/ItemCommandType.groovy index d7e802c6613..393727baa85 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/ItemCommand.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/ItemCommandType.groovy @@ -1,10 +1,13 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli +package org.terasology.cli.commands + +import org.terasology.cli.managers.ManagedItem + /** * Simple command type class that indicates the command deals with "items" - nested Git roots representing application elements */ -abstract class ItemCommand extends BaseCommand { +abstract class ItemCommandType extends BaseCommandType { /** * Return a manager class for interacting with the specific type of item * @param optionGitOrigin if the user indicated an alternative Git origin it will be used to vary some URLs diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/Module.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/ModuleCommand.groovy similarity index 68% rename from gradle/gooeycli/src/main/groovy/org/terasology/cli/Module.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/ModuleCommand.groovy index b161ee99aa8..825cf82dab2 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/Module.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/ModuleCommand.groovy @@ -1,20 +1,22 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli +package org.terasology.cli.commands +import org.terasology.cli.managers.ManagedItem +import org.terasology.cli.managers.ManagedModule import picocli.CommandLine.Command import picocli.CommandLine.HelpCommand -// If using local groovy files the subcommands section may highlight as bad syntax in IntelliJ - that's OK +// If using local groovy files without Gradle the subcommands section may highlight as bad syntax in IntelliJ - that's OK @Command(name = "module", synopsisSubcommandLabel = "COMMAND", // Default is [COMMAND] indicating optional, but sub command here is required subcommands = [ HelpCommand.class, // Adds standard help options (help as a subcommand, -h, and --help) - Recurse.class, - Update.class, - Get.class], // Note that these Groovy classes *must* start with a capital letter for some reason + RecurseCommand.class, + UpdateCommand.class, + GetCommand.class], // Note that these Groovy classes *must* start with a capital letter for some reason description = "Sub command for interacting with modules") -class Module extends ItemCommand { +class ModuleCommand extends ItemCommandType { @Override ManagedItem getManager(String optionGitOrigin) { return new ManagedModule(optionGitOrigin) diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/Recurse.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/RecurseCommand.groovy similarity index 84% rename from gradle/gooeycli/src/main/groovy/org/terasology/cli/Recurse.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/RecurseCommand.groovy index cb54cef4dab..8e874cd4b98 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/Recurse.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/RecurseCommand.groovy @@ -1,6 +1,8 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli +package org.terasology.cli.commands + +import org.terasology.cli.options.GitOptions import picocli.CommandLine.ParentCommand import picocli.CommandLine.Command import picocli.CommandLine.Mixin @@ -11,10 +13,10 @@ import picocli.CommandLine.Parameters // Distinct from the sibling command add-remote which does *not* mix in GitOptions @Command(name = "recurse", description = "Gets one or more items and all their dependencies") -class Recurse extends BaseCommand implements Runnable { +class RecurseCommand extends BaseCommandType implements Runnable { @ParentCommand - ItemCommand parent + ItemCommandType parent /** Mix in a variety of supported Git extras */ @Mixin diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/Update.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/UpdateCommand.groovy similarity index 80% rename from gradle/gooeycli/src/main/groovy/org/terasology/cli/Update.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/UpdateCommand.groovy index 1dd6dca1b7a..cd45242ff0e 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/Update.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/UpdateCommand.groovy @@ -1,6 +1,8 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli +package org.terasology.cli.commands + +import org.terasology.cli.options.GitOptions import picocli.CommandLine.ParentCommand import picocli.CommandLine.Command import picocli.CommandLine.Mixin @@ -8,10 +10,10 @@ import picocli.CommandLine.Parameters @Command(name = "update", description = "Updates one or more items directly") -class Update extends BaseCommand implements Runnable { +class UpdateCommand extends BaseCommandType implements Runnable { @ParentCommand - ItemCommand parent + ItemCommandType parent /** Mix in a variety of supported Git extras */ @Mixin diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/PropHelper.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/helpers/PropHelper.groovy similarity index 96% rename from gradle/gooeycli/src/main/groovy/org/terasology/cli/PropHelper.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/helpers/PropHelper.groovy index a36da4df2c7..475f3b5e3ea 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/PropHelper.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/helpers/PropHelper.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli +package org.terasology.cli.helpers /** * Convenience class for pulling properties out of a 'gradle.properties' if present, for various overrides * // TODO: YAML variant that can be added for more complex use cases? diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/DependencyProvider.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/DependencyProvider.groovy new file mode 100644 index 00000000000..12340f28933 --- /dev/null +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/DependencyProvider.groovy @@ -0,0 +1,11 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.cli.managers + +/** + * Marks a managed item as having the capacity to have dependencies, forcing implementation of a way to parse them. + */ +interface DependencyProvider { + def parseDependencies(String itemsToCheck) +} diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/ManagedItem.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/ManagedItem.groovy similarity index 75% rename from gradle/gooeycli/src/main/groovy/org/terasology/cli/ManagedItem.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/ManagedItem.groovy index 132a6eb2eb7..ee8fc15f44c 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/ManagedItem.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/ManagedItem.groovy @@ -1,9 +1,10 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli +package org.terasology.cli.managers @GrabResolver(name = 'jcenter', root = 'http://jcenter.bintray.com/') @Grab(group = 'org.ajoberstar', module = 'grgit', version = '1.9.3') import org.ajoberstar.grgit.Grgit +import org.terasology.cli.helpers.PropHelper /** * Utility class for dealing with items managed in a developer workspace. @@ -76,6 +77,44 @@ abstract class ManagedItem { return code.toString() == "200" } + List recurse(List items) { + def dependencies = [] + println "Going to retrieve the following items (recursively): $items" + for (String item : items) { + // Check for circular dependencies - we should only ever act on a request to *retrieve* an item once + if (itemsRetrieved.contains(item)) { + println "Uh oh, we got told to re-retrieve the same thing for $item - somebody oopsed a circular dependency? Skipping" + } else { + // We didn't already try to retrieve this item: get it (if we already have it then getItem will just be a no-op) + getItem(item) + // Then goes and checks the item on disk and parses the thing to see if it has dependencies (even if we already had it) + dependencies << ((DependencyProvider) this).parseDependencies(item) + } + // Mark this item as retrieved just in case somebody made a whoops and introduced a circular dependency + itemsRetrieved << item + } + + // If we parsed any dependencies, retrieve them recursively (and even if we already got them check them for dependencies as well) + if (!dependencies.isEmpty()) { + println "Got dependencies to fetch: " + dependencies + return recurse(dependencies) + } + + println "Finally done recursing, both initial items and any parsed dependencies" + return null + } + + def get(List items) { + for (String itemName : items) { + getItem(itenName) + } + } + + def getItem(String item) { + println "Going to get $item do we already have it? " + // Logic for a single retrieve, no dependency parsing involved + } + /** * Primary entry point for retrieving items, kicks off recursively if needed. * @param items the items we want to retrieve @@ -121,23 +160,9 @@ abstract class ManagedItem { Grgit.clone dir: itemDir, uri: targetUrl } /* - // This step allows the item type to check the newly cloned item and add in extra template stuff - TODO? + // This step allows the item type to check the newly cloned item and add in extra template stuff - TODO? Same as the recurse fix? //itemTypeScript.copyInTemplateFiles(itemDir) - - // Handle also retrieving dependencies if the item type cares about that - if (recurse) { - def foundDependencies = itemTypeScript.findDependencies(itemDir) - if (foundDependencies.length == 0) { - println "The $itemType $itemName did not appear to have any dependencies we need to worry about" - } else { - println "The $itemType $itemName has the following $itemType dependencies we care about: $foundDependencies" - String[] uniqueDependencies = foundDependencies - itemsRetrieved - println "After removing dupes already retrieved we have the remaining dependencies left: $uniqueDependencies" - if (uniqueDependencies.length > 0) { - retrieve(uniqueDependencies, true) - } - } - }*/ +*/ } } } diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/ManagedModule.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/ManagedModule.groovy similarity index 80% rename from gradle/gooeycli/src/main/groovy/org/terasology/cli/ManagedModule.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/ManagedModule.groovy index bf5b35091b9..322966b82f6 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/ManagedModule.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/ManagedModule.groovy @@ -1,7 +1,8 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli -class ManagedModule extends ManagedItem { +package org.terasology.cli.managers + +class ManagedModule extends ManagedItem implements DependencyProvider { ManagedModule() { super() } @@ -25,6 +26,15 @@ class ManagedModule extends ManagedItem { return "Terasology" } + @Override + List parseDependencies(String itemToCheck) { + List foundDependencies = [] + + // logic to parse module.txt for dependencies + + return foundDependencies + } + /** * Copies in a fresh copy of build.gradle for all modules (in case changes are made and need to be propagated) */ diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/GitOptions.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/options/GitOptions.groovy similarity index 90% rename from gradle/gooeycli/src/main/groovy/org/terasology/cli/GitOptions.groovy rename to gradle/gooeycli/src/main/groovy/org/terasology/cli/options/GitOptions.groovy index 6dd4bce7747..17b7ceb1ad1 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/GitOptions.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/options/GitOptions.groovy @@ -1,6 +1,6 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -package org.terasology.cli +package org.terasology.cli.options import picocli.CommandLine.Option /** diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/scm/ScmGet.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/scm/ScmGet.groovy new file mode 100644 index 00000000000..d32e1de7ded --- /dev/null +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/scm/ScmGet.groovy @@ -0,0 +1,11 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.cli.scm + +/** + * Generic wrapper around SCM operations resulting in the retrieval of a resource + */ +class ScmGet { + +} From 89b591f14997ff616eaa83b234b56005654bf1f9 Mon Sep 17 00:00:00 2001 From: Cervator Date: Fri, 10 Jul 2020 22:55:01 -0500 Subject: [PATCH 9/9] feat: working recurse command in the new style, misc cleanup and utility --- .../terasology/cli/commands/GetCommand.groovy | 4 +- .../cli/commands/InitCommand.groovy | 3 + .../cli/commands/ModuleCommand.groovy | 2 +- .../cli/commands/RecurseCommand.groovy | 9 +- .../terasology/cli/helpers/KitchenSink.groovy | 50 +++++++ .../cli/managers/DependencyProvider.groovy | 2 +- .../cli/managers/ManagedItem.groovy | 132 +++++++----------- .../cli/managers/ManagedModule.groovy | 36 ++++- .../org/terasology/cli/scm/ScmGet.groovy | 22 ++- 9 files changed, 162 insertions(+), 98 deletions(-) create mode 100644 gradle/gooeycli/src/main/groovy/org/terasology/cli/helpers/KitchenSink.groovy diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/GetCommand.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/GetCommand.groovy index 5d4ea7c3e4c..5509729023b 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/GetCommand.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/GetCommand.groovy @@ -6,7 +6,6 @@ import org.terasology.cli.options.GitOptions import org.terasology.cli.managers.ManagedItem import picocli.CommandLine.ParentCommand import picocli.CommandLine.Command -// Actually in use, annotation below may show syntax error due to Groovy's annotation by the same name. Works fine import picocli.CommandLine.Mixin import picocli.CommandLine.Parameters @@ -34,8 +33,9 @@ class GetCommand extends BaseCommandType implements Runnable { // The parent should be a ManagedItem. Make an instace including the possible git origin option ManagedItem mi = parent.getManager(gitOptions.origin) + println "Got a parent command, associated item is: " + mi.getDisplayName() // Having prepared an instance of the logic class we call it to actually retrieve stuff - mi.retrieve(items, false) + mi.get(items) } } diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/InitCommand.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/InitCommand.groovy index 309daa86f06..69cb5e95845 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/InitCommand.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/InitCommand.groovy @@ -10,6 +10,8 @@ import picocli.CommandLine.Help.Ansi import picocli.CommandLine.Mixin import picocli.CommandLine.Parameters +import static org.terasology.cli.helpers.KitchenSink.green + @Command(name = "init", description = "Initializes a workspace with some useful things") class InitCommand extends BaseCommandType implements Runnable { @@ -26,6 +28,7 @@ class InitCommand extends BaseCommandType implements Runnable { System.out.println(str) println "Do we have a Git origin override? " + gitOptions.origin println "Can has desired global prop? " + PropHelper.getGlobalProp("alternativeGithubHome") + green "Some green text" // Call logic elsewhere } } diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/ModuleCommand.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/ModuleCommand.groovy index 825cf82dab2..b24d29d0d3c 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/ModuleCommand.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/ModuleCommand.groovy @@ -7,7 +7,6 @@ import org.terasology.cli.managers.ManagedModule import picocli.CommandLine.Command import picocli.CommandLine.HelpCommand -// If using local groovy files without Gradle the subcommands section may highlight as bad syntax in IntelliJ - that's OK @Command(name = "module", synopsisSubcommandLabel = "COMMAND", // Default is [COMMAND] indicating optional, but sub command here is required subcommands = [ @@ -17,6 +16,7 @@ import picocli.CommandLine.HelpCommand GetCommand.class], // Note that these Groovy classes *must* start with a capital letter for some reason description = "Sub command for interacting with modules") class ModuleCommand extends ItemCommandType { + @Override ManagedItem getManager(String optionGitOrigin) { return new ManagedModule(optionGitOrigin) diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/RecurseCommand.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/RecurseCommand.groovy index 8e874cd4b98..468440fe27e 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/RecurseCommand.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/commands/RecurseCommand.groovy @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.cli.commands +import org.terasology.cli.managers.ManagedItem import org.terasology.cli.options.GitOptions import picocli.CommandLine.ParentCommand import picocli.CommandLine.Command @@ -27,6 +28,12 @@ class RecurseCommand extends BaseCommandType implements Runnable { void run() { println "Going to recurse $items! And from origin: " + gitOptions.origin - println "Command parent is: " + parent.getItemType() + + // The parent should be a ManagedItem. Make an instance including the possible git origin option + ManagedItem mi = parent.getManager(gitOptions.origin) + println "Got a parent command, associated item is: " + mi.getDisplayName() + + // Having prepared an instance of the logic class we call it to actually retrieve stuff + mi.recurse(items) } } diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/helpers/KitchenSink.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/helpers/KitchenSink.groovy new file mode 100644 index 00000000000..d63ea452da4 --- /dev/null +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/helpers/KitchenSink.groovy @@ -0,0 +1,50 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.cli.helpers + +import picocli.CommandLine + +class KitchenSink { + /** + * Tests a URL via a HEAD request (no body) to see if it is valid + * @param url the URL to test + * @return boolean indicating whether the URL is valid (code 200) or not + */ + static boolean isUrlValid(String url) { + def code = new URL(url).openConnection().with { + requestMethod = 'HEAD' + connect() + responseCode + } + return code.toString() == "200" + } + + // Logging methods to produce colored text. Other styling is inconsistent, for instance underline on Windows sets gray background instead + + /** + * Simply logs text in green + * @param message the message to color + */ + static void green(String message) { + System.out.println(CommandLine.Help.Ansi.AUTO.string("@|green $message|@")) + } + + /** + * Simply logs text in yellow + * @param message the message to color + */ + static void yellow(String message) { + System.out.println(CommandLine.Help.Ansi.AUTO.string("@|yellow $message|@")) + } + + /** + * Simply logs text in red + * @param message the message to color + */ + static void red(String message) { + System.out.println(CommandLine.Help.Ansi.AUTO.string("@|red $message|@")) + } + + +} diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/DependencyProvider.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/DependencyProvider.groovy index 12340f28933..25bf011b42a 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/DependencyProvider.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/DependencyProvider.groovy @@ -7,5 +7,5 @@ package org.terasology.cli.managers * Marks a managed item as having the capacity to have dependencies, forcing implementation of a way to parse them. */ interface DependencyProvider { - def parseDependencies(String itemsToCheck) + List parseDependencies(File targetDirectory, String itemToCheck) } diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/ManagedItem.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/ManagedItem.groovy index ee8fc15f44c..37683ae3508 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/ManagedItem.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/ManagedItem.groovy @@ -1,10 +1,12 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 package org.terasology.cli.managers -@GrabResolver(name = 'jcenter', root = 'http://jcenter.bintray.com/') -@Grab(group = 'org.ajoberstar', module = 'grgit', version = '1.9.3') -import org.ajoberstar.grgit.Grgit + import org.terasology.cli.helpers.PropHelper +import org.terasology.cli.scm.ScmGet + +import static org.terasology.cli.helpers.KitchenSink.green +import static org.terasology.cli.helpers.KitchenSink.yellow /** * Utility class for dealing with items managed in a developer workspace. @@ -25,32 +27,37 @@ abstract class ManagedItem { File targetDirectory abstract File getTargetDirectory() - String githubTargetHome + String targetGitOrigin abstract String getDefaultItemGitOrigin() ManagedItem() { displayName = getDisplayName() targetDirectory = getTargetDirectory() - githubTargetHome = calculateGitOrigin(null) + targetGitOrigin = calculateGitOrigin(null) } ManagedItem(String optionGitOrigin) { displayName = getDisplayName() targetDirectory = getTargetDirectory() - githubTargetHome = calculateGitOrigin(optionGitOrigin) + targetGitOrigin = calculateGitOrigin(optionGitOrigin) } + /** + * Initializer for the target origin to get resources from - option, workspace setting, or a default. + * @param optionOrigin an alternative if the user submitted a git option via CLI + * @return the highest priority override or the default + */ String calculateGitOrigin(String optionOrigin) { // If the user indicated a target Git origin via option parameter then use that (primary choice) if (optionOrigin != null) { - println "We have an option set for Git origin so using that: " + optionOrigin + green "We have an option set for Git origin so using that: " + optionOrigin return optionOrigin } // Alternatively if the user has a global override set for Git origin then use that (secondary choice) String altOrigin = PropHelper.getGlobalProp("alternativeGithubHome") if (altOrigin != null) { - println "There was no option set but we have a global proper override for Git origin: " + altOrigin + green "There was no option set but we have a global proper override for Git origin: " + altOrigin return altOrigin } @@ -59,110 +66,65 @@ abstract class ManagedItem { return getDefaultItemGitOrigin() } - // TODO: Likely everything below should just delegate to more specific classes to keep things tidy - // TODO: That would allow these methods to later just figure out exact required operations then delegate - // TODO: Should make it easier to hide the logic of (for instance) different Git adapters behind the next step - /** - * Tests a URL via a HEAD request (no body) to see if it is valid - * @param url the URL to test - * @return boolean indicating whether the URL is valid (code 200) or not + * The Get command simply retrieves one or more resources in one go. Easy! + * @param items to retrieve */ - boolean isUrlValid(String url) { - def code = new URL(url).openConnection().with { - requestMethod = 'HEAD' - connect() - responseCode + def get(List items) { + for (String itemName : items) { + println "Going to retrieve $displayName $itemName" + getItem(itemName) } - return code.toString() == "200" } + /** + * More advanced version of the Get command that also retrieves any dependencies defined by the items. + * @param items to retrieve + * @return discovered dependencies from one round of processing (if used recursively) + */ List recurse(List items) { - def dependencies = [] - println "Going to retrieve the following items (recursively): $items" + List dependencies = [] + println "Going to retrieve the following $displayName item(s) recursively: $items" for (String item : items) { // Check for circular dependencies - we should only ever act on a request to *retrieve* an item once if (itemsRetrieved.contains(item)) { - println "Uh oh, we got told to re-retrieve the same thing for $item - somebody oopsed a circular dependency? Skipping" + yellow "Uh oh, we got told to re-retrieve the same thing for $item - somebody wrote a circular dependency? Skipping" } else { // We didn't already try to retrieve this item: get it (if we already have it then getItem will just be a no-op) getItem(item) // Then goes and checks the item on disk and parses the thing to see if it has dependencies (even if we already had it) - dependencies << ((DependencyProvider) this).parseDependencies(item) + def newDependencyCandidates = ((DependencyProvider) this).parseDependencies(targetDirectory, item) + println "Got new dependency candidates: " + newDependencyCandidates + dependencies += newDependencyCandidates - itemsRetrieved - dependencies + println "Storing them without those already retrieved: " + dependencies } - // Mark this item as retrieved just in case somebody made a whoops and introduced a circular dependency + // Mark this item as retrieved - that way we'll disqualify it if it comes up again in the future itemsRetrieved << item } + println "Finished recursively retrieving the following list: " + items + dependencies -= itemsRetrieved + println "After disqualifying any dependencies that were already in that list the following remains: " + dependencies + // If we parsed any dependencies, retrieve them recursively (and even if we already got them check them for dependencies as well) if (!dependencies.isEmpty()) { - println "Got dependencies to fetch: " + dependencies + println "Got dependencies to fetch so we'll recurse and go again!" return recurse(dependencies) } - println "Finally done recursing, both initial items and any parsed dependencies" + green "Finally done recursing, both initial items and any parsed dependencies" return null } - def get(List items) { - for (String itemName : items) { - getItem(itenName) - } - } - - def getItem(String item) { - println "Going to get $item do we already have it? " - // Logic for a single retrieve, no dependency parsing involved - } - /** - * Primary entry point for retrieving items, kicks off recursively if needed. - * @param items the items we want to retrieve - * @param recurse whether to also retrieve dependencies of the desired items (only really for modules ...) + * Simple one-item execution point for attempting to get a resource. + * @param item the resource to get */ - def retrieve(List items, boolean recurse) { - println "Now inside retrieve, user (recursively? $recurse) wants: $items" - for (String itemName : items) { - println "Starting retrieval for $displayName $itemName, are we recursing? $recurse" - println "Retrieved so far: $itemsRetrieved" - retrieveItem(itemName, recurse) - } - } + void getItem(String item) { + println "Processing get request for $item via SCM" + // Logic for a single retrieve, no dependency parsing involved, nor Git origin tweaking - already handled + ScmGet.cloneRepo(item, targetGitOrigin, targetDirectory, displayName) - /** - * Retrieves a single item via Git Clone. Considers whether it exists locally first or if it has already been retrieved this execution. - * @param itemName the target item to retrieve - * @param recurse whether to also retrieve its dependencies (if so then recurse back into retrieve) - */ - def retrieveItem(String itemName, boolean recurse) { - File itemDir = new File(targetDirectory, itemName) - println "Request to retrieve $displayName $itemName would store it at $itemDir - exists? " + itemDir.exists() - if (itemDir.exists()) { - println "That $displayName already had an existing directory locally. If something is wrong with it please delete and try again" - itemsRetrieved << itemName - } else if (itemsRetrieved.contains(itemName)) { - println "We already retrieved $itemName - skipping" - } else { - itemsRetrieved << itemName - def targetUrl = "https://github.com/${githubTargetHome}/${itemName}" - if (!isUrlValid(targetUrl)) { - println "Can't retrieve $displayName from $targetUrl - URL appears invalid. Typo? Not created yet?" - return - } - println "Retrieving $displayName $itemName from $targetUrl" - if (githubTargetHome != getDefaultItemGitOrigin()) { - println "Doing a retrieve from a custom remote: $githubTargetHome - will name it as such plus add the ${getDefaultItemGitOrigin()} remote as '$defaultRemote'" - Grgit.clone dir: itemDir, uri: targetUrl, remote: githubTargetHome - println "Primary clone operation complete, about to add the '$defaultRemote' remote for the ${getDefaultItemGitOrigin()} org address" - //addRemote(itemName, defaultRemote, "https://github.com/${getDefaultItemGitOrigin()}/${itemName}") //TODO: Add me :p - } else { - println "Cloning $targetUrl to $itemDir" - Grgit.clone dir: itemDir, uri: targetUrl - } -/* - // This step allows the item type to check the newly cloned item and add in extra template stuff - TODO? Same as the recurse fix? - //itemTypeScript.copyInTemplateFiles(itemDir) -*/ - } + // TODO: Consider supporting copying in template files at this point if the type requests that } } diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/ManagedModule.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/ManagedModule.groovy index 322966b82f6..5454f2b45d1 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/ManagedModule.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/managers/ManagedModule.groovy @@ -2,7 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.cli.managers +import groovy.json.JsonSlurper + class ManagedModule extends ManagedItem implements DependencyProvider { + // TODO: Check these - why would they show up under modules/ ? Other than Index maybe? + def excludedItems = ["engine", "Index", "out", "build"] + ManagedModule() { super() } @@ -26,13 +31,30 @@ class ManagedModule extends ManagedItem implements DependencyProvider { return "Terasology" } - @Override - List parseDependencies(String itemToCheck) { - List foundDependencies = [] - - // logic to parse module.txt for dependencies - - return foundDependencies + /** + * Reads a given module info file to figure out which if any dependencies it has. Filters out any already retrieved. + * This method is only for modules. + * @param targetModuleInfo the target file to check (a module.txt file or similar) + * @return a String[] containing the next level of dependencies, if any + */ + List parseDependencies(File targetDirectory, String itemName, boolean respectExcludedItems = true) { + def qualifiedDependencies = [] + File targetModuleInfo = new File(targetDirectory, itemName + "/module.txt") + if (!targetModuleInfo.exists()) { + println "The module info file did not appear to exist - can't calculate dependencies" + return qualifiedDependencies + } + def slurper = new JsonSlurper() + def moduleConfig = slurper.parseText(targetModuleInfo.text) + for (dependency in moduleConfig.dependencies) { + if (respectExcludedItems && excludedItems.contains(dependency.id)) { + println "Skipping listed dependency $dependency.id as it is in the exclude list (shipped with primary project)" + } else { + println "Accepting listed dependency $dependency.id" + qualifiedDependencies << dependency.id + } + } + return qualifiedDependencies } /** diff --git a/gradle/gooeycli/src/main/groovy/org/terasology/cli/scm/ScmGet.groovy b/gradle/gooeycli/src/main/groovy/org/terasology/cli/scm/ScmGet.groovy index d32e1de7ded..889c874d421 100644 --- a/gradle/gooeycli/src/main/groovy/org/terasology/cli/scm/ScmGet.groovy +++ b/gradle/gooeycli/src/main/groovy/org/terasology/cli/scm/ScmGet.groovy @@ -3,9 +3,29 @@ package org.terasology.cli.scm +@GrabResolver(name = 'jcenter', root = 'http://jcenter.bintray.com/') +@Grab(group = 'org.ajoberstar', module = 'grgit', version = '1.9.3') +import org.ajoberstar.grgit.Grgit + +import static org.terasology.cli.helpers.KitchenSink.isUrlValid + /** * Generic wrapper around SCM operations resulting in the retrieval of a resource */ class ScmGet { - + static cloneRepo(String itemName, String targetGitOrigin, File targetDirectory, String displayName) { + File itemDir = new File(targetDirectory, itemName) + println "Request to retrieve $displayName $itemName would store it at $itemDir - exists? " + itemDir.exists() + if (itemDir.exists()) { + println "That $displayName already had an existing directory locally. If something is wrong with it please delete and try again" + } else { + def targetUrl = "https://github.com/${targetGitOrigin}/${itemName}" + if (!isUrlValid(targetUrl)) { + println "Can't retrieve $displayName from $targetUrl - URL appears invalid. Typo? Not created yet?" + return + } + println "Retrieving $displayName $itemName from $targetUrl" + Grgit.clone dir: itemDir, uri: targetUrl, remote: targetGitOrigin + } + } }