# `mksite` A file format-agnostic static site generator ## Installation If you already have [Rust](https://www.rust-lang.org) and [Cargo](https://doc.rust-lang.org/cargo/) installed: ```sh cargo install mksite ``` Alternatively, you can install via git: ```sh cargo install --git https://github.com/alterae/mksite ``` ## Usage ```help mksite Commands: build Build the site according to `mksite.toml` clean Delete all build outputs init Initialize a `mksite.toml` file in the current directory new Scaffold an empty site in a new directory help Print this message or the help of the given subcommand(s) Options: -q, --quiet Do not print log messages --log-level What level of logging to enable (error, warn, info, debug, or trace) [default: info] -h, --help Print help information -V, --version Print version information ``` `mksite` is a program for turning a tree of text files into a different tree of text files, usually a website. A typical `mksite` project has the following structure: - **`mksite.toml`** — The [`mksite.toml` file](#config) is the core of a project, and defines the names of the other significant directories, the data available to templates, and the [transforms](#transforms) to apply to files. - **`layout/`** _(optional)_ — The `layout/` directory contains [layouts](#layouts), such as html boilerplate, to be applied to files after they are transformed. If you don't want any layouts, or don't want to use `mksite`'s layout system, this folder can be safely omitted. The name of the `layout/` directory can be customized in `mksite.toml`. - **`out/`** _(generated)_ — The `out/` directory is generated by `mksite` when the site is built, and contains the transformed contents of the `src/` directory, as well as the contents of the `static/` directory, copied as-is. The name of the `out/` directory can be customized in `mksite.toml`. - **`src/`** — The `src/` directory holds all the non-static source files for the website. Files in `src` must be valid UTF-8 and can contain template expressions using the [Tera](https://tera.netlify.app) templating language. Other than that, they can be anything: LaTex, HTML, Markdown, your own custom markup language, or something else entirely. The name of the `src/` directory can be customized in `mksite.toml`. - **`static/`** _(optional)_ — The `static/` directory contains static files, such as stylesheets or images, which are copied as-is to the `out/` directory. No templating or transformation occurs. The name of the `static/` directory can be customized in `mksite.toml`. ### Config An example `mksite.toml` file looks like this: ```toml dirs.src = "src" dirs.out = "out" dirs.static = "static" dirs.layout = "layout" [data] author = { name = "Jane Doe", email = "email@example.com" } copyright = 2022 [transforms] md.html = "pandoc -f markdown -t html" scd.html = ["scdoc", "pandoc -f man -t html"] ``` The first four lines tell `mksite` the names of the `src/`, `out/`, `static/`, and `layout/` directories, respectively. Changing these will change where `mksite` reads and writes data. For example, `dirs.out = "www"` would cause `mksite` to write the build output in a folder called `www/`. Next is the **`data`** section, which is where you can define arbitrary data that will be passed to the template rendering. In templates, this data will be made available under the `data` variable. For details on the template syntax, see the [Tera documentation](https://tera.netlify.app/docs/). Finally, we have the **`transforms`** section. _Transforms_ are commands or chains of commands that take a stream of bytes on standard input, and return a stream of bytes for standard output. Transforms can be used to trivially implement many features `mksite` does not natively support, such as markdown rendering and syntax highlighting. The basic syntax of a transform definition is `in.out = "command"` or `in.out = ["command1", "command2", ...]` where `in` is the file extension the transform operates on, `out` is the file extension the transform produces, and `command` is a command to pipe the page through. For more details on the finer points of transforms, see [below](#transforms). All fields in this config file are optional. ### Layouts Layouts are simply Tera templates located in the `layout/` directory that accept an additional `page.content` variable. Layouts must be valid UTF-8, but aside from that they can be any format. An example layout file looks like this. ```html {{ page.content | safe }} ``` There are two kinds of layouts: default layouts and override layouts: _Override_ layouts have the same name, extension, and relative path as a specific file in the `out/` directory, and only apply to that file. For example, the layout `layout/blog/index.html` will only apply to the page `out/blog/index.html`. _Default_ layouts have the name `_.ext`, where `ext` is some file extension. Default layouts apply to all files in the corresponding directory and in nested directories that don't have a default layout. For example: ``` layout/ _.html blog/ _.html index.html ``` In this example, `layout/blog/_.html` will apply to all html files in `out/` _except_ `index.html`, and `layout/_.html` will apply to every html file in `out/` _except_ the contents of the `blog` directory. > **Note** > Layouts are applied _after_ transforms, based on the file extension of the transform output. As a result, a layout like `_.html` will apply to _all_ generated html files, regardless of whether these html files were hand-written or generated from markdown or something else via a transform. If no applicable layouts are found for a file, or if there is no `layout/` no layout will be applied. If an applicable layout exists, but you would like to prevent it from being applied to a file or folder, you can define an "empty" layout like so: ``` {{ page.content | safe }} ``` ### Transforms A transform has an _input extension_, an _output extension_, and a _command_ or _chain_ of commands. Each page in `src/` with a file extension matching a transform's input extension is piped into the transform as a stream of bytes, and the resulting stream of bytes is written to a file in the `out/` directory with the same name and path, and a file extension matching the transform's output extension. _Each page can be piped to multiple transforms, and multiple transforms can output the same format._ The relationship between inputs and outputs is many-to-many. > **Warning** > It is important to note that the inputs and outputs of transforms are _streams of arbitrary bytes_, not necessarily valid UTF-8 strings. This is important for interfacing with external non-rust tools, but there are some caveats: > > Though this may change in the future, at present all templates and layouts _must_ be valid UTF-8. This means that while transforms can both input and output arbitrary bytes, the original input to a transform (a file in the `src/` directory) will be UTF-8. Additionally, layouts for non-UTF-8 files **are not supported**, and attempting to define a layout for, say, a `.pdf` file will result in an error. If a transform has a single command, pages are piped to that command, and the output of the command is written to the output file. For example, these transforms: ```toml [transforms] md.html = "pandoc -f markdown" md.pdf = "pandoc -f markdown -t pdf" ``` Will use [pandoc](https://pandoc.org) to produce an html file and a pdf document in `out/` for every markdown file in `src/`. If a transform has a chain of commands, pages are piped to each command in the chain in order, and the ouput of the last command is written to the output file, like with shell pipelines. For example: ```toml [transforms] scd.html = ["scdoc", "pandoc -f man"] ``` Will use [`scdoc`](https://git.sr.ht/~sircmpwn/scdoc) to generate a man page from each `.scd` file, and immediately pipe that man page to `pandoc` to convert it to html. ## Contributing Pull requests and issues are welcome, but please ensure you run `cargo fmt` before submitting a PR. ## Example See the [`docs/`](./docs/) folder for an example of a website built using `mksite`. ## License `mksite` is licensed under the [MIT License](./LICENSE).