aux4
Documentation
HomeGetting StartedInstallationIDEsVariablesExecutorsFunctionsConfigurationCommandsHooksSecurityRenderTestingPackage ManagerPackagingGitHub ActionsDocker

Getting started with aux4

What's aux4?

aux4 is a CLI (Command-line Interface) generator, used to create high-level scripts and automate your daily tasks.

Install

1> curl https://aux4.sh | sh

IDEs

Add support for aux4 in your favorite IDE.

Visual Studio Code

Vim/Neovim

How to use

aux4 is a command-line interface generator tool designed to be extremely simple to learn and use. It requires creating a .aux4 file using JSON format. It all starts from the profiles array.

1{ 2 "profiles": [ 3 ... 4 ] 5}

Each profile has a name and a list of commands. But the most important profile is the main one.

1{ 2 "profiles": [ 3 { 4 "name": "main", 5 "commands": [ 6 ... 7 ] 8 } 9 ] 10}

The command is defined by its name, followed by a sequence of command-line instructions that will be executed, and a help section with its documentation.

1{ 2 "profiles": [ 3 { 4 "name": "main", 5 "commands": [ 6 { 7 "name": "<COMMAND NAME>" 8 "execute": [ 9 "<FIRST COMMAND-LINE INSTRUCTION>", 10 "<SECOND COMMAND-LINE INSTRUCTION>", 11 "..." 12 ], 13 "help": { 14 "text": "<DESCRIPTION OF THE COMMAND>" 15 } 16 } 17 ] 18 } 19 ] 20}

Hello World

The best way to start is creating a Hello World example.

We can create a hello command that will print Hello World.

First, create the .aux4 file.

1{ 2 "profiles": [ 3 { 4 "name": "main", 5 "commands": [ 6 { 7 "name": "hello", 8 "execute": [ 9 "echo 'Hello World'" 10 ], 11 "help": { 12 "text": "say hello world" 13 } 14 } 15 ] 16 } 17 ] 18}

The command hello (lines 6-14) will print the Hello World in the console output (line 9). The help section is used to document the command (line 12).

When you run aux4 in the same folder where the .aux4 file is, it lists all available commands.

1> aux4
1hello 2say hello world

To execute your command, just run aux4 hello.

1> aux4 hello
1Hello World

Using Variables

Now we can make our Hello World example a little more personal.

We can include the firstName and lastName in the greeting message (line 9).

In the help section, we also can document those variables, so we don't forget in the future (lines 13-23).

1{ 2 "profiles": [ 3 { 4 "name": "main", 5 "commands": [ 6 { 7 "name": "hello", 8 "execute": [ 9 "echo 'Hello ${firstName} ${lastName}!'" 10 ], 11 "help": { 12 "text": "say hello", 13 "variables": [ 14 { 15 "name": "firstName", 16 "text": "the first name to say hello" 17 }, 18 { 19 "name": "lastName", 20 "text": "the last name to say hello", 21 "default": "" 22 } 23 ] 24 } 25 } 26 ] 27 } 28 ] 29}

I hope you noticed the difference between those variables. For the lastName variable, we defined a default value for it (line 21). By adding a default value (even an empty string), the CLI will not prompt for that variable when it is not provided.

If you run aux4 command, it will display a short documentation on your command, and also the list of variables.

1> aux4
1hello 2say hello 3 --firstName 4 --lastName

However, when you run aux4 --help, it will display the full documentation, including the description of each variable.

1> aux4 --help
1hello 2say hello 3 4 --firstName 5 the first name to say hello 6 7 --lastName 8 the last name to say hello 9 10 Default:

Now you can run your command passing the variables.

1> aux4 hello --firstName Douglas --lastName Crockford
1Hello Douglas Crockford!

Maybe you're wondering what happens if you run without the variables. It will prompt the user to input the value for the required variables.

1> aux4 hello
1✔ the first name to say hello: |

Since we defined a default value for lastName, it will not prompt the user.

1> aux4 hello
1✔ the first name to say hello: David 2Hello David !

But you still can manually pass the value for that:

1> aux4 hello --lastName SG
1✔ the first name to say hello: David 2Hello David SG!

Parsing JSON

If you work with data or APIs, parsing and extracting data from JSON is inevitable. aux4 has a built-in tool to parse JSON. Let's see how easy it is to use.

Let's say we want to create a command that will extract the version from the package.json file.

