Compare commits
30 Commits
8153393d8d
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e1ea39a90 | ||
|
|
cd8f2b7c0d | ||
|
|
48fe726f31 | ||
| 5d9b2d56e5 | |||
| ea86be7b01 | |||
| b7664ad8a7 | |||
| 37542773e3 | |||
| 7c8d81f080 | |||
| 854c19f35f | |||
| 87df4b6d7d | |||
| 8bca66a7bb | |||
|
|
8def65f683 | ||
|
|
563a29aa58 | ||
|
|
0fbcf46307 | ||
|
|
59f627914d | ||
|
|
d4d03b0bb3 | ||
|
|
ad7007a8ee | ||
|
|
6cdd744093 | ||
|
|
604789d9a9 | ||
|
|
53b8527e12 | ||
|
|
e44c48efbd | ||
|
|
b008d4ebb0 | ||
|
|
d4a39b5dd5 | ||
|
|
1953b01148 | ||
|
|
3f2f23a446 | ||
|
|
5c1a6998b7 | ||
|
|
60fc6580d8 | ||
|
|
dd6875b79a | ||
|
|
aef49d322f | ||
|
|
82e5747b67 |
22
README.md
22
README.md
@@ -1,16 +1,19 @@
|
||||
# macOS System
|
||||
|
||||
Scripts to align a macOS system to Astzweig system configuration.
|
||||
|
||||
## Install
|
||||
|
||||
```zsh
|
||||
/bin/zsh -c "$(curl -fsSL https://raw.githubusercontent.com/astzweig/macos-system/main/bootstrap.sh)"
|
||||
/bin/zsh -c "$(curl -fsSL https://git.tabshift.dev/spacebar/macos-system/raw/branch/main/bootstrap.sh)"
|
||||
```
|
||||
|
||||
## What it does
|
||||
|
||||
1. Run all setup from a temporary directory and delete it in the end
|
||||
|
||||
## Process
|
||||
|
||||
1. `install.sh` queries all modules for their required information
|
||||
1. The modules print their required information to stdout using the format as described below.
|
||||
1. `install.sh` parses those informations and tries to read them from a configuration file.
|
||||
@@ -18,14 +21,17 @@ Scripts to align a macOS system to Astzweig system configuration.
|
||||
1. `install.sh` then runs the modules with their required informations passed in as parameter values.
|
||||
|
||||
## License exclusion
|
||||
|
||||
The license does not cover the file [Astzweig.png](resources/user-pictures/Astzweig.png).
|
||||
|
||||
## Required Information Format
|
||||
|
||||
Modules must print their required information to stdout if they're called with
|
||||
`show-questions` command. Required information are all information the module
|
||||
might want to ask the user in order to configure some aspect of the system.
|
||||
|
||||
### Schema
|
||||
|
||||
The general schema is:
|
||||
|
||||
```zsh
|
||||
@@ -33,14 +39,15 @@ The general schema is:
|
||||
s: --highlight-color=What color shall your system highlight color be? # choose from: blue,red,light green;
|
||||
p: --user-password=What color shall your system highlight color be?
|
||||
```
|
||||
|
||||
The letter at the beginning is the question type:
|
||||
|
||||
| Question type | Description | Arguments |
|
||||
| ------------- | ----------- | --------- |
|
||||
| i (info) | A question where the user has no restrictions on input | `default`: a default answer. |
|
||||
| p (password) | A question where the user input is not printed to standard output. | - |
|
||||
| c (confirm) | A yes/no question where the user is allowed to answer yes or no. | - |
|
||||
| s (select) | A list of choices where the user can select one using numbers. | `choose from`: a comma separated list of possible select values. |
|
||||
| Question type | Description | Arguments |
|
||||
| ------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------- |
|
||||
| i (info) | A question where the user has no restrictions on input | `default`: a default answer. |
|
||||
| p (password) | A question where the user input is not printed to standard output. | - |
|
||||
| c (confirm) | A yes/no question where the user is allowed to answer yes or no. | - |
|
||||
| s (select) | A list of choices where the user can select one using numbers. | `choose from`: a comma separated list of possible select values. |
|
||||
|
||||
`<PARAMETER NAME>` is the the parameter name, that will receive the user answer
|
||||
when the module is called. Single char parameter names will be prefixed with a
|
||||
@@ -50,4 +57,5 @@ the parameter name `highlight-color` becomes `--highlight-color <user response>`
|
||||
`<QUESTION>` must contain any punctuation you want to show.
|
||||
|
||||
[^zshlib-askUser]: Currently supported: info, password, confirm, choose. They map to [zshlib/askUser][zshlib-overview] commands.
|
||||
|
||||
[zshlib-overview]: https://github.com/astzweig/zshlib#whats-included
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
#!/usr/bin/env zsh
|
||||
# vi: set ft=zsh tw=80 ts=2
|
||||
|
||||
function _installMASApp() {
|
||||
mas install ${id} &> /dev/null
|
||||
}
|
||||
|
||||
function installMASApp() {
|
||||
local appName="$1"
|
||||
local id="$2"
|
||||
indicateActivity -- "Install ${appName} app" _installMASApp
|
||||
}
|
||||
|
||||
function main() {
|
||||
lop -y h1 -- -i 'Install Mac AppStore Apps'
|
||||
installMASApp 'Affinity Designer 2' 1616831348
|
||||
installMASApp 'Affinity Photo 2' 1616822987
|
||||
installMASApp 'Affinity Publisher 2' 1606941598
|
||||
installMASApp 'AusweisApp' 948660805
|
||||
installMASApp 'Compressor' 424390742
|
||||
installMASApp 'Developer' 640199958
|
||||
installMASApp 'Diagrams' 1276248849
|
||||
installMASApp 'Final Cut Pro' 424389933
|
||||
installMASApp 'Iconographer Mini' 1541509510
|
||||
installMASApp 'iMazing Profile Editor' 1487860882
|
||||
installMASApp 'Infuse' 1136220934
|
||||
installMASApp 'Keka' 470158793
|
||||
installMASApp 'Keynote' 409183694
|
||||
installMASApp 'Mass Rename' 1175416599
|
||||
installMASApp 'Microsoft Excel' 462058435
|
||||
installMASApp 'Microsoft Word' 462054704
|
||||
installMASApp 'Motion' 434290957
|
||||
installMASApp 'Numbers' 409203825
|
||||
installMASApp 'Outbank' 1094255754
|
||||
installMASApp 'Pages' 409201541
|
||||
installMASApp 'Pixelmator Pro' 1289583905
|
||||
installMASApp 'SnippetsLab' 1006087419
|
||||
installMASApp 'WorkingHours' 1495643653
|
||||
installMASApp 'Xcode' 497799835
|
||||
}
|
||||
|
||||
if [[ "${ZSH_EVAL_CONTEXT}" == toplevel ]]; then
|
||||
source autoload-zshlib
|
||||
main "$@"
|
||||
fi
|
||||
@@ -1,73 +0,0 @@
|
||||
#!/usr/bin/env zsh
|
||||
# vi: set ft=zsh tw=80 ts=2
|
||||
|
||||
function configureLogging() {
|
||||
local output=tostdout level=info
|
||||
[ -n "${logfile}" ] && output=${logfile}
|
||||
[ "${verbose}" = true ] && level=debug
|
||||
lop setoutput -l ${level} ${output}
|
||||
}
|
||||
|
||||
function getUsage() {
|
||||
local cmdName=$1 text=''
|
||||
read -r -d '' text <<- USAGE
|
||||
Usage:
|
||||
$cmdName [-v] [-d FILE] --hostname NAME
|
||||
|
||||
Configure host specific settings.
|
||||
|
||||
Options:
|
||||
--hostname NAME Set NAME as current host's host name.
|
||||
-d FILE, --logfile FILE Print log message to logfile instead of stdout.
|
||||
-v, --verbose Be more verbose.
|
||||
----
|
||||
$cmdName 0.1.0
|
||||
Copyright (C) 2022 Rezart Qelibari, Astzweig GmbH & Co. KG
|
||||
License EUPL-1.2. There is NO WARRANTY, to the extent permitted by law.
|
||||
USAGE
|
||||
print -- ${text}
|
||||
}
|
||||
|
||||
function quitSystemPreferences() {
|
||||
ps -A -o pid,comm | grep "MacOS/System Settings" | awk '{print "kill -9 " $1}' | /bin/sh
|
||||
}
|
||||
|
||||
function setComputerName() {
|
||||
scutil --set ComputerName "${hostname}"
|
||||
scutil --set HostName "${hostname}"
|
||||
scutil --set LocalHostName "${hostname}"
|
||||
systemsetup -setcomputername "${hostname}"
|
||||
systemsetup -setlocalsubnetname "${hostname}"
|
||||
}
|
||||
|
||||
function configureComputerHostname() {
|
||||
local currentComputerName="`scutil --get ComputerName`"
|
||||
if [[ "${currentComputerName}" != "${hostname}" ]]; then
|
||||
lop -- -i 'Hostname of computer has not been set.' -i "Will set to ${hostname}."
|
||||
indicateActivity -- 'Set computer name' setComputerName
|
||||
else
|
||||
lop -- -i 'Hostname of computer seems to have already been set. Skipping.' -i "Hostname: $currentComputerName"
|
||||
fi
|
||||
}
|
||||
|
||||
function requireRootPrivileges() {
|
||||
[[ `id -u` -eq 0 ]] || { lop -- -e 'Need root access to change hostname. Aborting.'; return 10 }
|
||||
}
|
||||
|
||||
function main() {
|
||||
local cmdPath=${1} cmdName=${1:t}
|
||||
shift
|
||||
eval "`getUsage $cmdName | docopts -f -V - -h - : "$@"`"
|
||||
configureLogging
|
||||
requireRootPrivileges || return $?
|
||||
|
||||
lop -y h1 -- -i 'Configure System Settings'
|
||||
indicateActivity -- 'Quitting System Preferences' quitSystemPreferences
|
||||
configureComputerHostname
|
||||
}
|
||||
|
||||
if [[ "${ZSH_EVAL_CONTEXT}" == toplevel || "${ZSH_EVAL_CONTEXT}" == cmdarg ]]; then
|
||||
_DIR="${0:A:h}"
|
||||
source autoload-zshlib
|
||||
main $0 "$@"
|
||||
fi
|
||||
45
bin/azw-setup-host
Executable file
45
bin/azw-setup-host
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env zsh
|
||||
# vi: set ft=zsh tw=80 ts=2
|
||||
|
||||
function _installMASApp() {
|
||||
mas install ${id} &> /dev/null
|
||||
}
|
||||
|
||||
function installMASApp() {
|
||||
local appName="$1"
|
||||
local id="$2"
|
||||
indicateActivity -- "Install ${appName} app" _installMASApp
|
||||
}
|
||||
|
||||
function main() {
|
||||
lop -y h1 -- -i 'Install Mac AppStore Apps'
|
||||
installMASApp 'AusweisApp' 948660805
|
||||
installMASApp 'Compressor' 424390742
|
||||
installMASApp 'Developer' 640199958
|
||||
installMASApp 'Diagrams' 1276248849
|
||||
installMASApp 'Final Cut Pro' 424389933
|
||||
installMASApp 'Iconographer Mini' 1541509510
|
||||
installMASApp 'iMazing Profile Editor' 1487860882
|
||||
installMASApp 'Infuse' 1136220934
|
||||
installMASApp 'Keka' 470158793
|
||||
installMASApp 'Keynote' 409183694
|
||||
installMASApp 'Mass Rename' 1175416599
|
||||
installMASApp 'Microsoft Excel' 462058435
|
||||
installMASApp 'Microsoft Word' 462054704
|
||||
installMASApp 'Motion' 434290957
|
||||
installMASApp 'Numbers' 409203825
|
||||
installMASApp 'Outbank' 1094255754
|
||||
installMASApp 'Pages' 409201541
|
||||
installMASApp 'Parallels Desktop' 1085114709
|
||||
installMASApp 'Pixelmator Pro' 1289583905
|
||||
installMASApp 'SnippetsLab' 1006087419
|
||||
installMASApp 'Tim' 1449619230
|
||||
installMASApp 'WorkingHours' 1495643653
|
||||
installMASApp 'Xcode' 497799835
|
||||
}
|
||||
|
||||
if [[ "${ZSH_EVAL_CONTEXT}" == toplevel || "${ZSH_EVAL_CONTEXT}" == cmdarg ]]; then
|
||||
_DIR="${0:A:h}"
|
||||
source autoload-zshlib
|
||||
main "$@"
|
||||
fi
|
||||
185
bin/azw-setup-user
Executable file
185
bin/azw-setup-user
Executable file
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env zsh
|
||||
# vi: set ft=zsh tw=80 ts=2
|
||||
|
||||
function getExecPrerequisites() {
|
||||
cmds+=(
|
||||
[launchctl]=''
|
||||
[git]=''
|
||||
[mkdir]=''
|
||||
[chmod]=''
|
||||
[]=''
|
||||
)
|
||||
}
|
||||
|
||||
function hideFolders() {
|
||||
chflags hidden ${HOME}/bin
|
||||
}
|
||||
|
||||
function checkExecPrerequisites() {
|
||||
local -A cmds
|
||||
getExecPrerequisites || return
|
||||
checkCommands -m 'This script needs %1$s to work. Please install and retry.' ${(k)cmds} || return
|
||||
}
|
||||
|
||||
function configureInstallPrefix() {
|
||||
local dirPath= desc=
|
||||
for dirPath desc in ${homebrew_prefix} 'Creating install prefix' ${homebrew_directory} 'Creating Homebrew directory'; do
|
||||
if [[ ! -d ${dirPath} ]]; then
|
||||
indicateActivity -- ${desc} createDirAndLogOnFailure ${dirPath}
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function createDirAndLogOnFailure() {
|
||||
local dirPath=$1
|
||||
mkdir -p ${dirPath} 2> /dev/null || {
|
||||
loptty -- -e 'Could not create directory' -e $dirPath
|
||||
return 10
|
||||
}
|
||||
chmod 744 ${dirPath}
|
||||
}
|
||||
|
||||
function downloadHomebrew() {
|
||||
local git_homebrew_remote=`getDefaultGitHomebrewURL`
|
||||
pushd -q ${homebrew_directory} || return 10
|
||||
test -d ".git" && return
|
||||
git init -q
|
||||
git config remote.origin.url "${git_homebrew_remote}"
|
||||
git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
|
||||
git config core.autocrlf false
|
||||
git config --replace-all homebrew.analyticsmessage false
|
||||
git config --replace-all homebrew.caskanalyticsmessage false
|
||||
git fetch --quiet --force origin > /dev/null
|
||||
git fetch --quiet --force --tags origin > /dev/null
|
||||
git reset --hard origin/master
|
||||
popd -q
|
||||
}
|
||||
|
||||
function getCanonicalBrewPath() {
|
||||
local brewPath=${homebrew_directory}/bin/brew
|
||||
if [[ $brewPath == $HOME* ]]; then
|
||||
brewPath="\${HOME}${brewPath#$HOME}"
|
||||
fi
|
||||
echo $brewPath
|
||||
}
|
||||
|
||||
function createBrewCallerScript() {
|
||||
local cmdPath=${HOME}/bin/brew
|
||||
local brewPath=`getCanonicalBrewPath`
|
||||
[[ -f ${cmdPath} ]] && rm ${cmdPath}
|
||||
mkdir -p ${cmdPath:h}
|
||||
cat <<- BREWCALLER > ${cmdPath}
|
||||
#!/usr/bin/env zsh
|
||||
export HOMEBREW_CASK_OPTS="--no-quarantine \${HOMEBREW_CASK_OPTS}"
|
||||
export HOMEBREW_NO_AUTO_UPDATE=1
|
||||
export HOMEBREW_NO_ANALYTICS=1
|
||||
export HOMEBREW_NO_ANALYTICS_THIS_RUN=1
|
||||
export HOMEBREW_NO_ANALYTICS_MESSAGE_OUTPUT=1
|
||||
"${brewPath}" "\$@"
|
||||
BREWCALLER
|
||||
chown $(id -un):$(id -gn) ${cmdPath}
|
||||
chmod u=rwx,go=r ${cmdPath}
|
||||
}
|
||||
|
||||
function createBrewPeriodicScript() {
|
||||
local brewPath=`getCanonicalBrewPath`
|
||||
local cmdPath=${HOME}/bin/brew-periodic
|
||||
[[ -f ${cmdPath} ]] && rm ${cmdPath}
|
||||
mkdir -p ${cmdPath:h}
|
||||
cat <<- BREWCALLER > ${cmdPath}
|
||||
#!/usr/bin/env zsh
|
||||
local brew='${brewPath}'
|
||||
\$brew update
|
||||
\$brew upgrade --greedy
|
||||
\$brew cleanup
|
||||
BREWCALLER
|
||||
chown $(id -un):$(id -gn) ${cmdPath}
|
||||
chmod u=rwx,go=r ${cmdPath}
|
||||
}
|
||||
|
||||
function updateBrew() {
|
||||
local brewPath=${homebrew_directory}/bin/brew
|
||||
${brewPath} update --force --quiet
|
||||
chmod go-w "${homebrew_directory}/share/zsh"
|
||||
}
|
||||
|
||||
function createLaunchDaemonsPlist() {
|
||||
local uid=`id -u`
|
||||
local serviceName="de.astzweig.macos.launchagents.$1"
|
||||
local launchAgentPath=${HOME}/Library/LaunchAgents
|
||||
local launcherPath="${launchAgentPath}/${serviceName}.plist"
|
||||
[[ -d ${launchAgentPath} ]] || mkdir ${launchAgentPath} || return
|
||||
[[ -f ${launcherPath} ]] && {
|
||||
launchctl disable gui/${uid}/${serviceName}
|
||||
rm ${launcherPath}
|
||||
}
|
||||
cat <<- LAUNCHDPLIST > ${launcherPath}
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>${serviceName}</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>${HOME}/bin/brew-periodic</string>
|
||||
</array>
|
||||
<key>StartInterval</key>
|
||||
<integer>1800</integer>
|
||||
</dict>
|
||||
</plist>
|
||||
LAUNCHDPLIST
|
||||
chmod u=rw,go=r ${launcherPath}
|
||||
launchctl enable gui/${uid}/${serviceName} &> /dev/null
|
||||
launchctl bootstrap gui/${uid}/ ${launcherPath} &> /dev/null || true
|
||||
}
|
||||
|
||||
function installHomebrewUpdater() {
|
||||
createLaunchDaemonsPlist brew-updater
|
||||
}
|
||||
|
||||
function getDefaultHomebrewPrefix() {
|
||||
print -- ${HOMEBREW_PREFIX:-${HOME}/Library/Application Support}
|
||||
}
|
||||
|
||||
function getHomebrewDirectoryPath() {
|
||||
print -- ${homebrew_prefix:-$(getDefaultHomebrewPrefix)}/Homebrew
|
||||
}
|
||||
|
||||
function getDefaultGitHomebrewURL() {
|
||||
print -- ${HOMEBREW_BREW_GIT_REMOTE:-https://github.com/Homebrew/brew.git}
|
||||
}
|
||||
|
||||
function configureFolders() {
|
||||
local dirPath
|
||||
for dirPath in ${HOME}/bin ${HOME}/.vim/{backups,swaps}; do
|
||||
[[ ! -d ${dirPath} ]] && indicateActivity -- "Creating ${dirPath}" mkdir ${dirPath}
|
||||
done
|
||||
indicateActivity -- 'Hide folders' hideFolders
|
||||
}
|
||||
|
||||
function installNode() {
|
||||
volta install node
|
||||
}
|
||||
|
||||
function main() {
|
||||
lop -y h1 -- -i 'Setup User'
|
||||
[[ $(id -u) -eq 0 ]] && { loptty -- -e 'Command must not be run as root.' -e $dirPath; return 16 }
|
||||
configureFolders
|
||||
indicateActivity -- 'Install node' installNode
|
||||
local homebrew_prefix=`getDefaultHomebrewPrefix`
|
||||
local homebrew_directory=`getHomebrewDirectoryPath`
|
||||
checkExecPrerequisites || return 17
|
||||
configureInstallPrefix || return 10
|
||||
indicateActivity -- 'Downloading Homebrew' downloadHomebrew || return 11
|
||||
indicateActivity -- 'Create brew caller script' createBrewCallerScript || return 12
|
||||
indicateActivity -- 'Create brew periodic script' createBrewPeriodicScript || return 13
|
||||
indicateActivity -- 'Update brew' updateBrew || return 14
|
||||
indicateActivity -- 'Install Homebrew updater' installHomebrewUpdater || return 15
|
||||
}
|
||||
|
||||
if [[ "${ZSH_EVAL_CONTEXT}" == toplevel || "${ZSH_EVAL_CONTEXT}" == cmdarg ]]; then
|
||||
_DIR="${0:A:h}"
|
||||
source autoload-zshlib
|
||||
main "$@"
|
||||
fi
|
||||
@@ -107,7 +107,7 @@ function ensureDocopts() {
|
||||
}
|
||||
|
||||
function cloneMacOSSystemRepo() {
|
||||
local repoUrl="${MACOS_SYSTEM_REPO_URL:-https://github.com/astzweig/macos-system.git}"
|
||||
local repoUrl="${MACOS_SYSTEM_REPO_URL:-https://git.tabshift.dev/spacebar/macos-system.git}"
|
||||
git clone --depth 1 -q "${repoUrl}" . 2> /dev/null || return 10
|
||||
[ -n "${MACOS_SYSTEM_REPO_BRANCH}" ] && git checkout -q ${MACOS_SYSTEM_REPO_BRANCH} 2> /dev/null || true
|
||||
}
|
||||
|
||||
54
modules/00a-sudo-settings.sh
Executable file
54
modules/00a-sudo-settings.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env zsh
|
||||
# vi: set ft=zsh tw=80 ts=2
|
||||
|
||||
function ensureTRBernsteinCanUpdateSystem() {
|
||||
local username=$1
|
||||
local sudoersFile='/etc/sudoers.d/allow-softwareupdate-for-all'
|
||||
[[ -f ${sudoersFile} ]] && return
|
||||
cat <<- SUDOERS > "${sudoersFile}"
|
||||
trbernstein ALL=(root) NOPASSWD: /usr/sbin/softwareupdate -irR --user admin
|
||||
SUDOERS
|
||||
chown root:wheel "${sudoersFile}" || return 10
|
||||
chmod u=rw,g=r,o= "${sudoersFile}" || return 20
|
||||
}
|
||||
|
||||
function configure_system() {
|
||||
lop -y h1 -- -i 'Configure sudoers files'
|
||||
ensurePathOrLogError ${dstDir} 'Could not install binaries.' || return 10
|
||||
indicateActivity -- "Allow trbernstein user to install updates using softwareupdate" ensureTRBernsteinCanUpdateSystem
|
||||
}
|
||||
|
||||
function getExecPrerequisites() {
|
||||
cmds=(
|
||||
[cat]=''
|
||||
[chown]=''
|
||||
[chmod]=''
|
||||
)
|
||||
}
|
||||
|
||||
function getUsage() {
|
||||
read -r -d '' text <<- USAGE
|
||||
Usage:
|
||||
$cmdName show-questions [<modkey> <modans>]...
|
||||
$cmdName [-v] [-d FILE]
|
||||
|
||||
Add sudo rules to:
|
||||
1. allow trbernstein user to install updates using softwareupdate
|
||||
|
||||
Options:
|
||||
-d FILE, --logfile FILE Print log message to logfile instead of stdout.
|
||||
-v, --verbose Be more verbose.
|
||||
----
|
||||
$cmdName 0.1.0
|
||||
Copyright (C) 2022 Rezart Qelibari, Astzweig GmbH & Co. KG
|
||||
License EUPL-1.2. There is NO WARRANTY, to the extent permitted by law.
|
||||
USAGE
|
||||
print -- ${text}
|
||||
}
|
||||
|
||||
if [[ "${ZSH_EVAL_CONTEXT}" == toplevel ]]; then
|
||||
_DIR="${0:A:h}"
|
||||
test -f "${ASTZWEIG_MACOS_SYSTEM_LIB}" || { echo 'This module requires macos-system library. Please run again with macos-system library provieded as a path in ASTZWEIG_MACOS_SYSTEM_LIB env variable.'; return 10 }
|
||||
source "${ASTZWEIG_MACOS_SYSTEM_LIB}"
|
||||
module_main $0 "$@"
|
||||
fi
|
||||
@@ -39,7 +39,7 @@ function configurePowerManagement() {
|
||||
${cmd} sleep 0
|
||||
${cmd} womp 0
|
||||
${cmd} acwake 0
|
||||
${cmd} proximitywake 0
|
||||
${cmd} proximitywake 1
|
||||
${cmd} destroyfvkeyonstandby 1
|
||||
pmset -b acwake 1
|
||||
${cmd} lidwake 1
|
||||
@@ -65,6 +65,24 @@ function configureMacOSFirewall() {
|
||||
${cmd} --setallowsignedapp on
|
||||
}
|
||||
|
||||
function setComputerName() {
|
||||
scutil --set ComputerName "${hostname}"
|
||||
scutil --set HostName "${hostname}"
|
||||
scutil --set LocalHostName "${hostname}"
|
||||
systemsetup -setcomputername "${hostname}"
|
||||
systemsetup -setlocalsubnetname "${hostname}"
|
||||
}
|
||||
|
||||
function configureComputerHostname() {
|
||||
local currentComputerName="`scutil --get ComputerName`"
|
||||
if [[ "${currentComputerName}" != "${hostname}" ]]; then
|
||||
lop -- -i 'Hostname of computer has not been set.' -i "Will set to ${hostname}."
|
||||
indicateActivity -- 'Set computer name' setComputerName
|
||||
else
|
||||
lop -- -i 'Hostname of computer seems to have already been set. Skipping.' -i "Hostname: $currentComputerName"
|
||||
fi
|
||||
}
|
||||
|
||||
function configure_system() {
|
||||
lop -y h1 -- -i 'Configure System Settings'
|
||||
indicateActivity -- 'Quitting System Preferences' quitSystemPreferences
|
||||
@@ -73,6 +91,13 @@ function configure_system() {
|
||||
indicateActivity -- 'Configuring login window' configureLoginWindow
|
||||
indicateActivity -- 'Configure global umask' launchctl config user umask 027
|
||||
indicateActivity -- 'Configure macOS firewall' configureMacOSFirewall
|
||||
configureComputerHostname
|
||||
}
|
||||
|
||||
function getQuestions() {
|
||||
questions=(
|
||||
'i: hostname=What shall the systems hostname be?'
|
||||
)
|
||||
}
|
||||
|
||||
function getUsage() {
|
||||
@@ -80,11 +105,12 @@ function getUsage() {
|
||||
read -r -d '' text <<- USAGE
|
||||
Usage:
|
||||
$cmdName show-questions [<modkey> <modans>]...
|
||||
$cmdName [-v] [-d FILE]
|
||||
$cmdName [-v] [-d FILE] --hostname NAME
|
||||
|
||||
Set energy, network and basic preferences.
|
||||
|
||||
Options:
|
||||
--hostname NAME Set NAME as current host's host name.
|
||||
-d FILE, --logfile FILE Print log message to logfile instead of stdout.
|
||||
-v, --verbose Be more verbose.
|
||||
----
|
||||
|
||||
@@ -35,13 +35,18 @@ function ensureUserCanRunPasswordlessSudo() {
|
||||
chmod u=rw,g=r,o= "${sudoersFile}" || return 20
|
||||
}
|
||||
|
||||
function ensureUserCanNoLongerRunPasswordlessSudo() {
|
||||
local username=$1
|
||||
local sudoersFile="/etc/sudoers.d/no-auth-sudo-for-${username}"
|
||||
[[ ! -f ${sudoersFile} ]] || rm ${sudoersFile}
|
||||
}
|
||||
|
||||
function getFirstFreeRoleAccountID() {
|
||||
local minUserID=450
|
||||
local maxUserID=499
|
||||
local uname_machine=$(/usr/bin/uname -m)
|
||||
if [[ ${uname_machine} == "arm64" ]]; then
|
||||
minUserID=200
|
||||
maxUserID=400
|
||||
local minUserID=200
|
||||
local maxUserID=400
|
||||
if is-at-least 13.0 $(sw_vers -productVersion); then
|
||||
minUserID=450
|
||||
maxUserID=499
|
||||
fi
|
||||
dscl . -list '/Users' UniqueID | grep '_.*' | sort -n -k2 | awk -v i=${minUserID} '$2>='${minUserID}' && $2<'${maxUserID}' {if(i < $2) { print i; nextfile} else i=$2+1;} END {if(i <= '${maxUserID}' && ($2 < '${minUserID}' || $2 > '${maxUserID}')) print i;}'
|
||||
}
|
||||
@@ -96,28 +101,93 @@ function getHomebrewRepositoryPath() {
|
||||
|
||||
function createBrewCallerScript() {
|
||||
ensureLocalBinFolder
|
||||
local uname_machine=$(/usr/bin/uname -m)
|
||||
local username=${homebrew_username}
|
||||
local brewCallerPath="/usr/local/bin/brew"
|
||||
[ -f "${brewCallerPath}" ] && rm "${brewCallerPath}"
|
||||
cat <<- BREWCALLER > ${brewCallerPath}
|
||||
#!/usr/bin/env zsh
|
||||
if [ "\$(id -un)" != "${username}" ]; then
|
||||
echo 'brew will be run as ${username} user.' >&2
|
||||
sudo -E -u "${username}" "\$0" "\$@"
|
||||
exit \$?
|
||||
fi
|
||||
export HOMEBREW_CACHE="${homebrew_cache}"
|
||||
export HOMEBREW_LOGS="${homebrew_log}"
|
||||
export HOMEBREW_CASK_OPTS="--no-quarantine \${HOMEBREW_CASK_OPTS}"
|
||||
export HOMEBREW_NO_AUTO_UPDATE=1
|
||||
export HOMEBREW_NO_ANALYTICS=1
|
||||
export HOMEBREW_NO_ANALYTICS_THIS_RUN=1
|
||||
export HOMEBREW_NO_ANALYTICS_MESSAGE_OUTPUT=1
|
||||
umask 002
|
||||
"$(getHomebrewRepositoryPath)/bin/brew" "\$@"
|
||||
local homebrewRepositoryPath="$(getHomebrewRepositoryPath)"
|
||||
local brewCallerPath="${homebrewRepositoryPath}/bin/brew-caller"
|
||||
local brewCallerSymlink="/usr/local/bin/brew"
|
||||
[[ -f "${brewCallerPath}" ]] && rm "${brewCallerPath}"
|
||||
[[ -f "${brewCallerSymlink}" || -h "${brewCallerSymlink}" ]] && rm "${brewCallerSymlink}"
|
||||
[[ ${uname_machine} == "arm64" ]] && brewCallerPath=${brewCallerSymlink}
|
||||
cat <<- BREWCALLER | clang -x c -O2 -Wall -o "${brewCallerPath}" -
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
extern char **environ;
|
||||
|
||||
char *format_env(const char *env_name, const char *format) {
|
||||
if (!env_name || !format) return NULL;
|
||||
const char *value = getenv(env_name);
|
||||
if (!value) return NULL;
|
||||
int formatted_len = snprintf(NULL, 0, format, value);
|
||||
if (formatted_len < 0) return NULL;
|
||||
char *formatted_value = malloc(formatted_len + 1);
|
||||
if (!formatted_value) return NULL;
|
||||
snprintf(formatted_value, formatted_len + 1, format, value);
|
||||
size_t result_len = strlen(env_name) + 1 + formatted_len;
|
||||
char *result = malloc(result_len + 1);
|
||||
if (!result) { free(formatted_value); return NULL; }
|
||||
sprintf(result, "%s=%s", env_name, formatted_value);
|
||||
free(formatted_value);
|
||||
return result;
|
||||
}
|
||||
|
||||
#define HOMEBREW_USER "${username}"
|
||||
#define HOMEBREW_DIR "${homebrewRepositoryPath}/bin"
|
||||
#define BREW_PATH HOMEBREW_DIR "/brew"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct passwd *pw;
|
||||
uid_t target_uid;
|
||||
gid_t target_gid;
|
||||
|
||||
pw = getpwnam(HOMEBREW_USER);
|
||||
if (!pw) { fprintf(stderr, "Error: user %s not found\n", HOMEBREW_USER); return 1; }
|
||||
target_uid = pw->pw_uid;
|
||||
target_gid = pw->pw_gid;
|
||||
|
||||
char *new_environ[] = {
|
||||
"PATH=" HOMEBREW_DIR ":/usr/bin:/bin:/usr/sbin:/sbin",
|
||||
"HOMEBREW_CACHE=${homebrew_cache}",
|
||||
"HOMEBREW_LOGS=${homebrew_log}",
|
||||
format_env("HOME", "%s"),
|
||||
format_env("HOMEBREW_CASK_OPTS", "--no-quarantine %s"),
|
||||
"HOMEBREW_PREFIX=${homebrewRepositoryPath}",
|
||||
"HOMEBREW_CELLAR=${homebrewRepositoryPath}/Cellar",
|
||||
"HOMEBREW_NO_AUTO_UPDATE=1",
|
||||
"HOMEBREW_NO_ANALYTICS=1",
|
||||
"HOMEBREW_NO_ANALYTICS_THIS_RUN=1",
|
||||
"HOMEBREW_NO_ANALYTICS_MESSAGE_OUTPUT=1",
|
||||
NULL
|
||||
};
|
||||
|
||||
if (setegid(target_gid) != 0) { fprintf(stderr, "setegid(%d): %s\n", target_gid, strerror(errno)); return 1; }
|
||||
|
||||
if (seteuid(target_uid) != 0) { fprintf(stderr, "seteuid(%d): %s\n", target_uid, strerror(errno)); return 1; }
|
||||
|
||||
char **newargv = malloc((argc + 1) * sizeof(char *));
|
||||
if (!newargv) { fprintf(stderr, "malloc failed for new argv\n"); return 1; }
|
||||
|
||||
newargv[0] = (char *)BREW_PATH;
|
||||
for (int i = 1; i < argc; ++i) newargv[i] = argv[i];
|
||||
newargv[argc] = NULL;
|
||||
umask(0002);
|
||||
|
||||
execve(BREW_PATH, newargv, new_environ);
|
||||
fprintf(stderr, "execv(%s) failed: %s\n", BREW_PATH, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
BREWCALLER
|
||||
chown root:admin ${brewCallerPath}
|
||||
chmod ug+x,o-x ${brewCallerPath}
|
||||
chmod 4550 ${brewCallerPath}
|
||||
[[ ${uname_machine} == "arm64" ]] || ln -s "${brewCallerPath}" "${brewCallerSymlink}"
|
||||
}
|
||||
|
||||
function createBrewPeriodicScript() {
|
||||
@@ -136,9 +206,8 @@ function createBrewPeriodicScript() {
|
||||
}
|
||||
|
||||
function installHomebrewCore() {
|
||||
export NONINTERACTIVE=1
|
||||
[ ! -d $(getHomebrewRepositoryPath) ] || return
|
||||
sudo --preserve-env=NONINTERACTIVE -u "${homebrew_username}" /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
[ ! -d $(getHomebrewRepositoryPath) ] || return
|
||||
NONINTERACTIVE=1 HOME= sudo --preserve-env=NONINTERACTIVE,HOME -u "${homebrew_username}" /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
[ -d $(getHomebrewRepositoryPath) ]
|
||||
}
|
||||
|
||||
@@ -213,6 +282,7 @@ function configure_system() {
|
||||
ensureHomebrewCacheDirectory || return 13
|
||||
ensureHomebrewLogDirectory || return 14
|
||||
indicateActivity 'Install Homebrew core' installHomebrewCore || return 15
|
||||
indicateActivity 'Ensure Homebrew user can nolonger run passwordless sudo' ensureUserCanNoLongerRunPasswordlessSudo ${homebrew_username} || return 20
|
||||
indicateActivity 'Create brew caller script' createBrewCallerScript || return 16
|
||||
indicateActivity 'Create brew periodic script' createBrewPeriodicScript || return 17
|
||||
indicateActivity 'Install Homebrew updater' installHomebrewUpdater || return 18
|
||||
@@ -285,6 +355,7 @@ function getUsage() {
|
||||
|
||||
if [[ "${ZSH_EVAL_CONTEXT}" == toplevel ]]; then
|
||||
test -f "${ASTZWEIG_MACOS_SYSTEM_LIB}" || { echo 'This module requires macos-system library. Please run again with macos-system library provieded as a path in ASTZWEIG_MACOS_SYSTEM_LIB env variable.'; return 10 }
|
||||
autoload is-at-least
|
||||
source "${ASTZWEIG_MACOS_SYSTEM_LIB}"
|
||||
module_main $0 "$@"
|
||||
fi
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
function brewInstall() {
|
||||
local identifier="$1"
|
||||
local cask="${2:+--cask}"
|
||||
indicateActivity -- "Installing ${identifier}${cask:+ (Cask)}" ${homebrew_path} install -q ${cask} ${identifier}
|
||||
HOME=/Users/Shared indicateActivity -- "Installing ${identifier}${cask:+ (Cask)}" sudo -u _homebrew ${homebrew_path} install -q ${cask} ${identifier}
|
||||
}
|
||||
|
||||
function installCask() {
|
||||
@@ -26,7 +26,9 @@ function installCasks() {
|
||||
installCask devonthink
|
||||
installCask firefox
|
||||
installCask hazel
|
||||
installCask hopper-disassembler
|
||||
installCask istat-menus
|
||||
installCask jdownloader
|
||||
installCask launchcontrol
|
||||
installCask makemkv
|
||||
installCask network-radar
|
||||
@@ -34,6 +36,7 @@ function installCasks() {
|
||||
installCask orbstack
|
||||
installCask rapidapi
|
||||
installCask rectangle
|
||||
installCask serverbuddy
|
||||
installCask sf-symbols
|
||||
installCask sketch
|
||||
installCask suspicious-package
|
||||
@@ -56,13 +59,14 @@ function installBrews() {
|
||||
lop -y body:h1 -- -i 'Installing Homebrew formulas'
|
||||
installBrew mas
|
||||
if ! isDebug; then
|
||||
installBrew bun
|
||||
installBrew chezmoi
|
||||
installBrew cocogitto
|
||||
installBrew composer
|
||||
installBrew curl
|
||||
installBrew docker
|
||||
installBrew docker-buildx
|
||||
installBrew exiftool
|
||||
installBrew f2
|
||||
installBrew ffmpeg
|
||||
installBrew gnupg
|
||||
installBrew go
|
||||
@@ -71,18 +75,16 @@ function installBrews() {
|
||||
installBrew imap-backup
|
||||
installBrew imapsync
|
||||
installBrew nmap
|
||||
installBrew node
|
||||
installBrew pdfgrep
|
||||
installBrew php
|
||||
installBrew python
|
||||
installBrew qpdf
|
||||
installBrew rcm
|
||||
installBrew ruby
|
||||
installBrew 'hay-kot/scaffold-tap/scaffold'
|
||||
installBrew 'lemoony/tap/snipkit'
|
||||
installBrew sqlite
|
||||
installBrew tree
|
||||
installBrew tidy-html5
|
||||
installBrew volta
|
||||
installBrew yq
|
||||
fi
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user