Initial setup: mac_os installer with custom config

Contains both components needed for Mac setup:
- mac_os/: Installer scripts (from bkuhlmann/mac_os)
- mac_os-config/: Custom app configuration

Configured apps:
- Homebrew formulas: atuin, bash, ffmpeg, mas, mole, node, rename, ykman
- Homebrew casks: chromium, deepl, element, nextcloud, nova, proton suite, signal, transmit
- App Store: Affinity suite, Bitwarden, Final Cut Pro, Invoice Ninja, iWork, PastePal, xSearch

Usage: cd mac_os && ./bin/run

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Andreas Düren
2026-01-09 08:33:22 -06:00
commit c94070723b
62 changed files with 3378 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
version: 2.1
jobs:
build:
working_directory: ~/project
docker:
- image: bkuhlmann/alpine-ruby:latest
steps:
- checkout
- restore_cache:
name: Gems Restore
keys:
- gem-cache-{{.Branch}}-{{checksum "Gemfile"}}
- gem-cache-
- run:
name: Gems Install
command: |
gem update --system
bundle config set path "vendor/bundle"
bundle install
- save_cache:
name: Gems Store
key: gem-cache-{{.Branch}}-{{checksum "Gemfile"}}
paths:
- vendor/bundle
- run:
name: Rake
command: bundle exec rake

View File

@@ -0,0 +1,2 @@
inherit_gem:
caliber: config/all.yml

1
mac_os-config/.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1 @@
github: [bkuhlmann]

View File

@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Community
url: https://alchemists.io/community
about: Please ask questions or discuss specifics here.
- name: Security
url: https://alchemists.io/policies/security
about: Please report security vulnerabilities here.

View File

@@ -0,0 +1,18 @@
---
name: Issue
title: "Add|Update|Fix|Remove|Refactor "
about: Report an issue. Please use only one of the subject prefixes.
---
<!--
Please focus on well written issues. Context: https://alchemists.io/articles/software_issues.
-->
## Why
<!-- Required. Describe, briefly, why this issue is important. -->
## How
<!-- Optional. List exact steps to implement or reproduce behavior. Screen shots/casts are welcome! -->
## Notes
<!-- Optional. Provide additional details like operating system, software version(s), stack dump, logs, or anything else that would be helpful. -->

View File

@@ -0,0 +1,8 @@
## Overview
<!-- Required. Describe, briefly, why this is necessary and what the overarching architecture is. -->
## Screenshots/Screencasts
<!-- Optional. Provide supporting screen shots/casts. -->
## Details
<!-- Optional. As bullet points, list related issue(s); major highlights; team callouts; and/or other information that is helpful. -->

1
mac_os-config/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
Gemfile.lock

View File

@@ -0,0 +1 @@
4.0.0

View File

@@ -0,0 +1,22 @@
cff-version: 1.2.0
message: Please use the following metadata when citing this project in your work.
title: macOS Configuration
abstract: Shell scripts for customized macOS machine setup.
version: 30.0.0
license: Hippocratic-2.1
date-released: 2026-01-01
authors:
- family-names: Kuhlmann
given-names: Brooke
affiliation: Alchemists
orcid: https://orcid.org/0000-0002-5810-6268
keywords:
- bash
- shell
- scripts
- automation
- setup
- recovery
repository-code: https://github.com/bkuhlmann/mac_os-config
repository-artifact: https://alchemists.io/projects/mac_os-config
url: https://alchemists.io/projects/mac_os-config

10
mac_os-config/Gemfile Normal file
View File

@@ -0,0 +1,10 @@
# frozen_string_literal: true
ruby file: ".ruby-version"
source "https://rubygems.org"
gem "caliber", "~> 0.82"
gem "debug", "~> 1.11"
gem "git-lint", "~> 10.0"
gem "rake", "~> 13.3"

134
mac_os-config/LICENSE.adoc Normal file
View File

@@ -0,0 +1,134 @@
= Hippocratic License
Version: 2.1.0.
Purpose. The purpose of this License is for the Licensor named above to
permit the Licensee (as defined below) broad permission, if consistent
with Human Rights Laws and Human Rights Principles (as each is defined
below), to use and work with the Software (as defined below) within the
full scope of Licensors copyright and patent rights, if any, in the
Software, while ensuring attribution and protecting the Licensor from
liability.
Permission and Conditions. The Licensor grants permission by this
license ("License"), free of charge, to the extent of Licensors
rights under applicable copyright and patent law, to any person or
entity (the "Licensee") obtaining a copy of this software and
associated documentation files (the "Software"), to do everything with
the Software that would otherwise infringe (i) the Licensors copyright
in the Software or (ii) any patent claims to the Software that the
Licensor can license or becomes able to license, subject to all of the
following terms and conditions:
* Acceptance. This License is automatically offered to every person and
entity subject to its terms and conditions. Licensee accepts this
License and agrees to its terms and conditions by taking any action with
the Software that, absent this License, would infringe any intellectual
property right held by Licensor.
* Notice. Licensee must ensure that everyone who gets a copy of any part
of this Software from Licensee, with or without changes, also receives
the License and the above copyright notice (and if included by the
Licensor, patent, trademark and attribution notice). Licensee must cause
any modified versions of the Software to carry prominent notices stating
that Licensee changed the Software. For clarity, although Licensee is
free to create modifications of the Software and distribute only the
modified portion created by Licensee with additional or different terms,
the portion of the Software not modified must be distributed pursuant to
this License. If anyone notifies Licensee in writing that Licensee has
not complied with this Notice section, Licensee can keep this License by
taking all practical steps to comply within 30 days after the notice. If
Licensee does not do so, Licensees License (and all rights licensed
hereunder) shall end immediately.
* Compliance with Human Rights Principles and Human Rights Laws.
[arabic]
. Human Rights Principles.
[loweralpha]
.. Licensee is advised to consult the articles of the United Nations
Universal Declaration of Human Rights and the United Nations Global
Compact that define recognized principles of international human rights
(the "Human Rights Principles"). Licensee shall use the Software in a
manner consistent with Human Rights Principles.
.. Unless the Licensor and Licensee agree otherwise, any dispute,
controversy, or claim arising out of or relating to (i) Section 1(a)
regarding Human Rights Principles, including the breach of Section 1(a),
termination of this License for breach of the Human Rights Principles,
or invalidity of Section 1(a) or (ii) a determination of whether any Law
is consistent or in conflict with Human Rights Principles pursuant to
Section 2, below, shall be settled by arbitration in accordance with the
Hague Rules on Business and Human Rights Arbitration (the "Rules");
provided, however, that Licensee may elect not to participate in such
arbitration, in which event this License (and all rights licensed
hereunder) shall end immediately. The number of arbitrators shall be one
unless the Rules require otherwise.
+
Unless both the Licensor and Licensee agree to the contrary: (1) All
documents and information concerning the arbitration shall be public and
may be disclosed by any party; (2) The repository referred to under
Article 43 of the Rules shall make available to the public in a timely
manner all documents concerning the arbitration which are communicated
to it, including all submissions of the parties, all evidence admitted
into the record of the proceedings, all transcripts or other recordings
of hearings and all orders, decisions and awards of the arbitral
tribunal, subject only to the arbitral tribunals powers to take such
measures as may be necessary to safeguard the integrity of the arbitral
process pursuant to Articles 18, 33, 41 and 42 of the Rules; and (3)
Article 26(6) of the Rules shall not apply.
. Human Rights Laws. The Software shall not be used by any person or
entity for any systems, activities, or other uses that violate any Human
Rights Laws. "Human Rights Laws" means any applicable laws,
regulations, or rules (collectively, "Laws") that protect human,
civil, labor, privacy, political, environmental, security, economic, due
process, or similar rights; provided, however, that such Laws are
consistent and not in conflict with Human Rights Principles (a dispute
over the consistency or a conflict between Laws and Human Rights
Principles shall be determined by arbitration as stated above). Where
the Human Rights Laws of more than one jurisdiction are applicable or in
conflict with respect to the use of the Software, the Human Rights Laws
that are most protective of the individuals or groups harmed shall
apply.
. Indemnity. Licensee shall hold harmless and indemnify Licensor (and
any other contributor) against all losses, damages, liabilities,
deficiencies, claims, actions, judgments, settlements, interest, awards,
penalties, fines, costs, or expenses of whatever kind, including
Licensors reasonable attorneys fees, arising out of or relating to
Licensees use of the Software in violation of Human Rights Laws or
Human Rights Principles.
* Failure to Comply. Any failure of Licensee to act according to the
terms and conditions of this License is both a breach of the License and
an infringement of the intellectual property rights of the Licensor
(subject to exceptions under Laws, e.g., fair use). In the event of a
breach or infringement, the terms and conditions of this License may be
enforced by Licensor under the Laws of any jurisdiction to which
Licensee is subject. Licensee also agrees that the Licensor may enforce
the terms and conditions of this License against Licensee through
specific performance (or similar remedy under Laws) to the extent
permitted by Laws. For clarity, except in the event of a breach of this
License, infringement, or as otherwise stated in this License, Licensor
may not terminate this License with Licensee.
* Enforceability and Interpretation. If any term or provision of this
License is determined to be invalid, illegal, or unenforceable by a
court of competent jurisdiction, then such invalidity, illegality, or
unenforceability shall not affect any other term or provision of this
License or invalidate or render unenforceable such term or provision in
any other jurisdiction; provided, however, subject to a court
modification pursuant to the immediately following sentence, if any term
or provision of this License pertaining to Human Rights Laws or Human
Rights Principles is deemed invalid, illegal, or unenforceable against
Licensee by a court of competent jurisdiction, all rights in the
Software granted to Licensee shall be deemed null and void as between
Licensor and Licensee. Upon a determination that any term or provision
is invalid, illegal, or unenforceable, to the extent permitted by Laws,
the court may modify this License to affect the original purpose that
the Software be used in compliance with Human Rights Principles and
Human Rights Laws as closely as possible. The language in this License
shall be interpreted as to its fair meaning and not strictly for or
against any party.
* Disclaimer. TO THE FULL EXTENT ALLOWED BY LAW, THIS SOFTWARE COMES
"AS IS," WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED, AND LICENSOR AND
ANY OTHER CONTRIBUTOR SHALL NOT BE LIABLE TO ANYONE FOR ANY DAMAGES OR
OTHER LIABILITY ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE
OR THIS LICENSE, UNDER ANY KIND OF LEGAL CLAIM.
This Hippocratic License is an link:https://ethicalsource.dev[Ethical Source license] and is offered
for use by licensors and licensees at their own risk, on an "AS IS" basis, and with no warranties
express or implied, to the maximum extent permitted by Laws.

522
mac_os-config/README.adoc Normal file
View File

