1. 23

Could you please share any ideas on (semi)declarative macOS configuration?

I use several mac machines and it’s inconvenient to configure/reconfigure/maintain their settings manually.

Currently I use Ansible as a configuration tool, though it’s unimaginably slow, inconvenient and unreliable.

Nix may be nice though it has many quirks and requires a lot of work, especially for GUI applicaitons. Writing a derivation is an order of magnitude harder than typing “brew install –cask”.

I’ve tried some MDM tools though they aren’t that easy to deal with too.

Actually I just wish to be able to declaratively specify packages which need to be installed on all my machines, content of some configuration files, OS settings (“defaults”), plist values. Ideally there should be a way to do it in centralized manner but local/offline mode must be supported too.

  1. 15

    I’ve had a great experience with Nix

    1. 6

      I have also had good experiences with Nix, but I share the same sentiment as the OP. When Nix works out of the box it’s amazing, but I end up investing a non-trivial amount of time making the edge cases work as well.

      I have also not been able to resolve a few problems in a short amount of time and instead reverted to the system package manager for those packages.

      For me it’s still a strong step towards declarative management, but I am not willing to invest the time required to learn Nix thoroughly, so the edge cases are rough.

      (Using Home Manager on Debian)

      1. 4

        Out of curiosity, what sort of edge cases have you ran into?

        1. 4

          I don’t remember all of them, but I kept a list of things I’ve “escaped” Nix for here: https://github.com/azuline/dotfiles#broken.

          (nixpkgs doesn’t actually suck)

          1. 2

            ah yeah I wouldn’t even wanna attempt to package calibre lol

      2. 2

        100% agreed. Highly recommend Nix.

      3. 6

        I just use a shell scripts with defaults write commands and for software, I use a Brewfile for Homebrew. Mostly works well.

        1. 3

          Same here - /bin/sh script with lots of defaults, installer, etc. lines. Assembled over the years, one-touch CLI-only setup - does 100% of what I need it to do.

          Hooking all of the work Macs up to an existing SaltStack server has been on my TODO list for a while now but it’s always on the back burner.

          1. 3

            If you install the mas package, your Brewfile will have the versions of software you’ve downloaded from the Mac App Store. It’s pretty nice.

          2. 3

            I just moved my configuration to chezmoi, leveraging defaults.sh to export settings into bash scripts. This is the best setup I’ve found thus far.

            1. 3

              Battle hardened and somewhat cynical opinion. Keep a virtual machine, set it up once, keep track of every click and command, then you have a run list.

              It’s up to you if it’s worth it to lift that to a higher level of abstraction. Your test is just bash bats tests from a clean virtual machine + setup script. Keep a Brewfile if you want to define a version set that way.

              Because it’s a domain that is not as well developed when it comes to tooling, I think the sober advice of just be disciplined about your recipe and roll a VM til it’s right is probably less time consuming than googling what’s wrong with some unpolished / sharp edges tool.

              1. 2

                I’m using home-manager (Nix): https://github.com/knl/dotskel. Even though I would like to avoid wasting 6 minutes to manually install apps and instead spend 6 hours to fail to automate it, I didn’t get to it. Thus, I keep a list of the apps that I need to install (README is essentially a runbook).

                In the past I had positive experiences with JAMF stack, where I would just push a bunch of scripts to configure the machines. Almost declarative, since there are many scripts available online :)

                1. 2

                  I’m not sure how feasible it is without cobbling things together. I did recently stumble on https://twocanoes.com/products/mac/mac-deploy-stick/ but I’m not sure if it’s really an option. If the other options aren’t desirable, I guess it’s at least worth looking at. :)

                  I feel like I have my bootstrapping process worked out fairly well (i.e., I’m pretty happy with the result), but it’s got a substantive amount of shell gluing together my dotfile manager/dotfiles, Nix+nix-darwin, brew bundle (just for casks), fiddling settings that aren’t covered by that (some OS, some app-specific), and restoring some stuff from backups. This is pretty good in the sense that everything I regularly fiddle with flows through Nix. The brewfile almost never changes. OS settings almost never change.

                  I’ve also been slowly building a component that roughly meets the inverse need of the bootstrap: it accumulates the knowledge I need to get myself back off of a system as quickly as feasible without missing/losing things. I run it alongside my backups and save the result, and also manually when I’m actively working on triaging issues it has found. It’s a hodgepodge, but a few broad-stroke examples are:

                  • audit ~/ for new dirs/files that I haven’t previously triaged
                  • auto-commit things in my dotfiles that churn with regular use (apps that fiddle their own configs, history/state files, etc.)
                  • print reminders of all of the little nagging anxieties that I have looked into in the past and verified don’t need action
                  1. 1

                    Do you use brewfiles? That takes care of WHAT is installed pretty well.

                    Packages come and go though, especially after the great pruning. They are also not versioned for the most part.

                    They do support App Store apps, docker images, and individual options for casks (so you can globally install or locally install).

                    Then, for config, I started at a feature full dotfiles that includes a bunch of good defaults write commands, command line config, and terminal utilities: https://github.com/skwp/dotfiles/blob/master/bin/macos

                    Most of the rest is actually very importantly not changed. With macos there isn’t a ton to configure anyhow, but when you work with other people or on another person’s machine, you end up wanting either your settings or the default macos settings. When that host crashes, or I want to sit down at any machine, it’s pretty much:

                    Git clone homebrew
                    Git clone bundlefile/localdotfiles
                    Brew bundle
                    Git clone skwp/dotfiles
                    Rake install
                    Restart terminal
                    Macos script

                    All of which I can do from memory and I’m 99% productive.

                    1. 1

                      For years I’ve used my custom setup program to manage my Macs. I source control everything possible and it helps keeps my home/work computers in sync and lets me bootstrap a new machine asap.

                      Here’s its config and you can see how it has configuration for every package manager. Each section of the config translates into a command-line argument for setup, so, for example, I can type setup brew and it uses brew bundle to install all my Homebrew packages and then runs post-install steps. All the packages for each package manager are in the conf directory.

                      Finally, there’s a ‘manual’ section that can install software without a package manager by checking out a git repository or downloading a tarball and then building the software.

                      1. 1

                        Just popping in to drop https://github.com/minamarkham/formation/ since no one seems to have mentioned it yet.

                        What I haven’t yet figured out doing is how to make all those settings one manually sets in System Preferences (eg: Hot Corners) repeatable without me having to manually set it every time I move to a new machine. In fact I interpreted this to be your original question, but from reading the other esponses it seems that is not true.

                        Unfortunately I am moving between machines at least 3 or 4 times a year, and my setup hasn’t changed in the last six years, so this is a problem that I want to spend time solving.

                        1. 1

                          Since I know Chef I’d probably reach for that in your situation (or, the open source version, CINC)

                          1. 1

                            Well, I’ve tried Chef and have no idea how to debug it.

                            ‘package’ task with 21-element array argument works, the same tasks with 22 element array fails with a useless stacktrace.