|
1 | 1 | # Rootbeer |
| 2 | + |
2 | 3 | > Manage your dotfiles with Lua! |
3 | 4 |
|
4 | 5 | Rootbeer is a dotfile manager that lets you define your system configuration |
5 | 6 | in Lua scripts. Think [chezmoi](https://www.chezmoi.io/), but with the full |
6 | | -power of a real scripting language. Write declarative config tables, use |
7 | | -conditionals based on your OS/hostname, and generate shell configs — all |
8 | | -without learning a templating DSL. |
| 7 | +power of a real scripting language instead of Go templates. |
| 8 | + |
| 9 | +**[Documentation →](https://rootbeer.dev)** |
9 | 10 |
|
10 | 11 | ## Quick Start |
11 | | -```bash |
12 | | -# Initialize with a new source directory |
13 | | -rb init |
14 | 12 |
|
15 | | -# Or clone an existing dotfiles repo |
16 | | -rb init tale/dotfiles |
| 13 | +Install and bootstrap in one command: |
17 | 14 |
|
18 | | -# Apply your configuration |
19 | | -rb apply |
| 15 | +```bash |
| 16 | +# Clone an existing dotfiles repo |
| 17 | +sh -c "$(curl -fsSL rootbeer.tale.me/rb.sh)" -- init tale/dotfiles |
20 | 18 |
|
21 | | -# Dry run (preview without writing files) |
22 | | -rb apply -n |
| 19 | +# Or start fresh |
| 20 | +sh -c "$(curl -fsSL rootbeer.tale.me/rb.sh)" -- init |
23 | 21 | ``` |
24 | 22 |
|
25 | | -`rb init` creates a source directory at `~/.local/share/rootbeer/source/` |
26 | | -with a starter `rootbeer.lua` manifest. When you run `rb apply`, it |
27 | | -evaluates the manifest and writes/links your dotfiles into place. |
| 23 | +Then apply your configuration: |
28 | 24 |
|
29 | | -## Example Config |
| 25 | +```bash |
| 26 | +rb apply # apply configuration |
| 27 | +rb apply -n # dry run (preview without writing) |
| 28 | +rb apply personal # apply with a profile |
| 29 | +``` |
| 30 | + |
| 31 | +## What It Looks Like |
30 | 32 |
|
31 | 33 | ```lua |
32 | | -local rb = require("@rootbeer") |
33 | | -local zsh = require("@rootbeer/shells/zsh") |
34 | | -local d = rb.data() |
35 | | - |
36 | | --- Write a generated .zshrc |
37 | | -rb.file("~/.zshrc", zsh.config({ |
38 | | - env = { |
39 | | - EDITOR = "nvim", |
40 | | - LANG = "en_US.UTF-8", |
| 34 | +local rb = require("rootbeer") |
| 35 | +local git = require("rootbeer.git") |
| 36 | +local zsh = require("rootbeer.zsh") |
| 37 | +local profile = require("rootbeer.profile") |
| 38 | + |
| 39 | +git.config({ |
| 40 | + user = { |
| 41 | + name = "Aarnav Tale", |
| 42 | + email = profile.select({ |
| 43 | + default = "aarnav@personal.me", |
| 44 | + work = "aarnav@company.com", |
| 45 | + }), |
41 | 46 | }, |
42 | | - aliases = { |
43 | | - g = "git", |
44 | | - v = "nvim", |
45 | | - ls = "ls -la", |
| 47 | + editor = "nvim", |
| 48 | + signing = { |
| 49 | + key = "~/.ssh/id_ed25519.pub", |
46 | 50 | }, |
47 | | - sources = { "~/.config/zsh/local.zsh" }, |
48 | | - extra = "autoload -Uz compinit && compinit", |
49 | | -})) |
50 | | - |
51 | | --- Conditionals based on system data |
52 | | -if d.os == "macos" then |
53 | | - rb.file("~/.config/homebrew/env", 'export HOMEBREW_PREFIX="/opt/homebrew"\n') |
| 51 | +}) |
| 52 | + |
| 53 | +zsh.config({ |
| 54 | + env = { EDITOR = "nvim" }, |
| 55 | + aliases = { g = "git", vim = "nvim" }, |
| 56 | + prompt = '%F{cyan}%~%f %F{white}>%f ', |
| 57 | + history = { size = 10000 }, |
| 58 | + evals = { "mise activate zsh" }, |
| 59 | +}) |
| 60 | + |
| 61 | +-- Conditionals — it's just Lua |
| 62 | +if rb.host.os == "macos" then |
| 63 | + local brew = require("rootbeer.brew") |
| 64 | + brew.config({ |
| 65 | + taps = { "homebrew/cask-fonts" }, |
| 66 | + formulae = { "lsd", "delta", "mise" }, |
| 67 | + }) |
54 | 68 | end |
55 | | - |
56 | | --- Symlink a file from your source directory |
57 | | -rb.link_file("config/gitconfig", "~/.gitconfig") |
58 | 69 | ``` |
59 | 70 |
|
60 | | -## Lua API |
61 | | - |
62 | | -### Core (`require("@rootbeer")`) |
63 | | - |
64 | | -| Function | Description | |
65 | | -|---|---| |
66 | | -| `rb.file(path, content)` | Write `content` to `path` (`~` expands to `$HOME`) | |
67 | | -| `rb.link_file(src, dest)` | Symlink `src` (relative to source dir) to `dest` | |
68 | | -| `rb.data()` | Returns `{os, arch, hostname, home, username}` | |
| 71 | +## Key Ideas |
69 | 72 |
|
70 | | -### Shells (`require("@rootbeer/shells/zsh")`) |
71 | | - |
72 | | -`zsh.config(table)` renders a declarative config table into a zshrc string. |
73 | | -Supported keys: `env`, `aliases`, `evals`, `sources`, `extra`. |
74 | | - |
75 | | -## How It Works |
76 | | - |
77 | | -Rootbeer uses a **plan-first architecture**: your Lua script declares intent |
78 | | -(write this file, create this symlink) without touching the filesystem. |
79 | | -After the script completes, the plan is validated and executed — or in |
80 | | -dry-run mode, just printed. |
| 73 | +- **Config is code** — Lua, not templates. Loops, conditionals, functions, and modules. |
| 74 | +- **Plan & apply** — `rb.file()`, `rb.link_file()`, and module calls queue operations. Nothing touches the filesystem until `rb apply`. |
| 75 | +- **Declarative modules** — zsh, git, SSH, Homebrew, macOS, and more. Describe the end state as a table, rootbeer generates the files. |
| 76 | +- **Profiles** — Manage multiple machines from one repo with `profile.select`, `profile.when`, and `profile.config`. |
| 77 | +- **Editor support** — `rb lsp` sets up lua-language-server for full autocomplete and type checking. |
81 | 78 |
|
82 | 79 | ## Building |
83 | 80 |
|
84 | 81 | Requires Rust 1.79+. |
85 | 82 |
|
86 | | -### With Cargo |
87 | | - |
88 | | -```bash |
89 | | -cargo build |
90 | | -``` |
91 | | - |
92 | | -Builds the binary to `./target/debug/rb`. |
93 | | - |
94 | | -### With Nix |
95 | | - |
96 | 83 | ```bash |
97 | | -nix build |
| 84 | +cargo build # → ./target/debug/rb |
| 85 | +nix build # → ./result/bin/rb |
98 | 86 | ``` |
99 | 87 |
|
100 | | -Builds the binary to `./result/bin/rb`. |
101 | | - |
102 | 88 | ## License |
103 | 89 |
|
104 | 90 | MIT |
0 commit comments