@@ -0,0 +1,522 @@
:toc: macro
:toclevels: 5
:figure-caption!:
= macOS Configuration
This project provides a highly opinionated default configuration built upon the
link:https://alchemists.io/projects/mac_os[macOS] project. Should the configuration provided by
this project not be to your liking, feel free to fork and customize for your specific needs.
toc::[]
== Features
Due to the amount of tooling used, the following features are broken down into subsections for
easier navigation.
=== Homebrew Formulas
Installs the following link:https://brew.sh[formulas]:
* link:https://www.gnu.org/software/bash[Bash]
* link:http://bash-completion.alioth.debian.org[Bash Completion]
* link:https://github.com/sharkdp/bat[Bat]
* link:https://github.com/toy/blueutil[blueutil]
* link:https://github.com/cloudflare/cloudflared[cloudflared]
* link:https://github.com/schollz/croc[croc]
* link:https://crystal-lang.org[Crystal]
* link:http://ctags.sourceforge.net[CTags]
* link:https://difftastic.wilfred.me.uk[Difftastic]
* link:https://direnv.net[direnv]
* link:https://github.com/wagoodman/dive[Dive]
* link:https://github.com/muesli/duf[duf]
* link:https://github.com/bootandy/dust[Dust]
* link:http://duti.org[duti]
* link:https://eradman.com/entrproject[Entr]
* link:https://exiftool.org/index.html[ExifTool]
* link:https://github.com/sharkdp/fd[fd]
* link:https://github.com/tako8ki/frum[Frum]
* link:https://github.com/Schniz/fnm[Fast Node Manager]
* link:https://fx.wtf[fx]
* link:https://github.com/junegunn/fzf[FZF]
* link:https://git-scm.com[Git]
* link:https://github.com/dandavison/delta[Git Delta]
* link:https://github.com/newren/git-filter-repo[Git Filter Repo]
* link:https://github.com/github/git-sizer[Git Sizer]
* link:https://www.gnupg.org[GPG]
* link:https://github.com/orf/gping[gping]
* link:http://www.graphicsmagick.org[Graphics Magick]
* link:https://www.graphviz.org[Graphviz]
* link:https://github.com/sharkdp/hexyl[hexyl]
* link:http://www.andre-simon.de/doku/highlight/en/highlight.php[Highlight]
* link:https://hisham.hm/htop[htop]
* link:https://github.com/reorx/httpstat[HTTP Stat]
* link:https://github.com/sharkdp/hyperfine[Hyperfine]
* link:https://imagemagick.org[ImageMagick]
* link:https://stedolan.github.io/jq[jq]
* link:https://lnav.org[lnav]
* link:https://github.com/CISOfy/lynis[Lynis]
* link:https://mailpit.axllent.org[Mailpit]
* link:https://github.com/mas-cli/mas[Mac App Store]
* link:https://jedisct1.github.io/minisign[Minisign]
* link:https://github.com/variadico/noti[Noti]
* link:https://github.com/hatoo/oha[Oha]
* link:https://ollama.com[Ollama]
* link:https://www.openssh.com[OpenSSH]
* link:https://openssl.org[OpenSSL]
* link:https://osv.dev[Open Source Vulnerability Scanner]
* link:https://github.com/DarthSim/overmind[Overmind]
* link:https://pandoc.org[Pandoc]
* link:https://savannah.gnu.org/projects/parallel[Parallel]
* link:https://github.com/sharkdp/pastel[Pastel]
* link:https://www.zlib.net/pigz[Pigz]
* link:https://github.com/GPGTools/pinentry[Pinentry]
* link:https://github.com/dalance/procs[Procs]
* link:https://tiswww.case.edu/php/chet/readline/rltop.html[Readline]
* link:https://github.com/BurntSushi/ripgrep[ripgrep]
* link:https://github.com/koalaman/shellcheck[ShellCheck]
* link:https://www.joedog.org/siege-home[Siege]
* link:https://www.tarsnap.com[Tarsnap]
* link:https://www.terraform.io[Terraform]
* link:https://github.com/ggreer/the_silver_searcher[The Silver Surfer]
* link:https://github.com/tmux/tmux/wiki[tmux]
* link:https://github.com/XAMPPRocky/tokei[Tokie]
* link:https://vale.sh[Vale]
* link:https://valkey.io[Valkey]
* link:https://github.com/sachaos/viddy[Viddy]
* link:https://www.vim.org[Vim]
* link:https://github.com/libvips/libvips[Vips]
* link:https://github.com/vi/websocat[Websocat]
* link:https://developers.yubico.com/yubikey-manager[YubiKey Manager CLI]
* link:https://github.com/ajeetdsouza/zoxide[Zoxide]
=== Homebrew Casks
Installs the following link:https://brew.sh[casks]:
* link:https://www.alfredapp.com[Alfred]
* link:https://freemacsoft.net/appcleaner[App Cleaner]
* link:https://www.rogueamoeba.com/audiohijack[Audio Hijack]
* link:https://www.balena.io/etcher[Balena Etcher]
* link:https://bombich.com[Carbon Copy Cloner]
* link:https://getcleanshot.com[CleanShot]
* link:https://discord.com[Discord]
* link:https://software.charliemonroe.net/downie[Downie]
* link:https://www.getdoxie.com[Doxie]
* link:https://www.dropbox.com[Dropbox]
* link:https://www.mozilla.com/en-US/firefox[Firefox]
* link:https://www.rogueamoeba.com/fission[Fission]
* link:https://www.google.com/chrome[Google Chrome]
* link:https://www.noodlesoft.com[Hazel]
* link:https://iina.io[IINA]
* link:http://imageoptim.pornel.net[ImageOptim]
* link:https://bjango.com/mac/istatmenus[iStat Menus]
* link:https://www.iterm2.com[iTerm2]
* link:https://mitmproxy.org[mitmproxy]
* link:https://netnewswire.com[NewNewsWire]
* link:https://ngrok.com[Ngrok]
* link:https://numi.app[Numi]
* link:https://obsidian.md[Obsidian]
* link:https://www.openoffice.org[OpenOffice]
* link:https://orbstack.dev[OrbStack]
* link:https://kagi.com/orion[Orion]
* link:https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project[OWASP Zed Attack Proxy (ZAP)]
* link:https://cocoatech.com[Path Finder]
* link:https://www.pgadmin.org[pgAdmin]
* link:https://superhighfives.com/pika[Pika]
* link:https://getpixelsnap.com[PixelSnap]
* link:https://protonvpn.com[ProtonVPN]
* link:https://paw.cloud[Rapid API]
* link:https://manytricks.com/resolutionator[Resolutionator]
* link:https://flyingmeat.com/retrobatch[Retrobatch]
* link:https://signal.org[Signal]
* link:https://skim-app.sourceforge.io[Skim]
* link:https://www.sonos.com[Sonos]
* link:https://www.sublimetext.com[Sublime Text]
* link:https://panic.com/transmit[Transmit]
* link:https://twist.com[Twist]
* link:https://www.sparklabs.com/viscosity[Viscosity]
* link:https://vivaldi.com[Vivaldi]
* link:https://zed.dev[Zed]
=== App Store
Installs link:https://www.apple.com/app-store[App Store] applications as managed by the link:https://github.com/mas-cli/mas[Mac App Store] CLI which assumes you've _purchased_ the applications listed below:
* link:https://secure.flyingmeat.com/acorn[Acorn]
* link:https://bitwarden.com[Bitwarden]
* link:https://ccmenu.org[CCMenu]
* link:https://sindresorhus.com/system-color-picker[Color Picker]
* link:https://daisydiskapp.com[DaisyDisk]
* link:https://www.apple.com/mac/garageband[GarageBand]
* link:https://handmirror.app[Hand Mirror]
* link:https://www.apple.com/imovie[iMovie]
* link:https://firecore.com/infuse[Infuse]
* link:https://manytricks.com/keycodes[Key Codes]
* link:https://manytricks.com/keymou[Keymou]
* link:https://www.apple.com/keynote[Keynote]
* link:https://apps.apple.com/us/app/amazon-kindle/id302584613[Kindle]
* link:http://limechat.net/mac[LimeChat]
* link:https://marked2app.com[Marked 2]
* link:http://getmedis.com[Medis]
* link:https://trymeeter.com[Meeter]
* link:https://www.markvapps.com/metadatics[Metadatics]
* link:https://mindnode.com[MindNode]
* link:https://manytricks.com/namemangler[Name Mangler]
* link:https://www.apple.com/numbers[Numbers]
* link:https://www.omnigroup.com/omnifocus[OmniFocus]
* link:https://www.apple.com/pages[Pages]
* link:https://krillapps.com/patterns[Patterns]
* link:https://software.charliemonroe.net/permute[Permute]
* link:https://apps.apple.com/app/apple-store/id1494948845[Paletter]
* link:https://apps.apple.com/gb/app/sequence-diagram/id1195426709[Sequence Diagram]
* link:https://shapesapp.com[Shapes]
* link:https://slack.com[Slack]
* link:https://www.adriangranados.com[WiFi Explorer]
=== Applications
Installs the following, basic, macOS applications which are not located in the App Store:
* link:https://appmap.io[AppMap]
* link:https://www.docker.com[Docker]
* link:https://icemenubar.app[Ice]
* link:https://moneywell.app[MoneyWell]
* link:https://manytricks.com/moom[Moom]
* link:https://github.com/theory/pgenv[pgenv]
* link:https://tana.inc[Tana]
=== Application Extensions
Installs the following extensions to existing applications:
* link:https://github.com/tpope/vim-bundler[Vim Bundler]
* link:https://github.com/tpope/vim-commentary[Vim Commentary]
* link:https://github.com/tpope/vim-fugitive[Vim Fugitive]
* link:https://github.com/airblade/vim-gitgutter[Vim Git Gutter]
* link:https://github.com/tpope/vim-pathogen[Vim Pathogen]
* link:https://github.com/tpope/vim-projectionist[Vim Projectionist]
* link:https://github.com/tpope/vim-rails[Vim Rails]
* link:https://github.com/vim-ruby/vim-ruby[Vim Ruby]
* link:https://github.com/AndrewRadev/splitjoin.vim[Vim Splitjoin]
* link:https://github.com/kana/vim-textobj-user[Vim Text Object User]
* link:https://github.com/tpope/vim-unimpaired[Vim Unimpaired]
=== Node Packages
Installs the following link:https://nodejs.org[Node] link:https://www.npmjs.com[packages]:
_None are used at the moment._
=== Ruby Gems
Installs the following link:https://www.ruby-lang.org[Ruby] link:https://rubygems.org[gems]:
* link:https://github.com/amazing-print/amazing_print[Amazing Print]
* link:https://asciidoctor.org[ASCII Doctor]
* link:https://github.com/evanphx/benchmark-ips[Benchmark IPS]
* link:https://github.com/jmmastey/bundler-stats[Bundler Stats]
* link:https://github.com/mattbrictson/bundleup[BundleUp]
* link:https://alchemists.io/projects/caliber[Caliber]
* link:https://alchemists.io/projects/gemsmith[Gemsmith]
* link:https://alchemists.io/projects/git-lint[Git Lint]
* link:https://hanamirb.org[Hanami]
* link:https://alchemists.io/projects/hanamismith[Hanamismith]
* link:https://alchemists.io/projects/irb-kit[IRB Kit]
* link:https://github.com/jaredbeck/libyear-bundler[Libyear (Bundler)]
* link:https://alchemists.io/projects/pennyworth[Pennyworth]
* link:https://github.com/joonty/pessimize[Pessimize]
* link:https://alchemists.io/projects/pragmater[Pragmater]
* link:https://rubyonrails.org[Ruby on Rails]
* link:https://github.com/troessner/reek[Reek]
* link:https://github.com/AlexB52/retest[Retest]
* link:https://rspec.info[RSpec]
* link:https://alchemists.io/projects/rubysmith[Rubysmith]
* link:https://solargraph.org/guides[Solargraph]
* link:https://alchemists.io/projects/sublime_text_kit[Sublime Text Kit]
* link:https://github.com/ruby-syntax-tree/syntax_tree[Syntax Tree]
* link:https://github.com/red-data-tools/YouPlot[YouPlot]
=== Rust Crates
Installs the following link:https://www.rust-lang.org[Rust] link:https://crates.io[crates]:
* link:https://atuin.sh[Atuin]
* link:https://github.com/nabijaczleweli/cargo-update[Cargo Update]
* link:https://dotenv-linter.github.io[Dotenv Linter]
* link:https://eza.rocks[Eza]
* link:https://jj-vcs.github.io[Jujutsu]
* link:https://jless.io[jless]
* link:https://github.com/chmln/sd[sd]
== Requirements
. Apple Silicon hardware.
. link:https://alchemists.io/projects/mac_os[macOS]
. link:https://developer.apple.com/xcode[Xcode]
== Setup
To install, run:
[source,bash]
----
git clone https://github.com/bkuhlmann/mac_os-config.git
cd mac_os-config
git checkout 30.0.0
----
== Usage
The following will walk you through the steps of installing/re-installing your machine.
=== Pre-Install
Ensure you have the following in place for your Silicon machine:
. Ensure a backup of your Apple, NAS, backup image, and Dropbox credentials are available.
. Ensure a recent backup of your machine exists and works properly.
. Ensure link:https://support.apple.com/en-us/HT208198[Startup Security Utility] is disabled.
.. Turn off your machine.
.. Start your machine by pressing and holding the `POWER` button until you see startup options being
loaded.
.. Select Utilities → Startup Security Utility from the main menu.
.. Select _Reduced Security_.
.. Quit the utility and restart the machine.
=== Install
. Create a link:https://alchemists.io/projects/mac_os/#_boot_disk[macOS Boot Disk] and follow
instructions.
. Ensure latest software updates are applied per
link:https://alchemists.io/projects/mac_os/#_requirements[macOS Requirements].
. Ensure Xcode is installed per link:https://alchemists.io/projects/mac_os/#_requirements[macOS
Requirements].
. Run link:https://alchemists.io/projects/mac_os#_usage[macOS Install] and follow all prompts.
=== Post-Install
The following are additional steps, not easily automated, that are worth completing after the
install scripts have completed:
* System Preferences
** Apple ID
*** Login (if not already).
*** Update avatar.
*** Configure iCloud.
*** Enable Find My Mac.
** Bluetooth
*** Reconnect keyboard, mouse, and earbuds.
** Sound
*** Disable _Play sound on startup_.
*** Disable _Play user interface sound effects_.
** Screen Time
*** Disable entire feature.
** General
*** AirDrop & Handoff
**** Disable _AirPlay Receiver_ so you can run link:https://github.com/rack/rack[Rack] applications on Port 5000.
*** AutoFill & Passwords
**** Disable _AutoFill Passwords and Passkeys_.
*** Login Items
**** Ensure only _Alfred_ is listed.
*** Language and Region
**** Set _First day of week_ to _Monday_.
**** Set _Date format_ to _YYYY-MM-DD_.
** Accessibility
*** Hearing
**** Enable _Turn off background sounds when your Mac is not in use._
** Appearance
*** Use _Light_ theme.
** Apple Intelligence & Siri
*** Disable _Listen for_.
*** Disable _Keyboard shortcut_ (use Alfred instead).
** Privacy & Security
*** Enable _FileVault_.
** Wallpaper
*** Select custom image from _Documents_.
** Spotlight
*** Disable _Help Apple Improve Search_. link:https://obdev.at/blog/what-happens-on-your-device-stays-on-your-device-until-it-doesnt[Details].
** Screen Saver
*** Use _Message_ with custom text.
** Battery
*** Click _Options_ and enable _Prevent automatic sleeping on power adapter when the
display is off_.
** Lock Screen
*** Set _Start Screen Saver when inactive_ for 5 minutes.
*** Set _Turn display off on battery when inactive_ for 2 minutes.
*** Set _Turn display off on power adapter when inactive_ for 10 minutes.
*** Set _Require password after screen saver begins or display is turned off_ for 5 minutes.
*** Set _Show message when locked_. Example: `<url> | <email> | <phone>`.
** Touch ID & Password
*** Rename fingerprint.
*** Enable use of Touch ID for all settings.
*** Enable use of Apple Watch.
** Users & Groups
*** Update avatar image.
*** Remove unused login items.
*** Disable guest account.
** Internet Accounts
*** Add all accounts.
** Wallet & Apple Pay
*** Reenable all accounts and assign default card.
** Keyboard
*** Set _Key repeat rate_ to max level.
*** Set _Delay until repeat_ to short (max) level.
*** Keyboard Shortcuts
**** Select _Launchpad and Dock_ and uncheck _Turn Dock Hiding On/Off_.
**** Select _Mission Control_ and assign `CONTROL + OPTION + COMMAND + N` to _Show Notification
Center_.
**** Within _Mission Control_, assign `CONTROL + OPTION + COMMAND + W` to _Mission Control_.
**** Select _Screenshots_ and uncheck all boxes.
**** Select _Spotlight_ and uncheck all boxes.
** Mouse
*** Ensure tracking speed is on the 5th setting (i.e. 5th from right of _Slow_).
** Trackpad
*** Ensure tracking speed is on the 5th setting (i.e. 5th from right of _Slow_).
** Printers & Scanners
*** Add printer/scanner.
* iStat Menus
** Double click, within the Applications folder, to install as a system preference.
* Carbon Copy Cloner
** Rename old backup, create new backup, and schedule frequency.
* Notifications
** Set _Show previews when unlocked_.
** Disable _Allow notifications when the display is sleeping_.
** Disable _Allow notifications when the screen is locked_.
** Disable _Allow notifications when mirroring or sharing the display_.
** Disable _Show notifications on lock screen_ and _Play sound for notification_ for all applications.
** Enable _Allow notifications from iPhone_ but disable _Play sounds for notifications from iPhone_ within this option.
=== Keyboard Shortcuts
Several applications provide global hotkey support. These are the associations I use (which are also
captured in the `+restore.bom+` as well):
* *COMMAND (x2)*: Siri (open)
* *COMMAND + SPACE*: Alfred/Spotlight (open)
* link:https://alchemists.io/articles/clean_shot/#_shortcuts[CleanShot]
* *CONTROL + OPTION + COMMAND + c*: Pika (copy color)
* *CONTROL + OPTION + COMMAND + d*: Alfred Define (use OPTION to open Dictionary)
* *CONTROL + OPTION + COMMAND + h*: Alfred Highlight Syntax
* *CONTROL + OPTION + COMMAND + k*: Keymou (cursor highlight show/hide)
* *CONTROL + OPTION + COMMAND + m*: Moom (toggle)
* *CONTROL + OPTION + SHIFT + m*: Moom (open custom actions)
* *CONTROL + OPTION + COMMAND + n*: Notification Center (show/hide)
* *CONTROL + OPTION + COMMAND + o*: Alfred Open URL in default browser
* link:https://alchemists.io/articles/pixel_snap/#_shortcuts[PixelSnap]
* *CONTROL + OPTION + COMMAND + r*: Resolutionator (selector)
* *CONTROL + OPTION + COMMAND + t*: Alfred Large Type
* *CONTROL + OPTION + COMMAND + w*: Mission Control
* *CONTROL + OPTION + COMMAND + ←*: Keymou (move cursor left)
* *CONTROL + OPTION + COMMAND + ↑*: Keymou (move cursor up)
* *CONTROL + OPTION + COMMAND + →*: Keymou (move cursor right)
* *CONTROL + OPTION + COMMAND + ↓*: Keymou (move cursor down)
* *CONTROL + OPTION + COMMAND + ENTER*: Keymou (move cursor by division)
* *CONTROL + OPTION + SPACE*: OmniFocus (quick entry)
* *OPTION + SPACE*: Alfred (open)
💡 See additional link:https://saurabhs.org/macos-tips[tips] for details.
=== Newsyslog
Native to macOS, link:https://www.freebsd.org/cgi/man.cgi?newsyslog.conf(5)[newsyslog] can be used
to configure system-wide log rotation across multiple projects. Its a good recommendation to set
this up so that disk space is carefully maintained. Heres how to configure it for your system,
start by creating a configuration for your projects in the `+/etc/newsyslog.d+` directory. In my
case, I use the following configurations:
* `+/etc/newsyslog.d/alchemists.conf+`
+
....
# logfilename [owner:group] mode count size when flags
/Users/bkuhlmann/Dropbox/Development/Work/**/log/*.log 644 2 5120 * GJN
....
* `+/etc/newsyslog.d/homebrew.conf+`
+
....
# logfilename [owner:group] mode count size when flags
/usr/local/var/log/**/*.log 644 2 5120 * GJN
....
These configurations ensure that logs are rotated every 5MB (5120KB). In order to test that these
configurations are valid, run:
....
sudo newsyslog -nvv
....
If you dont see any errors in the output, then your configuration settings are correct.
The last thing to do is to add a launch configuration to ensure the log rotations happen at
regularly scheduled intervals. To do this create the following file:
`+$HOME/Library/LaunchAgents/com.apple.newsyslog.plist+`. It should have the following content:
[source,xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.apple.newsyslog</string>
<key>ProgramArguments</key>
<array>
<string>/usr/sbin/newsyslog</string>
</array>
<key>LowPriorityIO</key>
<true/>
<key>Nice</key>
<integer>1</integer>
<key>StartCalendarInterval</key>
<dict>
<key>Minute</key>
<integer>30</integer>
</dict>
</dict>
</plist>
----
Thats it. System-wide log rotation is setup for your projects.
=== Customization
While this projects configuration is opinionated and tailored for my setup, you can easily fork
this project and customize it for your environment. Start by editing the files found in the `+bin+`
and `+lib+` directories. Check out the
link:https://alchemists.io/projects/mac_os/#_customization[macOS Customization Documentation]
for further details.
_TIP_: The installer determines which applications/extensions to install as defined in the
`+settings.sh+` script. Applications defined with the "`APP_NAME`" suffix and extensions defined
with the "`EXTENSION_PATH`" suffix inform the installer what to care about. Removing/commenting out
these applications/extensions within the `+settings.sh+` file will cause the installer to skip these
applications/extensions.
== Development
To contribute, run:
[source,bash]
----
git clone https://github.com/bkuhlmann/mac_os-config.git
cd mac_os-config
----
== link:https://alchemists.io/policies/license[License]
== link:https://alchemists.io/policies/security[Security]
== link:https://alchemists.io/policies/code_of_conduct[Code of Conduct]
== link:https://alchemists.io/policies/contributions[Contributions]
== link:https://alchemists.io/policies/developer_certificate_of_origin[Developer Certificate of Origin]
== link:https://alchemists.io/projects/mac_os-config/versions[Versions]
== link:https://alchemists.io/community[Community]
== Credits
Engineered by link:https://alchemists.io/team/brooke_kuhlmann[Brooke Kuhlmann].

12
mac_os-config/Rakefile Normal file
View File

@@ -0,0 +1,12 @@
# frozen_string_literal: true
require "git/lint/rake/register"
require "rubocop/rake_task"
Git::Lint::Rake::Register.call
RuboCop::RakeTask.new
desc "Run code quality checks"
task quality: %i[git_lint rubocop]
task default: :quality

View File

@@ -0,0 +1,17 @@
#! /usr/bin/env bash
# Installs App Store software.
# Affinity Suite
mas install 1616831348 # Affinity Designer 2
mas install 1616822987 # Affinity Photo 2
mas install 1606941598 # Affinity Publisher 2
# Productivity
mas install 1352778147 # Bitwarden
mas install 424389933 # Final Cut Pro
mas install 1503970375 # Invoice Ninja
mas install 409203825 # Numbers
mas install 409201541 # Pages
mas install 1503446680 # PastePal
mas install 1579902068 # xSearch

View File

@@ -0,0 +1,7 @@
#! /usr/bin/env bash
# Installs non-App Store, non-Homebrew applications.
# Add custom app installations here using functions from lib/installers.sh:
# install_dmg_app, install_zip_app, install_bare_pkg, etc.
# Currently empty - all apps are installed via Homebrew or App Store.

View File

@@ -0,0 +1,39 @@
#! /usr/bin/env bash
# Installs basic system settings.
read -p "What is this machine's label (Example: \"Alchemist\")? " mac_os_label
if [[ -z "$mac_os_label" ]]; then
printf "%s\n" "ERROR: Invalid MacOS label."
exit 1
fi
read -p "What is this machine's name (Example: \"alchemist\")? " mac_os_name
if [[ -z "$mac_os_name" ]]; then
printf "%s\n" "ERROR: Invalid MacOS name."
exit 1
fi
read -p "Delete all files in $HOME/Documents (y/n)? " documents
if [[ "$documents" == "y" ]]; then
rm -rf "$HOME/Documents/*"
printf "%s\n" "Documents deleted."
fi
read -p "Delete all files in $HOME/Downloads (y/n)? " downloads
if [[ "$downloads" == "y" ]]; then
rm -rf "$HOME/Downloads/*"
printf "%s\n" "Downloads deleted."
fi
read -p "Change /usr/local ownership to $USER:staff (y/n)? " ownership
if [[ "$ownership" == "y" ]]; then
sudo chown -R "$USER":staff /usr/local
printf "%s\n" "Ownership changed."
fi
printf "Setting system label and name...\n"
sudo scutil --set ComputerName "$mac_os_label"
sudo scutil --set HostName "$mac_os_name"
sudo scutil --set LocalHostName "$mac_os_name"
sudo defaults write /Library/Preferences/SystemConfiguration/com.apple.smb.server NetBIOSName -string $mac_os_name

View File

@@ -0,0 +1,566 @@
#! /usr/bin/env bash
# Installs system and application default settings.
printf "%s\n" "System - Disable boot sound effects."
sudo nvram SystemAudioVolume=" "
printf "%s\n" "System - Reveal IP address, hostname, OS version, etc. when clicking login window clock."
sudo defaults write /Library/Preferences/com.apple.loginwindow AdminHostInfo HostName
printf "%s\n" "System - Disable launching of previously open applications upon reboot."
defaults write -g ApplePersistence -bool no
printf "%s\n" "System - Disable automatic termination of inactive apps."
defaults write NSGlobalDomain NSDisableAutomaticTermination -bool true
printf "%s\n" "System - Expand save panel by default."
defaults write NSGlobalDomain NSNavPanelExpandedStateForSaveMode -bool true
printf "%s\n" "System - Disable 'Are you sure you want to open this application?' dialog."
defaults write com.apple.LaunchServices LSQuarantine -bool false
printf "%s\n" "System - Increase window resize speed for Cocoa applications."
defaults write NSGlobalDomain NSWindowResizeTime -float 0.001
printf "%s\n" "System - Disable window resume system-wide."
defaults write NSGlobalDomain NSQuitAlwaysKeepsWindows -bool false
printf "%s\n" "System - Disable auto-correct."
defaults write NSGlobalDomain NSAutomaticSpellingCorrectionEnabled -bool false
printf "%s\n" "System - Disable smart quotes (not useful when writing code)."
defaults write NSGlobalDomain NSAutomaticQuoteSubstitutionEnabled -bool false
printf "%s\n" "System - Disable smart dashes (not useful when writing code)."
defaults write NSGlobalDomain NSAutomaticDashSubstitutionEnabled -bool false
printf "%s\n" "System - Require password immediately after sleep or screen saver begins."
defaults write com.apple.screensaver askForPassword -int 1
defaults write com.apple.screensaver askForPasswordDelay -int 0
printf "%s\n" "System - Avoid creating .DS_Store files on network volumes."
defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool true
printf "%s\n" "System - Automatically restart if system freezes."
systemsetup -setrestartfreeze on
printf "%s\n" "System - Disable software updates."
sudo softwareupdate --schedule off
printf "%s\n" "Keyboard - Automatically illuminate built-in MacBook keyboard in low light."
defaults write com.apple.BezelServices kDim -bool true
printf "%s\n" "Keyboard - Turn off keyboard illumination when computer is not used for 5 minutes."
defaults write com.apple.BezelServices kDimTime -int 300
printf "%s\n" "Keyboard - Enable keyboard access for all controls."
defaults write NSGlobalDomain AppleKeyboardUIMode -int 3
printf "%s\n" "Keyboard - Set a fast keyboard repeat rate."
defaults write NSGlobalDomain KeyRepeat -int 0
printf "%s\n" "Keyboard - Disable press-and-hold for keys in favor of key repeat."
defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool false
printf "%s\n" "Trackpad - Map bottom right corner to right-click."
defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad TrackpadCornerSecondaryClick -int 2
defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad TrackpadRightClick -bool true
defaults -currentHost write NSGlobalDomain com.apple.trackpad.trackpadCornerClickBehavior -int 1
defaults -currentHost write NSGlobalDomain com.apple.trackpad.enableSecondaryClick -bool true
printf "%s\n" "Trackpad - Enable tap to click for current user and the login screen."
defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool true
defaults -currentHost write NSGlobalDomain com.apple.mouse.tapBehavior -int 1
defaults write NSGlobalDomain com.apple.mouse.tapBehavior -int 1
printf "%s\n" "Trackpad - Use CONTROL (^) with scroll to zoom."
defaults write com.apple.universalaccess closeViewScrollWheelToggle -bool true
defaults write com.apple.universalaccess HIDScrollZoomModifierMask -int 262144
printf "%s\n" "Trackpad - Follow keyboard focus while zoomed in."
defaults write com.apple.universalaccess closeViewZoomFollowsFocus -bool true
printf "%s\n" "Bluetooth - Increase sound quality for headphones/headsets."
defaults write com.apple.BluetoothAudioAgent "Apple Bitpool Min (editable)" -int 40
printf "%s\n" "Menu Bar - Show only Bluetooth and Airport."
for domain in $HOME/Library/Preferences/ByHost/com.apple.systemuiserver.*; do
defaults write "${domain}" dontAutoLoad -array "/System/Library/CoreServices/Menu Extras/TimeMachine.menu"
done
defaults write com.apple.systemuiserver menuExtras -array \
"/System/Library/CoreServices/Menu Extras/Bluetooth.menu" \
"/System/Library/CoreServices/Menu Extras/AirPort.menu"
printf "%s\n" "Dock - Remove all default app icons."
defaults write com.apple.dock persistent-apps -array
printf "%s\n" "Dock - Automatically hide and show."
defaults write com.apple.dock autohide -bool true
printf "%s\n" "Dock - Remove the auto-hiding delay."
defaults write com.apple.Dock autohide-delay -float 0
printf "%s\n" "Dock - Dont show Dashboard as a Space."
defaults write com.apple.dock "dashboard-in-overlay" -bool true
printf "%s\n" "iCloud - Save to disk by default."
defaults write NSGlobalDomain NSDocumentSaveNewDocumentsToCloud -bool false
printf "%s\n" "Finder - Show the $HOME/Library folder."
chflags nohidden $HOME/Library
printf "%s\n" "Finder - Show hidden files."
defaults write com.apple.finder AppleShowAllFiles -bool true
printf "%s\n" "Finder - Show filename extensions."
defaults write NSGlobalDomain AppleShowAllExtensions -bool true
printf "%s\n" "Finder - Disable the warning when changing a file extension."
defaults write com.apple.finder FXEnableExtensionChangeWarning -bool false
printf "%s\n" "Finder - Show path bar."
defaults write com.apple.finder ShowPathbar -bool true
printf "%s\n" "Finder - Show status bar."
defaults write com.apple.finder ShowStatusBar -bool true
printf "%s\n" "Finder - Display full POSIX path as window title."
defaults write com.apple.finder _FXShowPosixPathInTitle -bool true
printf "%s\n" "Finder - Use list view in all Finder windows."
defaults write com.apple.finder FXPreferredViewStyle -string "Nlsv"
printf "%s\n" "Finder - Allow quitting via COMMAND+Q -- Doing so will also hide desktop icons."
defaults write com.apple.finder QuitMenuItem -bool true
printf "%s\n" "Finder - Disable the warning before emptying the Trash."
defaults write com.apple.finder WarnOnEmptyTrash -bool false
printf "%s\n" "Finder - Allow text selection in Quick Look."
defaults write com.apple.finder QLEnableTextSelection -bool true
printf "%s\n" "iOS Simulator - Symlink the iOS Simulator application."
sudo ln -sf "/Applications/Xcode.app/Contents/Applications/iPhone Simulator.app" "/Applications/iOS Simulator.app"
printf "%s\n" "Safari - Set home page to 'about:blank' for faster loading."
defaults write com.apple.Safari HomePage -string "about:blank"
printf "%s\n" "Safari - Hide bookmarks bar."
defaults write com.apple.Safari ShowFavoritesBar -bool false
printf "%s\n" "Safari - Use Contains instead of Starts With in search banners."
defaults write com.apple.Safari FindOnPageMatchesWordStartsOnly -bool false
printf "%s\n" "Safari - Enable debug menu."
defaults write com.apple.Safari IncludeInternalDebugMenu -bool true
printf "%s\n" "Safari - Enable the Develop menu and the Web Inspector."
defaults write com.apple.Safari IncludeDevelopMenu -bool true
defaults write com.apple.Safari WebKitDeveloperExtrasEnabledPreferenceKey -bool true
defaults write com.apple.Safari com.apple.Safari.ContentPageGroupIdentifier.WebKit2DeveloperExtrasEnabled -bool true
printf "%s\n" "Safari - Add a context menu item for showing the Web Inspector in web views."
defaults write NSGlobalDomain WebKitDeveloperExtras -bool true
printf "%s\n" "Safari - Disable sending search queries to Apple.."
defaults write com.apple.Safari UniversalSearchEnabled -bool false
printf "%s\n" "Chrome - Prevent native print dialog, use system dialog instead."
defaults write com.google.Chrome DisablePrintPreview -boolean true
printf "%s\n" "Mail - Copy email addresses as 'foo@example.com' instead of 'Foo Bar <foo@example.com>'."
defaults write com.apple.mail AddressesIncludeNameOnPasteboard -bool false
printf "%s\n" "Mail - Disable send animation."
defaults write com.apple.mail DisableSendAnimations -bool true
printf "%s\n" "Mail - Disable reply animation."
defaults write com.apple.mail DisableReplyAnimations -bool true
printf "%s\n" "Mail - Enable COMMAND+ENTER to send mail."
defaults write com.apple.mail NSUserKeyEquivalents -dict-add "Send" -string "@\\U21a9"
printf "%s\n" "Address Book - Enable debug menu."
defaults write com.apple.addressbook ABShowDebugMenu -bool true
printf "%s\n" "iCal - Enable debug menu."
defaults write com.apple.iCal IncludeDebugMenu -bool true
printf "%s\n" "TextEdit - Use plain text mode for new documents."
defaults write com.apple.TextEdit RichText -int 0
printf "%s\n" "TextEdit - Open and save files as UTF-8 encoding."
defaults write com.apple.TextEdit PlainTextEncoding -int 4
defaults write com.apple.TextEdit PlainTextEncodingForWrite -int 4
printf "%s\n" "Disk Utility - Enable debug menu."
defaults write com.apple.DiskUtility DUDebugMenuEnabled -bool true
defaults write com.apple.DiskUtility advanced-image-options -bool true
printf "%s\n" "Time Machine - Prevent prompting to use new hard drives as backup volume."
defaults write com.apple.TimeMachine DoNotOfferNewDisksForBackup -bool true
printf "%s\n" "Printer - Expand print panel by default."
defaults write NSGlobalDomain PMPrintingExpandedStateForPrint -bool true
printf "%s\n" "Printer - Automatically quit printer app once the print jobs complete."
defaults write com.apple.print.PrintingPrefs "Quit When Finished" -bool true
printf "%s\n" "Game Center - Disable Game Center."
defaults write com.apple.gamed Disabled -bool true
printf "%s\n" "App Store - Enable the WebKit Developer Tools in the Mac App Store."
defaults write com.apple.appstore WebKitDeveloperExtras -bool true
printf "%s\n" "App Store - Enable Debug Menu in the Mac App Store."
defaults write com.apple.appstore ShowDebugMenu -bool true
printf "CCMenu - Add open source projects\n"
defaults write net.sourceforge.cruisecontrol.CCMenu '
{
NSNavLastRootDirectory = "~/Downloads";
NSNavPanelExpandedSizeForSaveMode = "{800, 448}";
"NSStatusItem Preferred Position Item-0" = 628;
"PlaySound Broken" = 0;
"PlaySound Fixed" = 0;
"PlaySound StillFailing" = 0;
"PlaySound Successful" = 0;
ProjectOrder = 1;
"SendNotification Broken" = 1;
"SendNotification Fixed" = 1;
"SendNotification StillFailing" = 1;
"SendNotification Successful" = 1;
ShowPipelineStatusInWindow = 1;
"Sound Broken" = Sosumi;
"Sound Fixed" = Sosumi;
"Sound StillFailing" = Sosumi;
"Sound Successful" = Sosumi;
pipelines = (
{
feedName = "bkuhlmann/auther";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/auther.cc.xml";
name = Auther;
},
{
feedName = "bkuhlmann/bashsmith";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/bashsmith.cc.xml";
name = Bashsmith;
},
{
feedName = "bkuhlmann/benchmarks";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/benchmarks.cc.xml";
name = Benchmarks;
},
{
feedName = "bkuhlmann/caliber";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/caliber.cc.xml";
name = Caliber;
},
{
feedName = "bkuhlmann/cogger";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/cogger.cc.xml";
name = Cogger;
},
{
feedName = "bkuhlmann/containable";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/containable.cc.xml";
name = Containable;
},
{
feedName = "bkuhlmann/core";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/core.cc.xml";
name = Core;
},
{
feedName = "bkuhlmann/docker-alpine-base";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/docker-alpine-base.cc.xml";
name = "Docker Alpine Base";
},
{
feedName = "bkuhlmann/docker-alpine-ruby";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/docker-alpine-ruby.cc.xml";
name = "Docker Alpine Ruby";
},
{
feedName = "bkuhlmann/dotfiles";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/dotfiles.cc.xml";
name = Dotfiles;
},
{
feedName = "bkuhlmann/etcher";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/etcher.cc.xml";
name = Etcher;
},
{
feedName = "bkuhlmann/functionable";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/functionable.cc.xml";
name = "Functionable";
},
{
feedName = "bkuhlmann/gemsmith";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/gemsmith.cc.xml";
name = Gemsmith;
},
{
feedName = "bkuhlmann/ghub";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/ghub.cc.xml";
name = Ghub;
},
{
feedName = "bkuhlmann/git-lint";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/git-lint.cc.xml";
name = "Git Lint";
},
{
feedName = "bkuhlmann/gitt";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/gitt.cc.xml";
name = Gitt;
},
{
feedName = "bkuhlmann/hanamismith";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/hanamismith.cc.xml";
name = Hanamismith;
},
{
feedName = "bkuhlmann/htmx";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/htmx.cc.xml";
name = HTMX;
},
{
feedName = "bkuhlmann/htmx-remove";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/htmx-remove.cc.xml";
name = "htmx Remove";
},
{
feedName = "bkuhlmann/htmx-select";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/htmx-select.cc.xml";
name = "htmx Select";
},
{
feedName = "bkuhlmann/hemo";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/hemo.cc.xml";
name = Hemo;
},
{
feedName = "bkuhlmann/http-fake";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/http-fake.cc.xml";
name = "HTTP Fake";
},
{
feedName = "bkuhlmann/infusible";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/infusible.cc.xml";
name = Infusible;
},
{
feedName = "bkuhlmann/initable";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/initable.cc.xml";
name = Initable;
},
{
feedName = "bkuhlmann/inspectable";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/inspectable.cc.xml";
name = Inspectable;
},
{
feedName = "bkuhlmann/irb-kit";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/irb-kit.cc.xml";
name = "IRB Kit";
},
{
feedName = "bkuhlmann/kagi-api";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/kagi-api.cc.xml";
name = "Kagi API";
},
{
feedName = "bkuhlmann/lode";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/lode.cc.xml";
name = Lode;
},
{
feedName = "bkuhlmann/mac_os";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/mac_os.cc.xml";
name = macOS;
},
{
feedName = "bkuhlmann/mac_os-config";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/mac_os-config.cc.xml";
name = "macOS Configuration";
},
{
feedName = "bkuhlmann/marameters";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/marameters.cc.xml";
name = Marameters;
},
{
feedName = "bkuhlmann/milestoner";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/milestoner.cc.xml";
name = Milestoner;
},
{
feedName = "bkuhlmann/navigator";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/navigator.cc.xml";
name = Navigator;
},
{
feedName = "bkuhlmann/pennyworth";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/pennyworth.cc.xml";
name = Pennyworth;
},
{
feedName = "bkuhlmann/petail";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/petail.cc.xml";
name = Petail;
},
{
feedName = "bkuhlmann/pipeable";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/pipeable.cc.xml";
name = Pipeable;
},
{
feedName = "bkuhlmann/pkce";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/pkce.cc.xml";
name = PKCE;
},
{
feedName = "bkuhlmann/pragmater";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/pragmater.cc.xml";
name = Pragmater;
},
{
feedName = "bkuhlmann/prawn_plus";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/prawn_plus.cc.xml";
name = "Prawn+";
},
{
feedName = "bkuhlmann/refinements";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/refinements.cc.xml";
name = Refinements;
},
{
feedName = "bkuhlmann/rubysmith";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/rubysmith.cc.xml";
name = Rubysmith;
},
{
feedName = "bkuhlmann/runcom";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/runcom.cc.xml";
name = Runcom;
},
{
feedName = "bkuhlmann/sod";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/sod.cc.xml";
name = Sod;
},
{
feedName = "bkuhlmann/spek";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/spek.cc.xml";
name = Spek;
},
{
feedName = "bkuhlmann/sublime_text_kit";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/sublime_text_kit.cc.xml";
name = "Sublime Text Kit";
},
{
feedName = "bkuhlmann/sublime_text_setup";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/sublime_text_setup.cc.xml";
name = "Sublime Text Setup";
},
{
feedName = "bkuhlmann/tana";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/tana.cc.xml";
name = Tana;
},
{
feedName = "bkuhlmann/tocer";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/tocer.cc.xml";
name = Tocer;
},
{
feedName = "bkuhlmann/tone";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/tone.cc.xml";
name = Tone;
},
{
feedName = "usetrmnl/trmnl-api";
feedType = cctray;
feedUrl = "https://circleci.com/gh/usetrmnl/trmnl-api.cc.xml";
name = "TRMNL API";
},
{
feedName = "usetrmnl/byos_hanami";
feedType = cctray;
feedUrl = "https://circleci.com/gh/usetrmnl/byos_hanami.cc.xml";
name = "TRMNL Terminus";
},
{
feedName = "bkuhlmann/versionaire";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/versionaire.cc.xml";
name = Versionaire;
},
{
feedName = "bkuhlmann/wholeable";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/wholeable.cc.xml";
name = Wholeable;
},
{
feedName = "bkuhlmann/xdg";
feedType = cctray;
feedUrl = "https://circleci.com/gh/bkuhlmann/xdg.cc.xml";
name = XDG;
}
);
}'

View File

@@ -0,0 +1,6 @@
#! /usr/bin/env bash
# Installs application extensions (editor plugins, etc.)
# Add extensions here using install_git_app or install_file from lib/installers.sh
# Currently empty - add extensions as needed.

View File

@@ -0,0 +1,21 @@
#! /usr/bin/env bash
# Installs Homebrew Casks (GUI applications).
# Browsers
brew install --cask eloston-chromium
# Communication
brew install --cask deepl
brew install --cask element
brew install --cask signal
# Cloud & Sync
brew install --cask nextcloud
brew install --cask proton-drive
brew install --cask proton-mail
brew install --cask protonvpn
# Development
brew install --cask nova
brew install --cask transmit

View File

@@ -0,0 +1,20 @@
#! /usr/bin/env bash
# Installs Homebrew formulas (CLI tools).
# Shell & Terminal
brew install atuin
brew install bash
brew install bash-completion
# Development
brew install node
# Media
brew install ffmpeg
# Utilities
brew install mas
brew install mole
brew install rename
brew install ykman

View File

@@ -0,0 +1,6 @@
#! /usr/bin/env bash
# Installs global Node.js packages.
# Add packages here: npm install -g <package>
# Currently empty - add packages as needed.

View File

@@ -0,0 +1,6 @@
#! /usr/bin/env bash
# Installs Ruby gems.
# Add gems here: gem install <gem>
# Currently empty - add gems as needed.

View File

@@ -0,0 +1,6 @@
#! /usr/bin/env bash
# Installs Rust crates.
# Add crates here: cargo install <crate>
# Currently empty - add crates as needed.

11
mac_os-config/bin/install_shell Executable file
View File

@@ -0,0 +1,11 @@
#! /usr/bin/env bash
# Installs shell.
if [[ -z $(cat /etc/shells | grep "$(get_homebrew_bin_root)/bash") ]]; then
sudo bash -c "printf '$(get_homebrew_bin_root)/bash\n' >> /etc/shells"
chsh -s "$(get_homebrew_bin_root)/bash"
rm -f "$HOME/.bash_profile"
else
printf "%s\n" "Shell is installed."
fi

6
mac_os-config/bin/rake Executable file
View File

@@ -0,0 +1,6 @@
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/setup"
load Gem.bin_path "rake", "rake"

View File

@@ -0,0 +1,48 @@
#! /usr/bin/env bash
# Performs restoration of backups.
read -p "Enter the backup volume path (Example: \"/Volumes/alchemist\")? " mac_os_backup_root
if [[ ! -e "$mac_os_backup_root" ]]; then
printf "%s\n" "ERROR: Backup volume cannot be found: $mac_os_backup_root."
exit 1
fi
mkdir -p log
rsync \
--rsync-path="sudo rsync" \
--perms \
--recursive \
--compress \
--numeric-ids \
--links \
--hard-links \
--files-from="$MAC_OS_CONFIG_PATH/lib/restore.bom" \
--log-file="log/restore.log" \
--human-readable \
--verbose \
"$mac_os_backup_root/" /
# Newsyslog
sudo cp -p "$mac_os_backup_root/etc/newsyslog.d/alchemists.conf" "/etc/newsyslog.d"
sudo cp -p "$mac_os_backup_root/etc/newsyslog.d/homebrew.conf" "/etc/newsyslog.d"
# Dotfiles
(
cd "$HOME/Engineering/OSS/dotfiles"
bin/run l
)
# Sublime Text
(
cd "$HOME/Engineering/OSS/sublime_text_setup"
bin/run l
)
# Duti
duti "$HOME/.config/duti/configuration.duti"
# Reboot
printf "%s\n" "Please reboot machine and then finish by installing all libraries."

View File

@@ -0,0 +1,232 @@
# APPLICATIONS
# Acorn
/Users/bkuhlmann/Library/Preferences/com.flyingmeat.Acorn5.LSSharedFileList.plist
# Alfred
/Users/bkuhlmann/Library/Preferences/com.runningwithcrayons.Alfred-Preferences.plist
/Users/bkuhlmann/Library/Preferences/com.runningwithcrayons.Alfred.plist
# App Cleaner
/Users/bkuhlmann/Library/Preferences/com.freemacsoft.AppCleaner.plist
/Users/bkuhlmann/Library/Preferences/net.freemacsoft.AppCleaner.plist
# Apple AirPlay
/Users/bkuhlmann/Library/Preferences/com.apple.airplay.plist
# Apple App Store
/Users/bkuhlmann/Library/Preferences/com.apple.appstore.commerce.plist
/Users/bkuhlmann/Library/Preferences/com.apple.appstore.plist
# Apple Clock
/Users/bkuhlmann/Library/Preferences/com.apple.menuextra.clock.plist
# Apple Contacts
/Users/bkuhlmann/Library/Preferences/com.apple.AddressBook.plist
# Apple Control Center
/Users/bkuhlmann/Library/Preferences/com.apple.controlcenter.plist
# Apple Dock
/Users/bkuhlmann/Library/Preferences/com.apple.dock.plist
# Apple FaceTime
/Users/bkuhlmann/Library/Preferences/com.apple.facetime.bag.plist
/Users/bkuhlmann/Library/Preferences/com.apple.FaceTime.plist
/Users/bkuhlmann/Library/Preferences/com.apple.imservice.ids.FaceTime.plist
# Apple Finder
/Users/bkuhlmann/Library/Preferences/com.apple.finder.plist
# Apple Image Capture
/Users/bkuhlmann/Library/Preferences/com.apple.ImageCaptureExtension2.plist
/Users/bkuhlmann/Library/Preferences/com.apple.Image_Capture.plist
# Apple iTunes
/Users/bkuhlmann/Library/Preferences/com.apple.iTunes.eq.plist
/Users/bkuhlmann/Library/Preferences/com.apple.iTunes.Gracenote.plist
/Users/bkuhlmann/Library/Preferences/com.apple.iTunes.Gracenote.plist
/Users/bkuhlmann/Library/Preferences/com.apple.iTunes.plist
/Users/bkuhlmann/Library/Preferences/com.apple.iTunesHelper.plist
# Apple Mouse and Trackpad
/Users/bkuhlmann/Library/Preferences/com.apple.driver.AppleBluetoothMultitouch.mouse.plist
/Users/bkuhlmann/Library/Preferences/com.apple.driver.AppleBluetoothMultitouch.trackpad.plist
/Users/bkuhlmann/Library/Preferences/com.apple.driver.AppleHIDMouse.plist
# Apple Siri
/Users/bkuhlmann/Library/Preferences/com.apple.Siri.plist
# Apple System Preferences
/Users/bkuhlmann/Library/Preferences/com.apple.systempreferences.plist
# Audio Hijack
/Users/bkuhlmann/Library/Preferences/com.rogueamoeba.audiohijack3.plist
# Balena Etcher
/Users/bkuhlmann/Library/Preferences/io.balena.etcher.plist
# Carbon Copy Cloner
/Users/bkuhlmann/Library/Preferences/com.bombich.ccc.plist
# CleanShot
/Users/bkuhlmann/Library/Preferences/pl.maketheweb.cleanshotx.plist
# Discord
/Users/bkuhlmann/Library/Preferences/com.hnc.Discord.plist
# Docker
/Users/bkuhlmann/Library/Preferences/com.docker.docker.plist
# Doxie
/Users/bkuhlmann/Library/Preferences/com.getdoxie.doxie.plist
# Firefox
/Users/bkuhlmann/Library/Preferences/org.mozilla.firefox.plist
# Fission
/Users/bkuhlmann/Library/Preferences/com.rogueamoeba.Fission.plist
# Google Chrome
/Users/bkuhlmann/Library/Preferences/com.google.Chrome.plist
# Hazel
/Users/bkuhlmann/Library/Application Support/Hazel
/Users/bkuhlmann/Library/Preferences/com.noodlesoft.Hazel.plist
/Users/bkuhlmann/Library/Preferences/com.noodlesoft.HazelHelper.plist
# Ice
/Users/bkuhlmann/Library/Preferences/com.jordanbaird.Ice.plist
# IINA
/Users/bkuhlmann/Library/Preferences/com.colliderli.iina.plist
# ImageOptim
/Users/bkuhlmann/Library/Preferences/net.pornel.ImageOptim.plist
# iStat Menus
/Users/bkuhlmann/Library/Preferences/com.bjango.istatmenus.plist
/Users/bkuhlmann/Library/Preferences/com.bjango.istatmenus6.extras.plist
# iTerm
/Users/bkuhlmann/Library/Preferences/com.googlecode.iterm2.plist
# Kagi
/Users/bkuhlmann/Library/Preferences/com.kagi.kagimacOS.plist
# Keymou
/Users/bkuhlmann/Library/Preferences/com.manytricks.Keymo.plist
# LimeChat
/Users/bkuhlmann/Library/Preferences/net.limechat.LimeChat-AppStore.plist
# Max
/Users/bkuhlmann/Library/Preferences/org.sbooth.Max.LSSharedFileList.plist
/Users/bkuhlmann/Library/Preferences/org.sbooth.Max.plist
# MoneyWell
/Users/bkuhlmann/Library/Preferences/com.nothirst.moneywell.mac.LSSharedFileList.plist
# Moom
/Users/bkuhlmann/Library/Preferences/com.manytricks.Moom.plist
# NetNewsWire
/Users/bkuhlmann/Library/Preferences/com.ranchero.NetNewsWire-Evergreen.plist
# Numi
/Users/bkuhlmann/Library/Preferences/com.dmitrynikolaev.numi.plist
# Obsidian
/Users/bkuhlmann/Library/Preferences/md.obsidian.plist
# Path Finder
/Users/bkuhlmann/Library/Application Support/Path Finder
/Users/bkuhlmann/Library/Preferences/com.cocoatech.PathFinder.LSSharedFileList.plist
/Users/bkuhlmann/Library/Preferences/com.cocoatech.PathFinder.plist
# pgAdmin
/Users/bkuhlmann/Library/Preferences/org.pgadmin.pgAdmin 4.plist
# Pika
/Users/bkuhlmann/Library/Preferences/com.superhighfives.Pika.plist
# PixelSnap
/Users/bkuhlmann/Library/Preferences/pl.maketheweb.pixelsnap2.plist
# Retrobatch
/Users/bkuhlmann/Library/Preferences/com.flyingmeat.Retrobatch.plist
# Resolutionator
/Users/bkuhlmann/Library/Preferences/com.manytricks.Resolutionator.plist
# Skim
/Users/bkuhlmann/Library/Prererences/net.sourceforge.skim-aoo.skim.bookmarks.plist
/Users/bkuhlmann/Library/Preferences/net.sourceforge.skim-app.skim.plist
# Signal
/Users/bkuhlmann/Library/Preferences/org.whispersystems.signal-desktop.helper.plist
/Users/bkuhlmann/Library/Preferences/org.whispersystems.signal-desktop.plist
# Sonos
/Users/bkuhlmann/Library/Preferences/com.sonos.macController.plist
# Tana
/Users/bkuhlmann/Library/Preferences/inc.tana.desktop.plist
# Transmit
/Users/bkuhlmann/Library/Preferences/com.panic.Transmit.plist
# Viscosity
/Users/bkuhlmann/Library/Preferences/com.viscosityvpn.Viscosity.plist
# Vivaldi
/Users/bkuhlmann/Library/Preferences/com.vivaldi.Vivaldi.plist
# SYSTEM
# newsyslog
/Users/bkuhlmann/Library/LaunchAgents/com.apple.newsyslog.plist
# USER
/Users/bkuhlmann/.asciinema
/Users/bkuhlmann/.cache/milestoner
/Users/bkuhlmann/.cache/psql
/Users/bkuhlmann/.cache/ruby
/Users/bkuhlmann/.cache/zoxide
/Users/bkuhlmann/.config/asciinema
/Users/bkuhlmann/.config/atuin
/Users/bkuhlmann/.config/bash
/Users/bkuhlmann/.config/bundler
/Users/bkuhlmann/.config/duti
/Users/bkuhlmann/.config/gemsmith
/Users/bkuhlmann/.config/git
/Users/bkuhlmann/.config/hanamismith
/Users/bkuhlmann/.config/htop
/Users/bkuhlmann/.config/iterm2
/Users/bkuhlmann/.config/lnav
/Users/bkuhlmann/.config/milestoner
/Users/bkuhlmann/.config/pennyworth
/Users/bkuhlmann/.config/pgcli
/Users/bkuhlmann/.config/pragmater
/Users/bkuhlmann/.config/rubysmith
/Users/bkuhlmann/.config/sublime_text_kit
/Users/bkuhlmann/.gem/credentials
/Users/bkuhlmann/.gem/gem-private_key.pem
/Users/bkuhlmann/.gem/gem-public_cert.pem
/Users/bkuhlmann/.gnupg
/Users/bkuhlmann/.local/share/atuin/history.db
/Users/bkuhlmann/.minisign
/Users/bkuhlmann/.netrc
/Users/bkuhlmann/.parallel
/Users/bkuhlmann/.pgadmin
/Users/bkuhlmann/.siege
/Users/bkuhlmann/.ssh
/Users/bkuhlmann/.vscode
/Users/bkuhlmann/Apps
/Users/bkuhlmann/Desktop
/Users/bkuhlmann/Documents
/Users/bkuhlmann/Downloads
/Users/bkuhlmann/Dropbox
/Users/bkuhlmann/Engineering
/Users/bkuhlmann/Scratch
/Users/bkuhlmann/Watch

View File

@@ -0,0 +1,19 @@
#! /usr/bin/env bash
# Defines global settings.
# General
set -o nounset
set -o errexit
set -o pipefail
IFS=$'\n\t'
# Homebrew
export HOMEBREW_CURL_RETRIES=3
# Custom Applications
# Add app URLs and names here for apps not available via Homebrew or App Store.
# Example:
# export MY_APP_NAME="MyApp.app"
# export MY_APP_URL="https://example.com/download/myapp.dmg"
# export MY_APP_VOLUME_NAME="MyApp"

View File

@@ -0,0 +1,31 @@
version: 2.1
jobs:
build:
working_directory: ~/project
docker:
- image: bkuhlmann/alpine-ruby:latest
steps:
- checkout
- restore_cache:
name: Gems Restore
keys:
- gem-cache-{{.Branch}}-{{checksum "Gemfile"}}
- gem-cache-
- run:
name: Gems Install
command: |
gem update --system
bundle config set path "vendor/bundle"
bundle install
- save_cache:
name: Gems Store
key: gem-cache-{{.Branch}}-{{checksum "Gemfile"}}
paths:
- vendor/bundle
- run:
name: Rake
command: bundle exec rake

View File

@@ -0,0 +1,2 @@
inherit_gem:
caliber: config/all.yml

1
mac_os/.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1 @@
github: [bkuhlmann]

View File

@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Community
url: https://alchemists.io/community
about: Please ask questions or discuss specifics here.
- name: Security
url: https://alchemists.io/policies/security
about: Please report security vulnerabilities here.

18
mac_os/.github/ISSUE_TEMPLATE/issue.md vendored Normal file
View File

@@ -0,0 +1,18 @@
---
name: Issue
title: "Add|Update|Fix|Remove|Refactor "
about: Report an issue. Please use only one of the subject prefixes.
---
<!--
Please focus on well written issues. Context: https://alchemists.io/articles/software_issues.
-->
## Why
<!-- Required. Describe, briefly, why this issue is important. -->
## How
<!-- Optional. List exact steps to implement or reproduce behavior. Screen shots/casts are welcome! -->
## Notes
<!-- Optional. Provide additional details like operating system, software version(s), stack dump, logs, or anything else that would be helpful. -->

View File

@@ -0,0 +1,8 @@
## Overview
<!-- Required. Describe, briefly, why this is necessary and what the overarching architecture is. -->
## Screenshots/Screencasts
<!-- Optional. Provide supporting screen shots/casts. -->
## Details
<!-- Optional. As bullet points, list related issue(s); major highlights; team callouts; and/or other information that is helpful. -->

1
mac_os/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
Gemfile.lock

1
mac_os/.ruby-version Normal file
View File

@@ -0,0 +1 @@
4.0.0

22
mac_os/CITATION.cff Normal file
View File

@@ -0,0 +1,22 @@
cff-version: 1.2.0
message: Please use the following metadata when citing this project in your work.
title: macOS
abstract: Shell scripts for automated macOS machine setup.
version: 22.0.0
license: Hippocratic-2.1
date-released: 2026-01-01
authors:
- family-names: Kuhlmann
given-names: Brooke
affiliation: Alchemists
orcid: https://orcid.org/0000-0002-5810-6268
keywords:
- bash
- shell
- scripts
- automation
- setup
- recovery
repository-code: https://github.com/bkuhlmann/mac_os
repository-artifact: https://alchemists.io/projects/mac_os
url: https://alchemists.io/projects/mac_os

10
mac_os/Gemfile Normal file
View File

@@ -0,0 +1,10 @@
# frozen_string_literal: true
ruby file: ".ruby-version"
source "https://rubygems.org"
gem "caliber", "~> 0.87"
gem "debug", "~> 1.11"
gem "git-lint", "~> 10.0"
gem "rake", "~> 13.3"

134
mac_os/LICENSE.adoc Normal file
View File

@@ -0,0 +1,134 @@
= Hippocratic License
Version: 2.1.0.
Purpose. The purpose of this License is for the Licensor named above to
permit the Licensee (as defined below) broad permission, if consistent
with Human Rights Laws and Human Rights Principles (as each is defined
below), to use and work with the Software (as defined below) within the
full scope of Licensors copyright and patent rights, if any, in the
Software, while ensuring attribution and protecting the Licensor from
liability.
Permission and Conditions. The Licensor grants permission by this
license ("License"), free of charge, to the extent of Licensors
rights under applicable copyright and patent law, to any person or
entity (the "Licensee") obtaining a copy of this software and
associated documentation files (the "Software"), to do everything with
the Software that would otherwise infringe (i) the Licensors copyright
in the Software or (ii) any patent claims to the Software that the
Licensor can license or becomes able to license, subject to all of the
following terms and conditions:
* Acceptance. This License is automatically offered to every person and
entity subject to its terms and conditions. Licensee accepts this
License and agrees to its terms and conditions by taking any action with
the Software that, absent this License, would infringe any intellectual
property right held by Licensor.
* Notice. Licensee must ensure that everyone who gets a copy of any part
of this Software from Licensee, with or without changes, also receives
the License and the above copyright notice (and if included by the
Licensor, patent, trademark and attribution notice). Licensee must cause
any modified versions of the Software to carry prominent notices stating
that Licensee changed the Software. For clarity, although Licensee is
free to create modifications of the Software and distribute only the
modified portion created by Licensee with additional or different terms,
the portion of the Software not modified must be distributed pursuant to
this License. If anyone notifies Licensee in writing that Licensee has
not complied with this Notice section, Licensee can keep this License by
taking all practical steps to comply within 30 days after the notice. If
Licensee does not do so, Licensees License (and all rights licensed
hereunder) shall end immediately.
* Compliance with Human Rights Principles and Human Rights Laws.
[arabic]
. Human Rights Principles.
[loweralpha]
.. Licensee is advised to consult the articles of the United Nations
Universal Declaration of Human Rights and the United Nations Global
Compact that define recognized principles of international human rights
(the "Human Rights Principles"). Licensee shall use the Software in a
manner consistent with Human Rights Principles.
.. Unless the Licensor and Licensee agree otherwise, any dispute,
controversy, or claim arising out of or relating to (i) Section 1(a)
regarding Human Rights Principles, including the breach of Section 1(a),
termination of this License for breach of the Human Rights Principles,
or invalidity of Section 1(a) or (ii) a determination of whether any Law
is consistent or in conflict with Human Rights Principles pursuant to
Section 2, below, shall be settled by arbitration in accordance with the
Hague Rules on Business and Human Rights Arbitration (the "Rules");
provided, however, that Licensee may elect not to participate in such
arbitration, in which event this License (and all rights licensed
hereunder) shall end immediately. The number of arbitrators shall be one
unless the Rules require otherwise.
+
Unless both the Licensor and Licensee agree to the contrary: (1) All
documents and information concerning the arbitration shall be public and
may be disclosed by any party; (2) The repository referred to under
Article 43 of the Rules shall make available to the public in a timely
manner all documents concerning the arbitration which are communicated
to it, including all submissions of the parties, all evidence admitted
into the record of the proceedings, all transcripts or other recordings
of hearings and all orders, decisions and awards of the arbitral
tribunal, subject only to the arbitral tribunals powers to take such
measures as may be necessary to safeguard the integrity of the arbitral
process pursuant to Articles 18, 33, 41 and 42 of the Rules; and (3)
Article 26(6) of the Rules shall not apply.
. Human Rights Laws. The Software shall not be used by any person or
entity for any systems, activities, or other uses that violate any Human
Rights Laws. "Human Rights Laws" means any applicable laws,
regulations, or rules (collectively, "Laws") that protect human,
civil, labor, privacy, political, environmental, security, economic, due
process, or similar rights; provided, however, that such Laws are
consistent and not in conflict with Human Rights Principles (a dispute
over the consistency or a conflict between Laws and Human Rights
Principles shall be determined by arbitration as stated above). Where
the Human Rights Laws of more than one jurisdiction are applicable or in
conflict with respect to the use of the Software, the Human Rights Laws
that are most protective of the individuals or groups harmed shall
apply.
. Indemnity. Licensee shall hold harmless and indemnify Licensor (and
any other contributor) against all losses, damages, liabilities,
deficiencies, claims, actions, judgments, settlements, interest, awards,
penalties, fines, costs, or expenses of whatever kind, including
Licensors reasonable attorneys fees, arising out of or relating to
Licensees use of the Software in violation of Human Rights Laws or
Human Rights Principles.
* Failure to Comply. Any failure of Licensee to act according to the
terms and conditions of this License is both a breach of the License and
an infringement of the intellectual property rights of the Licensor
(subject to exceptions under Laws, e.g., fair use). In the event of a
breach or infringement, the terms and conditions of this License may be
enforced by Licensor under the Laws of any jurisdiction to which
Licensee is subject. Licensee also agrees that the Licensor may enforce
the terms and conditions of this License against Licensee through
specific performance (or similar remedy under Laws) to the extent
permitted by Laws. For clarity, except in the event of a breach of this
License, infringement, or as otherwise stated in this License, Licensor
may not terminate this License with Licensee.
* Enforceability and Interpretation. If any term or provision of this
License is determined to be invalid, illegal, or unenforceable by a
court of competent jurisdiction, then such invalidity, illegality, or
unenforceability shall not affect any other term or provision of this
License or invalidate or render unenforceable such term or provision in
any other jurisdiction; provided, however, subject to a court
modification pursuant to the immediately following sentence, if any term
or provision of this License pertaining to Human Rights Laws or Human
Rights Principles is deemed invalid, illegal, or unenforceable against
Licensee by a court of competent jurisdiction, all rights in the
Software granted to Licensee shall be deemed null and void as between
Licensor and Licensee. Upon a determination that any term or provision
is invalid, illegal, or unenforceable, to the extent permitted by Laws,
the court may modify this License to affect the original purpose that
the Software be used in compliance with Human Rights Principles and
Human Rights Laws as closely as possible. The language in this License
shall be interpreted as to its fair meaning and not strictly for or
against any party.
* Disclaimer. TO THE FULL EXTENT ALLOWED BY LAW, THIS SOFTWARE COMES
"AS IS," WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED, AND LICENSOR AND
ANY OTHER CONTRIBUTOR SHALL NOT BE LIABLE TO ANYONE FOR ANY DAMAGES OR
OTHER LIABILITY ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE
OR THIS LICENSE, UNDER ANY KIND OF LEGAL CLAIM.
This Hippocratic License is an link:https://ethicalsource.dev[Ethical Source license] and is offered
for use by licensors and licensees at their own risk, on an "AS IS" basis, and with no warranties
express or implied, to the maximum extent permitted by Laws.

245
mac_os/README.adoc Normal file
View File

@@ -0,0 +1,245 @@
:toc: macro
:toclevels: 5
:figure-caption!:
:mac_os_defaults_link: link:https://macos-defaults.com[macOS Defaults]
= macOS
Shell scripts for automated macOS machine setup.
This project is a framework for automating the setup of a macOS machine. In order to illustrate the
potential of what this project can do, please see the companion
link:https://alchemists.io/projects/mac_os-config[macOS Config] project for details. The _macOS
Config_ project is an opinionated configuration which meets the needs of my development environment
but is also meant to serve as an example and guide for building your own personalized setup. Here is
how the two projects are meant to be used:
* *macOS* (this project) - The foundational framework for building custom macOS machine setups.
* *link:https://alchemists.io/projects/mac_os-config[macOS Configuration]* - The layer on top of
this _macOS_ project which defines a custom machine implementation. The project is meant to be
forked for as many custom machine setups as needed.
toc::[]
== Features
* Provides a command line interface, written in Bash, with no additional dependencies for
installation and management of a macOS machine.
* Supports macOS boot disk creation for fresh install of operating system.
* Installs link:https://developer.apple.com/xcode[Xcode Command Line Tools].
* Installs link:http://brew.sh[Homebrew] formulas and casks.
* Installs link:http://www.apple.com/macosx/whats-new/app-store.html[App Store] software.
* Installs non-App Store software applications.
* Installs software application extensions.
* Installs dotfiles.
* Installs link:https://nodejs.org[Node] link:https://www.npmjs.com[packages].
* Installs link:https://www.ruby-lang.org[Ruby] link:https://rubygems.org[gems].
* Installs link:https://www.rust-lang.org[Rust] link:https://crates.io[crates].
* Applies {mac_os_defaults_link}.
* Configures installed software.
* Supports restoration of machine backups.
== Requirements
. link:https://www.apple.com/os/macos[macOS 26.0.0 (Tahoe)]
. link:https://developer.apple.com/xcode[Xcode]
== Setup
To install, run:
[source,bash]
----
git clone https://github.com/bkuhlmann/mac_os.git
cd mac_os
git checkout 22.0.0
----
== Usage
Run the following:
[source,bash]
----
bin/run
----
You will be presented with the following options (listed in order of
use):
....
Boot:
B: Create boot disk.
Install:
b: Apply basic settings.
t: Install development tools.
hf: Install Homebrew Formulas.
hc: Install Homebrew Casks.
m: Install Mac App Store software.
a: Install application software.
x: Install application software extensions.
df: Install dotfiles.
np: Install Node packages.
rg: Install Ruby gems.
rc: Install Rust crates.
d: Apply default settings.
cs: Configure installed software.
i: Install everything (i.e. executes all install options in order listed).
Restore:
R: Restore settings from backup.
Manage:
c: Check status of managed software.
C: Caffeinate machine.
ua: Uninstall application software.
ux: Uninstall application software extension.
ra: Reinstall application software.
rx: Reinstall application software extension.
w: Clean work (temp) directory.
q: Quit/Exit.
....
Choose option `i` to run a full install or select a specific option to run a single action. Each
option is designed to be re-run if necessary. This can also be handy for performing upgrades,
re-running a missing/failed install, etc.
The option prompt can be skipped by passing the desired option directly to the `bin/run` script. For
example, executing `bin/run i` will execute the full install process.
The machine should be rebooted after all install tasks have completed to ensure all settings have
been loaded.
It is recommended that the `mac_os` project directory not be deleted and kept on the local machine
in order to manage installed software and benefit from future upgrades.
=== Boot Disk
When attempting to create a boot disk via `bin/run B`, youll be presented with the following
documentation (provided here for reference):
....
macOS Boot Disk Setup
1. Insert a USB drive (8GB or higher).
2. Use Disk Utility to format as "Mac OS Extended (Journaled)".
3. Use Disk Utility to set the schema, if available, as "GUID Partition Map".
4. Use Disk Utility to label as "Untitled".
5. Run this script to install the OS and create a bootable USB drive.
macOS Boot Disk Usage:
1. Insert the USB drive, created above, into the machine to be upgraded.
2. Reboot the machine.
3. Press and hold the POWER key before the Apple logo appears.
4. Select the USB boot disk from the menu.
5. Use Disk Utility to delete and/or erase the hard drive including associated partitions.
6. Use Disk Utility to create a single "APFS" drive.
7. Install the new operating system.
macOS Boot Disk Recovery:
1. Start/restart the machine.
2. Press and hold the POWER key before the Apple logo appears.
3. Wait for the macOS installer to load from the recovery partition.
4. Use the dialog options to launch Disk Utility, reinstall the system, etc.
....
💡 You can ensure the right installer is downloaded and available for Boot Disk creation by running the following commands:
[source,bash]
----
# Show which installers are available.
softwareupdate --list-full-installers
# Download desired version.
sudo softwareupdate --fetch-full-installer --full-installer-version 26.0
----
=== Customization
All executable scripts can be found in the `bin` folder:
* `bin/apply_basic_settings` (optional, customizable): Applies basic and initial settings for
setting up a machine.
* `bin/apply_default_settings` (optional, customizable): Applies {mac_os_defaults_link}.
* `bin/configure_software` (optional, customizable): Configures installed software as part of the
post install process.
* `bin/create_boot_disk` (optional): Creates a macOS boot disk.
* `bin/install_app_store` (optional, customizable): Installs macOS, GUI-based, App Store
applications.
* `bin/install_applications` (optional, customizable): Installs macOS, GUI-based, non-App Store
applications.
* `bin/install_dev_tools` (required): Installs macOS development tools required by Homebrew.
* `bin/install_dotfiles` (optional, customizable): Installs personal dotfiles so the system is
tailored to your workflow.
* `bin/install_extensions` (optional, customizable): Installs macOS application extensions and
add-ons.
* `bin/install_homebrew_casks` (optional, customizable): Installs Homebrew Formulas.
* `bin/install_homebrew_formulas` (optional, customizable): Installs Homebrew Casks.
* `bin/install_node_packages` (optional, customizable): Installs Node packages.
* `bin/install_ruby_gems` (optional, customizable): Installs Ruby gems.
* `bin/install_rust_crates` (optional, customizable): Installs Rust crates.
* `bin/restore_backup` (optional, customizable): Restores system/application settings from backup
image.
* `bin/run` (required): The main script and interface for macOS setup.
The `lib` folder provides the base framework for installing, re-installing, and uninstalling
software. Everything provided via the link:https://alchemists.io/projects/mac_os-config[macOS
Config] project is built upon the functions found in the `lib` folder. See the
link:https://alchemists.io/projects/mac_os-config[macOS Config] project for further details.
* `lib/settings.sh`: Defines global settings for software applications, extensions, etc.
=== Troubleshooting
* *Pi-hole*: When using link:https://pi-hole.net[Pi-hole], you might need to temporarily disable
prior to upgrading as you might experience various errors with Apple not being able to detect an
internet connection which prevents the installer from working.
* *Recovery Mode*: When using the boot disk and the installer fails in some catastrophic manner,
reboot the machine into recovery mode -- pass:[<kbd>POWER</kbd>] (Silicon) or
pass:[<kbd>COMMAND</kbd>] + pass:[<kbd>r</kbd>] (Intel) buttons -- to download and install the
last operating system used. Alternatively, you can also use pass:[<kbd>COMMAND</kbd>] +
pass:[<kbd>OPTION</kbd>] + pass:[<kbd>r</kbd>] (Intel) to attempt to download the latest operating
system.
* *NVRAM/PRAM Reset*: When using the boot disk, you might experience a situation where you see a
black screen with a white circle and diagonal line running through it. This means macOS lost or
can't find the boot disk for some reason. To correct this, shut down and boot up the system again
while holding down pass:[<kbd>OPTION</kbd>] + pass:[<kbd>COMMAND</kbd>] + pass:[<kbd>r</kbd>] +
pass:[<kbd>p</kbd>] (Intel) keys simultaneously. You might want to wait for the system boot sound
to happen a few times before releasing the keys. This will clear the system NVRAM/PRAM. At this
point you can shut down and restart the system following the boot disk instructions (the boot disk
will be recognized now).
* *System Management Controller (SMC) Reset*: Sometimes it can help to reset the SMC to improve
system speed. To fix, follow these steps:
** Shut down your Mac.
** Hold down pass:[<kbd>CONTROL</kbd>] + pass:[<kbd>OPTION</kbd>] on the left side of the keyboard
and pass:[<kbd>SHIFT</kbd>] on the right side of the keyboard.
** After seven seconds, hold down the Power button as well.
** Release all keys after another seven seconds.
** Turn on your Mac.
** For more troubleshooting tips, check out The Eclectic Light Company's link:https://eclecticlight.co/mac-troubleshooting-summary/[Mac Troubleshooting Summary].
== Development
To contribute, run:
[source,bash]
----
git clone https://github.com/bkuhlmann/mac_os.git
cd mac_os
----
== link:https://alchemists.io/policies/license[License]
== link:https://alchemists.io/policies/security[Security]
== link:https://alchemists.io/policies/code_of_conduct[Code of Conduct]
== link:https://alchemists.io/policies/contributions[Contributions]
== link:https://alchemists.io/policies/developer_certificate_of_origin[Developer Certificate of Origin]
== link:https://alchemists.io/projects/mac_os/versions[Versions]
== link:https://alchemists.io/community[Community]
== Credits
Engineered by link:https://alchemists.io/team/brooke_kuhlmann[Brooke Kuhlmann].

