Omiros is a command-line tool to semi-declaratively automate the setup of a new
environment on macOS. It's configured using a simple TOML file (system.toml)
and a directory containing your dotfiles.
It currently supports:
- Installing Homebrew formulae and casks.
- Installing Mac App Store applications using
mas. - Installing VSCode extensions.
- Symlinking dotfiles from a specified
dotfiles/directory to wherever you need. - Setting some macOS system configuration, pretty much the ones that I care about.
NOTE: omiros currently only installs software/extensions that are present
in the configuration file and missing from the system. It does not yet remove
packages that are present on the machine and absent from the configuration file.
This safety constraint will probably be lifted in the future.
-
Create a
system.tomlfile:This file defines the packages and applications you want to install, and enumerates the dotfiles you want to link.
# system.toml # brew formulae and casks as you would find in `brew search` or `brew info`. [brew] formulae = ["fish", "neovim", "git"] casks = ["alacritty", "slack"] # mas apps declared by both name and app id. [[mas.apps]] name = "Amphetamine" id = "937984704" [dotfiles] files = [ # By default, omiros will symlink your dotfiles to the same path in your # home directory. For example, the following line will create a symlink # from `dotfiles/.config/alacritty/alacritty.toml` to # `~/.config/alacritty/alacritty.toml`. ".config/alacritty/alacritty.toml", ".config/fish/config.fish", # If you want to create a symlink to a different path, you can specify a # `original` and `link` path. The `original` path is relative to your # dotfiles directory, and the `link` path can be anywhere you want, but # I'm partial to XDG-compliant configuration paths. { original = ".config/git/config", link = "~/.gitconfig" } ] [vscode] extensions = [ # Extension names can be found under "Unique Identifier" in the "More # Info" section of the extension Marketplace. For example VSCodeVim can # be found here: # https://marketplace.visualstudio.com/items?itemName=vscodevim.vim "vscodevim.vim", "rust-lang.rust-analyzer" ] [macos.dock] orientation = "left" autohide = true icon-size = 48 [macos.safari] show-full-url = true [macos.system] show-file-extensions = true # Set scrolling to "natural", like an animal. weird-mac-scrolling = true
-
Organize your dotfiles:
Create a directory containing the dotfiles you want to manage. The paths in the
[dotfiles]section of yoursystem.tomlare relative to this directory.. ├── dotfiles/ │ ├── .config/ │ │ ├── alacritty/ │ │ │ └── alacritty.toml │ │ ├── fish/ │ │ │ └── config.fish │ │ └── git/ │ │ └── config │ └── .zshrc └── system.tomlThis is a great directory to track under version control.
-
Run the application:
Build the application using
cargo build --release. Then, run the executable, providing the path to the directory containing yoursystem.tomland the path to yourdotfilesdirectory../target/release/omiros --system-config-dir . --dotfiles-dir ./dotfiles--system-config-dir: The path to the directory containing yoursystem.tomlfile.--dotfiles-dir: The path to the directory containing your dotfiles.
The tool will then check for missing packages and applications and install them, and symlink your dotfiles.
tldr; Cuz I'm too dumb to use Nix, but nothing else comes close!
Many years ago I wrote a tool like this in Python to help set up my own personal machines. It worked, but I was always on the lookout for something better.
That's when I discovered Ansible. I thought, that's a cool sci-fi inspired name. At the time I was also getting into configuration management systems at work to set up large batches of test machines. So it seemed like a reasonable thing to try and convert my Python script to be a declarative Ansible playbook. That also worked, but Ansible is a pretty large hammer for this particular nail. Ansible is great at setting up a lot of the same machines over as short period of time, not a single machine one at a time over long periods of time, and I was discovering that each time I went back to run my ansible playbook, I'd have to tinker with it to get it to work again. I wasn't setting up new personal machines at a fast enough cadence to pay back my investment in keeping my Ansible playbook up-to-date.
Having come to that realization, I decided to start over, this time writing the whole thing in Bash to avoid having any external dependencies. This also worked! There seems to be a pattern forming. These scripts always seem to work, but I'm never really happy with them.
The reason is because:
An idea is like a virus, resilient, highly contagious. The smallest seed of an idea can grow. It can grow to define or destroy you.
-Cobb (Inception)
In my case it was Nix, and it destroyed me. I had been playing with Nix on the
side on-and-off for a few years at this point. Mostly learning about the
language and reading about the theory behind this very particular package
manager. At some point I got a new computer and I decided this is my chance!
Finally, I would figure out how to use Nix (both the language and the package
manager) to declaratively and reproducibly generate / maintain my development
environment. This is not a decision to be taken lightly. One does not simply
walk into using Nix; it permeates through everything that you do on your
computer. It's a completely different way of thinking. When it worked, it was
beautiful. Everything was reproducible, everything was declarative. nix-darwin
and home-manager opened my eyes to a new way of thinking about how to manage a
machine. But at the same time Nix itself was completely impenetrable. I read a
lot of blogs and a lot of docs, but it never quite clicked, and the longer it
didn't click the less I wanted to use my system, because making modifications to
it became a pain. Immutable configuration caused all sorts of problems with
applications that did not expect that to be the case. I ran into edge-cases at
every turn, and the more that I ran into these issues, the less I wanted to hack
on stuff.
This is not a critique of Nix. Purity is not free. There is a price to pay, and in my particular case, the price was too high.
Oh, I also tried a few dotfile managers like dotter. They worked, and they
were great, but they mostly focused on dotfiles, and nix-darwin/home-manager
really showed me how nice it is to have a single place to both declare system
configuration, package management, and dotfiles related configuration.
So here I am. I've written a script like this at least 4 times now. Maybe this will be the last time. Maybe...
- Support
aptpackage manager on Linux machines.