bootstrap/README.md

239 lines
7.3 KiB
Markdown
Raw Normal View History

2023-11-23 18:02:40 +00:00
# bootstrap
2023-11-25 19:43:41 +00:00
CLI utility for defining custom project initialization scripts.
## Overview
2023-11-25 19:43:41 +00:00
`bootstrap` is a tool for quickly defining your own init-like scripts. If you
are familiar with tools like
* `npm init`
* `nix flake init`
* `django-admin startproject`
* `mix phx.new`
* etc.
2023-11-25 19:43:41 +00:00
this project will feel at home. Ultimately the goal is to create (optionally)
interactive scripts like those mentioned in the above list to quickly scaffold
your new projects in a consistent way.
2023-11-25 22:25:01 +00:00
---
2023-11-25 19:43:41 +00:00
We start with an example. Consider the following *spec*, which we'll name
2023-11-25 22:25:01 +00:00
`touch` (this example exists as a [pre-packaged spec](./specs/touch)):
2023-11-25 19:43:41 +00:00
```json
{
2023-11-25 19:43:41 +00:00
"filename": {
2023-11-25 22:25:01 +00:00
"type": "text",
2023-11-25 19:48:21 +00:00
"prompt": "What file should I create for you? "
2023-11-25 19:43:41 +00:00
}
}
```
2023-11-25 22:25:01 +00:00
and its associated *runner*:
2023-11-25 19:43:41 +00:00
```bash
#!/usr/bin/env bash
echo "Creating $FILENAME"
touch "$OUT/$FILENAME"
```
Running `bootstrap` with these two files configured will invoke the following
interactive script:
```bash
2023-11-25 22:25:01 +00:00
$> bootstrap touch
What file should I create for you? hello-world.txt
Creating hello-world.txt
$> ls
... hello-world.txt ...
2023-11-25 19:43:41 +00:00
```
2023-11-25 22:25:01 +00:00
You should now see a new `hello-world.txt` file in your current working
2023-11-25 19:48:21 +00:00
directory.
2023-11-26 20:49:07 +00:00
## Installation
### Nix
It is recommended you use Nix to install `bootstrap`. If using a flake, specify
`bootstrap` as an `inputs` attribute the normal way. Otherwise, if you have a
new enough version of nix, import the executable like so:
```nix
2023-11-26 20:57:22 +00:00
(builtins.getFlake "github:jrpotter/bootstrap/${version}").packages.${system}.default;
2023-11-26 20:49:07 +00:00
```
If flakes is not enabled or your nix version does not support
`builtins.getFlake`, you can instead use:
```nix
(import (pkgs.fetchFromGitHub {
owner = "jrpotter";
repo = "bootstrap";
2023-11-26 20:57:22 +00:00
rev = "${version}";
sha256 = "${sha256}";
2023-11-26 20:49:07 +00:00
})).packages.${system}.default;
```
2023-11-26 20:49:07 +00:00
### Source
2023-11-25 19:43:41 +00:00
2023-11-26 20:49:07 +00:00
If you do not have Nix or prefer building from source, clone this repository and
run
```bash
$> make BUILD=release
```
The `bootstrap` binary will be made available in `dist/release` by default.
Keep in mind, there is no default `BOOTSTRAP_ROOT_DIR` environment variable
value set in this case so either set this to the path of some `specs` directory
or always use the `-d` flag when running `bootstrap`.
## Usage
2023-11-25 19:43:41 +00:00
2023-11-25 22:25:01 +00:00
### Runners
2023-11-25 19:43:41 +00:00
2023-11-25 22:25:01 +00:00
A spec refers to any directory containing a file named `runner`. The only
requirement enforced by `bootstrap` is for this file to be an executable (e.g.
`chmod +x`), but typically the `runner` is a shell script:
```bash
#!/usr/bin/env bash
...
```
The `runner` is invoked with its current working directory set to that of the
directory containing it. For instance, if we have a `runner` script living in
directory `~/Documents/specs/example` with contents:
```bash
#!/usr/bin/env bash
echo "$PWD"
```
the output of `bootstrap example` will *always* be e.g.
```bash
> bootstrap example
/home/jrpotter/Documents/specs/example
```
regardless of where we call the `bootstrap` command.
#### Exit Code
`bootstrap` always invokes the `runner` using the system `sh` command:
```bash
> /bin/sh sh -c ./runner
```
The exit code emitted by `bootstrap` will mirror that returned by the `runner`
executable.
### Specs
If interested in making the `runner` more flexible, you can provide different
environment variables in the form of a `spec.json` file. This file must live
in the same spec as the `runner`. When invoking `bootstrap`, the file is used to
determine what prompts should be displayed to the user before executing the
`runner` file. The user's responses are then included as environment variables
to the `runner` process.
The file contents should consist of a top-level JSON object and any number of
child objects called *fields*. A typical `spec.json` file looks like:
```json
{
"fieldname": {
"type": "text",
"prompt": "Prompt for field> "
},
...
}
```
In this example, the first field is called `"fieldname"`. `bootstrap` sees this
field and writes the prompt `"Prompt for field> "` to `stdout`. Since
`"fieldname"` has type `"text"`, `bootstrap` will wait for the user to input
a string (submitted with a newline).
If the user were to enter `fieldvalue` in response to the prompt, the `runner`
script would then have access to an environment variable `FIELDNAME` set to
`fieldvalue`. Field names should respect the [POSIX standard](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html)
on environment variable naming. In particular, all field names consist solely
of alphanumeric characters or underscores and cannot start with a digit.
2023-11-25 22:25:01 +00:00
#### Types
The value of `type` determines how a field is prompted for. Note the value of
`type` is case insenstive. The currently supported list of types are:
* `text`
* The simplest prompt type. Takes in a free-form response submitted after a
newline (`\n`) is encountered.
#### Root Directory
All specs should exist in the same *root directory*. As an example of what this
directory might look like, refer to `specs` at the top-level of this project.
When invoking `bootstrap <name>`, `<name>` is expected to correspond to some
spec found within the root directory.
To tell `bootstrap` where your specs are located, you can provide the path to
the root directory using the `-d` option like so:
```bash
> bootstrap -d ~/Documents/specs example
...
```
If no option is set, `bootstrap` will fallback to using the value of the
`BOOTSTRAP_ROOT_DIR` environment variable. If this also isn't set, `bootstrap`
will abort with an appropriate error message.
2023-11-25 19:43:41 +00:00
### Other Environment Variables
2023-11-25 22:25:01 +00:00
By default, the `runner` command will have the following environment variables
defined. Defining these fields in a `spec.json` file will override the default
values:
2023-11-25 19:43:41 +00:00
2023-11-25 22:25:01 +00:00
* `OUT`
* The directory `bootstrap` was invoked from. Named since this is usually
where you want to initialize new files of your project in.
2023-11-25 19:43:41 +00:00
2023-11-25 22:25:01 +00:00
### Supplied Specs
2023-11-25 19:43:41 +00:00
2023-11-25 22:25:01 +00:00
A number of specs are provided out of the box. If you installed `bootstrap`
using `nix`, the `BOOTSTRAP_ROOT_DIR` will automatically be set to the location
of these [specs](./specs). Keep in mind this list is very opinionated - they
reflect my personal needs for projects. Feel free to specify a different specs
root directory if these do not fit your needs.
2023-11-25 19:43:41 +00:00
2023-11-25 22:25:01 +00:00
As a suggestion, use `nix` from within your `runner` scripts for maximum
reproducibility. Refer to the provided specs for inspiration on how you can do
this.
2023-11-23 15:21:50 +00:00
## Development
2023-11-26 15:43:57 +00:00
This tool was originally written for personal usage and, as such, any
functionality (or lack thereof) reflects my own needs as I have come across
them. If interested in adding more capabilities, please send a PR or just fork
the project for your own purposes.
2023-11-25 19:43:41 +00:00
### Testing
2023-11-26 15:43:57 +00:00
We use [Sput](https://www.use-strict.de/sput-unit-testing/) for unit tests. To
run tests, type:
```bash
$> make test
```
Tests are located in the `test` directory. `test/suites.c` serves as the
entrypoint for the test runner.
2023-11-25 19:43:41 +00:00
### Documentation
We use [doxygen](https://www.doxygen.nl/index.html) for documentation
generation. Run either of the following two commands to generate documentation
locally:
```bash
$> make docs
$> doxygen
```
2023-11-23 15:21:50 +00:00
### Formatting
We use `clang-format` to ensure consistent formatting. A `pre-commit` file is
included in `.githooks` to enforce usage. Run the following to configure `git`
to use it:
2023-11-23 15:21:50 +00:00
```bash
git config --local core.hooksPath .githooks/
```
If running [direnv](https://direnv.net/), this is done automatically upon
entering the project directory.