12
mac_os/Rakefile Normal file
View File

@@ -0,0 +1,12 @@
# frozen_string_literal: true
require "git/lint/rake/register"
require "rubocop/rake_task"
Git::Lint::Rake::Register.call
RuboCop::RakeTask.new
desc "Run code quality checks"
task quality: %i[git_lint rubocop]
task default: :quality

37
mac_os/bin/create_boot_disk Executable file
View File

@@ -0,0 +1,37 @@
#! /usr/bin/env bash
# Creates macOS boot disk.
printf "%s\n" "macOS Boot Disk Setup"
printf "%s\n" " 1. Insert a USB drive (8GB or higher)."
printf "%s\n" " 2. Use Disk Utility to format as \"Mac OS Extended (Journaled)\"."
printf "%s\n" " 3. Use Disk Utility to set the schema, if available, as \"GUID Partition Map\"."
printf "%s\n" " 4. Use Disk Utility to label as \"Untitled\"."
printf "%s\n" " 5. Run this script to install the OS and create a bootable USB drive."
printf "\n%s\n" "macOS Boot Disk Usage:"
printf "%s\n" " 1. Insert the USB drive, created above, into the machine to be upgraded."
printf "%s\n" " 2. Reboot the machine."
printf "%s\n" " 3. Press and hold the POWER key before the Apple logo appears."
printf "%s\n" " 4. Select the USB boot disk from the menu."
printf "%s\n" " 5. Use Disk Utility to delete and/or erase the hard drive including associated partitions."
printf "%s\n" " 6. Use Disk Utility to create a single \"APFS\" drive."
printf "%s\n" " 7. Install the new operating system."
printf "\n%s\n" "macOS Boot Disk Recovery:"
printf "%s\n" " 1. Start/restart the machine."
printf "%s\n" " 2. Press and hold the POWER key before the Apple logo appears."
printf "%s\n" " 3. Wait for the macOS installer to load from the recovery partition."
printf "%s\n" " 4. Use the dialog options to launch Disk Utility, reinstall the system, etc."
printf "\n%s\n" "Creating macOS boot disk..."
if [[ ! -e "$MAC_OS_BOOT_DISK_CREATOR" ]]; then
printf "%s\n" "ERROR: macOS installer does not exist: $MAC_OS_BOOT_DISK_CREATOR. Use System Preferences → Software Update to download."
exit 1
fi
if [[ ! -d "$MAC_OS_BOOT_DISK_PATH" ]]; then
printf "%s\n" "ERROR: Boot disk must be mounted at: $MAC_OS_BOOT_DISK_PATH."
exit 1
fi
sudo "$MAC_OS_BOOT_DISK_CREATOR" --volume "$MAC_OS_BOOT_DISK_PATH" --downloadassets --nointeraction

