Compare commits
10 Commits
8153393d8d
...
e44c48efbd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e44c48efbd | ||
|
|
b008d4ebb0 | ||
|
|
d4a39b5dd5 | ||
|
|
1953b01148 | ||
|
|
3f2f23a446 | ||
|
|
5c1a6998b7 | ||
|
|
60fc6580d8 | ||
|
|
dd6875b79a | ||
|
|
aef49d322f | ||
|
|
82e5747b67 |
12
README.md
12
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,10 +39,11 @@ 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. | - |
|
||||
@@ -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
|
||||
44
bin/azw-setup-host
Executable file
44
bin/azw-setup-host
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/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 '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
|
||||
173
bin/azw-setup-user
Executable file
173
bin/azw-setup-user
Executable file
@@ -0,0 +1,173 @@
|
||||
#!/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 createBrewCallerScript() {
|
||||
local cmdPath=${HOME}/bin/brew
|
||||
local brewPath=${homebrew_directory}/bin/brew
|
||||
[[ -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 brewCallerPath=${HOME}/bin/brew
|
||||
local cmdPath=${HOME}/bin/brew-periodic
|
||||
[[ -f ${cmdPath} ]] && rm ${cmdPath}
|
||||
mkdir -p ${cmdPath:h}
|
||||
cat <<- BREWCALLER > ${cmdPath}
|
||||
#!/usr/bin/env zsh
|
||||
local brew='${brewCallerPath}'
|
||||
\$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 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
Normal file
54
modules/00a-sudo-settings.sh
Normal 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
|
||||
@@ -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.
|
||||
----
|
||||
|
||||
@@ -24,17 +24,6 @@ function ensureUserIsInAdminGroup() {
|
||||
dseditgroup -o edit -a "${username}" -t user admin
|
||||
}
|
||||
|
||||
function ensureUserCanRunPasswordlessSudo() {
|
||||
local username=$1
|
||||
local sudoersFile="/etc/sudoers.d/no-auth-sudo-for-${username}"
|
||||
[[ -f ${sudoersFile} ]] && return
|
||||
cat <<- SUDOERS > "${sudoersFile}"
|
||||
Defaults:${username} !authenticate
|
||||
SUDOERS
|
||||
chown root:wheel "${sudoersFile}" || return 10
|
||||
chmod u=rw,g=r,o= "${sudoersFile}" || return 20
|
||||
}
|
||||
|
||||
function getFirstFreeRoleAccountID() {
|
||||
local minUserID=450
|
||||
local maxUserID=499
|
||||
@@ -97,27 +86,87 @@ function getHomebrewRepositoryPath() {
|
||||
function createBrewCallerScript() {
|
||||
ensureLocalBinFolder
|
||||
local username=${homebrew_username}
|
||||
local brewCallerPath="/usr/local/bin/brew"
|
||||
local homebrewRepositoryPath="$(getHomebrewRepositoryPath)"
|
||||
local brewCallerPath="${homebrewRepositoryPath}/bin/brew-caller"
|
||||
local brewCallerSymlink="/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" "\$@"
|
||||
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",
|
||||
"HOMEBREW_CACHE=${homebrew_cache}",
|
||||
"HOMEBREW_LOGS=${homebrew_log}",
|
||||
format_env("HOME", "%s"),
|
||||
format_env("HOMEBREW_CASK_OPTS", "--no-quarantine %s"),
|
||||
"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}
|
||||
ln -s "${brewCallerPath}" "${brewCallerSymlink}"
|
||||
}
|
||||
|
||||
function createBrewPeriodicScript() {
|
||||
@@ -209,7 +258,6 @@ function configure_system() {
|
||||
lop -y h1 -- -i 'Install System Homebrew'
|
||||
createHomebrewUserIfNeccessary || return 10
|
||||
indicateActivity 'Ensure Homebrew user is in admin group' ensureUserIsInAdminGroup ${homebrew_username} || return 11
|
||||
indicateActivity 'Ensure Homebrew user can run passwordless sudo' ensureUserCanRunPasswordlessSudo ${homebrew_username} || return 12
|
||||
ensureHomebrewCacheDirectory || return 13
|
||||
ensureHomebrewLogDirectory || return 14
|
||||
indicateActivity 'Install Homebrew core' installHomebrewCore || return 15
|
||||
|
||||
@@ -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
|
||||
@@ -57,6 +60,7 @@ function installBrews() {
|
||||
installBrew mas
|
||||
if ! isDebug; then
|
||||
installBrew bun
|
||||
installBrew chezmoi
|
||||
installBrew cocogitto
|
||||
installBrew composer
|
||||
installBrew curl
|
||||
@@ -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