# g.bash A Bash framework. ## Documentation (WIP) ### Global Helpers - `g::eval [...command]` - Execute a command, but w/ in-framework logging - `g::silence [...command]` - Execute a command, squashing all output - `g::now` - Get a timestamp in ISO8061 - `g::bc [...args]` - Execute a `bc` math statement - `g::awk [...inputs]` - Execute an `awk` print command ### Utilties (`g::util`) - `isNumeric [value]` - Checks if a given value is a number with optional decimal and positive/negative - `true` - A successful exit code/return value (`0`) - `false` - A failure exit code/return value (`1`) - `returnToEcho [...command]` - Execute a command that returns `true`/`false` and instead echo `1` on success, `0` otherwise - `uuid` - Generate a UUID - `uuid::underscore` - Generate a UUID (underscore-separated) - `escape [value]` - Bash-escape a value for safe use in `eval` strings - `realpath [path]` - A non-GNU real path resolver - `trace [?message] [?skip = frames to exclude]` - Generate a stack trace with an optional message ### Strings (`g::str`) - `quote [str]` - Surround a string in quotes - `eval [...args]` - Execute a command and quote the output - `length [str]` - Get the number of chars in a string - `padLeft [str] [length] [pad character=' ']` - Left-pad a string to the given length - `padRight [str] [length] [pad character=' ']` - Right-pad a string to the given length - `padCenter [str] [length] [pad character=' ']` - Center-pad a string to the given length - `substring [str] [startAt] [length]` - Get a substring - `offset [str] [startAt]` - Drop the first `n` characters of a string - `reverse [str]` - Reverse a string - `startsWith [haystack] [needle]` - Check if the haystack starts with the needle - `endsWith [haystack] [needle]` - Check if the haystack ends with the needle - `trim [str]` - Trim the whitespace from either end of the string - `indexOf [str] [substring]` - Print the character index where the `substring` appears, if any (returns `g::util::false` if no match) - `replace [str] [find] [replace]` - Find-and-replace all occurrences in a string - `replace::once [str] [find] [replace]` - Find-and-replace the first occurrence in a string ### Arrays (`g::arr`) > Note: When passing an array as an argument to a function, it should be passed as `"${array[@]}"` - `includes [value] [array]` - Checks if a given value exists in the array - `assoc::hasKey [key] [array]` - Checks if an associative array has a given key - `join [delimiter] [array]` - Implodes a list of values to a string using the given delimiter ### Math (`g::math`) - Constants (`g::math::c`) - `e` - Euler's constant - `ln2` - Natural log of 2 - `ln10` - Natural log of 10 - `pi` - Pi - `sqrt05` - Square root of 1/2 - `sqrt2` - Square root of 2 - `abs [num]` - Absolute value of a number - `cubeRoot [num]` - Cube root of a number - `squareRoot [num]` - Square root of a number - `lessThan [left] [right]` - Check if `left < right` - `greaterThan [left] [right]` - Check if `left > right` - `equalTo [left] [right]` - Check if `left == right`, numerically - `isPositive [num]` - Check if `num > 0` - `isNegative [num]` - Check if `num < 0` - `signOf [num]` - Prints the leading sign of a number (either `+` or `-`) - `mod [num] [modulus]` - Compute the modulus of a number - `ceiling [num]` - Round the number up to the nearest int - `truncate [num]` - Truncate the number to an int - `floor [num]` - Round the number down to the nearest int - `exponent [num] [power]` - Compute `num^power` - `cos [num]` - Cosine of a number - `sine [num]` - Sine of a number - `tan [num]` - Tangent of a number - `ln [num]` - Natural log of a number - `log10 [num]` - Log base 10 of a number - `log2 [num]` - Log base 2 of a number - `log [num] [base]` - Arbitrary base logarithm - `random` - Get a random float - `max [...nums]` - Get the max value of some numbers - `min [...nums]` - Get the min value of some numbers - `round [num] [precision]` - Round a number to the specified number of decimal points ### Files (`g::file`) - `appendString [path] [string]` - Append the string contents to the end of a file - `exists [path]` - Checks if a file exists - `directoryExists [path]` - Checks if a directory exists - `touch [path]` - Create a file if it does not exist - `truncate [path]` - If a file exists, empty its contents ### Source Code (`g::source`) `g::source` allows you to organize your scripts into multiple files, and perform filesystem-relative source imports. Similarly, it will prevent the same source file from being re-imported multiple times. Example: ```shell # index.bash g::source src/setup g::source src/logging # src/setup.bash g::source logging # src/logging.bash # This file is included once ``` - `g::source [path] [?up=1]` - Load a source file relative to the current script (must end in `.bash` and will only be loaded once) - `resolve [path] [?up=1]` - Resolve the path of a source file relative to the current script - `exists [path] [?up=1]` - Check if a source file exists relative to the current script - `force [path] [?up=1]` - Resolve and load a source file, bypassing the cache - `has [path] [?up=1]` - Check if the given source file has been loaded ### Configuration File (`g::config`) Provides a simple key-value way of storing persistent configuration. Example: ```shell echo "Last run: $(g::config::get last-run Never)" g::config::set 'last-run' "$(g::now)" ``` - `setDefault [name]` - Set the default name of the config file - `getDefault` - Get the default name of the config file - `init [?name]` - Make sure a config file exists - `get [name] [?default value]` - Get a value from the default config file - `get::forFile [file] [name] [?default value]` - Get a value from a non-default config file - `set [name] [value]` - Store a value in the default config file - `set::forFile [file] [name] [value]` - Store a value in a non-default config file ### Paths (`g::path`) - `concat [path] [...parts]` - Combine path segments into a path, accounting for leading and trailing slashes - `resolve [...parts]` - Concat path parts and determine the real path - `resolveFrom [base dir] [...parts]` - Concat path parts and determine the real path relative to some base directory - `cd [...parts]` - Resolve path parts and change directories - `tmp` - Get a temp file path (and mark it for cleanup) - `tmpdir` - Get a temp dir path (and mark it for cleanup) ### Errors (`g::error`) - `throw [message]` - Throw an error - (global) `try` - (global) `catch` ### Logging (`g::log`) `g::log` provides level- and target-aware logging output. The `internal` level is used by `g.bash` itself. Available levels: `error` | `warn` | `info` | `debug` | `verbose` | `internal` - `enableTarget [name]` - Enable log outputs for the given target - `enableAllTargets` - Enable log outputs for ALL targets - `all` - Shorthand to enable the highest verbosity for ALL targets - `getLevel` - Get the current logging level - `setLevel [name]` - Set a new logging level - `enable [target=stdout|stderr|file] [?param]` - Enable logging to the specified target - `disable [target=stdout|stderr|file]` - Disable logging to the specified target - `g::error [output] [?target]` - Write a log message at the `error` level, optionally for a specific target - Same format for `g::warn`, `g::info`, `g::debug`, `g::verbose`, and `g::internal` - `g::log::rotate` - Archive the log file to a timestamped version and start a new one ### Locks (`g::lock`) - `try [name]` - Try to acquire a lock, returning `g::util::true` if successful - `acquire [name]` - Acquire a lock, sleeping until it is available - `holds [name]` - Check if we currently hold the given lock - `release [name]` - Release the given lock if held - `singleton` - Throw an error if this script is being executed concurrently - `singleton::acquire` - Wait for other instances of this script to finish ### App Framework (`g::app`) `g::app` is a way of defining multi-directive CLI applications with argument/option parsing. Each application is broken up into "commands," and each command can have multiple arguments/flags. Your source code can provide multiple applications (switching between them using `g::app`) with app-scoped storage. - `g::app [?name=app] [?description]` - Create a new top-level application - `get [name] [?default value]` - Get the value of an app-scoped variable - `set [name] [value]` - Set the value of an app-scoped variable - `has [name]` - Check if the app-scope has a variable with the given name - `usage` - Print usage information for the current application - `invoke [command] [...args]` - Invoke a command in the current application #### Defining Commands (`g::app::command`) A command is an invokable sub-command function for an application, which can have multiple flags and positional arguments associated with it. When a command is executed, its arguments are parsed and a function `app::::` is called. Basic example: ```shell g::app myapp "An example application" g::app::command greet "Greeting command" g::app::command::arg name "Name of the person to greet" "World" g::app::command::flag greeting= "Override the greeting" function app::myapp::greet() { local args="$1" name="$(g::arg "$args" name)" greeting="$(g::flag "$args" greeting)" if [ -z "$greeting" ]; then greeting="Hello," fi echo "$greeting $name" } ``` - `g::app::command [name] [?description]` - Start defining a new command in the current app - `exists [name]` - Check if a given command exists in the current app - `description [name]` - Get the description for a command in the current app - `arg [name] [?description] [?default value]` - Add a positional argument to the current command - `flag [name] [?description]` - Add a position-less flag option. If `name` trails with a `=`, then a value is expected - `rest [name] [?description]` - Register a rest-argument (`[...args]`) for the current command #### Accessing Arguments When arguments for a command are parsed, they are stored in an "argument set." The argument set is a series of data structures containing the parsed/validated flags & positional arguments. The argument set ID is passed to the command handler as the only parameter (`$1`) and can be used to look up the values of flags and arguments. - `g::args [uuid]` - Get the raw arguments from a parsed set (akin to `$@`) - `g::arg [uuid] [name]` - Get the value of a positional argument - `g::arg::has [uuid] [name]` - Checks if a positional argument was provided - `g::arg::rest [uuid]` - Get all the unmatched CLI arguments/flags - `g::flag [uuid] [name]` - Get the value of a position-less flag - `g::flag::has [uuid] [name]` - Checks if a position-less flag was specified