1
1
mirror of https://github.com/tweag/nickel.git synced 2024-11-10 19:09:08 +03:00
nickel/README.md

246 lines
9.7 KiB
Markdown
Raw Normal View History

# Nickel
2021-04-19 13:09:51 +03:00
[![Continuous integration](https://github.com/tweag/nickel/workflows/Continuous%20integration/badge.svg)](https://github.com/tweag/nickel/actions?query=branch%3Amaster)
[![Website](https://img.shields.io/website-up-down-green-red/http/cv.lbesson.qc.to.svg)](https://nickel-lang.org)
2021-04-19 13:09:51 +03:00
Nickel is the cheap configuration language.
Its purpose is to automate the generation of static configuration files - think
JSON, YAML, XML, or your favorite data representation language - that are then
fed to another system. It is designed to have a simple, well-understood core: it
is in essence JSON with functions.
Nickel's salient traits are:
- **Lightweight**: Nickel is easy to embed. An interpreter should be simple to
implement. The reference interpreter can be called from many programming
languages.
- **Composable code**: the basic building blocks for computing are functions.
They are first-class citizens, which can be passed around, called and
composed.
- **Composable data**: the basic building blocks for data are records
(called *objects* in JSON). In Nickel, records can be merged at will,
including associated metadata (documentation, default values, type
contracts, etc).
- **Typed, but only when it helps**: static types improve code quality, serve as
documentation and eliminate bugs early. But application-specific
self-contained code will always evaluate to the same value, so type errors
will show up at runtime anyway. Some JSON is hard to type. There, types are
only a burden. Whereas reusable code - that is, *functions* - is evaluated
on potentially infinitely many different inputs, and is impossible to test
exhaustively. There, types are precious. Nickel has types, but you get to
2021-10-29 03:06:18 +03:00
choose when you want it or not, and it handles safely the interaction between
the typed and the untyped world.
- **Design by contract**: complementary to the type system, contracts are
a principled approach to checking assertions. The interpreter automatically
inserts assertions at the boundary between typed and untyped code. Nickel
lets users add arbitrary assertions of their own and easily understand why
2021-04-19 13:09:51 +03:00
when assertions fail.
2020-07-30 14:36:49 +03:00
The motto guiding Nickel's design is:
> Great defaults, design for extensibility
There should be a standard, clear path for common things. There should be no
arbitrary restrictions that limit what you can do you the one day you need to go
beyond.
2020-07-30 14:36:49 +03:00
## Use cases
2021-10-29 03:06:18 +03:00
Nickel is a good fit in any situation where you need to generate a complex
configuration, be it for a single app, a machine, whole infrastructure, or a
2020-07-30 14:36:49 +03:00
build system.
The motivating use cases are in particular:
2022-08-04 18:31:21 +03:00
2020-07-30 14:36:49 +03:00
- The [Nix package manager](https://nixos.org/): Nix is a declarative package
manager using its own language for specifying packages. Nickel is an
evolution of the Nix language, while trying to overcome some of its
limitations.
- Infrastructure as code: infrastructure is becoming increasingly complex,
requiring a rigorous approach to deployment, modification and configuration.
This is where a declarative approach also shines, as adopted by
[Terraform](https://www.terraform.io/),
2020-07-30 14:36:49 +03:00
[NixOps](https://github.com/NixOS/nixops) or
[Kubernetes](https://kubernetes.io/), all requiring potentially complex
generation of configuration.
- Build systems: build systems (like [Bazel](https://bazel.build/)) need
a specification of the dependency graph.
2020-07-30 14:36:49 +03:00
Most aforementioned projects have their own bespoke configuration language. See
2022-08-04 18:31:21 +03:00
[Related projects and inspirations](#related-projects-and-inspirations). In
general, application-specific languages might suffer from feature creep, lack of
abstractions or just feel ad hoc. Nickel buys you more for less.
2020-07-30 14:36:49 +03:00
## Getting started
Please follow the getting started guide for Nickel users on the [nickel-lang
website](https://nickel-lang.org/getting-started). The instructions below are
either reproduced for this document to be relatively self-sufficient, or because
they are aimed toward hacking on the Nickel interpreter itself (e.g. building
the `nickel-lang` crate documentation).
2020-07-30 14:36:49 +03:00
### Run
2021-05-31 15:28:33 +03:00
1. Start Nickel
2022-08-04 18:31:21 +03:00
- with [flake-enabled](https://nixos.wiki/wiki/Flakes) Nix directly
with `nix run nickel` (which pulls it from the global flakes
registry), or with `nix run github:tweag/nickel` (which pulls it
from the repo). You can use [our binary cache](https://nickel.cachix.org) to
prevent rebuilding a lot of packages. You pass in arguments with
an extra `--` as in `nix run nickel -- repl`,
2022-08-04 18:31:21 +03:00
- with `./nickel`, after [building](#build) this repo, depending on the
2021-05-31 15:34:40 +03:00
location of the executable and passing in arguments directly,
2022-08-04 18:31:21 +03:00
- or with `cargo run` after [building](#build), passing in arguments with
2021-11-17 21:08:14 +03:00
an extra `--` as in `cargo run -- -f program.ncl`.
2020-07-30 14:36:49 +03:00
2. Run your first program:
2022-08-04 18:31:21 +03:00
```console
$ ./nickel <<< 'let x = 2 in x + x'
4
```
Or load it from a file:
```console
$ echo 'let s = "world" in "Hello, " ++ s' > program.ncl
$ ./nickel -f program.ncl
"Hello, world"
```
3. Start a REPL:
2021-03-29 11:36:54 +03:00
2022-08-04 18:31:21 +03:00
```console
$ ./nickel repl
nickel> let x = 2 in x + x
4
nickel>
```
2022-08-04 18:31:21 +03:00
Use `:help` for a list of available commands.
2021-03-29 11:36:54 +03:00
4. Export your configuration to JSON, YAML or TOML:
2022-08-04 18:31:21 +03:00
2021-08-23 14:56:25 +03:00
```console
$ ./nickel export --format json <<< '{foo = "Hello, world!"}'
2021-03-29 11:36:54 +03:00
{
"foo": "Hello, world!"
}
```
2021-03-31 12:48:57 +03:00
Use `nickel help` for a list of subcommands, and `nickel help <subcommand>`
2021-03-29 11:36:54 +03:00
for help about a specific subcommand.
2020-07-30 14:36:49 +03:00
2022-01-18 20:22:57 +03:00
#### Editor Setup
2022-08-04 18:31:21 +03:00
Nickel has syntax highlighting plugins for Vim/Neovim, and VSCode. In-editor
diagnostics, type hints, and auto-completion are provided by the Nickel Language
Server. Please follow
[this guide](https://github.com/tweag/nickel/tree/master/lsp) to setup syntax
highlighting and NLS.
2022-01-18 20:22:57 +03:00
2021-04-30 22:47:41 +03:00
### Build
[rust-guide]: https://doc.rust-lang.org/cargo/getting-started/installation.html
1. Download build dependencies:
2022-08-04 18:31:21 +03:00
2021-04-30 22:47:41 +03:00
- **With Nix**: If you have [Nix](https://nixos.org/nix) installed:
2022-08-04 18:31:21 +03:00
2021-08-23 14:56:25 +03:00
```console
2022-08-04 18:31:21 +03:00
nix-shell shell.nix
2021-04-30 22:47:41 +03:00
```
2022-08-04 18:31:21 +03:00
to be dropped in a shell, ready to build. You can use [our binary
2022-08-04 18:31:21 +03:00
cache](https://nickel.cachix.org) to prevent rebuilding a lot of packages.
2021-04-30 22:47:41 +03:00
- **Without Nix**: otherwise, follow [this guide][rust-guide] to install Rust
and Cargo first.
2022-08-04 18:31:21 +03:00
2022-01-01 10:07:16 +03:00
1. Build Nickel:
2022-08-04 18:31:21 +03:00
2021-08-23 14:56:25 +03:00
```console
2022-08-04 18:31:21 +03:00
cargo build
2021-04-30 22:47:41 +03:00
```
2022-08-04 18:31:21 +03:00
2021-04-30 22:47:41 +03:00
And voilà! Generated files are placed in `target/debug`.
1. *(optional)* make a symbolic link to the executable:
2022-08-04 18:31:21 +03:00
2021-08-23 14:56:25 +03:00
```console
2022-08-04 18:31:21 +03:00
ln -S nickel target/debug/nickel
2021-04-30 22:47:41 +03:00
```
2020-07-30 14:36:49 +03:00
### Tests
2021-08-23 14:56:25 +03:00
```console
2022-08-04 18:31:21 +03:00
cargo test
2020-07-30 14:36:49 +03:00
```
### Documentation
The user manual is available [on the nickel-lang.org
website](https://nickel-lang.org/user-manual/introduction), and in this
repository as a collection of Markdown files in `doc/manual`.
To get the documentation of the `nickel-lang` codebase itself:
2020-07-30 14:36:49 +03:00
1. Build the doc:
2022-08-04 18:31:21 +03:00
```console
cargo doc --no-deps
```
2020-07-30 14:36:49 +03:00
2. Open the file `target/doc/nickel/index.html` in your browser.
### Examples
2022-03-08 11:27:29 +03:00
You can find examples in the [`./examples`](./examples) directory.
## Current state and roadmap
Nickel has been released in version `0.1`. This version should be functional, it
is intended to gather feedback and real-life testing. Nickel `0.1` isn't intended
to be used in production. The next steps we plan to work on are:
- Nix integration: being able to seamlessly use Nickel to write shells, packages
and NixOS modules.
- Custom merge functions and priorities (second part of the
2022-03-14 15:35:31 +03:00
[overriding proposal](https://github.com/tweag/nickel/blob/9fd6e436c0db8f101d4eb26cf97c4993357a7c38/rfcs/001-overriding.md))
2022-03-08 11:27:29 +03:00
- Performance improvements
2020-07-30 14:36:49 +03:00
## Related projects and inspirations
2022-05-21 01:44:59 +03:00
- [CUE](https://cuelang.org/) is a configuration language with a focus on data
validation. It introduces a new constraint system backed by a solid theory
2020-07-30 14:36:49 +03:00
which ensures strong guarantees about your code. It allows for very elegant
schema specifications. In return, the cost to pay is to abandon functions
and
[Turing-completeness](https://en.wikipedia.org/wiki/Turing_completeness).
Nickel's merge system is inspired by the one of CUE, even if since Nickel
does have general functions and is Turing-complete, they are necessarily
different.
- [Nix](https://nixos.org/): The Nix language, or *Nix expressions*, is one of
the main inspirations for Nickel. It is a very simple yet powerful lazy
2020-07-30 14:36:49 +03:00
functional language. We strive to retain this simplicity, while adding
typing capabilities, modularity, and detaching the language from the Nix
package manager.
- [Dhall](https://dhall-lang.org/) is a statically typed configuration language.
It is also inspired by Nix, to which it adds a powerful static type system.
However, this forces the programmer to annotate all of their code with types.
2020-07-30 14:36:49 +03:00
- [Jsonnet](https://jsonnet.org/) is another language which could be dubbed as
"JSON with functions" (and others things as well). It is a lazy functional
language with object oriented features, among which inheritance is similar
to Nickel's merge system. One big difference with Nickel is the absence of
typing.
- [Pulumi](https://www.pulumi.com/) is not a language in itself, but a cloud
tool (like Terraform) where you can use your preferred language for
describing your infrastructure. This is a different approach to the problem,
with different trade-offs.
- [Starlark](https://docs.bazel.build/versions/master/skylark/language.html) is
the language of [Bazel](https://bazel.build/), which is a dialect of
[Python](https://www.python.org/). It does not have types and recursion is
forbidden, making it not Turing-complete.
2020-07-30 14:36:49 +03:00
2020-08-12 18:56:40 +03:00
See [RATIONALE.md](./RATIONALE.md) for the design rationale and a more detailed
comparison with a selection of these languages.