Super-fast command aliases with arguments.

Related tags

System tools bonnie
Overview

Bonnie

Bonnie is a command aliasing tool. If you have a super-long command that you have to run all the time, Bonnie is for you! Just define the command in bonnie.toml at the root of your project, and you're good to go!

[scripts]
short = "really long command..."

For example, if you're running docker-compose a lot, and you have a custom environment variables file, it's annoying to type out docker-compose --env-file .my.env ... every time you want to do something! Bonnie can shorten this easily!

[scripts]
dc = "docker-compose --env-file .my.env %%"

The double percent sign (%%) at the end tells Bonnie to append any arguments you provide to the end of the command.

You can even insert custom arguments into custom places in a custom order!

[scripts]
greet.cmd = "echo \"Greetings %lastname. I see your first name is %firstname?\""
greet.args = [
	"firstname",
	"lastname"
]

Now if you run bonnie greet Donald Knuth you should get Greetings Knuth. I see your first name is Donald?

Installation

Bonnie is built in Rust, and you can either download a pre-compiled binary from here if you're running on one of the three major OSes on a 64-bit architecture, or you can clone this repository and build the code yourself. I'm happy to add more binaries for more OSes by request, please file an issue for the matter.

Using a pre-compiled binary

If you head over to the releases page on this repository, you'll be able to download binaries for the most recent version of Bonnie for the three major operating systems (Linux, MacOS, and Windows). GitHub Actions builds these automatically whenever a new tag is pushed, though I personally develop on Linux, so if the Windows or MacOS binaries don't work for some reason, please let me know! After downloading the binary, it should work immediately, though you may need to allow executing it as a program on Unix systems with chmod +x ./bonnie-linux-amd64 (or whatever your download is called). Then, you can move it to a location that suits you, like /usr/local/bin on Linux so you can execute it from anywhere on your system.

Building manually

  1. Clone this repository to your local machine.
  2. Ensure you have Rust and Cargo installed.
  3. Run cargo build --release && cp target/releases/bonnie bonnie. The built executable will be at ./bonnie. You can then copy this to somewhere you put binaries, like /usr/local/bin.

Syntax

Basics

Bonnie is a simple command-line interface that looks for a bonnie.toml file in whatever directory you run the command in. All configuration is defined in there. If you want to put your config file somewhere else, or name it something else, see Using a custom config file below. A basic Bonnie config file should look like this:

[scripts]

You can define all your command aliases, which Bonnie calls scripts under the [scripts] heading. This file uses TOML, which is like JSON, but much easier to read for humans. You can learn more about it and the syntax it supports at toml.io. If you use any invalid TOML syntax or you don't define scripts properly in your config, Bonnie will tell you straight away, without trying to run the command you specified, so don't worry about something blowing up!

Command with arguments

Bonnie supports inserting arguments into commands. This requires you to use the following syntax in bonnie.toml:

[scripts]
greet.cmd = "echo \"Greetings %lastname. I see your first name is %firstname?\""
greet.args = [
	"firstname",
	"lastname"
]

