{"id":18554440,"url":"https://github.com/oracle/olcut","last_synced_at":"2025-04-09T13:10:14.305Z","repository":{"id":37862969,"uuid":"84968327","full_name":"oracle/olcut","owner":"oracle","description":"A Java configuration, shell, and general utility toolkit","archived":false,"fork":false,"pushed_at":"2023-10-06T20:00:37.000Z","size":17358,"stargazers_count":26,"open_issues_count":0,"forks_count":10,"subscribers_count":9,"default_branch":"main","last_synced_at":"2024-04-14T23:30:39.652Z","etag":null,"topics":["command-line-arguments","command-shell","configuration","dependency-injection-framework","java","options-parsing","provenance"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oracle.png","metadata":{"files":{"readme":"README-Commands.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-03-14T15:54:55.000Z","updated_at":"2024-03-28T14:50:18.000Z","dependencies_parsed_at":"2024-10-25T19:20:22.321Z","dependency_job_id":"74886351-c6a9-4611-aa8a-67a694bf48a2","html_url":"https://github.com/oracle/olcut","commit_stats":null,"previous_names":[],"tags_count":49,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oracle%2Folcut","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oracle%2Folcut/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oracle%2Folcut/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oracle%2Folcut/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oracle","download_url":"https://codeload.github.com/oracle/olcut/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248045245,"owners_count":21038554,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["command-line-arguments","command-shell","configuration","dependency-injection-framework","java","options-parsing","provenance"],"created_at":"2024-11-06T21:21:58.653Z","updated_at":"2025-04-09T13:10:14.285Z","avatar_url":"https://github.com/oracle.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Command Interpreter\n\nOLCUT provides a Command Interpreter that can be used for invoking or interacting\nwith your software.  It can be used as a test harness to poke and prod different\nparts of your code, or can be used inside a JVM that is also running other\npieces of software that you'd like to monitor or in some other way interact\nwith. It is also a great way to build simple shell-based utilities without having\nto make a million different main classes or command line arguments.\n\nThe `CommandInterpreter` has a number of built-in commands for things like shell\nhistory, status, file redirection, running a script of commands, etc.  These\ncommands are all grouped together for convenience, meaning they'll appear\ntogether when you run \"help\".\n\nThe gnu-readline capability in the `CommandInterpreter` is provided by the\n[jline3 library](https://github.com/jline/jline3). It offers native readline-style\nsupport (including history and tab completion) on the following platforms: Solaris,\nLinux, OS X, FreeBSD, and Windows. While OLCUT is 100% Java, JLine does require\na few native bits to run the Command Interpreter properly on these platforms. \n\n## Defining commands\n\nTo add your own commands to the shell you simply define and annotate methods\nthat take a `CommandInterpreter` as their first argument and supported types\nas any additional arguments.  Any object containing commands must implement\nthe `CommandGroup` interface.  All commands contained within the object will\nbe put together in the same group.\n\nDefining a command looks like this\n\n```java\n    public class Processor implements CommandGroup {\n        protected int numProcessed = 0;\n        \n        public String getName() {\n            return \"Process\";\n        }\n    \n        public String getDescription() {\n            return \"Commands for the Oracle Labs Sound Processor\";\n        }\n    \n        @Command(usage=\"\u003cfileName\u003e - filter the given file\")\n        public String filter(CommandInterpreter ci, File file) {\n            pipeline.filter(file);\n            ci.out.println(\"Processing \" + file.getName());\n            numProcessed++; \n            return \"\";\n        }\n        \n        @Command(usage=\"Prints stats for this processor\")\n        public String printStats(CommandInterpreter ci) {\n            return \"numProcessed: \" + numProcessed;\n        }\n    }\n```\n\nThen you can create and start a shell with that command in your main program,\nperhaps after having loaded any relevant configuration.\n\n```java\n    Processor p = new Processor(pipelineInstance);\n    CommandInterpreter shell = new CommandInterpreter();\n    shell.add(p);\n    shell.run();\n```\n\nYour main thread will block in a read/eval/print loop at this point.\n`CommandInterpreter` may also be run as a separate thread by invoking `start()`.\n\nAny number of parameters may be given to a `Command`. The `CommandInterpreter` will\ncheck the number provided and give appropriate error messages including the\nusage string in the `@Command` annotation.  It will parse the arguments and convert\nthem to the appropriate types and invoke the Command if possible.  Supported\nargument types are:\n\n* `String`\n* `Integer`, `int`\n* `Long`, `long`\n* `Double`, `double`\n* `Float`, `float`\n* `Boolean`, `boolean`\n* `File`\n* `Enum` of any type\n* `String[]` (as the only parameter type)\n\nNote that there is a one-to-one correspondence between method names and\n`Commands`.  No distinctions are made for method signatures with different\nparameters.  No guarantee is made for the behavior of a shell with multiple\nmethods that have the same name (See Layered Command Interpreter below).\nThe `CommandInterpreter` instance that is passed in will be the currently\nrunning shell. It is a best practice to use the shell's output (`ci.out`) for writing\noutput so that output can be easily redirected to any output stream the\nshell may be embedded in.\n\n## Optional parameters\n\nFor more flexibility in your commands, you may specify that trailing method\nparameters be optional.  Any optional parameter must have a default value\nassigned to it, expressed as a string that would be entered on the command\nline.  The default value may be the text \"null\" if you choose, although this\nshould only be used with object/reference types and not base types.  Optional\nparameters are tagged with the `@Optional` annotation.  The above filter method\ncould take an optional parameter to specify where the output of the pipeline\nshould go:\n\n```java\n        @Command(usage=\"\u003cinFile\u003e [\u003coutFile\u003e] - run this filter on a file\")\n        public String filter(CommandInterpreter ci,\n                             File inFile, \n                             @Optional(val=\"/tmp/output.au\") File outFile) {\n            pipeline.filter(inFile, outFile);\n            return \"\";\n        }\n```\n\n## Tab Completion\n\nCommands added to a `CommandInterpreter` may provide tab completion for each of\ntheir arguments. A separate method may be used to specify how each argument should\nbe completed. The method returns an array of `Completer` objects (described below),\none per argument, and takes no parameters. These methods may either be associated\nin the `@Command` annotation (described below), or can follow a naming convention\nto be paired with the method they provide completers for. The following example\nmethod would be used to find completers for the `filter` command:\n\n```java\n        public Completer[] filterCompleters() {\n            return new Completer[]{\n                new FileNameCompleter(),\n                new FileNameCompleter()\n            };\n        }\n```\n\nIn this example, an array of completers is returned, one per argument.  This\ncould actually be simplified because the behavior of the completers is to\nreuse the last completer in the array for all further arguments.  Simply\nproviding a single `FileNameCompleter` would work the same for this method.  To\nprevent tab-completion for a particular parameter, or to prevent the last\ncompleter from repeating, place a `NullCompleter` in the array in the appropriate\nspot.\n\nThe following types of completers are available in OLCUT.  These are provided\nby the [jline library](https://github.com/jline/jline3).\n\n* `FileNameCompleter` - Completes file names starting in the PWD\n* `StringsCompleter` - Pass it a list of strings or a Supplier to give it the values it should complete to\n* `EnumCompleter` - Completes with values from a specified Enum type\n* `NullCompleter` - Does not complete with anything.\n* `IntCompleter` - Just kidding.\n\nIf you wish to reuse a method that generates completers, you can use an\nattribute of the `@Command` annotation to specify the name of the completer method\nto use instead of relying on the `xxxCompleters` convention.  For example,\nif multiple commands take a single File parameter, you might make a method such\nas this one:\n\n```java\n        public Completers[] fileCompleter() {\n            return new Completer[]{\n                new FileNameCompleter(),\n                new NullCompleter()\n            }\n        }\n```\n\nThen when annotating a method that takes a `File` as its parameter, you would\nspecify:\n\n```java\n        @Command(usage=\"Processes a single file\",\n                 completers=\"fileCompleter\")\n```\n\nMultiple annotated commands may share the same completer method in this way.\n\n## Manual argument processing\n\nIn some cases, taking the supported types as arguments doesn't provide enough\nflexibility for the way you want your command to work.  In this case, you can\ninstead have your method use `String[]` as its second parameter (after the\n`CommandInterpreter`) and all arguments provided in the shell will be passed\nthrough verbatim to allow you to do your own argument parsing.  This is\nparticularly useful if you want to support a varargs-style syntax.  You may\nstill provide `Completer`s even if the arguments are not otherwise specified.\n\n## Layered Command Interpreter (Mixing in more commands)\n\nSometimes when building a large shell, you may have multiple `CommandGroup`s that\nprovide commands with the same name. To avoid namespace collisions, you can add\nyour commands to a layer, then add the layer to the top-level shell.\n\n```java\n    CommandInterpreter shell = new CommandInterpreter();\n    LayeredCommandInterpreter lci = new LayeredCommandInterpreter(\"pipe\", \"Pipeline Commands\");\n    lci.add(processor);\n    shell.add(lci);\n```\n\nTo avoid ambiguity, all commands defined in `processor` can now be referred to\nwith a \".pipe\" extension (e.g. `filter.pipe`), but may also be used without any\nextension when there is no conflict.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foracle%2Folcut","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foracle%2Folcut","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foracle%2Folcut/lists"}