17
mac_os/bin/install_app_store Executable file
View File

@@ -0,0 +1,17 @@
#! /usr/bin/env bash
# Installs App Store software.
set -o nounset
set -o errexit
set -o pipefail
IFS=$'\n\t'
SCRIPT_PATH="$MAC_OS_CONFIG_PATH/bin/install_app_store"
if [[ -x "$SCRIPT_PATH" ]]; then
check_mas_install
"$SCRIPT_PATH"
else
printf "%s\n" "WARNING: App Store install script does not exist or is not executable."
fi

16
mac_os/bin/install_applications Executable file
View File

@@ -0,0 +1,16 @@
#! /usr/bin/env bash
# Installs applications.
set -o nounset
set -o errexit
set -o pipefail
IFS=$'\n\t'
SCRIPT_PATH="$MAC_OS_CONFIG_PATH/bin/install_applications"
if [[ -x "$SCRIPT_PATH" ]]; then
"$SCRIPT_PATH"
else
printf "%s\n" "WARNING: Applications install script does not exist or is not executable."
fi

16
mac_os/bin/install_basics Executable file
View File

@@ -0,0 +1,16 @@
#! /usr/bin/env bash
# Installs basic system settings.
set -o nounset
set -o errexit
set -o pipefail
IFS=$'\n\t'
SCRIPT_PATH="$MAC_OS_CONFIG_PATH/bin/install_basics"
if [[ -x "$SCRIPT_PATH" ]]; then
"$SCRIPT_PATH"
else
printf "%s\n" "WARNING: Basic settings script does not exist or is not executable."
fi