1{ 2 "version": "1.0" 3}

By using the json: executor prefix, it automatically parses the output of the command to JSON (line 9).

You can always get the output of the previous command using the response variable ${response}, in this case the value will be a JSON object instead of string (line 10).

1{ 2 "profiles": [ 3 { 4 "name": "main", 5 "commands": [ 6 { 7 "name": "get-version", 8 "execute": [ 9 "json:cat package.json", 10 "echo 'version ${response.version}'" 11 ], 12 "help": { 13 "text": "get the version from package.json" 14 } 15 } 16 ] 17 } 18 ] 19}

When you run the command, it will display the version.

1> aux4 get-version
1version 1.0

I know you want to make it fancier. So we can change it to read the JSON from an URL instead of local file.

We just need to use curl -s to get the data from the URL (line 9), and include the variable in the documentation (lines 14-19).

1{ 2 "profiles": [ 3 { 4 "name": "main", 5 "commands": [ 6 { 7 "name": "get-version", 8 "execute": [ 9 "json:curl -s ${url}", 10 "echo 'version ${response.version}'" 11 ], 12 "help": { 13 "text": "get the version from package.json", 14 "variables": [ 15 { 16 "name": "url", 17 "text": "the url of the package" 18 } 19 ] 20 } 21 } 22 ] 23 } 24 ] 25}

Now when you run the command, it will display the version from the URL.

1> aux4 get-version --url https://raw.githubusercontent.com/heroku/node-js-sample/master/package.json
1version 0.2.0

Confirmation Prompt

Depending on what the command-line does, it's important to make sure the user really wants to execute it.

aux4 has a built-in confirmation prompt using the confirm: executor. You just need to provide the message to the user (line 9).

1{ 2 "profiles": [ 3 { 4 "name": "main", 5 "commands": [ 6 { 7 "name": "execute", 8 "execute": [ 9 "confirm:Are you sure you want to execute it in ${env}", 10 "echo 'Executing in ${env}...'" 11 ], 12 "help": { 13 "text": "execute the command in the specified environment", 14 "variables": [ 15 { 16 "name": "env", 17 "text": "the environment to execute the command" 18 } 19 ] 20 } 21 } 22 ] 23 } 24 ] 25}

Once you run the command, it will prompt the confirmation to the user.

1> aux4 execute --env PROD
1? Are you sure you want to execute it in PROD? [y/N] |

If the user says yes, it will proceed the execution.

1Are you sure you want to execute it in PROD: y 2Executing in PROD...

If the user says no, it will abort the execution.

1Are you sure you want to execute it in PROD: N 2User aborted

For Each

Let's iterate over this. We both know there are better ways to do it, but let's use a simple use case to make it very clear to everybody how to use this tool.

We are going to create a command to count the lines of each .txt file.

First, we just list the *.txt files using ls (line 9). Note that we are using a nout: executor prefix. This means we don't want to print the output of that command. nout stands for no output.

Second, we will iterate over the previous output, and for each file using the each: executor, we are going to count its lines (line 10).

1{ 2 "profiles": [ 3 { 4 "name": "main", 5 "commands": [ 6 { 7 "name": "count-lines", 8 "execute": [ 9 "nout:ls *.txt", 10 "each:wc -l ${item}" 11 ], 12 "help": { 13 "text": "count the number of lines in each text file" 14 } 15 } 16 ] 17 } 18 ] 19}

We can run the command, assuming you have .txt files in the directory, it should show their number of lines.

1> aux4 count-lines
1 3 f1.txt 2 1 f2.txt 3 5 f3.txt

How does each work? It's always based on the previous command output. If the output is text, it will iterate over the lines. If the output is a JSON array, it will iterate over the elements of the array.

Assuming we have people.json file, with an array of people with their names and ages.

1[ 2 { 3 "name": "Sarah", 4 "age": 30 5 }, 6 { 7 "name": "Joshua", 8 "age": 40 9 }, 10 { 11 "name": "Noah", 12 "age": 50 13 } 14]

We can create a command to list the people and show how old they are.

1{ 2 "profiles": [ 3 { 4 "name": "main", 5 "commands": [ 6 { 7 "name": "list-people", 8 "execute": [ 9 "json:cat people.json", 10 "each:echo '${item.name} is ${item.age} years old'" 11 ], 12 "help": { 13 "text": "list the people in the people.json file" 14 } 15 } 16 ] 17 } 18 ] 19}

