{"id":920,"url":"https://github.com/nsomar/Guaka","last_synced_at":"2025-08-06T13:31:54.169Z","repository":{"id":50438918,"uuid":"72358663","full_name":"nsomar/Guaka","owner":"nsomar","description":"The smartest and most beautiful (POSIX compliant) Command line framework for Swift 🤖","archived":false,"fork":false,"pushed_at":"2019-10-07T09:08:51.000Z","size":271,"stargazers_count":1147,"open_issues_count":11,"forks_count":30,"subscribers_count":25,"default_branch":"master","last_synced_at":"2024-12-08T10:06:03.589Z","etag":null,"topics":["cli","command-line","framework","generator","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nsomar.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-10-30T15:47:29.000Z","updated_at":"2024-11-01T17:43:07.000Z","dependencies_parsed_at":"2022-08-05T07:30:22.035Z","dependency_job_id":null,"html_url":"https://github.com/nsomar/Guaka","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nsomar%2FGuaka","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nsomar%2FGuaka/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nsomar%2FGuaka/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nsomar%2FGuaka/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nsomar","download_url":"https://codeload.github.com/nsomar/Guaka/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228905441,"owners_count":17989766,"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":["cli","command-line","framework","generator","swift"],"created_at":"2024-01-05T20:15:34.666Z","updated_at":"2024-12-09T14:30:42.589Z","avatar_url":"https://github.com/nsomar.png","language":"Swift","readme":"\u003cp align=\"center\"\u003e\n\u003cbr/\u003e\n\u003cbr/\u003e\n\u003cimg src=\"https://rawgit.com/nsomar/Guaka/master/Misc/logo.svg\" height=150px/\u003e\n\u003cbr/\u003e\u003cbr/\u003e\u003cbr/\u003e\u003cbr/\u003e\n\u003c/p\u003e\n\n[![SwiftPM compatible](https://img.shields.io/badge/SwiftPM-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager)\n![Swift Version](https://img.shields.io/badge/Swift-5.0-orange.svg)\n[![Build Status](https://travis-ci.org/nsomar/Guaka.svg?branch=master)](https://travis-ci.org/nsomar/Guaka)\n[![codecov](https://codecov.io/gh/nsomar/Guaka/branch/master/graph/badge.svg)](https://codecov.io/gh/nsomar/Guaka)\n[![Platform](https://img.shields.io/badge/platform-osx-lightgrey.svg)](https://travis-ci.org/nsomar/Guaka)\n![License MIT](https://img.shields.io/badge/License-MIT-lightgrey.svg) \n[![Analytics](https://ga-beacon.appspot.com/UA-90175183-1/repo/github/guaka?pixel)](https://github.com/nsomar/Guaka)\n\n\n`Guaka` - Smart and beautiful POSIX compliant CLI framework for Swift.   \nIt helps you create modern and familiar CLI apps in the vein of widely used projects such as: Docker, Kubernetes, OpenShift, Hugo and more!.\n\nGuaka is both a swift library and a command line application that help generate Guaka projects. Inspired by the amazing [Cobra package](https://github.com/spf13/cobra) from the Golang's ecosystem.\n\n## Is it any good?\n\n### [Yes](https://news.ycombinator.com/item?id=3067434)\n\n## Why?\n- **Simple and idiomatic API**: No rocket science here! Full modern CLI apps in a few lines of code.\n- **Easy to use**: With the Guaka generator you can bootstrap your own CLI in matter of minutes.\n- **Lightweight and portable**: No libFoundation and friends, can be statically linked.\n- **POSIX compliant**: Short and long flags, flags can appear anywhere.\n- **Safe and crash free**: 100% safe code as in: unsafe code.\n- **Tested**: Close to 100% test coverage and 100% dog fooded (the Guaka CLI app is written in, yes you guessed, Guaka ;).\n- **Documented**: Lots of docs and samples.\n- **Batteries included**: We created a set cross-platform Swift libraries to [work with files](https://github.com/getGuaka/FileUtils.git), [regular expressions](https://github.com/getGuaka/Regex.git), [launching processes](https://github.com/getGuaka/Process.git), [dealing with the environment variables](https://github.com/getGuaka/Env.git) and [colorizing ouput](https://github.com/getGuaka/Colorizer) so you can be productive instantaneously.\n\n----\n\n## In this readme\n\n- [Features](#features)\n- [Introduction](#introduction)\n  - [Command](#command)\n  - [Flag](#flag)\n- [Getting started](#getting-started)\n  - [Using Guaka generator](#using-guaka-generator)\n  - [Manually implementing Guaka](#manually-implementing-guaka)\n- [Cross-Platform utility libraries - aka batteries](#cross-platform-utility-libraries-aka-batteries)\n- [Documentation](#documentation)\n  - [Command documentation](#command-documentation)\n  - [Flag documentation](#flag-documentation)\n  - [Help customization](#help-customization)\n- [Tests](#tests)\n- [Future work](#future-work)\n- [Contributing](#Contributing)\n\n## Features\n- [x] Easy to use API: Create a modern command line app in 2 lines.\n- [x] Super customizable Commands and Flags; customize the usage, the short message, long message, example and others\n- [x] [POSIX-Compliant](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html) flags: Handles short and long flags (-f, --flag)\n- [x] Commands can have code sub-commands. Allowing you to create CLI apps similar to git `git remote show`\n- [x] Inheritable and non-inheritable flags. Create root flags that are inherited from all the command's sub-commands\n- [x] Batteries included: With our\n  [Args](https://github.com/getGuaka/Args.git),\n  [Colorizer](https://github.com/getGuaka/Colorizer),\n  [Env](https://github.com/getGuaka/Env.git),\n  [FileUtils](https://github.com/getGuaka/FileUtils.git),\n  [Process](https://github.com/getGuaka/Process.git),\n  [Prompt](https://github.com/getGuaka/Prompt.git),\n  [Regex](https://github.com/getGuaka/Regex.git) and\n  [Run](https://github.com/getGuaka/Run.git)\n  cross-platform libraries you\n  can be productive instantaneously.\n- [x] Automatically generates help message for your commands, sub-commands and flags\n- [x] Handles user input errors with useful help messages\n- [x] Customizable help and error messages\n- [x] Type safe flags: specify the type of the flag when defining it and Guaka will make sure the user inputs the correct flag type\n- [x] Custom flag support; you can define your own flag types\n- [x] Command and Flag deprecation; guaka will the user know that they are using deprecated command/flags\n- [x] Command and Flag aliasing; you can alias a command or a flag to different names\n- [x] Define code that runs before the command and after the command is executed\n- [x] Aptly documented: lots of documentation in code (we tried)\n- [x] Levenshtein distance for subcommand names\n\nPlanned Features:\n- [ ] Generate Markdown documentation\n- [ ] Man pages and bash/zsh/tcsh completions\n- [ ] Generate a command line application from a configuration (Yaml, Taml, Json)file\n- [ ] Carthage and CocoaPods support (maybe?)\n\n## Introduction\n\nWith Guaka you can build modern command line applications that are composed of **Commands** and **Flags**. \n\nEach command represents an action with flags that represent switches or modifiers on this command. Also, each command can have a group of sub-commands under it.\n\nWith Guaka you can build command line applications with interfaces like the following:\n\n```\n\u003e git checkout \"NAME Of Branch\"\n```\n\n`git` command CLI has a `checkout` subcommand that accepts a string as its argument.\n\n```\n\u003e docker ps --all\n```\n\n`docker` command CLI has `ps` subcommand that accepts the `--all` flag.\n\nGuaka also automatically generate the command line help for your command tree. This help is accessible by passing `-h` or `--help` to any of your commands:\n\n```\n\u003e docker --help\n\u003e git checkout -h\n```\n\nThe help displays the commands, subcommands, and flag information.\n\n### Command\n\nThe `Command` it the main object of a Guaka CLI project. It represents a verb with a block that will get executed.\n\nIn the `docker ps --all` example. We have a `docker` command that has a `ps` command as its sub-command.\n\n```\n└── docker\n    ├── ps\n    └── ...\n```\n\nThe `Command` class has a lot of customization objects. At its minimum, a command must have the following:\n\n```swift\nlet command = Command(usage: \"command\") { flags, args in\n  // the flags passed to the command\n  // args the positional arguments passed to the command\n}\n```\n\nCheck the [Command documentation](https://getguaka.github.io/Classes/Command.html)\n\n### Flag\nA `Flag` represent an option or switch that a `Command` accepts. Guaka supports both short and long flag formats (inline with POSIX flags).\n\nIn `docker ps --all`. `--all` is a flag that `ps` accepts.\n\nFlags have lots of costumization objects. The simplest way to create a flag and add it to ps would look like the following:\n\n```swift\nlet flag = Flag(longName: \"all\", value: false, description: \"Show all the stuff\")\nlet command = Command(usage: \"ps\", flags: [flag]) { flags, args in\n  flags.getBool(name: \"all\")\n  // args the positional arguments passed to the command\n}\n```\n\nAbove we defined a `Flag` with `all` as longName  and a default value of `false`.    \nTo read this flag in the command we use `flags.getBool(...)` which returns the flag value.\n\nCheck the [Flag documentation](https://getguaka.github.io/Structs/Flag.html)\n\n## Getting started\nYou can create you Guaka command line application using the `guaka` generator app or by manually creating a swift project.\n\n### Using Guaka generator\nThe easiest way to use guaka is by using `guaka` generator command line app. This CLI app helps you generate a Guaka project.\n\nFirst lets install `guaka` using brew:\n\n```\n\u003e brew install getGuaka/tap/guaka\n```\n\nAs an alternative, you can install `guaka` using the installation script (This works on macOS and Linux):\n\n```\n\u003e curl https://raw.githubusercontent.com/getGuaka/guaka-cli/master/scripts/install.sh -sSf | bash\n```\n\n(Note: For other installation options check [Guaka Generator readme](https://github.com/getGuaka/guaka-cli#installing).)\n\nCheck that `guaka` is installed:\n\n```\n\u003e guaka --version\n \nVersion x.x.x\n```\n\nTo understand `guaka` generator, let's say we want to create the following command tree:\n- git checkout\n- git remote\n- git remote show\n- git remote --some-flag\n\n#### guaka create\nTo create a new Guaka project you can run `guaka create`. This command creates a new swift project and the swift project files required to have a minimal Guaka project.\n\n`guaka create` behaves differently based on the parameter that is passed it:\n\n- If nothing is passed, the project is created in the current working folder.\n- If a name is passed, a new folder with that name will be created. This folder will contain the Guaka project.\n- If an absolute or relative path is passed. Guaka will resolve the path and create the project there.\n\nTo create the `git` command we described above, we do the following:\n\n```\n\u003e guaka create git\n```\n\nThe generated Guaka swift project structure will look like:\n\n```\n├── Package.swift\n└── Sources\n    ├── main.swift\n    ├── root.swift\n    └── setup.swift\n```\n\nLet's run this newly created project.\n\n```\n\u003e swift build\n```\n\nThe generated built binary will be located under `./.build/debug/git`.\n\n```\n\u003e ./.build/debug/git --help\n```\n\nWhich will print out:\n\n```\nUsage:\n  git\n\nUse \"git [command] --help\" for more information about a command.\n```\n\n#### guaka add\nAfter running `guaka create` we have a skeleton Guaka project. This project will only have a root command.\n\nYou can add new sub-commands to your project you can use `guaka add ...`.\n\nLets add the checkout and remote command. Both these commands are sub-commands of the root.\n\n```\n\u003e guaka add checkout\n\u003e guaka add remote\n```\n\nNext, lets add a sub-command for `remote`:\n\n```\n\u003e guaka add show --parent remote\n```\n\nThe generated Guaka swift project structure will look like:\n\n```\n├── Package.swift\n└── Sources\n    ├── main.swift\n    ├── root.swift\n    ├── checkout.swift\n    ├── remote.swift\n    ├── show.swift\n    └── setup.swift\n```\n\n#### Adding a flag\nTo add a flag we need to alter the command swift file. To add a flag to our sample `Command` (git remote --some-flag). We edit `Sources/remote.swift`.\n\nLocate the `command.add(flags: [])` function call and edit it to look like this:\n\n```swift\ncommand.add(flags: [\n  Flag(longName: \"some-name\", value: false, description: \"...\")\n  ]\n)\n```\n\nNow save the file and build it with `swift build`. Run the built binary `./.build/debug/git -h` and check the created command structure.\n\nCheck [add flag documentation](https://getguaka.github.io/Classes/Command.html#/s:FC5Guaka7Command3addFT4flagVS_4Flag_T_)\n\n### Manually implementing Guaka\nAlternatively, you can create a Guaka command line app by implementing `Guaka` in a swift project.\n\n#### Adding Guaka to the project dependencies\nWe start by creating a swift executable project:\n\n```\nswift package init --type executable\n```\n\nAdd `Guaka` library to your `Package.swift` file\n\n```swift\nimport PackageDescription\n\nlet package = Package(name: \"YourPackage\",\n  dependencies: [\n    .Package(url: \"https://github.com/nsomar/Guaka.git\", majorVersion: 0),\n  ]\n)\n```\n\nRun `swift package fetch` to fetch the dependencies.\n\n#### Implementing the first command\nNext, lets add our first command. Go to `main.swift` and type in the following:\n\n```swift\nimport Guaka\n\nlet command = Command(usage: \"hello\") { _, args in\n  print(\"You passed \\(args) to your Guaka app!\")\n}\n\ncommand.execute()\n```\n\nRun `swift build` to build your project. Congratulations! You have created your first Guaka app.\n\nTo run it execute:\n\n```\n\u003e ./.build/debug/{projectName} \"Hello from cli\"\n```\n\nYou should get:\n\n```\nYou passed [\"Hello from cli\"] to your Guaka app!\n```\n\nCheck the [Command documentation](https://getguaka.github.io/Classes/Command.html)\n\n#### Adding a flag to the command\nLets proceed at adding a flag. Go to `main.swift` and change it to the following:\n\n```swift\nimport Guaka\n\nlet version = Flag(longName: \"version\", value: false, description: \"Prints the version\")\n\nlet command = Command(usage: \"hello\", flags: [version]) { flags, args in\n  if let hasVersion = flags.getBool(name: \"version\"),\n     hasVersion == true {\n    print(\"Version is 1.0.0\")\n    return\n  }\n\n  print(\"You passed \\(args) to your Guaka app!\")\n}\n\ncommand.execute()\n```\n\nThe above adds a flag called `version`. Notices how we are getting the flag using `flags.getBool`.\n\nNow lets test it by building and running the command:\n\n```\n\u003e swift build\n\u003e ./.build/debug/{projectName} --version\n\nVersion is 1.0.0\n```\n\nCheck [add flag documentation](https://getguaka.github.io/Classes/Command.html#/s:FC5Guaka7Command3addFT4flagVS_4Flag_T_)\n\n#### Adding a subcommand\nTo add a subcommand we alter `main.swift`. Add the following before calling `command.execute()`\n\n```swift\n// Create the command\n...\n\nlet subCommand = Command(usage: \"sub-command\") { _, _ in\n  print(\"Inside subcommand\")\n}\n\ncommand.add(subCommand: subCommand)\n\ncommand.execute()\n```\n\nNow build and run the command:\n\n```\n\u003e swift build\n\u003e ./.build/debug/{projectName} sub-command\n\nInside subcommand\n```\n\nCheck [add sub command](Check [add flag documentation](https://getguaka.github.io/Classes/Command.html#/s:FC5Guaka7Command3addFT4flagVS_4Flag_T_))\n\n#### Displaying the command help message\nGuaka automatically generates help for your commands. We can get the help by running:\n\n```\n\u003e ./.build/debug/{projectName} --help\n\nUsage:\n  hello [flags]\n  hello [command]\n\nAvailable Commands:\n  sub-command\n\nFlags:\n      --version   Prints the version\n\nUse \"hello [command] --help\" for more information about a command.\n```\n\nNotice how the command the sub-command and flag info are displayed.\n\nRead more about the [help message](https://getguaka.github.io/Protocols/HelpGenerator.html)\n\n## Cross-Platform utility libraries aka batteries\n\nWriting a command line application is more than just parsing the command line arguments and flags. \n\nSwift ecosystem is still very young and lacks of a cross-platform standard library. We did not wanted to make Guaka depend on libFoundation, so we rolled up our sleeves and built a few small cross-platform (as in whenever there is a usable C standard library) libraries. so you don't have to and can be productive instantaneously. Also , they are usable on their own. You are welcome to use them too! \u003c3:\n\n- [FileUtils](https://github.com/getGuaka/FileUtils.git): Help you work with files, directories and paths. \n- [Regex](https://github.com/getGuaka/Regex.git): Match and capture regex.\n- [Process](https://github.com/getGuaka/Process.git): Launch external programs and capture their standard output and standard error.\n- [Env](https://github.com/getGuaka/Env.git): Read and write environment variables sent to your process.\n\n## Documentation\n\n### Command documentation\n`Command` represents the main class in Guaka. It encapsulates a command or subcommand that Guaka defines.\n\nFor the full [Command documentation](https://getguaka.github.io/Classes/Command.html)\n\n#### Usage and Run block\nAs a minimum, a command needs a usage string and a `Run` block. The usage string describes how this command can be used.\n\n- If the usage is a single string `command-name`; the command will have that name\n- If the usage is a string with spaces `command-name args..`; the command name is the first segment of the string.\n\n```swift\nlet c = Command(usage: \"command-name\") { _, args in\n}\n```\n\nThe `Run` block gets called with two parameters. The `Flags` class which contains the flags passed to the command and the `args` which is an array of arguments passed to the command.\n\nThe `Command` constructor takes lots of parameters. However most of them have sensible defaults. Feel free to fill as much or as little of the parameters as you want:\n\n```\nCommand(usage: \"...\",\n        shortMessage: \"...\",\n        longMessage: \"...\",\n        flags: [],\n        example: \"...\",\n        parent: nil,\n        aliases: [],\n        deprecationStatus: .notDeprecated,\n        run: {..})\n```\n\nAt a minimum, you need to pass the `usage` and the `run` block. Refer to the code documentation for info about the parameters.\n\nCheck the [Flags documentation](https://getguaka.github.io/Structs/Flags.html)\n\n#### Adding Sub-commands to the command\nCommands are organised in a tree structure. Each command can have zero, one or many sub-commands associated with it.\n\nWe can add a sub-command by calling `command.add(subCommand: theSubCommand)`. If we wanted to add `printCommand` as a sub-command to `rootCommand`, we would do the following:\n\n```swift\nlet rootCommand = //Create the root command\nlet printCommand = //Create the print command\n\nrootCommand.add(subCommand: printCommand)\n```\n\nAlternatively, you can pass the `rootCommand` as the `parent` when creating the `printCommand`:\n\n```swift\nlet rootCommand = //Create the root command\nlet printCommand = Command(usage: \"print\",\n                           parent: rootCommand) { _, _ in\n}\n```\n\nOur command line application will now respond to both:\n\n```\n\u003e mainCommand\n\u003e mainCommand print\n```\n\nYou can build your command trees in this fashion and create modern, complex, elegant command line applications.\n\n#### Short and Long messages\nThe `Command` defines the `shortMessage` and the `longMessage`. These are two strings that get displayed when showing the `Command` help.\n\n```swift\nCommand(usage: \"print\",\n        shortMessage: \"prints a string\",\n        longMessage: \"This is the long mesage for the print command\") { _, _ in\n} \n```\n\nThe `shortMessage` is shown when the command is a sub-command.\n\n```\n\u003e mainCommand -h\n\nUsage:\n  mainCommand [flags]\n  mainCommand [command]\n\nAvailable Commands:\n  print    prints a string\n\nUse \"mainCommand [command] --help\" for more information about a command.\nProgram ended with exit code: 0\n```\n\nThe `longMessage` is shown when getting help of the current command\n\n```\n\u003e mainCommand print -h\n\nThis is the long message for the print command\n\nUsage:\n  mainCommand print\n\nUse \"mainCommand print [command] --help\" for more information about a command.\nProgram ended with exit code: 0\n```\n\n#### Command flags\nYou can add a `Flag` to a command in two ways.\n\nYou can pass the flags in the constructor:\n\n```\nlet f = Flag(longName: \"some-flag\", value: \"value\", description: \"flag information\")\n\nlet otherCommand = Command(usage: \"print\",\n        shortMessage: \"prints a string\",\n        longMessage: \"This is the long mesage for the print command\",\n        flags: [f]) { _, _ in\n}\n```\n\nAlternatively, you can call `command.add(flag: yourFlag)`.\n\nNow the flag will be associated with the command. We can see it if we display the help of the command.\n\n```\n\u003e mainCommand print -h\n\nThis is the long message for the print command\n\nUsage:\n  mainCommand print [flags]\n\nFlags:\n      --some-flag string  flag information (default value)\n\nUse \"mainCommand print [command] --help\" for more information about a command.\n```\n\n#### Command example section\nYou can attach a textual example on how to use the command. You do that by setting the `example` variable in the `Command` (or by filling the `example` parameter in the constructor):\n\n```swift\nprintCommand.example = \"Use it like this `mainCommand print \\\"the string to print\\\"\"\n```\n\nThen we can see it in the command help:\n\n```\n\u003e mainCommand print -h\n\nThis is the long message for the print command\n\nUsage:\n  mainCommand print\n\nExamples:\nUse it like this `mainCommand print \"the string to print\"\n\nUse \"mainCommand print [command] --help\" for more information about a command.\n```\n\n##### Command aliases and deprecation\nYou can mark a command as deprecated by setting the `deprecationStatus` on the command.\n\n```swift\nprintCommand.deprecationStatus = .deprecated(\"Dont use it\")\n```\nWhen the user call this command, a deprecation message will be displayed.\n\nAliases help giving command alternative names. We can have both `print` and `echo` represent the same command:\n\n```swift\nprintCommand.aliases = [\"echo\"]\n```\n\n#### Different kind of Run Hooks\nThe command can have different run Hooks. If they are set, they will be executed in this order.\n\n- `inheritablePreRun`\n- `preRun` \n- `run`\n- `postRun`\n- `inheritablePostRun`\n\nWhen a command is about to execute. It will first search for its parent list. If any of its parents have an `inheritablePreRun` then Guaka will first execute that block.\n\nNext the current command `preRun` is executed. Followed by the `run` and the `postRun`.\n\nAfter that, as with the `inheritablePreRun`, Guaka will search for any parent that has an `inheritablePostRun` and execute that too.\n\nAll of `inheritablePreRun`, `preRun`, `postRun` and `inheritablePostRun` blocks return a boolean. If they return `false` then the command execution will end. \n\nThis allows you to create smart command trees where the parent of the command can decide if any of it sub-commands must continue executing.\n\nFor example. The parent command can define a version flag. If this flag is set, the parent will handle the call and return false from its `inheritablePreRun`. Doing that help us to not repeat the version handling in each sub-command.\n\nThe example bellow shows this use case:\n\n```swift\n// Create root command\nlet rootCommand = Command(usage: \"main\")  { _, _ in\n  print(\"main called\")\n}\n\n// Create sub command\nlet subCommand = Command(usage: \"sub\", parent: rootCommand) { _, _ in\n  print(\"sub command called\")\n}\n\n// Add version flag to the root\n// We made the version flag inheritable \n// print will also have this flag as part of its flags\nlet version = Flag(longName: \"version\", value: false,\n                   description: \"Prints the version\", inheritable: true)\n\nrootCommand.add(flag: version)\nrootCommand.inheritablePreRun = { flags, args in\n  if\n    let version = flags.getBool(name: \"version\"),\n    version == true {\n    print(\"Version is 0.0.1\")\n    return false\n  }\n\n  return true\n}\n\nrootCommand.execute()\n```\n\nNow we can get the version by calling:\n\n```\n\u003e main --version\n\u003e main sub --version\n```\n\n#### Exiting early from a command\n\nIn some sitiuation you might want to exit early from a command you can use `command.fail(statusCode: errorCode, errorMessage: \"Error message\")`\n\n```swift\nlet printCommand = Command(usage: \"print\",\n                           parent: rootCommand) { _, _ in\n    // Error happened\n    printCommand.fail(statusCode: 1, errorMessage: \"Some error happaned\")\n}\n```\n\n### Flag documentation\n\nA `Flag` represent an option or switch that a `Command` accepts. Guaka defines 4 types of flags; integer, boolean, string and custom types.\n\nCheck the full [Flag documentation](https://getguaka.github.io/Structs/Flag.html)\n\n#### Creating a flag with default value\nTo create a `Flag` with default value, we call do the following:\n\n```swift\nlet f = Flag(longName: \"version\", value: false, description: \"prints the version\")\n```\n\nWe created a flag that has a `longName` of `version`. Has a default value of `false` and has a description. This creates a POSIX compliant flag. To set this flag:\n\n```\n\u003e myCommand --version\n\u003e myCommand --version=true\n\u003e myCommand --version true\n```\n\n`Flag` is a generic class, in the previous example, since we set `false` as its value, that creates a `boolean` `Flag`. If you try to pass a non-bool argument in the terminal, Guaka will display an error message.\n\nThe flag constructor, as with the command, defines lots of parameters. Most of them have sensible defaults, so feel free to pass as much, or little, as you need. \n\nFor example, we could set the flag short name by doing this:\n\n```swift\nFlag(shortName: \"v\", longName: \"version\", value: false, description: \"prints the version\")\n```\n\nNow we can either use `-v` or `--version` when calling the command.\n\n#### Creating a flag with flag type\nWe can create a flag that has no default value. This type of flag can be marked as optional or required.\n\nTo create an optional flag\n```\nFlag(longName: \"age\", type: Int.self, description: \"the color\")\n```\n\nHere we defined a flag that has an int value. If we execute the command with a non-integer value, Guaka will inform us of an error.\n\nA required flag can be created by passing true to the `required` argument in the `Flag` constructor:\n\n```swift\nFlag(longName: \"age\", type: Int.self, description: \"the color\", required: true)\n```\n\nNow if we call the command without setting the `--age=VALUE`. Guaka will display an error.\n\n#### Reading the flag values\nWhen the `Command` `run` block is called, a `Flags` argument will be sent to the block. This `Flags` argument contains the values for each flag the command defined.\n\nThis example illustrate flag reading:\n\n```swift\n// Create the flag\nvar uppercase = Flag(shortName: \"u\", longName: \"upper\",\n                     value: false, description: \"print in bold\")\n\n// Create the command\nlet printCommand = Command(usage: \"print\", parent: rootCommand) { flags, args in\n\n  // Read the flag\n  let isUppercase = flags.getBool(name: \"upper\") ?? false\n\n  if isUppercase {\n    print(args.joined().uppercased())\n  } else {\n    print(args.joined())\n  }\n}\n\n// Add the flag\nprintCommand.add(flag: uppercase)\n```\n\nLet's execute this command:\n\n```\n\u003e print \"Hello World\"\n\nHello World\n\n\u003e print -u \"Hello World\"\n\nHELLO WORLD\n```\n\n`Flags` class defines methods to read all the different type of flags:\n\n- `func getBool(name: String) -\u003e Bool?`\n- `func getInt(name: String) -\u003e Int?`\n- `func getString(name: String) -\u003e String?`\n- `func get\u003cT: FlagValue\u003e(name: String, type: T.Type) -\u003e T?`\n\nCheck the full [Flags documentation](https://getguaka.github.io/Structs/Flags.html)\n\n#### Inheritable flags\nFlags that are set to a parent `Command` can be also inherited to the sub-commands by passing `true` to the `inheritable` argument in the flag constructor.\n\nTo create an inheritable flag:\n\n```swift\nvar version = Flag(longName: \"version\", value: false,\n                   description: \"print in bold\", inheritable: true)\n\nrootCommand.add(flag: version)\n```\n\nThis makes `--version` a flag that can be set in the `rootCommand` and any of its sub-commands.\n\n#### Flag deprecation\nAs with a `Command`, a `Flag` can be set to be deprecated by setting it's `deprecationStatus`:\n\n```swift\nvar version = Flag(longName: \"version\", value: false,\n                   description: \"print in bold\", inheritable: true)\nversion.deprecationStatus = .deprecated(\"Dont use this flag\")\n```\n\nGuaka will warn each time this flag is set.\n\n#### Flag with custom types\nOut of the box, you can create flags with integer, boolean and string values and types. If you however, want to define custom types for your flags, you can do it by implementing the `FlagValue` protocol.\n\nLet's define a flag that has a `User` type:\n\n```swift\n// Create the enum\nenum Language: FlagValue {\n  case english, arabic, french, italian\n\n  // Try to convert a string to a Language\n  static func fromString(flagValue value: String) throws -\u003e Language {\n    switch value {\n    case \"english\":\n      return .english\n    case \"arabic\":\n      return .arabic\n    case \"french\":\n      return .french\n    case \"italian\":\n      return .italian\n    default:\n\n      // Wrong parameter passed. Throw an error\n      throw FlagValueError.conversionError(\"Wrong language passed\")\n    }\n  }\n\n  static var typeDescription: String {\n    return \"the language to use\"\n  }\n}\n\n// Create the flag\nvar lang = Flag(longName: \"lang\", type: Language.self, description: \"print in bold\")\n\n// Create the command\nlet printCommand = Command(usage: \"print\", parent: rootCommand) { flags, args in\n\n  // Read the flag\n  let lang = flags.get(name: \"lang\", type: Language.self)\n  // Do something with it\n}\n\n// Add the flag\nprintCommand.add(flag: lang)\n\n// Execute the command\nprintCommand.execute()\n```\n\nNotice that incase the argument is not correct we throw a `FlagValueError.conversionError`. This error will be printed to the console.\n\n```\n\u003e print --lang undefined \"Hello\"\n\nError: wrong flag value passed for flag: 'lang' Wrong language passed\nUsage:\n  main print [flags]\n\nFlags:\n      --lang the language to use  print in bold \n\nUse \"main print [command] --help\" for more information about a command.\n\nwrong flag value passed for flag: 'lang' Wrong language passed\nexit status 255\n```\n\nCheck the full [FlagValue documentation](https://getguaka.github.io/Protocols/FlagValue.html) and the [FlagValueError documentation](https://getguaka.github.io/Enums/FlagValueError.html).\n\n### Help customization\nGuaka allows you to customize the format of the generated help. You can do that by implementing the `HelpGenerator` and passing your class to `GuakaConfig.helpGenerator`.\n\nThe `HelpGenerator` protocol defines all the sections of the help message that you can subclass. `HelpGenerator` provides protocol extensions with defaults for all the section. That allows you to cherry-pick which sections of the help you want to alter.\n\nEach of the variable and section in the `HelpGenerator` corresponds to a section in the printed help message. To get the documentation of each section, refer to the in-code documentation of `HelpGenerator`.\n\nSay we only want to change the `usageSection` of the help, we would do the following:\n\n```swift\nstruct CustomHelp: HelpGenerator {\n  let commandHelp: CommandHelp\n\n  init(commandHelp: CommandHelp) {\n    self.commandHelp = commandHelp\n  }\n\n  var usageSection: String? {\n    return \"This is the usage section of \\(commandHelp.name) command\"\n  }\n}\n\nGuakaConfig.helpGenerator = CustomHelp.self\n```\n\nAny `HelpGenerator` subclass will have a `commandHelp` variable which is an instance of `CommandHelp` structure. This structure contains all the info available for a command.\n\nCheck the full [HelpGenerator documentation](https://getguaka.github.io/Protocols/HelpGenerator.html)\n\n## Tests\nTests can be found [here](https://github.com/nsomar/Guaka/tree/master/Tests).\n\nRun them with\n```\nswift test\n```\n\n## Future work\n\n- [x] Levenshtein distance for subcommand names\n- [ ] Generate Markdown documentation\n- [ ] Man pages and bash/zsh/tcsh completions\n- [ ] Generate a command line application from a configuration (Yaml, Taml, Json)file\n- [ ] Carthage and Cocoapod support\n\nFor a list of task planned, head to the [Guaka GitHub project](https://github.com/nsomar/Guaka/projects/1)\n\n## Contributing\n\nJust send a PR! We don't bite ;)\n","funding_links":[],"categories":["Libs","Command Line","Swift","Command Line [🔝](#readme)"],"sub_categories":["Command Line","Linter","Other free courses"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnsomar%2FGuaka","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnsomar%2FGuaka","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnsomar%2FGuaka/lists"}