16
mac_os/bin/install_defaults Executable file
View File

@@ -0,0 +1,16 @@
#! /usr/bin/env bash
# Installs system and application default settings.
set -o nounset
set -o errexit
set -o pipefail
IFS=$'\n\t'
SCRIPT_PATH="$MAC_OS_CONFIG_PATH/bin/install_defaults"
if [[ -x "$SCRIPT_PATH" ]]; then
"$SCRIPT_PATH"
else
printf "%s\n" "WARNING: Default settings script does not exist or is not executable."
fi

17
mac_os/bin/install_dev_tools Executable file
View File

@@ -0,0 +1,17 @@
#! /usr/bin/env bash
# Installs development tooling requirements.
printf "%s\n" "Installing Xcode CLI tools..."
xcode-select --install
printf "%s\n" "💡 ALT+TAB to view and accept Xcode license window."
read -p "Have you completed the Xcode CLI tools install (y/n)? " xcode_response
if [[ "$xcode_response" != "y" ]]; then
printf "%s\n" "ERROR: Xcode CLI tools must be installed before proceeding."
exit 1
fi
if [[ "$(/usr/bin/arch)" == "arm64" ]]; then
softwareupdate --install-rosetta --agree-to-license
fi

16
mac_os/bin/install_extensions Executable file
View File

