Skip to content

Latest commit

 

History

History
242 lines (194 loc) · 8.52 KB

File metadata and controls

242 lines (194 loc) · 8.52 KB

Boop! Documentation

When boop is ran it will look for a file in the current working directly named tasks.boop and execute the specified task from there.

Simple file globbing

Globs can return a selection of files:

{src/**/*.cpp}

or return a selection with the filenames altered:

{src/**/*.cpp as *.hpp}

additionally, if you have a filename in a variable, you can return an altered version of that:

{filename as *.bak}

You can use the each keyword to iterate over lists of things, or globs, inside of or outside of tasks:

each file in {src/**/*.cpp} {utils/**/*.cpp}
	task build
		provides {file}.o
		requires {file}
		run g++ {file} -o {file}.o {cxxflags}

task build
	run gcc -o {executable} {src/**/*.cpp as *.cpp.o} {lflags}

task clean
	each object in {src/**/*.o} {utils/**/*.o}
		run rm {object}

In the above, running the build task will run every task with that name, meaning every file will first get built (if out of date), and they will then be linked together by the final build task. A failure in any of the build tasks, will cause an abort.

Having a seperate build task within each glob iteration allows us to have a separate provides and requires clause for each task. Thus only the nested tasks which are out of date need to be executed each time.

In the case of the clean task this is not needed, so we can simply iterate all object files within the task and delete them directly.

Simple dependency checks and file checking

Tasks can have optional provides and requires values.

Provides should always refer to files generated by this task. Depends can specify filepaths, as direct values or tasks (if a task, they are written with the keyword task first, i.e. task build)

If a task has provides it will execute if any of provides files do not exist.

If a task has requires it will only execute if all of those requires files exist, and none of the requires tasks fail.

If a task has provides AND requires, it will also execute if any of the requires files are newer than the provides files.

Thus, a common task may look like:

task compile
	provides code.o
	requires code.cpp

	g++ code.cpp -o code.o

This will compile the C++ file if it isn't already compiled, or if the cpp file is newer, meaning the compilation is out of date.

Syntax

Codeblocks are whitespace indented. Tabs or spaces can be used. If mixed, 1 tab = 2 spaces.

Variable names can start with a letter or underscore, and may contain letters, numbers, underscores and dashes.

Flag names can be any non-whitespace sequence of characters, that does not contain an =

Task names can start with a letter or underscore, and may contain letters, numbers, underscores and dashes.

A value is any sequence of characters beginning with a non-whitespace character, and continues until the last non-whitespace character before the end of the line.
Quotes are not used.

Statements

set NAME = VALUE

Set a variable named NAME to VALUE.
The same variable can be set multiple times, and can reference its previous value in VALUE.
NAME can be any valid variable name.
VALUE can be any valid value.

flag NAME
  ...

Execute the code within only if this commandline flag was passed in.
NAME can be any valid flag name.

flag not NAME
  ...

Execute the code within only if this commandline flag wasn't passed in.
NAME can be any valid flag name.

each NAME in LIST
  ...

Iterate through every value in LIST, setting a local variable NAME to each iterated value, while executing the code within.
NAME can be any valid variable name.
LIST can be any valid value (space separated, but obeying shell escaping/quoting, to allow for spaces and special characters in items).

task NAME
  ...

Declare a task named NAME, containing the nested code.
The same task name can be used multiple times.
When a task is used all tasks by that name will be executed.
NAME can be any valid task name.

provides FILENAMES

Declares the current task as providing the specified filename(s).
This is only valid inside a task.
A task can contain multiple provides declarations.
FILENAMES is any valid value (space separated, but obeying shell escaping/quoting, to allow for spaces and special characters in filenames)

requires task TASKS

Declares the current task as depending on the specified task(s).
This is only valid inside a task.
A task can contain multiple requires declarations.
TASKS is any valid value (space separated if multiple)

requires optional task TASKS

Declares the current task as optionally depending on the specified task(s).
However, if these tasks fail, execution will still continue.
This is only valid inside a task.
A task can contain multiple requires declarations.
TASKS is any valid value (space separated if multiple)

requires FILENAMES

Declares the current task as depending on the specified filename(s).
This is only valid inside a task.
A task can contain multiple requires declarations.
FILENAMES is any valid value (space separated if multiple, with shell escaping rules for spaces and special characters)

cd PATH

Change the current run directory for the current task to the specified relative path.
This is only valid inside a task.
PATH is a valid relative path and the full path must resolve to a directory that exists.

cd -

Change the run directory for the current task to the previous path it was set to.
This is only valid inside a task.

run COMMAND ARGUMENTS...

Run the specified COMMAND with optional ARGUMENTS.
This is only valid inside a task.
COMMAND can be any valid value.
ARGUMENTS can be 0 or more of any valid value.

optional run COMMAND ARGUMENTS...

Attempt to optionally run the specified COMMAND with optional ARGUMENTS.
If the specified command fails, execution will still continue.
This is only valid inside a task.
COMMAND can be any valid value.
ARGUMENTS can be 0 or more of any valid value.

Expressions

Expressions can be embedded within values. They sit within {...}.
Expressions are evaluated immediately, using the current variable values at that point in code.
To embed variable values simple write the name within {}:

set noun1 = stranger
set verb1 = love
set verb2 = know
set noun2 = rules
set additional = so do I

set example = I'm no {noun1} to {verb1}. You {verb2} the {noun2} and {additional}

To access just the directory path of a variable containing a filepath use {NAME.dir}

To access just the filename of a variable containing a filepath, without the directory, use {NAME.file}

To access just the file extension of a variable containing a filepath, use {NAME.ext}

To access just the name of a filename, without any directory or extension use {NAME.name}

To retrieve a list of filenames, based on a search glob, use {GLOB}. All filenames will be space seperated:

each doc in {docs/**/*.md}
  ...

As lists are space-seperated (with spaces and special characters in filenames escaped/quoted), this also makes a glob valid to use as multiple program arguments:

run gcc -o program {src/**/*.c}

To retrieve a list of altered filenames, you can specify {GLOB as PATTERN}. This does not actually modify the files, it simply provides the names modified using the specified pattern:

set originals = {docs/**/*.md}
set olds = {docs/**/*.md as old-*}
set backups = {docs/**/*.md as *.bak}

To retrieve the result of an executed command, you can use the syntax {eval COMMANDLINE}:

set params = {eval pkg-config --cflags --libs gtk+-3.0}

If the command returns successfully, the output of this command will be returned.
If it returns unsuccessfully, an error will be printed to the console and an empty ("") value will be returned.

If you wish to use the { } characters within a command (for example, if running awk and passing parameters to it), you can escape these characters by writing them twice:

run awk '{{print $0}}' {file}

Building/Hacking Boop!

Boop is written in TypeScript and runs on Deno.
To execute it manually, simply install Deno and run via Deno, enabling read, write, env and run access:
(you can also use the included shellscript, boop)

> deno run --allow-read --allow-write --allow-env --allow-run boop.ts ...

Or install it using the Deno install command and simply run it from whereever by calling boop:

> deno install --allow-read --allow-write --allow-env --allow-run boop.ts ...