In this case, we parse the JSON on line 9, and for each element we print the name and age (line 10).

1> aux4 list-people
1Sarah is 30 years old 2Joshua is 40 years old 3Noah is 50 years old

Multiple Profiles

Okay, it's time to make things more interesting. In this scenario, we will create two commands to call two REST API endpoints.

As a matter of organization, we will create one profile for the REST API (lines 17-59), to keep the commands isolated. We can add one command for each endpoint:

  • get-person (lines 20-38)
  • get-person-transactions (lines 39-57)

The main profile is required (lines 3-16). So, we can include a command called api that redirects to the profile api using the profile: executor (line 9).

1{ 2 "profiles": [ 3 { 4 "name": "main", 5 "commands": [ 6 { 7 "name": "api", 8 "execute": [ 9 "profile:api" 10 ], 11 "help": { 12 "text": "the company api" 13 } 14 } 15 ] 16 }, 17 { 18 "name": "api", 19 "commands": [ 20 { 21 "name": "get-person", 22 "execute": [ 23 "curl -s https://${env}-mycompanyapi.com/person/${id}" 24 ], 25 "help": { 26 "text": "get person's information", 27 "variables": [ 28 { 29 "name": "env", 30 "text": "the api environment" 31 }, 32 { 33 "name": "id", 34 "text": "the person id" 35 } 36 ] 37 } 38 }, 39 { 40 "name": "get-person-transactions", 41 "execute": [ 42 "curl -s https://${env}-mycompanyapi.com/person/${id}/transactions" 43 ], 44 "help": { 45 "text": "get all the person's transactions", 46 "variables": [ 47 { 48 "name": "env", 49 "text": "the api environment" 50 }, 51 { 52 "name": "id", 53 "text": "the person id" 54 } 55 ] 56 } 57 } 58 ] 59 } 60 ] 61}

When you run aux4, it will show the api command from the main profile.

1> aux4
1api 2the company api

But when you run aux4 api, it will list the commands from the api profile.

1> aux4 api
1get-person 2get person's information 3 --env 4 --id 5 6get-person-transactions 7get all the person's transactions 8 --env 9 --id

In this case, if you want to get the person's information, you can call the command. This is a great way to organize your commands, grouping them in a way that makes more sense to your business.

1> aux4 api get-person --env dev --id 120
1{ 2 "id": 120, 3 "name": "Simon" 4}

Nested Folders

aux4 loads the .aux4 files from all parent directories and combines them automatically. Considering you have the following structure:

  • /home/user
    • /.aux4
    • /data
      • /.aux4

Imagine the /home/user/.aux4 file is the same we used in the previous example (Multiple Profiles).

Let's say we want to include another command to the api profile, but we just want to see that when we are in the data folder. So we can add to the /home/user/data/.aux4 file:

1{ 2 "profiles": [ 3 { 4 "name": "api", 5 "commands": [ 6 { 7 "name": "another-command", 8 "execute": [ 9 "echo 'another api endpoint'" 10 ], 11 "help": { 12 "text": "another api call" 13 } 14 } 15 ] 16 } 17 ] 18}

I hope you noticed that we didn't include the main profile in this case. Because it already loaded it from the parent directory.

In this way, when we run aux4 api from the /home/user/data/ directory. We can see the extra command.

1> aux4 api
1get-person 2get person's information 3 --env 4 --id 5 6get-person-transactions 7get all the person's transactions 8 --env 9 --id 10 11another-command 12another api call

However, if you want to add extra commands, that is not under the api profile. You still can include them to the main profile (lines 3-16).

1{ 2 "profiles": [ 3 { 4 "name": "main", 5 "commands": [ 6 { 7 "name": "hello", 8 "execute": [ 9 "echo 'Hello World!'" 10 ], 11 "help": { 12 "text": "say hello" 13 } 14 } 15 ] 16 }, 17 { 18 "name": "api", 19 "commands": [ 20 { 21 "name": "another-command", 22 "execute": [ 23 "echo 'another api endpoint'" 24 ], 25 "help": { 26 "text": "another api call" 27 } 28 } 29 ] 30 } 31 ] 32}

Now if you run again aux4 from /home/user/data directory. It will list both commands hello and api.

1> aux4
1hello 2say hello 3 4api 5the company api