@@ -0,0 +1,16 @@
#! /usr/bin/env bash
# Installs application extensions.
set -o nounset
set -o errexit
set -o pipefail
IFS=$'\n\t'
SCRIPT_PATH="$MAC_OS_CONFIG_PATH/bin/install_extensions"
if [[ -x "$SCRIPT_PATH" ]]; then
"$SCRIPT_PATH"
else
printf "%s\n" "WARNING: Application extensions install script does not exist or is not executable."
fi

View File

@@ -0,0 +1,17 @@
#! /usr/bin/env bash
# Installs Homebrew Cask software.
set -o nounset
set -o errexit
set -o pipefail
IFS=$'\n\t'
SCRIPT_PATH="$MAC_OS_CONFIG_PATH/bin/install_homebrew_casks"
if [[ -x "$SCRIPT_PATH" ]]; then
install_homebrew
"$SCRIPT_PATH"
else
printf "%s\n" "WARNING: Homebrew Casks install script does not exist or is not executable."
fi

View File

@@ -0,0 +1,17 @@
#! /usr/bin/env bash
# Installs Homebrew Formula software.
set -o nounset
set -o errexit
set -o pipefail
IFS=$'\n\t'
SCRIPT_PATH="$MAC_OS_CONFIG_PATH/bin/install_homebrew_formulas"
if [[ -x "$SCRIPT_PATH" ]]; then
install_homebrew
"$SCRIPT_PATH"
else
printf "%s\n" "WARNING: Homebrew Formulas install script does not exist or is not executable."
fi

