TIL: Gradle tasks and doLast

I’ve known about custom Gradle tasks and functions for a while (Android Studio). I’ve used one, copied from SO and edited to suit my needs, in one of my projects before. This week I got to create a task from scratch to add a dev feature to the app at work. So far so good.

This TIL is not about learning about Gradle tasks. This is about a tiny detail that I didn’t know. I usually write/see tasks written like this

task countChicken {
    // count chicken
    ...
}

When written like this, the chicken are counted immediately every time the Gradle project is synced or built (task configuration).

What I had not known till this week was that anything directly inside that task definition block is executed at the task configuration stage. So, in this case the whole counting of chicken is happening at the task configuration stage, whether we explicitly execute the task or not.

If we only want to execute the task on demand, the task configuration needs to be separated from execution, like so:

task countChicken {
    doLast {
        // count chicken
        ...
    }
}

The doLast ensures that this code block is only executed during task execution. It basically tells Gradle during configuration to run this code block last while executing this task1. We can also use the doFirst code block to run something first while executing the task. Continue reading

TIL: VS Code tasks and bash scripts

I use Hugo for some static pages on the website. I wanted to convert some common actions that take a couple of steps into a single command. The one I tacked now is to create a new ‘Book’ page template in Hugo and open it in the editor. It’s a simple action, but took me a bit to figure out the basic stuff.

1. Create a VSCode task to execute the commands without opening terminal.

If the workspace doesn’t have a ‘tasks.json‘ already, create one
Press 'F1' - my shortcut key for "Show all commands" Select "Run task", and follow the prompts to create a new task. Select "Other" when selecting task type. VSCode will create a 'tasks.json'  file with a single task that prints 'Hello' on the command line.
If there’s already a ‘tasks.json‘ in the workspace folder, add a new task

Simplest way is to just copy a previous task and change details – label, type, command, args, problemMatcher, etc

2. Configure task and inputs

Label is just the name for the task.

"label": "New Book"

Type is the command type. In my case, this was just ‘shell

"type": "shell"

For command, we’ll just point to the shell script. I use VSC’s in-built variable, ‘${workspaceFolder}‘ to mark the path to the script.

"command": "${workspaceFolder}/pages/makebooks.sh"

I provided two arguments to the shell script—the workspace folder path and the name of the book to create.

"args": [
    "${workspaceFolder}",
    "${input:bookName}"
]

Finally, since I was using a user input ‘input:bookName‘, I had to create an inputs section too.

"inputs": [{
    "id": "bookName",
    "type": "promptString",
    "description": "Name of the book, please:",
    "default": "A book"
}]

Here, id is the variable name of the input which we can use to reference it in the task section. type is the type of input. It can be a promptString asking user to type a string, a pickString providing user options to choose from, or a command which runs a command and returns the output as input. description is the prompt shown to the user when input is asked, and default is the default input.

That’s the task creation done. I still have to make the actual shell script to execute, but this bit is done.

3. Create a shell script to execute when the task is run

Create a new file with the name and path chosen in ‘command‘ section above. Also make the shell script executable.

Now open the shell script in VSC, and make it do the work.

First, just switch to the subfolder where hugo related content is kept.

cd "$1"/pages

$1 is the first argument to the script, which in our case is the first item in the ‘args‘ provided in the task description—the home folder of the VSC workspace.

TIL: Escape inputs with "" to send them to other commands.
It took me a bit of googling to figure out that the easiest way to take user inputs and pass them, escaped, to other commands is to just enclose them in "". Specially, like in my case when there are spaces in book names or paths.
Another alternative that didn’t work for me was using printf: printf -v bookName "%q" $2. This will escape the $2 arg and save it in variable bookName.

Next, create the new books page:

hugo new books/"$2".md

Now, check if the command succeeded (it fails if a book with that name already exists).

if [ $? -eq 0 ]; then

If it succeeded, open the book file for editing:

code content/books/"$2".md

TIL

  • Using $? to get the exit code of the last command. 0 means successfully completed, anything higher means failure.
  • How to use the shell if-then-else
  • Using test with the [...] syntax

That’s it. We’re done. Now when I need to create a new book page, all I do is press F1, select Run task, type in the book name, and it opens a new page with the template for the book.

Continue reading