Originally based on wincent’s conf, I then realized Ansible was too complex and had too many dependencies to continue using it for managing dotfiles and some defaults. (Funnily enough, wincent seems to have reached the same conclusion as me and switched away from Ansible in his conf repo too!)
The repo is now pure zsh.
You can try and install it at home using ./install
.
When prompted for the passphrase, just leave it empty; the actions requiring the password will simply fail.
On macOS, the command-line tools are enough to use this repo; on Linux you should install ccrypt
, curl
, git
, locale-gen
and m4
.
To simply see what I do, and steal whatever you like, go in the src/components
folder.
There is one folder per component I install.
I do a somehow twisted Homebrew setup, with a “system” brew and a “user” one.
This is done to be able to use brew on a multi-user machine properly: the admin manages the system brew, and “normal” users can use a “user” brew without issues (well, at least for formulae which do not fail compilation, but that’s another problem).
Future direction: Fully switch to Nix, which manages a multi-user install properly, and is IMHO generally better, though more complex.
A “lib” function (e.g. libdefaults__set_bool
).
These are functions that only do one simple “atomic” thing (e.g. set a user default).
The function must check whether the action is needed first.
If it is not, the function must output "ok" to stdout and do nothing.
If something is required to be done, the function must do it, then output "changed" to stdout.
In case of an error, the function must log the failure using log_task_failure
, and then output "failed" to stdout.
Most, if not all calls to executables or functions should be done through the run_and_log
function.
Most of the time the libs are found in the ./src/lib
folder, but some components have their own lib
folder with their own libs.
A function doing an actual task.
The task must start with a call to start_task "name of the task"
and
end with a call to one of log_task_{ok,change,warning,failure}
, or use the convenience log_task_from_res
or log_task_from_res_list
.
Note: The log_task_from_res{,_list}
convenience expects log_task_failure
or log_task_warning
to be called manually.
This should probably be a Brew formula in our private tap for convenience; then we’d only have to install the formula directly.
Prepare Rule Group Subscription and automate installation of said subscription in Little Snitch (if possible).
The “system” brew installations fails for now (no sudo, no support for install in /usr/local). See Homebrew System Install Task for more info.
This tool allows changing a few things (timezone, time before sleep, …). It might be useful. It must be run with sudo though.
It just works: the user gets a prompt from TCC telling the launched program wants to use AppleScript.
In theory this is not a problem, but if the program is /bin/sh
(or some other generic script interpreter, or a script whose shebang will be the actual binary), the interpreter will be whitelisted (if the user accepts it).
This is not great security-wise.
The only proper alternative I found is not to launch the script directly, but instead use a custom wrapper whose sole purpose is to exec the script.
This is what exec-script.c
(in this repo) is for.
Other unsuccessful attempts:
-
exec
’ing from the shell script; -
Creating a soft link to the interpreter and launching this link. This does not work because it’s not the link which is launched, it’s the link’s destination;
-
Hard-linking
/bin/sh
and launching this link. This probably works (hard-linking does work), but hard-linking/bin/sh
is forbidden (SIP-protected).
Because of this, the compiled wrapper depends on the C source, of course, but also the script, which means whenever is modified, the final binary will be recompiled.
local myvar="$(false)"; echo $?
prints 0
. Why? Because local
never fails!
Thus, for a script with the -e
option set, local myvar="$(false)
will happily succeed, and the script will continue to the next line.
To workaround this, one should separate the local declaration and the value assignment: local myvar; myvar="$(false)"
.
Now how about a readonly local variable? In theory, we could do this: local -r myvar="$(false)"
(BTW, certainly not readonly local myvar…
, nor local readonly myvar…
!),
however, we would have the same problem.
The solution here is local myvar; myvar="$(false)"; readonly myvar
.
Shell scripts are great.
PS: Of course, test "" = "$(false)"
does not fail either.
Lexicographic note: When I say “conf that is propagated to its children,” I mean for instance export var=
, or export -f function_name
in bash.
That is everything that is exported to children of the shell.
Should contain only bash-specific conf that is propagated to its children.
For instance, exported env variables, exported functions (this is possible with bash with export -f func_name
).
It is important to know aliases cannot be exported.
Should contain only POSIX-compliant conf that is propagated to its children.
Important: In theory it is not possible to export a function in a POSIX shell,
though bash --posix
does not complain when doing it, for whatever reason, neither on Debian, nor on macOS!
Should contain only bash-specific conf that cannot be propagated to children.
Aliases might fall into this category, but you might want to put them in .shrc
if they’re POSIX-compliant.
All login shells are considered interactive.
All of this has been tested on macOS and Debian.
On both, the shell is bash
, even when launching an sh
shell.
However, when bash
is launched as sh
, it tries and mimic the startup behavior of sh
, while still conforming to the POSIX standard (says the man of bash).