In that example, you denote the script by specifying the system command to run with the key greet.cmd (where greet is the script's name). You can then specify arguments with greet.args, setting that equal to an array containing the names of all the arguments in the script. You can have as many arguments as you want! Back in the greet.cmd value, you define where each argument goes by writing %firstname, where firstname is the name of the argument. You can do this in any order, the order that matters is that of the greet.args array, that's the order you'll be expected to supply arguments in when you run the script. If you stuff up and forget to put in an argument placeholder, Bonnie will tell you and not run the command. If you misspell an argument placeholder, Bonnie will tell you.

You can if you want to insert one argument more than once, Bonnie just replaces all instances of %firstname or the like, so that should work fine (not part of the test suite though).

As yet, Bonnie doesn't support optional arguments or default values, but hopefully that won't inconvenience you too much! If enough people want those features, I'll implement them at some point in the future.

Shorthand

Many of the commands you specify won't need arguments, they'll just be simple aliases. These can be specified trivially by just writing a key-value pair:

[scripts]
foobar = "echo Hello World"

You don't need .cmd or .args, you can just define it as foobar, where that's the name of the script. This is the most common way to define scripts with Bonnie.

Appending arguments

There are a lot of use cases where you'd want any arguments you provide to be appended to the end of a Bonnie script (this is the default behavior of NPM and Yarn scripts). You can do this easily in Bonnie by using shorthand syntax and adding a %% to the end of the command like so:

[scripts]
dc = "docker-compose --env-file .my.env %%"

Note that you cannot combine this appending behavior with custom arguments yet, and Bonnie will tell you if you try to (and won't run the command). If enough people want this combination to be possible, I'm happy to implement the feature at some point in the future.

Note that when you run a script that appends arguments, it will accept any number of arguments, including 0. Bonnie will tell you neither about too many or too few arguments provided. If enough people want support for the allowed number of arguments to be able to be specified by a range, I'm happy to implement that feature.

As of yet, you can only append all arguments at the end of a command, nowhere else. This does mean that if you try echo '%%' (note the ending '), Bonnie will not append any arguments, and will treat that as ordinary shorthand syntax. Support for appending arguments inside a script is on the roadmap.

Escaping %

Bonnie uses % to denote arguments in commands. If you have something like %firstnameBlah, where firstname is the argument, Bonnie will only replace that. Any instances of % signs not connected to arguments or other special flags (right now only the %% append flag) will be left untouched. If you need to put %firstname in and not have it replaced by an argument named firstname, you'll have to pick a different argument name.

Slightly surprising behaviour can be if you have two arguments, one firstname and the other first. If first is provided before firstname, Bonnie will replace the %first part of %firstname and then tell you it couldn't insert the firstname argument. In other words, if one argument is a substring of another from index 0 (e.g. first and firstname) and you provide the substring before the superstring, Bonnie will accidentally mangle instances of the superstring argument and then complain that said argument couldn't be inserted. Basically, don't have arguments that are substrings of each other from index 0, they'll behave weirdly in certain cases.

Running commands

After you've set up your bonnie.toml file, you can run any of the commands you've defined easily like so:

bonnie [script_name] [arg1] [arg2] [etc.]

Just type the name of the script, and then add any arguments it expects. If you don't give enough arguments, Bonnie will tell you and won't run the command. If you provide too many, Bonnie will run the command, and will add a warning telling you you've provided too many arguments. That'll be written to stdout rather than stderr, so if you're parsing the output of a Bonnie script, make sure you've got the right number of arguments, or you're ready to handle that warning.

The output of the command (stdout and stderr) will be piped directly to the corresponding properties of the Bonnie process. All commands are run as child processes, and they do not inherit the stdin of Bonnie. If you're trying to pipe data into a script, unfortunately that isn't yet possible. If enough people would find this helpful, then I'm happy to implement it at some point in the future.

Using a custom config file

There may be cases in which your bonnie config file is in a different directory, and these can easily be handled by setting the BONNIE_CONF environment variable. On Unix systems (MacOS and Linux), this can be done by running BONNIE_CONF=path/to/bonnie.toml bonnie ....

Reserved commands

Bonnie does have a few internal commands, and your own scripts defined in bonnie.toml cannot conflict with these. You won't be warned about this, Bonnie will just completely ignore your scripts whenever you run one of these commands:

  • bonnie help - displays the Bonnie documentation
  • bonnie init - creates a new bonnie.toml file in the current directory (won't override existing files)

Motivation

I used to use JavaScript a lot, where I had access to beautiful tools like Yarn and NPM scripts. I learned to love those a lot, and then I switched to Elm and Rust, and I was suddenly deprived of a nice script tool! Make was the most obvious option, but it felt a little dated and cumbersome for something so simple, so I decided to make my own version while Ia was learning Rust! This is that.

Aim

Right now, Bonnie is a really simple development automation tool, but in future, I may expand its capabilities so that it becomes a proper build tool with highly extensible scripting functionalities!

Why 'Bonnie'?

No particular reason, the name just sounded nice, and I thought I may as well name this program Bonnie. No offense intended whatsoever to those named Bonnie!

Stability

Right now, Bonnie is in beta because of the youth of the project and to allow time for bugs to be reported. I use the project daily, and I'll continue adding features on the roadmap as I do so. Right now, there are some parts of Bonnie that aren't covered by automated tests (though I test those parts manually before any releases), so I'll complete those before the project moves into stable 1.0. Right now, v1.0 will probably be released some time in May 2021, but the program is perfectly fine to use up until that point!

Roadmap

  • Add automated tests for the warning system to when too many arguments are provided
  • Add automated tests for the command running system
  • Support inserting all arguments somewhere into a command rather than just at the end
  • Support a combination of custom arguments and appending arguments
  • Support optional arguments
  • Support giving default values for optional arguments
  • Support specifying the upper and lower bounds of acceptable numbers of appended arguments with a range
  • Support piping data into Bonnie scripts with a special opening flag (maybe %[stdin]?)

Authors

  • arctic_hen7

License

See LICENSE.txt

Comments
  • Add OS-specific shells and commands

    Add OS-specific shells and commands

    Currently, Bonnie uses cmd on Windows, with no option to change it to something else — PowerShell, for instance. This presents difficulties when trying to use the various features of PowerShell. For example, (get-command pwsh).Path is valid PowerShell, but cmd says that .Path was unexpected at this time. This is why I propose the following:

    • Add the ability to have customise the shell you're using for a project. I propose a shell field be added at the top-level to bonnie.toml, as follows:

      shell = "string" # Normal syntax
      # Or this:
      shell = {
          default = "optional string"
          linux = "optional string"
          macos = "optional string"
          windows = "optional string"
      }   
      

      default would be used if one or more platforms was not specified; the default for default would be the current behaviour.

    • Add the ability to have OS-specific commands. This would be useful if you were using equivalent commands on different platforms — which <command> and (get-command <command>).Path for example. I propose that commands should be able to be specified as a record, as well a string. This would look like the following:

      [scripts]
      example = "command" # Normal syntax
      # Or this:
      example = {
          default: "optional string"
          linux = "optional string"
          macos = "optional string"
          windows = "optional string"
      }
      

      Again, default is used if one or more platforms are not specified. If one or more platforms are not specified and default is not specified, an error would be thrown.

    • Change the default shell on Windows to Windows PowerShell. This would be a breaking change that would bring Bonnie on Windows closer to Bonnie on Linux and macOS — ls is not valid cmd, but it is valid PowerShell. Modern, open-source PowerShell is probably too new to make the default, but Windows PowerShell has been available since 2006.

    enhancement 
    opened by ostev 32
  • Switch default shell on Windows to PowerShell

    Switch default shell on Windows to PowerShell

    It's been proposed in #12 that the default shell on Windows should be switched to PowerShell. Since that issue contains another main point, I'm moving the conversation on the matter of changing the default to here.

    enhancement help wanted 
    opened by arctic-hen7 10
  • Update to install node js packages

    Update to install node js packages

    For this tool to compete among other current package managers, it should be able to install npm packages, dev dependencies, etc.

    Example

    In your bonnie.toml file, users can specify dependencies as such

    [dependecies]
    express="1.0.1"
    body-parser="2.0.1"
    
    [dev-dependencies]
    @node-types="1.0.1"
    
    enhancement 
    opened by Valentine-Mario 10
  • A way to list all the commands in the file

    A way to list all the commands in the file

    Description Please add a reserved command, or maybe a switch, to list all the commands bonnie knows about in the folder where the toml resides. Something like bonnie ls, bonnie list, or bonnie --list.

    Reasoning Bonnie is awesome but, unless I'm mistaken, you must open the toml file to see what commands exist, and there's no quick reference. You have to read through it all and, in some cases, parse the bonnie structure to figure out what works.

    Are you willing to work on an implementation of this? I am not confident enough in my rust skills yet to dissect someone else's code and add such a command. If I get to that point, I will be happy to send a PR, but in the meantime, I am placing my hopes in someone else who has such skill and recognizes this as a good feature to add. If not, I suppose I will live without it for the time being. Thank you!

    enhancement triage 
    opened by damccull 5
  • Global template support

    Global template support

    Description Support for a global template in ~/.bonnie/template.toml that would automatically be used instead of the pre-programmed default if it's present when bonnie -i is executed.

    Reasoning Bonnie currently lacks any form of global configuration ability. This is the best solution that provides both global configuration and atomicity and portability.

    Are you willing to work on an implementation of this? I'm happy to, but I think @ostev wanted to.

    enhancement 
    opened by arctic-hen7 5
  • Multistage commands run each stage in a different shell

    Multistage commands run each stage in a different shell

    Describe the bug Any command with multiple stages will have each of its stages executed in a different subshell.

    Minimum reproducible configuration

    version = "0.3.0"
    
    [scripts]
    test = [ "cd /tmp", "pwd" ]
    

    Expected behavior The above example should print /tmp as the current directory, assuming that the two stages run in the same shell.

    Actual behavior The above example will instead print the directory in which it was executed, as the commands run in different shells.

    Runtime information Ubuntu 20.10, but this affects all systems.

    bug 
    opened by arctic-hen7 3
  • Add version tag to config file

    Add version tag to config file

    I'm very conscious that as more features are added to Bonnie, we're going to run into the issue of compatibility between one version of config file and a different version of Bonnie. In view of that, I think it would be prudent to add a version tag in the config file so we can check for semantic version differences and then warn or throw an error appropriately.

    enhancement 
    opened by arctic-hen7 2
  • Support environment variable interpolation

    Support environment variable interpolation

    This feature could easily be added by allowing the definition of a .env parameter or the like in long-form notation, along with a separate object [env_files] or similar in which the user could define a list of files to pull in environment variables from (in addition to any provided to Bonnie itself on the command line). The system would then fail gracefully if a variable isn't defined.

    I think this feature would make developing more complex and integrated systems much easier. For example, if you define Docker ports to be opened in an environment variable file and then interpolate that into docker-compose.yml, if you need to expose those same ports in a docker-compose run command you alias with Bonnie, you should be able to read from that very same file.

    enhancement 
    opened by arctic-hen7 2
  • Add command domains

    Add command domains

    Right now, Bonnie only supports defining individual commands, however there is a very prevalent use case where we may want to support command domains. It's best to show this by example.

    Right now, you'd have to do this:

    [scripts]
    test = "some unrelated script"
    sh-server = "this shells into a server"
    sh-db = "this shells into a database"
    

    But I think it'd be a good idea to have this be an option:

    [scripts]
    test = "some unrelated script"
    [scripts.domains.sh]
    server = "this shells into a server"
    db = "this shells into a database"
    

    That way, you'd be able to run the commands like so:

    bonnie sh server
    bonnie sh db
    

    This would be a reasonably simple modification to Bonnie's serialization logic. The only issue case would be if a user defines a script and domain with the same name. In that case, we could do one of two things:

    1. Run the script if no arguments are given, and the domain if arguments are given.
    2. Throw an error.

    I think option 2 would be far better and more logical, as otherwise the user simply couldn't define a script with the same name as a domain that takes any arguments, and they wouldn't get any error.

    enhancement 
    opened by arctic-hen7 2
  • Add self-documenting ability

    Add self-documenting ability

    Description Self-documenting functionality so that users can run bonnie help and receive an outline of what each alias does. This could be done through a .description property (these would probably be defined all together at the top of a file for ease).

    Reasoning Currently, users have to read through the file and try to understand it. Unfamiliarity with Bonnie can slow this process, and it's generally inconvenient.

    Are you willing to work on an implementation of this? Yes.

    enhancement 
    opened by arctic-hen7 1
  • Add `.bonnie.cache.json`

    Add `.bonnie.cache.json`

    This would be implemented later in future, but I propose a system whereby very large Bonnie config files that don't change often can have the entire Bonnie parsing system run on them and the output cached into a file like .bonnie.cache.json. We could then read directly from this file, making future command runs much faster. We could also store the bonnie.toml file's hash, allowing us to update if it changes. Right now, this isn't an issue, but if and when ordered domain execution is finalised, processing speed could become a significant issue for configurations with complex control flows.

    enhancement 
    opened by arctic-hen7 1
  • Parallelism of commands

    Parallelism of commands

    Description NPM has a package called Concurrently. It provides a command that can run multiple commands parallel to each other.

    Reasoning In a typical (real) web dev environment, there are multiple tools required to be run. Coming from my current project I have to run:

    • trunk serve --open
    • cargo tauri dev
    • tailwindcss -o ./tailwind.css --watch

    tauri can run trunk serve on its own from its devCommand, but that still requires a 2nd command to run the tailwind watch.

    More tools may require more commands to be run in parallel.

    Are you willing to work on an implementation of this? I can try, but I am not the strongest in rust. With some help/ direction on what to do I may be able to help on an implementation.

    enhancement 
    opened by Isfirs 1
  • Support variables

    Support variables

    Description A new top-level HashMap [variables], which would allow the derivation of values that can be interpolated into commands. When preparing a command to be run, we'd compute their values (they'd be fully-fledged command cores themselves, their outputs become the values) and interpolate them. We could then store the values we've attained in a temporary HashMap that we pass around to each subcommand etc. so we don't compute any unnecessary values, but we also don't compute any values twice.

    Reasoning Make does this excellently, and Bonnie has reached the point where this feature is really a must. I see this as the third type of interpolation in addition to arguments and environment variables.

    Are you willing to work on an implementation of this? Yes.

    enhancement 
    opened by arctic-hen7 1
  • Add ability to rerun command on directory change

    Add ability to rerun command on directory change

    Description A new command core property (lowest level, next to shell/exec specification) .watch that is provided a directory path to watch. Then, the command will be rerun whenever any file in that directory changes.

    Reasoning This would make Bonnie able to easily run commands that need to watch one or more files. Quite frankly, it'd just be a useful feature. The only possible issue is that we'd need to assume the directory exists until runtime, and we'll have to check it before we run the command for the first time (on invocation) and fail fast, but that shouldn't be a problem.

    Are you willing to work on an implementation of this? Yes.

    enhancement 
    opened by arctic-hen7 1
  • Add `.cleanup`

    Add `.cleanup`

    Description A new property .cleanup next to shell configuration that specifies a command/series of commands to run after the normal command is done. This would allow for example starting a database and then running cargo watch on a server, and then shutting down the database when the command ends. We should also catch termination signals and run the cleanup commands then if possible.

    Reasoning This would allow greater command flow, and the setup and takedown of multiple services.

    Are you willing to work on an implementation of this? Yes.

    enhancement 
    opened by arctic-hen7 0
Releases(v0.3.2)
Owner
arctic_hen7
Hi! I'm a human that likes building cool stuff with code!
arctic_hen7
minimalistic command launcher in rust

rrun Note: Apart from the occasional fix, this project is not actively developed anymore. rrun works fine and should run/compile for the time being on

null 105 Nov 18, 2022
Performs distributed command execution, written in Rust w/ Tokio

Concurr: Distributed and Concurrent Command Execution, in Rust This project is dual licensed under MIT and Apache 2.0. Originally inspired by the GNU

Michael Murphy 93 Dec 18, 2022
The next gen ls command

LSD (LSDeluxe) Table of Contents Description Screenshot Installation Configuration External Configurations Required Optional F.A.Q. Contributors Credi

Pierre Peltier 9k Jan 2, 2023
A modern alternative to watch command

A modern alternative to watch command

Tavo Annus 7 Oct 7, 2022
A fast duplicate file finder

The Directory Differential hTool DDH traverses input directories and their subdirectories. It also hashes files as needed and reports findings. The H

Jon Moroney 384 Dec 24, 2022
Blazing 💥 fast terminal-ui for git written in rust 🦀

Blazing fast terminal client for git written in Rust Features Fast and intuitive keyboard only control Context based help (no need to memorize tons of

Stephan Dilly 11.8k Jan 5, 2023
A simple and fast download accelerator, written in Rust

zou A simple and fast download accelerator, written in Rust Zou is a Snatch fork by @k0pernicus. Snatch is a fast and interruptable download accelerat

Antonin Carette 173 Dec 4, 2022
A simple, fast and user-friendly alternative to 'find'

fd [中文] [한국어] fd is a program to find entries in your filesytem. It is a simple, fast and user-friendly alternative to find. While it does not aim to

David Peter 25.8k Dec 30, 2022
A fast and minimalistic image viewer forked from the now discontinued emulsion.

Alloy Image viewer based on (now-discontinued) Emulsion. Alloy targets Windows, Mac, and Linux (with more targets to come!). A note for Linux users: W

Ardaku Systems 9 Dec 1, 2022
A super super super voting system on near block chain :)

Disp41r-Super-Voting-System a super super super voting system on near block chain :) Finish! I call it super voting system, because it is really cool!

Disp41r 1 Jan 15, 2022
repl / scripting language / namespaced command line aliases

Adana Toy project with the following goals in mind: Making something concrete with rust Learning more about parser combinator Use the minimum amount o

Nordine Bittich 10 Aug 28, 2022
A fast, extensible, command-line arguments parser

parkour A fast, extensible, command-line arguments parser. Introduction ?? The most popular argument parser, clap, allows you list all the possible ar

Ludwig Stecher 18 Apr 19, 2021
Trait aliases on stable Rust

trait-set: trait aliases on stable Rust Status: Project info: Support for trait aliases on stable Rust. Description This crate provide support for tra

Igor Aleksanov 39 Oct 12, 2022
Parse command line arguments by defining a struct.

StructOpt Parse command line arguments by defining a struct. It combines clap with custom derive. Documentation Find it on Docs.rs. You can also check

Guillaume P. 2.6k Jan 5, 2023
parse command-line arguments into a hashmap and vec of positional args

parse command-line arguments into a hashmap and vec of positional args This library doesn't populate custom structs, format help messages, or convert types.

James Halliday 17 Aug 11, 2022
Easy-to-use optional function arguments for Rust

OptArgs uses const generics to ensure compile-time correctness. I've taken the liberty of expanding and humanizing the macros in the reference examples.

Jonathan Kelley 37 Nov 18, 2022
ddi is a wrapper for dd. It takes all the same arguments, and all it really does is call dd in the background

ddi A safer dd Introduction If you ever used dd, the GNU coreutil that lets you copy data from one file to another, then you may have encountered a ty

Tomás Ralph 80 Sep 8, 2022
zero runtime cost default arguments in rust

Default Arguments in Rust Enables default arguments in rust by macro in zero cost. Just wrap function with default_args! and macro with name of functi

Jaeyong Sung 73 Sep 6, 2022
Finds matching solidity function signatures for a given 4 byte signature hash and arguments.

Finds matching solidity function signatures for a given 4 byte signature hash and arguments. Useful for finding collisions or 0x00000000 gas saving methods (though there are better techniques for saving gas on calldata)

null 73 Dec 22, 2022