View File

@@ -0,0 +1,17 @@
#! /usr/bin/env bash
# Installs Node packages.
set -o nounset
set -o errexit
set -o pipefail
IFS=$'\n\t'
SCRIPT_PATH="$MAC_OS_CONFIG_PATH/bin/install_node_packages"
if [[ -x "$SCRIPT_PATH" ]]; then
install_node
"$SCRIPT_PATH"
else
printf "%s\n" "WARNING: Node packages install script does not exist or is not executable."
fi

17
mac_os/bin/install_ruby_gems Executable file
View File

@@ -0,0 +1,17 @@
#! /usr/bin/env bash
# Installs Ruby gems.
set -o nounset
set -o errexit
set -o pipefail
IFS=$'\n\t'
SCRIPT_PATH="$MAC_OS_CONFIG_PATH/bin/install_ruby_gems"
if [[ -x "$SCRIPT_PATH" ]]; then
install_ruby
"$SCRIPT_PATH"
else
printf "%s\n" "WARNING: Ruby gems install script does not exist or is not executable."
fi

17
mac_os/bin/install_rust_crates Executable file
View File

@@ -0,0 +1,17 @@
#! /usr/bin/env bash
# Installs Rust crates.
set -o nounset
set -o errexit
set -o pipefail
IFS=$'\n\t'
SCRIPT_PATH="$MAC_OS_CONFIG_PATH/bin/install_rust_crates"
if [[ -x "$SCRIPT_PATH" ]]; then
install_rust
"$SCRIPT_PATH"
else
printf "%s\n" "WARNING: Rust crates install script does not exist or is not executable."
fi

16
mac_os/bin/install_shell Executable file
View File

@@ -0,0 +1,16 @@
#! /usr/bin/env bash
# Installs shell.
set -o nounset
set -o errexit
set -o pipefail
IFS=$'\n\t'
SCRIPT_PATH="$MAC_OS_CONFIG_PATH/bin/install_shell"
if [[ -x "$SCRIPT_PATH" ]]; then
"$SCRIPT_PATH"
else
printf "%s\n" "WARNING: Shell script does not exist or is not executable."
fi

6
mac_os/bin/rake Executable file
View File

@@ -0,0 +1,6 @@
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/setup"
load Gem.bin_path "rake", "rake"

16
mac_os/bin/restore_backup Executable file
View File

@@ -0,0 +1,16 @@
#! /usr/bin/env bash
# Performs restoration of backup data.
set -o nounset
set -o errexit
set -o pipefail
IFS=$'\n\t'
SCRIPT_PATH="$MAC_OS_CONFIG_PATH/bin/restore_backup"
if [[ -x "$SCRIPT_PATH" ]]; then
"$SCRIPT_PATH"
else
printf "%s\n" "WARNING: Restore backup script does not exist or is not executable."
fi

62
mac_os/bin/run Executable file
View File

@@ -0,0 +1,62 @@
#! /usr/bin/env bash
# Executes the command line interface.
source lib/installers.sh
source lib/options.sh
source lib/settings.sh
source lib/utilities.sh
source lib/verifiers.sh
if [[ -e "$MAC_OS_CONFIG_PATH" ]]; then
source "$MAC_OS_CONFIG_PATH/lib/settings.sh"
else
printf "%s\n\n" "ERROR: Unable to load macOS configuration: $MAC_OS_CONFIG_PATH."
printf "%s\n" "Please check the following before continuing:"
printf "%s\n" " • Download the default macOS configuration here: https://github.com/bkuhlmann/mac_os-config."
printf "%s\n" " • Customize as necessary for your setup or fork the project and make your own configuration."
printf "%s\n" " • When finished, your folder structure should look like this:"
printf "%s\n" " • <root path>/mac_os:"
printf "%s\n" " • <root path>/mac_os-config:"
exit 1
fi
configure_environment
while true; do
if [[ $# == 0 ]]; then
printf "\n%s\n" "Usage: run OPTION"
printf "\n%s\n" "OSX Options:"
printf "%s\n" " Boot:"
printf "%s\n" " B: Create boot disk."
printf "%s\n" " Install:"
printf "%s\n" " b: Install basics."
printf "%s\n" " t: Install development tools."
printf "%s\n" " hf: Install Homebrew Formulas."
printf "%s\n" " hc: Install Homebrew Casks."
printf "%s\n" " m: Install Mac App Store software."
printf "%s\n" " a: Install application software."
printf "%s\n" " x: Install application software extensions."
printf "%s\n" " d: Install defaults."
printf "%s\n" " s: Install shell."
printf "%s\n" " r: Restore backups."
printf "%s\n" " i: Install all (i.e. executes all of the above steps in order listed)."
printf "%s\n" " Libraries:"
printf "%s\n" " rc: Install Rust crates."
printf "%s\n" " rg: Install Ruby gems."
printf "%s\n" " np: Install Node packages."
printf "%s\n" " l: Install libraries (i.e. executes all of the above steps in order listed)."
printf "%s\n" " Manage:"
printf "%s\n" " c: Check status of managed software."
printf "%s\n" " C: Caffeinate machine."
printf "%s\n" " w: Clean work (temp) directory."
printf "%s\n\n" " q: Quit/Exit."
read -p "Enter selection: " response
printf "\n"
process_option "$response"
else
process_option "$1"
fi
break
done

370
mac_os/lib/installers.sh Normal file
View File

@@ -0,0 +1,370 @@
#! /usr/bin/env bash
# Defines software installer functions.
# Label: Download File
# Description: Download remote file to local disk.
# Parameters: $1 (required): URL, $2 (required): File name, $3 (optional): HTTP header.
download_file() {
local url="$1"
local file_name="$2"
local http_header="$3"
printf "%s\n" "Downloading $1..."
clean_work_path
mkdir "$MAC_OS_WORK_PATH"
curl --header "$http_header" \
--location \
--retry 3 \
--retry-delay 5 \
--fail \
--silent \
--show-error \
"$url" >> "$MAC_OS_WORK_PATH/$file_name"
}
export -f download_file
# Label: Install Application
# Description: Install an application.
# Parameters: $1 (required): Install path, $2 (required): Name.
install_app() {
local install_path="$1"
local name="$2"
local install_root=""
local file_extension=""
install_root=$(get_install_root "$name")
file_extension=$(get_extension "$name")
printf "%s\n" "Installing: $install_root/$name..."
case $file_extension in
'')
cp -a "$install_path/$name" "$install_root";;
'app')
cp -a "$install_path/$name" "$install_root";;
'prefPane')
sudo cp -pR "$install_path/$name" "$install_root";;
'qlgenerator')
sudo cp -pR "$install_path/$name" "$install_root" && qlmanage -r;;
*)
printf "%s\n" "ERROR: Unknown file extension: $file_extension."
esac
}
export -f install_app
# Label: Install DMG Application
# Description: Install DMG application.
# Parameters: $1 (required): URL, $2 (required): Mount path, $3 (required): Application name.
install_dmg_app() {
local url="$1"
local mount_point="/Volumes/$2"
local app_name="$3"
local install_path=""
local work_file="download.dmg"
install_path=$(get_install_path "$app_name")
if [[ ! -e "$install_path" ]]; then
download_file "$url" "$work_file"
mount_image "$MAC_OS_WORK_PATH/$work_file"
install_app "$mount_point" "$app_name"
unmount_image "$mount_point"
verify_application "$app_name"
fi
}
export -f install_dmg_app
# Label: Install DMG Package
# Description: Install DMG application via a package file.
# Parameters: $1 (required): URL, $2 (required): Mount path, $3 (required): Application name.
install_dmg_pkg() {
local url="$1"
local mount_point="/Volumes/$2"
local app_name="$3"
local install_path=""
local work_file="download.dmg"
install_path=$(get_install_path "$app_name")
if [[ ! -e "$install_path" ]]; then
download_file "$url" "$work_file"
mount_image "$MAC_OS_WORK_PATH/$work_file"
install_pkg "$mount_point" "$app_name"
unmount_image "$mount_point"
printf "%s\n" "Installed: $app_name."
verify_application "$app_name"
fi
}
export -f install_dmg_pkg
# Label: Install File
# Description: Install a single file.
# Parameters: $1 (required): URL, $2 (required): Install path.
install_file() {
local file_url="$1"
local file_name=""
local install_path="$2"
file_name=$(get_basename "$1")
if [[ ! -e "$install_path" ]]; then
download_file "$file_url" "$file_name"
mkdir -p $(dirname "$install_path")
mv "$MAC_OS_WORK_PATH/$file_name" "$install_path"
printf "%s\n" "Installed: $file_name."
verify_path "$install_path"
fi
}
export -f install_file
# Label: Install Git Application
# Description: Install application from a Git repository.
# Parameters: $1 (required): URL, $2 (required): Install path, $3 (optional): Git clone options.
install_git_app() {
local url="$1"
local install_path="$2"
local app_name=""
local options="--quiet"
app_name="$(get_basename "$2")"
if [[ -n "$3" ]]; then
local options="$options $3"
fi
if [[ ! -e "$install_path" ]]; then
printf "%s\n" "Installing: $install_path..."
git clone $options "$url" "$install_path"
printf "%s\n" "Installed: $app_name."
verify_path "$install_path"
fi
}
export -f install_git_app
# Label: Install Git Project
# Description: Install Git project.
# Parameters: $1 (required): URL, $2 (required): Version, $3 (required): Project directory, $4 (required): Script to run (including any arguments).
install_git_project() {
local repo_url="$1"
local repo_version="$2"
local project_dir="$3"
local script="$4"
git clone "$repo_url"
(
cd "$project_dir"
git -c advice.detachedHead=false checkout "$repo_version"
eval "$script"
)
rm -rf "$project_dir"
}
export -f install_git_project
# Label: Install Homebrew
# Description: Install and setup Homebrew.
install_homebrew() {
if ! command -v brew > /dev/null; then
/bin/bash -c "$(curl --location --fail --silent --show-error https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
echo "eval \"($(get_homebrew_bin_root)/brew shellenv)\"" > "$HOME/.zprofile"
eval "$($(get_homebrew_bin_root)/brew shellenv)"
fi
}
export -f install_homebrew
# Label: Install Bare Package
# Description: Install a bare package.
# Parameters: $1 (required): URL, $2 (required): Application name.
install_bare_pkg() {
local url="$1"
local app_name="$2"
local install_path=""
local work_file="$app_name.pkg"
install_path=$(get_install_path "$app_name")
if [[ ! -e "$install_path" ]]; then
download_file "$url" "$work_file"
install_pkg "$MAC_OS_WORK_PATH" "$app_name"
printf "%s\n" "Installed: $app_name."
verify_application "$app_name"
fi
}
export -f install_bare_pkg
# Label: Install Package
# Description: Install local package.
# Parameters: $1 (required): Package source path, $2 (required): Application name.
install_pkg() {
local source_path="$1"
local name="$2"
local install_root=""
local package=""
install_root=$(get_install_root "$name")
package=$(sudo find "$source_path" -maxdepth 1 -type f -name "*.pkg" -o -name "*.mpkg")
printf "%s\n" "Installing: $install_root/$name..."
sudo installer -pkg "$package" -target /
}
export -f install_pkg
# Label: Install Program
# Description: Installs program without any packaging.
# Parameters: $1 (required): URL, $2 (required): Name.
install_program() {
local url="$1"
local program_name="$2"
local install_root=""
local install_path=""
install_root=$(get_install_root "$program_name")
install_path=$(get_install_path "$program_name")
if [[ ! -e "$install_path" ]]; then
download_file "$url" "$program_name"
mkdir -p "$install_root"
mv "$MAC_OS_WORK_PATH/$program_name" "$install_path"
chmod 755 "$install_path"
printf "%s\n" "Installed: $program_name."
verify_application "$program_name"
fi
}
export -f install_program
# Label: Install Node
# Description: Install and setup Node for local development.
install_node() {
if [[ ! -x "$(command -v node)" ]]; then
"$(get_homebrew_bin_root)/fnm" install --latest
fi
}
export -f install_node
# Label: Install Ruby
# Description: Install and setup Ruby for local development.
install_ruby() {
local version=""
version="$(cat $HOME/.ruby-version | tr -d '\n')"
if [[ ! -x "$(command -v ruby)" && -n $(ruby --version | grep --quiet "$version") ]]; then
"$(get_homebrew_bin_root)"/frum install "$version" \
--with-openssl-dir="$(brew --prefix openssl)" \
--enable-shared \
--disable-silent-rules
"$(get_homebrew_bin_root)"/frum local "$version"
fi
}
export -f install_ruby
# Label: Install Rust
# Description: Install and setup Rust for local development.
install_rust() {
if ! command -v cargo > /dev/null; then
curl --proto "=https" --tlsv1.2 --fail --silent --show-error https://sh.rustup.rs | sh
fi
}
export -f install_rust
# Label: Install Tar Application
# Description: Install application from tar file.
# Parameters: $1 (required): URL, $2 (required): Name, $3 (required): Decompress options.
install_tar_app() {
local url="$1"
local app_name="$2"
local options="$3"
local install_path=""
local work_file="download.tar"
install_path=$(get_install_path "$app_name")
if [[ ! -e "$install_path" ]]; then
download_file "$url" "$work_file"
(
printf "Preparing...\n"
cd "$MAC_OS_WORK_PATH"
tar "$options" "$work_file"
)
install_app "$MAC_OS_WORK_PATH" "$app_name"
printf "%s\n" "Installed: $app_name."
verify_application "$app_name"
fi
}
export -f install_tar_app
# Label: Install Zip Application
# Description: Install application from zip file.
# Parameters: $1 (required): URL, $2 (required): Name.
install_zip_app() {
local url="$1"
local app_name="$2"
local install_path=""
local work_file="download.zip"
install_path=$(get_install_path "$app_name")
if [[ ! -e "$install_path" ]]; then
download_file "$url" "$work_file"
(
printf "Preparing...\n"
cd "$MAC_OS_WORK_PATH"
unzip -q "$work_file"
find . -type d -name "$app_name" -print -exec cp -pR {} . > /dev/null 2>&1 \;
)
install_app "$MAC_OS_WORK_PATH" "$app_name"
printf "%s\n" "Installed: $app_name."
verify_application "$app_name"
fi
}
export -f install_zip_app
# Label: Install Zip Package
# Description: Install application from a package within a zip file.
# Parameters: $1 (required): URL, $2 (required): Application name.
install_zip_pkg() {
local url="$1"
local app_name="$2"
local install_path=""
local work_file="download.zip"
install_path=$(get_install_path "$app_name")
if [[ ! -e "$install_path" ]]; then
download_file "$url" "$work_file"
(
printf "Preparing...\n"
cd "$MAC_OS_WORK_PATH"
unzip -q "$work_file"
)
install_pkg "$MAC_OS_WORK_PATH" "$app_name"
printf "%s\n" "Installed: $app_name."
verify_application "$app_name"
fi
}
export -f install_zip_pkg
# Label: Mount Image
# Description: Mount disk image.
# Parameters: $1 (required): Path.
mount_image() {
printf "%s\n" "Mounting image..."
hdiutil attach -quiet -nobrowse -noautoopen "$1"
}
export -f mount_image
# Label: Unmount Image
# Description: Unmount disk image.
# Parameters: $1 (required): Path.
unmount_image() {
printf "%s\n" "Unmounting image..."
hdiutil detach -force "$1"
}
export -f unmount_image

74
mac_os/lib/options.sh Normal file
View File

@@ -0,0 +1,74 @@
#! /usr/bin/env bash
# Defines command line prompt options.
# Label: Process Option
# Description: Run script based on selection.
# Parameters: $1 (required): The option to process.
process_option() {
case $1 in
'B')
bin/create_boot_disk;;
'b')
bin/install_basics;;
't')
bin/install_dev_tools;;
'hf')
bin/install_homebrew_formulas;;
'hc')
bin/install_homebrew_casks;;
'm')
bin/install_app_store;;
'a')
bin/install_applications;;
'x')
bin/install_extensions;;
'd')
bin/install_defaults;;
's')
bin/install_shell;;
'r')
bin/restore_backup;;
'i')
caffeinate_machine
bin/install_basics
bin/install_dev_tools
bin/install_homebrew_formulas
bin/install_homebrew_casks
bin/install_app_store
bin/install_applications
bin/install_extensions
bin/install_defaults
bin/install_shell
bin/restore_backup
clean_work_path;;
'np')
bin/install_node_packages;;
'rg')
bin/install_ruby_gems;;
'rc')
bin/install_rust_crates;;
'l')
bin/install_rust_crates
bin/install_ruby_gems
bin/install_node_packages;;
'c')
verify_homebrew_formulas
verify_homebrew_casks
verify_app_store_applications
verify_applications
verify_extensions
verify_node_packages
verify_ruby_gems
verify_rust_crates;;
'C')
caffeinate_machine;;
'w')
clean_work_path;;
'q');;
*)
printf "ERROR: Invalid option.\n";;
esac
}
export -f process_option

11
mac_os/lib/settings.sh Normal file
View File

@@ -0,0 +1,11 @@
#! /usr/bin/env bash
set -o nounset
set -o errexit
set -o pipefail
IFS=$'\n\t'
export MAC_OS_BOOT_DISK_CREATOR="/Applications/Install macOS Tahoe.app/Contents/Resources/createinstallmedia"
export MAC_OS_BOOT_DISK_PATH="/Volumes/Untitled"
export MAC_OS_WORK_PATH=/tmp/downloads
export MAC_OS_CONFIG_PATH="../mac_os-config"

128
mac_os/lib/utilities.sh Normal file
View File

@@ -0,0 +1,128 @@
#! /usr/bin/env bash
# Defines general utility functions.
# Label: Caffeinate Machine
# Description: Keep machine running for a very long time.
caffeinate_machine() {
if [[ -n "$(pgrep -x caffeinate)" ]]; then
printf "Machine is already caffeinated!\n"
else
caffeinate -s -u -d -i -t 3153600000 > /dev/null &
printf "Machine caffeinated.\n"
fi
}
export -f caffeinate_machine
# Label: Clean Work Path
# Description: Clean work path of artifacts.
clean_work_path() {
rm -rf "$MAC_OS_WORK_PATH"
}
export -f clean_work_path
# Label: Get Basename
# Description: Answer file or directory basename.
# Parameters: $1 (required): Path.
get_basename() {
printf "%s" "${1##*/}"
}
export -f get_basename
# Label: Get Extension
# Description: Answer file extension without dot prefix.
# Parameters: $1 (required): Path.
get_extension() {
local name=""
local extension="${1##*.}"
name=$(get_basename "$1")
if [[ "$name" == "$extension" ]]; then
printf ''
else
printf "%s" "$extension"
fi
}
export -f get_extension
# Label: Get Homebrew Root
# Description: Answer Homebrew root path.
get_homebrew_root() {
if [[ "$(/usr/bin/arch)" == "arm64" ]]; then
printf "%s" "/opt/homebrew"
else
printf "%s" "/usr/local/Homebrew"
fi
}
export -f get_homebrew_root
# Label: Get Homebrew Bin Root
# Description: Answer Homebrew binary root path.
get_homebrew_bin_root() {
if [[ "$(/usr/bin/arch)" == "arm64" ]]; then
printf "%s" "/opt/homebrew/bin"
else
printf "%s" "/usr/local/bin"
fi
}
export -f get_homebrew_bin_root
# Label: Get Install Path
# Description: Answer full install path (including file name).
# Parameters: $1 (required): Path.
get_install_path() {
local file_name="$1"
local install_path=""
install_path=$(get_install_root "$file_name")
printf "%s" "$install_path/$file_name"
}
export -f get_install_path
# Label: Get Install Root
# Description: Answer root install path.
# Parameters: $1 (required): Path.
get_install_root() {
local file_name="$1"
case $(get_extension "$file_name") in
'')
printf "%s" "$HOME/.local/bin";;
'app')
printf "/Applications";;
'prefPane')
printf "/Library/PreferencePanes";;
'qlgenerator')
printf "/Library/QuickLook";;
*)
printf "/tmp/unknown";;
esac
}
export -f get_install_root
# Label: Check Mac App Store Install
# Description: Check Mac App Store (mas) CLI has been installed.
check_mas_install() {
if ! command -v mas > /dev/null; then
printf "%s\n" "ERROR: Mac App Store (mas) CLI can't be found."
printf "%s\n" " Please ensure mas (i.e. brew install mas) is installed."
exit 1
fi
}
export -f check_mas_install
# Label: Configure Environment
# Description: Configure shell and ensure PATH is properly configured.
configure_environment() {
if [[ ! -s "$HOME/.bash_profile" ]]; then
printf "%s\n" "if [ -f ~/.bashrc ]; then . ~/.bashrc; fi" > "$HOME/.bash_profile"
fi
if [[ ! -s "$HOME/.bashrc" ]]; then
printf "%s\n" 'export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"' > "$HOME/.bashrc"
source "$HOME/.bashrc"
fi
}
export -f configure_environment

202
mac_os/lib/verifiers.sh Normal file
View File

@@ -0,0 +1,202 @@
#! /usr/bin/env bash
# Defines verification/validation functions.
# Label: Verify App Store Applications
# Description: Check for missing App Store applications.
verify_app_store_applications() {
local applications=""
printf "\n%s\n" "Checking App Store applications..."
applications="$(mas list)"
while read line; do
if [[ "$line" == "mas install"* ]]; then
application=$(printf "$line" | awk '{print $3}')
verify_listed_application "$application" "${applications[*]}"
fi
done < "$MAC_OS_CONFIG_PATH/bin/install_app_store"
printf "%s\n" "App Store check complete."
}
export -f verify_app_store_applications
# Label: Verify Application
# Description: Verify application exists.
# Parameters: $1 (required): File name.
verify_application() {
local file_name="$1"
if [[ ! -e "$(get_install_path "$file_name")" ]]; then
printf "%s\n" " - Missing: $file_name"
fi
}
export -f verify_application
# Label: Verify Applications
# Description: Check for missing applications suffixed by "APP_NAME" as defined in settings.
verify_applications() {
local file_names=""
printf "\n%s\n" "Checking application software..."
# Only use environment keys that end with "APP_NAME".
file_names=$(set | awk -F "=" '{print $1}' | grep ".*APP_NAME")
# For each application name, check to see if the application is installed. Otherwise, skip.
for name in $file_names; do
verify_application "${!name}"
done
printf "%s\n" "Application software check complete."
}
export -f verify_applications
# Label: Verify Extensions
# Description: Check for missing extensions suffixed by "EXTENSION_PATH" as defined in settings.
verify_extensions() {
local extensions=""
printf "\n%s\n" "Checking application extensions..."
# Only use environment keys that end with "EXTENSION_PATH".
extensions=$(set | awk -F "=" '{print $1}' | grep ".*EXTENSION_PATH")
# For each extension, check to see if the extension is installed. Otherwise, skip.
for extension in $extensions; do
# Evaluate/extract the key (extension) value and pass it on for verfication.
verify_path "${!extension}"
done
printf "%s\n" "Application extension check complete."
}
export -f verify_extensions
# Label: Verify Homebrew Casks
# Description: Check for missing Homebrew casks.
verify_homebrew_casks() {
local applications=""
printf "\nChecking Homebrew casks...\n"
applications="$(brew list --casks)"
while read line; do
if [[ "$line" == "brew cask install"* ]]; then
application=$(printf "%s" "$line" | awk '{print $4}')
verify_listed_application "$application" "${applications[*]}"
fi
done < "$MAC_OS_CONFIG_PATH/bin/install_homebrew_casks"
printf "%s\n" "Homebrew cask check complete."
}
export -f verify_homebrew_casks
# Label: Verify Homebrew Formulas
# Description: Check for missing Homebrew formulas.
verify_homebrew_formulas() {
local applications=""
printf "Checking Homebrew formulas...\n"
applications="$(brew list --formulae)"
while read line; do
if [[ "$line" == "brew install"* ]]; then
application=$(printf "%s" "$line" | awk '{print $3}')
# Exception: "gpg" is the binary but is listed as "gnugp".
if [[ "$application" == "gpg" ]]; then
application="gnupg"
fi
verify_listed_application "$application" "${applications[*]}"
fi
done < "$MAC_OS_CONFIG_PATH/bin/install_homebrew_formulas"
printf "%s\n" "Homebrew formula check complete."
}
export -f verify_homebrew_formulas
# Label: Verify Listed Application
# Description: Verify listed application exists.
# Parameters: $1 (required): Current application, $2 (required): Application list.
verify_listed_application() {
local application="$1"
local applications="$2"
if [[ "${applications[*]}" != *"$application"* ]]; then
printf "%s\n" " - Missing: $application"
fi
}
export -f verify_listed_application
# Label: Verify Path
# Description: Verify path exists.
# Parameters: $1 (required): Path.
verify_path() {
local path="$1"
if [[ ! -e "$path" ]]; then
printf "%s\n" " - Missing: $path"
fi
}
export -f verify_path
# Label: Verify Node Packages
# Description: Check for missing Node packages.
verify_node_packages() {
printf "\n%s\n" "Checking Node packages..."
while read line; do
if [[ "$line" == "npm "* ]]; then
package=$(printf "$line" | awk '{print $4}')
packages=($(npm list --global --depth=0 | grep "$package"))
verify_listed_application "$package" "${packages[*]}"
fi
done < "$MAC_OS_CONFIG_PATH/bin/install_node_packages"
printf "%s\n" "Node packages check complete."
}
export -f verify_node_packages
# Label: Verify Ruby Gems
# Description: Check for missing Ruby gems.
verify_ruby_gems() {
local gems=""
printf "\n%s\n" "Checking Ruby gems..."
gems="$(gem list --no-versions)"
while read line; do
if [[ "$line" == "gem install"* ]]; then
gem=$(printf "%s" "$line" | awk '{print $3}')
verify_listed_application "$gem" "${gems[*]}"
fi
done < "$MAC_OS_CONFIG_PATH/bin/install_ruby_gems"
printf "%s\n" "Ruby gems check complete."
}
export -f verify_ruby_gems
# Label: Verify Rust Crates
# Description: Check for missing Rust crates.
verify_rust_crates() {
local crates=""
printf "\n%s\n" "Checking Rust crates..."
crates="$(ls -A1 $HOME/.cargo/bin)"
while read line; do
if [[ "$line" == "cargo install"* ]]; then
crate=$(printf "%s" "$line" | awk '{print $3}')
verify_listed_application "$crate" "${crates[*]}"
fi
done < "$MAC_OS_CONFIG_PATH/bin/install_rust_crates"
printf "%s\n" "Rust crates check complete."
}
export -f verify_rust_crates