资源说明:
* Mac Setup
:properties:
:header-args: :cache yes :comments org :padline yes :results silent
:header-args:sh: :noweb tangle :shebang "#!/bin/sh" :tangle mac-setup.command
:end:
#+startup: showall nohideblocks hidestars indent
#+begin_quote
From zero to fully installed and configured, in an hour.
#+end_quote
** Overview
*** Quick Start
#+begin_src sh
case "${SHELL}" in
(*zsh) ;;
(*) chsh -s "$(which zsh)"; exit 1 ;;
esac
#+end_src
#+begin_example sh
curl --location --silent \
"https://github.com/ptb/mac-setup/raw/develop/mac-setup.command" | \
source /dev/stdin 0
#+end_example
#+begin_example sh
init && install && config
#+end_example
#+begin_example sh
custom && personalize_all
#+end_example
**** =init=
- Enter administrator account password only once
- Select the cache folder for repeat installations
- Turn off sleep and set computer name/hostname
- Set write permission on destination folders
- Cache software updates and App Store software
- Install developer tools and macOS updates
**** =install=
- [[https://brew.sh/][Homebrew]]: The missing package mananger for macOS
- [[https://caskroom.github.io/][Homebrew-Cask]]: “To install, drag this icon…” no more!
- [[https://github.com/mas-cli/mas][mas-cli/mas]]: Mac App Store command line interface
- [[https://github.com/Homebrew/homebrew-bundle][homebrew-bundle]]: List all Homebrew packages in =Brewfile=
- [[https://nodejs.org/][Node.js]]: Cross-platform JavaScript run-time environment
- [[https://www.perl.org/][Perl 5]]: Highly capable, feature-rich programming language
- [[https://www.python.org/][Python]]: Programming language that lets you work quickly
- [[https://www.ruby-lang.org/][Ruby]]: Language with a focus on simplicity and productivity
**** =config=
- Configure software requiring an administrator account
- Optionally configure local Dovecot secure IMAP server
- Create your primary /non-administrator/ account
- Remove password-less administrator account permission
- Recommended that you log out of administrator account
**** =custom=
- Log in with your new non-administrator account
- Create or clone a git repository into your home folder
- Install [[https://atom.io/][Atom]] [[https://atom.io/packages][packages]] and customize preferences
- Set the desktop picture to a solid black color
- Customize the dock with new default applications
- Customize Emacs with [[http://spacemacs.org/][Spacemacs]]: Emacs /plus/ Vim!
- Set all preferences automatically and consistently
*** Features
- *macOS High Sierra:* Tested with macOS High Sierra 10.13 (17A365).
- *Completely Automated:* Homebrew, Cask, and =mas-cli= install everything.
- *Latest Versions:* Includes Node, Perl, Python, and Ruby separate from macOS.
- *Customized Terminal:* Colors and fonts decyphered into editable preferences.
- *Idempotent:* This script is intended to be safe to run more than once.
*** Walkthrough
**** Clone Internal Hard Disk to External Disk
**** Select the External Disk as Startup Disk
**** Download macOS Install from the App Store
=macappstores://itunes.apple.com/app/id1209167288=
**** Open /Applications/Utilities/Terminal.app
#+begin_example sh
diskx="$(diskutil list internal physical | sed '/^\//!d;s/^\(.*\)\ (.*):/\1/')"
#+end_example
#+begin_example sh
diskutil zeroDisk $diskx
diskutil partitionDisk $diskx 2 GPT \
jhfs+ "Install" 6G \
apfs $(ruby -e "print '$(hostname -s)'.capitalize") R
#+end_example
#+begin_example sh
sudo "/Applications/Install macOS High Sierra.app/Contents/Resources/createinstallmedia" \
--applicationpath "/Applications/Install macOS High Sierra.app" --nointeraction \
--volume "/Volumes/Install"
#+end_example
**** Select the Install Disk as Startup Disk
*** License
#+begin_quote
Copyright 2017 [[https://github.com/ptb][Peter T Bosse II]]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
#+end_quote
** Initialize
*** Initialize New Terminal
#+begin_src sh
if test -z "${1}"; then
osascript - "${0}" << EOF > /dev/null 2>&1
<>
EOF
fi
#+end_src
**** =new_term.applescript=
#+begin_src applescript :noweb-ref new_term.applescript
on run { _this }
tell app "Terminal" to do script "source " & quoted form of _this & " 0"
end run
#+end_src
*** Define Function =ask=
#+begin_src sh
ask () {
osascript - "${1}" "${2}" "${3}" << EOF 2> /dev/null
<>
EOF
}
#+end_src
**** =ask.applescript=
#+begin_src applescript :noweb-ref ask.applescript
on run { _title, _action, _default }
tell app "System Events" to return text returned of (display dialog _title with title _title buttons { "Cancel", _action } default answer _default)
end run
#+end_src
*** Define Function =ask2=
#+begin_src sh
ask2 () {
osascript - "$1" "$2" "$3" "$4" "$5" "$6" << EOF 2> /dev/null
<>
EOF
}
#+end_src
**** =ask2.applescript=
#+begin_src applescript :noweb-ref ask2.applescript
on run { _text, _title, _cancel, _action, _default, _hidden }
tell app "Terminal" to return text returned of (display dialog _text with title _title buttons { _cancel, _action } cancel button _cancel default button _action default answer _default hidden answer _hidden)
end run
#+end_src
*** Define Function =p=
#+begin_src sh
p () {
printf "\n\033[1m\033[34m%s\033[0m\n\n" "${1}"
}
#+end_src
*** Define Function =run=
#+begin_src sh
run () {
osascript - "${1}" "${2}" "${3}" << EOF 2> /dev/null
<>
EOF
}
#+end_src
**** =run.applescript=
#+begin_src applescript :noweb-ref run.applescript
on run { _title, _cancel, _action }
tell app "Terminal" to return button returned of (display dialog _title with title _title buttons { _cancel, _action } cancel button 1 default button 2 giving up after 5)
end run
#+end_src
*** Define Function =init=
#+begin_src sh
init () {
init_sudo
init_cache
init_no_sleep
init_hostname
init_perms
init_maskeep
init_updates
config_new_account
config_rm_sudoers
}
if test "${1}" = 0; then
printf "\n$(which init)\n"
fi
#+end_src
*** Define Function =init_paths=
#+begin_src sh
init_paths () {
test -x "/usr/libexec/path_helper" && \
eval $(/usr/libexec/path_helper -s)
}
#+end_src
*** Eliminate Prompts for Password
#+begin_src sh
init_sudo () {
printf "%s\n" "%wheel ALL=(ALL) NOPASSWD: ALL" | \
sudo tee "/etc/sudoers.d/wheel" > /dev/null && \
sudo dscl /Local/Default append /Groups/wheel GroupMembership "$(whoami)"
}
#+end_src
*** Select Installation Cache Location
#+begin_src sh
init_cache () {
grep -q "CACHES" "/etc/zshenv" 2> /dev/null || \
a=$(osascript << EOF 2> /dev/null
<>
EOF
) && \
test -d "${a}" || \
a="${HOME}/Library/Caches/"
grep -q "CACHES" "/etc/zshenv" 2> /dev/null || \
printf "%s\n" \
"export CACHES=\"${a}\"" \
"export HOMEBREW_CACHE=\"${a}/brew\"" \
"export BREWFILE=\"${a}/brew/Brewfile\"" | \
sudo tee -a "/etc/zshenv" > /dev/null
. "/etc/zshenv"
if test -d "${CACHES}/upd"; then
sudo chown -R "$(whoami)" "/Library/Updates"
rsync -a --delay-updates \
"${CACHES}/upd/" "/Library/Updates/"
fi
}
#+end_src
**** =init_cache.applescript=
#+begin_src applescript :noweb-ref init_cache.applescript
on run
return text 1 through -2 of POSIX path of (choose folder with prompt "Select Installation Cache Location")
end run
#+end_src
*** Set Defaults for Sleep
#+begin_src sh
init_no_sleep () {
sudo pmset -a sleep 0
sudo pmset -a disksleep 0
}
#+end_src
*** Set Hostname from DNS
#+begin_src sh
init_hostname () {
a=$(ask2 "Set Computer Name and Hostname" "Set Hostname" "Cancel" "Set Hostname" $(ruby -e "print '$(hostname -s)'.capitalize") "false")
if test -n $a; then
sudo scutil --set ComputerName $(ruby -e "print '$a'.capitalize")
sudo scutil --set HostName $(ruby -e "print '$a'.downcase")
fi
}
#+end_src
*** Set Permissions on Install Destinations
#+begin_src sh :var _dest=_dest[3:11,1]
init_perms () {
printf "%s\n" "${_dest}" | \
while IFS="$(printf '\t')" read d; do
test -d "${d}" || sudo mkdir -p "${d}"
sudo chgrp -R admin "${d}"
sudo chmod -R g+w "${d}"
done
}
#+end_src
**** _dest
#+name: _dest
|-----------------+---------------------------|
| Location | Install Path |
|-----------------+---------------------------|
| | /usr/local/bin |
| | /Library/Desktop Pictures |
| colorpickerdir | /Library/ColorPickers |
| fontdir | /Library/Fonts |
| input_methoddir | /Library/Input Methods |
| prefpanedir | /Library/PreferencePanes |
| qlplugindir | /Library/QuickLook |
| screen_saverdir | /Library/Screen Savers |
| | /Library/User Pictures |
|-----------------+---------------------------|
*** Install Developer Tools
#+begin_src sh
init_devtools () {
p="${HOMEBREW_CACHE}/Cask/Command Line Tools (macOS High Sierra version 10.13).pkg"
i="com.apple.pkg.CLTools_SDK_macOS1013"
if test -f "${p}"; then
if ! pkgutil --pkg-info "${i}" > /dev/null 2>&1; then
sudo installer -pkg "${p}" -target /
fi
else
xcode-select --install
fi
}
#+end_src
*** Install Xcode
#+begin_src sh
init_xcode () {
if test -f ${HOMEBREW_CACHE}/Cask/xcode*.xip; then
p "Installing Xcode"
dest="${HOMEBREW_CACHE}/Cask/xcode"
if ! test -d "$dest"; then
pkgutil --expand ${HOMEBREW_CACHE}/Cask/xcode*.xip "$dest"
curl --location --silent \
"https://gist.githubusercontent.com/pudquick/ff412bcb29c9c1fa4b8d/raw/24b25538ea8df8d0634a2a6189aa581ccc6a5b4b/parse_pbzx2.py" | \
python - "${dest}/Content"
find "${dest}" -empty -name "*.xz" -type f -print0 | \
xargs -0 -l 1 rm
find "${dest}" -name "*.xz" -print0 | \
xargs -0 -L 1 gunzip
cat ${dest}/Content.part* > \
${dest}/Content.cpio
fi
cd /Applications && \
sudo cpio -dimu --file=${dest}/Content.cpio
for pkg in /Applications/Xcode*.app/Contents/Resources/Packages/*.pkg; do
sudo installer -pkg "$pkg" -target /
done
x="$(find '/Applications' -maxdepth 1 -regex '.*/Xcode[^ ]*.app' -print -quit)"
if test -n "${x}"; then
sudo xcode-select -s "${x}"
sudo xcodebuild -license accept
fi
fi
}
#+end_src
*** Install macOS Updates
#+begin_src sh
init_updates () {
sudo softwareupdate --install --all
}
#+end_src
*** Save Mac App Store Packages
#+begin_example sh
sudo lsof -c softwareupdated -F -r 2 | sed '/^n\//!d;/com.apple.SoftwareUpdate/!d;s/^n//'
sudo lsof -c storedownloadd -F -r 2 | sed '/^n\//!d;/com.apple.appstore/!d;s/^n//'
#+end_example
#+begin_src sh :var _maskeep_launchd=_maskeep_launchd[3:-2,0:3]
init_maskeep () {
sudo softwareupdate --reset-ignored > /dev/null
cat << EOF > "/usr/local/bin/maskeep"
<>
EOF
chmod a+x "/usr/local/bin/maskeep"
rehash
config_launchd "/Library/LaunchDaemons/com.github.ptb.maskeep.plist" "$_maskeep_launchd" "sudo" ""
}
#+end_src
**** _maskeep_launchd
#+name: _maskeep_launchd
|---------+--------------------+--------+-----------------------------------------------------------------------------------------------------------------|
| Command | Entry | Type | Value |
|---------+--------------------+--------+-----------------------------------------------------------------------------------------------------------------|
| add | :KeepAlive | bool | false |
| add | :Label | string | com.github.ptb.maskeep |
| add | :ProcessType | string | Background |
| add | :Program | string | /usr/local/bin/maskeep |
| add | :RunAtLoad | bool | true |
| add | :StandardErrorPath | string | /dev/stderr |
| add | :StandardOutPath | string | /dev/stdout |
| add | :UserName | string | root |
| add | :WatchPaths | array | |
| add | :WatchPaths:0 | string | $(sudo find '/private/var/folders' -name 'com.apple.SoftwareUpdate' -type d -user _softwareupdate -print -quit 2> /dev/null) |
| add | :WatchPaths:1 | string | $(sudo -u \\#501 -- sh -c 'getconf DARWIN_USER_CACHE_DIR' 2> /dev/null)com.apple.appstore |
| add | :WatchPaths:2 | string | $(sudo -u \\#502 -- sh -c 'getconf DARWIN_USER_CACHE_DIR' 2> /dev/null)com.apple.appstore |
| add | :WatchPaths:3 | string | $(sudo -u \\#503 -- sh -c 'getconf DARWIN_USER_CACHE_DIR' 2> /dev/null)com.apple.appstore |
| add | :WatchPaths:4 | string | /Library/Updates |
|---------+--------------------+--------+-----------------------------------------------------------------------------------------------------------------|
**** =/usr/local/bin/maskeep=
#+begin_src sh :noweb-ref maskeep.sh :tangle no
#!/bin/sh
asdir="/Library/Caches/storedownloadd"
as1="\$(sudo -u \\#501 -- sh -c 'getconf DARWIN_USER_CACHE_DIR' 2> /dev/null)com.apple.appstore"
as2="\$(sudo -u \\#502 -- sh -c 'getconf DARWIN_USER_CACHE_DIR' 2> /dev/null)com.apple.appstore"
as3="\$(sudo -u \\#503 -- sh -c 'getconf DARWIN_USER_CACHE_DIR' 2> /dev/null)com.apple.appstore"
upd="/Library/Updates"
sudir="/Library/Caches/softwareupdated"
su="\$(sudo find '/private/var/folders' -name 'com.apple.SoftwareUpdate' -type d -user _softwareupdate 2> /dev/null)"
for i in 1 2 3 4 5; do
mkdir -m a=rwxt -p "\$asdir"
for as in "\$as1" "\$as2" "\$as3" "\$upd"; do
test -d "\$as" && \
find "\${as}" -type d -print | \\
while read a; do
b="\${asdir}/\$(basename \$a)"
mkdir -p "\${b}"
find "\${a}" -type f -print | \\
while read c; do
d="\$(basename \$c)"
test -e "\${b}/\${d}" || \\
ln "\${c}" "\${b}/\${d}" && \\
chmod 666 "\${b}/\${d}"
done
done
done
mkdir -m a=rwxt -p "\${sudir}"
find "\${su}" -name "*.tmp" -type f -print | \\
while read a; do
d="\$(basename \$a)"
test -e "\${sudir}/\${d}.xar" ||
ln "\${a}" "\${sudir}/\${d}.xar" && \\
chmod 666 "\${sudir}/\${d}.xar"
done
sleep 1
done
exit 0
#+end_src
** Install
*** Define Function =install=
#+begin_src sh
install () {
install_macos_sw
install_node_sw
install_perl_sw
install_python_sw
install_ruby_sw
which config
}
#+end_src
*** Install macOS Software with =brew=
#+begin_src sh
install_macos_sw () {
p "Installing macOS Software"
install_paths
install_brew
install_brewfile_taps
install_brewfile_brew_pkgs
install_brewfile_cask_args
install_brewfile_cask_pkgs
install_brewfile_mas_apps
x=$(find '/Applications' -maxdepth 1 -regex '.*/Xcode[^ ]*.app' -print -quit)
if test -n "$x"; then
sudo xcode-select -s "$x"
sudo xcodebuild -license accept
fi
brew bundle --file="${BREWFILE}"
x=$(find '/Applications' -maxdepth 1 -regex '.*/Xcode[^ ]*.app' -print -quit)
if test -n "$x"; then
sudo xcode-select -s "$x"
sudo xcodebuild -license accept
fi
install_links
sudo xattr -rd "com.apple.quarantine" "/Applications" > /dev/null 2>&1
sudo chmod -R go=u-w "/Applications" > /dev/null 2>&1
}
#+end_src
*** Add =/usr/local/bin/sbin= to Default Path
#+begin_src sh
install_paths () {
if ! grep -Fq "/usr/local/sbin" /etc/paths; then
sudo sed -i "" -e "/\/usr\/sbin/{x;s/$/\/usr\/local\/sbin/;G;}" /etc/paths
fi
}
#+end_src
*** Install Homebrew Package Manager
#+begin_src sh
install_brew () {
if ! which brew > /dev/null; then
ruby -e \
"$(curl -Ls 'https://github.com/Homebrew/install/raw/master/install')" \
< /dev/null > /dev/null 2>&1
fi
printf "" > "${BREWFILE}"
brew analytics off
brew update
brew doctor
brew tap "homebrew/bundle"
}
#+end_src
*** Add Homebrew Taps to Brewfile
#+begin_src sh :var _taps=_taps[3:-2,0]
install_brewfile_taps () {
printf "%s\n" "${_taps}" | \
while IFS="$(printf '\t')" read tap; do
printf 'tap "%s"\n' "${tap}" >> "${BREWFILE}"
done
printf "\n" >> "${BREWFILE}"
}
#+end_src
**** _taps
#+name: _taps
|----------------------------+--------------------------------------------------------|
| Homebrew Tap Name | Reference URL |
|----------------------------+--------------------------------------------------------|
| caskroom/cask | https://github.com/caskroom/homebrew-cask |
| caskroom/fonts | https://github.com/caskroom/homebrew-fonts |
| caskroom/versions | https://github.com/caskroom/homebrew-versions |
| homebrew/bundle | https://github.com/Homebrew/homebrew-bundle |
| homebrew/command-not-found | https://github.com/Homebrew/homebrew-command-not-found |
| homebrew/nginx | https://github.com/Homebrew/homebrew-nginx |
| homebrew/php | https://github.com/Homebrew/homebrew-php |
| homebrew/services | https://github.com/Homebrew/homebrew-services |
| ptb/custom | https://github.com/ptb/homebrew-custom |
| railwaycat/emacsmacport | https://github.com/railwaycat/homebrew-emacsmacport |
|----------------------------+--------------------------------------------------------|
*** Add Homebrew Packages to Brewfile
#+begin_src sh :var _pkgs=_pkgs[3:-2,0]
install_brewfile_brew_pkgs () {
printf "%s\n" "${_pkgs}" | \
while IFS="$(printf '\t')" read pkg; do
# printf 'brew "%s", args: [ "force-bottle" ]\n' "${pkg}" >> "${BREWFILE}"
printf 'brew "%s"\n' "${pkg}" >> "${BREWFILE}"
done
printf "\n" >> "${BREWFILE}"
}
#+end_src
**** _pkgs
#+name: _pkgs
|------------------------------+-----------------------------------------------------------|
| Homebrew Package Name | Reference URL |
|------------------------------+-----------------------------------------------------------|
| aspell | http://aspell.net/ |
| bash | https://www.gnu.org/software/bash/ |
| certbot | https://certbot.eff.org/ |
| chromedriver | https://sites.google.com/a/chromium.org/chromedriver/ |
| coreutils | https://www.gnu.org/software/coreutils/ |
| dash | http://gondor.apana.org.au/~herbert/dash/ |
| duti | https://github.com/moretension/duti |
| e2fsprogs | https://e2fsprogs.sourceforge.io/ |
| fasd | https://github.com/clvv/fasd |
| fdupes | https://github.com/adrianlopezroche/fdupes |
| gawk | https://www.gnu.org/software/gawk/ |
| getmail | http://pyropus.ca/software/getmail/ |
| git | https://git-scm.com/ |
| git-flow | http://nvie.com/posts/a-successful-git-branching-model/ |
| git-lfs | https://git-lfs.github.com/ |
| gnu-sed | https://www.gnu.org/software/sed/ |
| gnupg | https://www.gnupg.org/ |
| gpac | https://gpac.wp.imt.fr/ |
| httpie | https://httpie.org/ |
| hub | https://hub.github.com/ |
| ievms | https://xdissent.github.io/ievms/ |
| imagemagick | https://www.imagemagick.org/ |
| mas | https://github.com/argon/mas |
| mercurial | https://www.mercurial-scm.org/ |
| mp4v2 | https://code.google.com/archive/p/mp4v2/ |
| mtr | https://www.bitwizard.nl/mtr/ |
| nmap | https://nmap.org/ |
| node | https://nodejs.org/ |
| nodenv | https://github.com/nodenv/nodenv |
| openssl | https://www.openssl.org/ |
| p7zip | http://p7zip.sourceforge.net/ |
| perl-build | https://github.com/tokuhirom/Perl-Build |
| pinentry-mac | https://github.com/GPGTools/pinentry-mac |
| plenv | https://github.com/tokuhirom/plenv |
| pyenv | https://github.com/pyenv/pyenv |
| rbenv | https://github.com/rbenv/rbenv |
| rsync | https://rsync.samba.org/ |
| selenium-server-standalone | http://www.seleniumhq.org/ |
| shellcheck | https://github.com/koalaman/shellcheck |
| sleepwatcher | http://www.bernhard-baehr.de/ |
| sqlite | https://sqlite.org |
| stow | https://www.gnu.org/software/stow/ |
| syncthing | https://syncthing.net/ |
| syncthing-inotify | https://github.com/syncthing/syncthing-inotify |
| tag | https://github.com/jdberry/tag |
| terminal-notifier | https://github.com/julienXX/terminal-notifier |
| the_silver_searcher | https://geoff.greer.fm/ag/ |
| trash | http://hasseg.org/trash/ |
| unrar | http://www.rarlab.com/ |
| vcsh | https://github.com/RichiH/vcsh |
| vim | https://vim.sourceforge.io/ |
| yarn | https://yarnpkg.com/ |
| youtube-dl | https://rg3.github.io/youtube-dl/ |
| zsh | https://www.zsh.org/ |
| zsh-syntax-highlighting | https://github.com/zsh-users/zsh-syntax-highlighting |
| zsh-history-substring-search | https://github.com/zsh-users/zsh-history-substring-search |
| homebrew/php/php71 | https://github.com/Homebrew/homebrew-php |
| ptb/custom/dovecot | |
| ptb/custom/ffmpeg | |
| sdl2 | |
| zimg | |
| x265 | |
| webp | |
| wavpack | |
| libvorbis | |
| libvidstab | |
| two-lame | |
| theora | |
| tesseract | |
| speex | |
| libssh | |
| libsoxr | |
| snappy | |
| schroedinger | |
| rubberband | |
| rtmpdump | |
| opus | |
| openh264 | |
| opencore-amr | |
| libmodplug | |
| libgsm | |
| game-music-emu | |
| fontconfig | |
| fdk-aac | |
| libcaca | |
| libbs2b | |
| libbluray | |
| libass | |
| chromaprint | |
| ptb/custom/nginx-full | |
|------------------------------+-----------------------------------------------------------|
*** Add Caskroom Options to Brewfile
#+begin_src sh :var _args=_dest[5:10,0:1]
install_brewfile_cask_args () {
printf 'cask_args \' >> "${BREWFILE}"
printf "%s\n" "${_args}" | \
while IFS="$(printf '\t')" read arg dir; do
printf '\n %s: "%s",' "${arg}" "${dir}" >> "${BREWFILE}"
done
sed -i "" -e '$ s/,/\
/' "${BREWFILE}"
}
#+end_src
*** Add Homebrew Casks to Brewfile
#+begin_src sh :var _casks=_casks[3:-2,0]
install_brewfile_cask_pkgs () {
printf "%s\n" "${_casks}" | \
while IFS="$(printf '\t')" read cask; do
printf 'cask "%s"\n' "${cask}" >> "${BREWFILE}"
done
printf "\n" >> "${BREWFILE}"
}
#+end_src
**** _casks
#+name: _casks
|--------------------------------------------------+---------------------------------------------------------------|
| Caskroom Package Name | Reference URL |
|--------------------------------------------------+---------------------------------------------------------------|
| java | https://www.oracle.com/technetwork/java/javase/ |
| xquartz | https://www.xquartz.org/ |
| adium | https://www.adium.im/ |
| alfred | https://www.alfredapp.com/ |
| arduino | https://www.arduino.cc/ |
| atom | https://atom.io/ |
| bbedit | https://www.barebones.com/products/bbedit/ |
| betterzip | https://macitbetter.com/ |
| bitbar | https://getbitbar.com/ |
| caffeine | http://lightheadsw.com/caffeine/ |
| carbon-copy-cloner | https://bombich.com/ |
| charles | https://www.charlesproxy.com/ |
| dash | https://kapeli.com/dash |
| dropbox | https://www.dropbox.com/ |
| exifrenamer | http://www.qdev.de/?location=mac/exifrenamer |
| find-empty-folders | http://www.tempel.org/FindEmptyFolders |
| firefox | https://www.mozilla.org/firefox/ |
| github-desktop | https://desktop.github.com/ |
| gitup | http://gitup.co/ |
| google-chrome | https://www.google.com/chrome/ |
| hammerspoon | http://www.hammerspoon.org/ |
| handbrake | https://handbrake.fr/ |
| hermes | http://hermesapp.org/ |
| imageoptim | https://imageoptim.com/mac |
| inkscape | https://inkscape.org/ |
| integrity | http://peacockmedia.software/mac/integrity/ |
| istat-menus | https://bjango.com/mac/istatmenus/ |
| iterm2 | https://www.iterm2.com/ |
| jubler | http://www.jubler.org/ |
| little-snitch | https://www.obdev.at/products/littlesnitch/ |
| machg | http://jasonfharris.com/machg/ |
| menubar-countdown | http://capablehands.net/menubarcountdown |
| meteorologist | http://heat-meteo.sourceforge.net/ |
| moom | https://manytricks.com/moom/ |
| mp4tools | http://www.emmgunn.com/mp4tools-home/ |
| musicbrainz-picard | https://picard.musicbrainz.org/ |
| namechanger | https://mrrsoftware.com/namechanger/ |
| nvalt | http://brettterpstra.com/projects/nvalt/ |
| nzbget | https://nzbget.net/ |
| nzbvortex | https://www.nzbvortex.com/ |
| openemu | http://openemu.org/ |
| opera | https://www.opera.com/ |
| pacifist | https://www.charlessoft.com/ |
| platypus | https://sveinbjorn.org/platypus |
| plex-media-server | https://www.plex.tv/ |
| qlstephen | https://whomwah.github.io/qlstephen/ |
| quitter | https://marco.org/apps#quitter |
| radarr | https://radarr.video/ |
| rescuetime | https://www.rescuetime.com/ |
| resilio-sync | https://www.resilio.com/individuals/ |
| scrivener | https://literatureandlatte.com/scrivener.php |
| sizeup | https://www.irradiatedsoftware.com/sizeup/ |
| sketch | https://www.sketchapp.com/ |
| sketchup | https://www.sketchup.com/ |
| skitch | https://evernote.com/products/skitch |
| skype | https://www.skype.com/ |
| slack | https://slack.com/ |
| sonarr | https://sonarr.tv/ |
| sonarr-menu | https://github.com/jefbarn/Sonarr-Menu |
| sourcetree | https://www.sourcetreeapp.com/ |
| steermouse | http://plentycom.jp/en/steermouse/ |
| subler | https://subler.org/ |
| sublime-text | https://www.sublimetext.com/3 |
| the-unarchiver | https://theunarchiver.com/ |
| time-sink | https://manytricks.com/timesink/ |
| torbrowser | https://www.torproject.org/projects/torbrowser.html |
| tower | https://www.git-tower.com/ |
| unrarx | http://www.unrarx.com/ |
| vimr | http://vimr.org/ |
| vlc | https://www.videolan.org/vlc/ |
| vmware-fusion | https://www.vmware.com/products/fusion.html |
| wireshark | https://www.wireshark.org/ |
| xld | http://tmkk.undo.jp/xld/index_e.html |
| caskroom/fonts/font-inconsolata-lgc | https://github.com/DeLaGuardo/Inconsolata-LGC |
| caskroom/versions/transmit4 | https://panic.com/transmit/ |
| ptb/custom/adobe-creative-cloud-2014 | https://www.adobe.com/creativecloud.html |
| ptb/custom/blankscreen | http://www.wurst-wasser.net/wiki/index.php/Blank_Screen_Saver |
| ptb/custom/composer | https://www.jamf.com/products/jamf-composer/ |
| ptb/custom/enhanced-dictation | |
| ptb/custom/ipmenulet | https://github.com/mcandre/IPMenulet |
| ptb/custom/pcalc-3 | http://www.pcalc.com/english/about.html |
| ptb/custom/sketchup-pro | https://www.sketchup.com/products/sketchup-pro |
| ptb/custom/text-to-speech-alex | |
| ptb/custom/text-to-speech-allison | |
| ptb/custom/text-to-speech-samantha | |
| ptb/custom/text-to-speech-tom | |
| railwaycat/emacsmacport/emacs-mac-spacemacs-icon | https://github.com/railwaycat/homebrew-emacsmacport |
|--------------------------------------------------+---------------------------------------------------------------|
*** Add App Store Packages to Brewfile
#+begin_src sh :var _mas=_mas[3:-3,0:1]
install_brewfile_mas_apps () {
open "/Applications/App Store.app"
run "Sign in to the App Store with your Apple ID" "Cancel" "OK"
MASDIR="$(getconf DARWIN_USER_CACHE_DIR)com.apple.appstore"
sudo chown -R "$(whoami)" "${MASDIR}"
rsync -a --delay-updates \
"${CACHES}/mas/" "${MASDIR}/"
printf "%s\n" "${_mas}" | \
while IFS="$(printf '\t')" read app id; do
printf 'mas "%s", id: %s\n' "${app}" "${id}" >> "${BREWFILE}"
done
}
#+end_src
**** _mas
#+name: _mas
|----------------------------+------------+-------------------------------------------|
| App Name | App ID | App Store URL |
|----------------------------+------------+-------------------------------------------|
| 1Password | 443987910 | https://itunes.apple.com/app/id443987910 |
| Affinity Photo | 824183456 | https://itunes.apple.com/app/id824183456 |
| Coffitivity | 659901392 | https://itunes.apple.com/app/id659901392 |
| Duplicate Photos Fixer Pro | 963642514 | https://itunes.apple.com/app/id963642514 |
| Growl | 467939042 | https://itunes.apple.com/app/id467939042 |
| HardwareGrowler | 475260933 | https://itunes.apple.com/app/id475260933 |
| I Love Stars | 402642760 | https://itunes.apple.com/app/id402642760 |
| Icon Slate | 439697913 | https://itunes.apple.com/app/id439697913 |
| Justnotes | 511230166 | https://itunes.apple.com/app/id511230166 |
| Keynote | 409183694 | https://itunes.apple.com/app/id409183694 |
| Metanota Pro | 515250764 | https://itunes.apple.com/app/id515250764 |
| Numbers | 409203825 | https://itunes.apple.com/app/id409203825 |
| Pages | 409201541 | https://itunes.apple.com/app/id409201541 |
| WiFi Explorer | 494803304 | https://itunes.apple.com/app/id494803304 |
| Xcode | 497799835 | https://itunes.apple.com/app/id497799835 |
| macOS High Sierra | 1209167288 | https://itunes.apple.com/app/id1209167288 |
|----------------------------+------------+-------------------------------------------|
*** Link System Utilities to Applications
#+begin_src sh :var _links=_links[3:-2,0]
install_links () {
printf "%s\n" "${_links}" | \
while IFS="$(printf '\t')" read link; do
find "${link}" -maxdepth 1 -name "*.app" -type d -print0 2> /dev/null | \
xargs -0 -I {} -L 1 ln -s "{}" "/Applications" 2> /dev/null
done
}
#+end_src
**** _links
#+name: _links
|--------------------------------------------------------------|
| Application Locations |
|--------------------------------------------------------------|
| /System/Library/CoreServices/Applications |
| /Applications/Xcode.app/Contents/Applications |
| /Applications/Xcode.app/Contents/Developer/Applications |
| /Applications/Xcode-beta.app/Contents/Applications |
| /Applications/Xcode-beta.app/Contents/Developer/Applications |
|--------------------------------------------------------------|
*** Install Node.js with =nodenv=
#+begin_src sh :var _npm=_npm[3:-2,0]
install_node_sw () {
if which nodenv > /dev/null; then
NODENV_ROOT="/usr/local/node" && export NODENV_ROOT
sudo mkdir -p "$NODENV_ROOT"
sudo chown -R "$(whoami):admin" "$NODENV_ROOT"
p "Installing Node.js with nodenv"
git clone https://github.com/nodenv/node-build-update-defs.git \
"$(nodenv root)"/plugins/node-build-update-defs
nodenv update-version-defs > /dev/null
nodenv install --skip-existing 8.7.0
nodenv global 8.7.0
grep -q "${NODENV_ROOT}" "/etc/paths" || \
sudo sed -i "" -e "1i\\
${NODENV_ROOT}/shims
" "/etc/paths"
init_paths
rehash
fi
T=$(printf '\t')
printf "%s\n" "$_npm" | \
while IFS="$T" read pkg; do
npm install --global "$pkg"
done
rehash
}
#+end_src
#+name: _npm
|------------------------+----------------------------------------------------|
| NPM Package Name | Reference URL |
|------------------------+----------------------------------------------------|
| eslint | https://eslint.org/ |
| eslint-config-cleanjs | https://github.com/bodil/eslint-config-cleanjs |
| eslint-plugin-better | https://github.com/idmitriev/eslint-plugin-better |
| eslint-plugin-fp | https://github.com/jfmengels/eslint-plugin-fp |
| eslint-plugin-import | https://github.com/benmosher/eslint-plugin-import |
| eslint-plugin-json | https://github.com/azeemba/eslint-plugin-json |
| eslint-plugin-promise | https://github.com/xjamundx/eslint-plugin-promise |
| eslint-plugin-standard | https://github.com/xjamundx/eslint-plugin-standard |
| gatsby | |
| json | http://trentm.com/json/ |
| sort-json | https://github.com/kesla/sort-json |
|------------------------+----------------------------------------------------|
*** Install Perl 5 with =plenv=
#+begin_src sh
install_perl_sw () {
if which plenv > /dev/null; then
PLENV_ROOT="/usr/local/perl" && export PLENV_ROOT
sudo mkdir -p "$PLENV_ROOT"
sudo chown -R "$(whoami):admin" "$PLENV_ROOT"
p "Installing Perl 5 with plenv"
plenv install 5.26.0 > /dev/null 2>&1
plenv global 5.26.0
grep -q "${PLENV_ROOT}" "/etc/paths" || \
sudo sed -i "" -e "1i\\
${PLENV_ROOT}/shims
" "/etc/paths"
init_paths
rehash
fi
}
#+end_src
*** Install Python with =pyenv=
#+begin_src sh
install_python_sw () {
if which pyenv > /dev/null; then
CFLAGS="-I$(brew --prefix openssl)/include" && export CFLAGS
LDFLAGS="-L$(brew --prefix openssl)/lib" && export LDFLAGS
PYENV_ROOT="/usr/local/python" && export PYENV_ROOT
sudo mkdir -p "$PYENV_ROOT"
sudo chown -R "$(whoami):admin" "$PYENV_ROOT"
p "Installing Python 2 with pyenv"
pyenv install --skip-existing 2.7.13
p "Installing Python 3 with pyenv"
pyenv install --skip-existing 3.6.2
pyenv global 2.7.13
grep -q "${PYENV_ROOT}" "/etc/paths" || \
sudo sed -i "" -e "1i\\
${PYENV_ROOT}/shims
" "/etc/paths"
init_paths
rehash
pip install --upgrade "pip" "setuptools"
# Reference: https://github.com/mdhiggins/sickbeard_mp4_automator
pip install --upgrade "babelfish" "guessit<2" "qtfaststart" "requests" "stevedore==1.19.1" "subliminal<2"
pip install --upgrade "requests-cache" "requests[security]"
# Reference: https://github.com/pixelb/crudini
pip install --upgrade "crudini"
fi
}
#+end_src
*** Install Ruby with =rbenv=
#+begin_src sh
install_ruby_sw () {
if which rbenv > /dev/null; then
RBENV_ROOT="/usr/local/ruby" && export RBENV_ROOT
sudo mkdir -p "$RBENV_ROOT"
sudo chown -R "$(whoami):admin" "$RBENV_ROOT"
p "Installing Ruby with rbenv"
rbenv install --skip-existing 2.4.2
rbenv global 2.4.2
grep -q "${RBENV_ROOT}" "/etc/paths" || \
sudo sed -i "" -e "1i\\
${RBENV_ROOT}/shims
" "/etc/paths"
init_paths
rehash
printf "%s\n" \
"gem: --no-document" | \
tee "${HOME}/.gemrc" > /dev/null
gem update --system > /dev/null
trash "$(which rdoc)"
trash "$(which ri)"
gem update
gem install bundler
fi
}
#+end_src
** Configure
*** Define Function =config=
#+begin_src sh
config () {
config_admin_req
config_bbedit
config_certbot
config_desktop
config_dovecot
config_emacs
config_environment
config_ipmenulet
config_istatmenus
config_nginx
config_openssl
config_sysprefs
config_zsh
config_guest
which custom
}
#+end_src
*** Define Function =config_defaults=
#+begin_src sh
config_defaults () {
printf "%s\n" "${1}" | \
while IFS="$(printf '\t')" read domain key type value host; do
${2} defaults ${host} write ${domain} "${key}" ${type} "${value}"
done
}
#+end_src
*** Define Function =config_plist=
#+begin_src sh
T="$(printf '\t')"
config_plist () {
printf "%s\n" "$1" | \
while IFS="$T" read command entry type value; do
case "$value" in
(\$*)
$4 /usr/libexec/PlistBuddy "$2" \
-c "$command '${3}${entry}' $type '$(eval echo \"$value\")'" 2> /dev/null ;;
(*)
$4 /usr/libexec/PlistBuddy "$2" \
-c "$command '${3}${entry}' $type '$value'" 2> /dev/null ;;
esac
done
}
#+end_src
*** Define Function =config_launchd=
#+begin_src sh
config_launchd () {
test -d "$(dirname $1)" || \
$3 mkdir -p "$(dirname $1)"
test -f "$1" && \
$3 launchctl unload "$1" && \
$3 rm -f "$1"
config_plist "$2" "$1" "$4" "$3" && \
$3 plutil -convert xml1 "$1" && \
$3 launchctl load "$1"
}
#+end_src
*** Mark Applications Requiring Administrator Account
#+begin_src sh :var _admin_req=_admin_req[3:-2,0]
config_admin_req () {
printf "%s\n" "${_admin_req}" | \
while IFS="$(printf '\t')" read app; do
sudo tag -a "Red, admin" "/Applications/${app}"
done
}
#+end_src
**** _admin_req
#+name: _admin_req
|------------------------|
| Admin Apps |
|------------------------|
| Carbon Copy Cloner.app |
| Charles.app |
| Composer.app |
| Dropbox.app |
| iStat Menus.app |
| Moom.app |
| VMware Fusion.app |
| Wireshark.app |
|------------------------|
*** Configure BBEdit
#+begin_src sh
config_bbedit () {
if test -d "/Applications/BBEdit.app"; then
test -f "/usr/local/bin/bbdiff" || \
ln /Applications/BBEdit.app/Contents/Helpers/bbdiff /usr/local/bin/bbdiff && \
ln /Applications/BBEdit.app/Contents/Helpers/bbedit_tool /usr/local/bin/bbedit && \
ln /Applications/BBEdit.app/Contents/Helpers/bbfind /usr/local/bin/bbfind && \
ln /Applications/BBEdit.app/Contents/Helpers/bbresults /usr/local/bin/bbresults
fi
}
#+end_src
*** Configure Let’s Encrypt
#+begin_src sh
config_certbot () {
test -d "/etc/letsencrypt" || \
sudo mkdir -p /etc/letsencrypt
sudo tee "/etc/letsencrypt/cli.ini" << EOF > /dev/null
agree-tos = True
authenticator = standalone
eff-email = True
manual-public-ip-logging-ok = True
nginx-ctl = $(which nginx)
nginx-server-root = /usr/local/etc/nginx
preferred-challenges = tls-sni-01
keep-until-expiring = True
rsa-key-size = 4096
text = True
EOF
if ! test -e "/etc/letsencrypt/.git"; then
a=$(ask "Existing Let’s Encrypt Git Repository Path or URL?" "Clone Repository" "")
test -n "$a" && \
case "$a" in
(/*)
sudo tee "/etc/letsencrypt/.git" << EOF > /dev/null ;;
gitdir: $a
EOF
(*)
sudo git -C "/etc/letsencrypt" remote add origin "$a"
sudo git -C "/etc/letsencrypt" fetch origin master ;;
esac
sudo git -C "/etc/letsencrypt" reset --hard
sudo git checkout -f -b master HEAD
fi
sudo launchctl unload /Library/LaunchDaemons/org.nginx.nginx.plist 2> /dev/null
sudo certbot renew
while true; do
test -n "$1" && server_name="$1" || \
server_name="$(ask 'New SSL Server: Server Name?' 'Create Server' 'example.com')"
test -n "$server_name" || break
test -n "$2" && proxy_address="$2" || \
proxy_address="$(ask "Proxy Address for $server_name?" 'Set Address' 'http://127.0.0.1:80')"
sudo certbot certonly --domain $server_name
key1="$(openssl x509 -pubkey < /etc/letsencrypt/live/$server_name/fullchain.pem | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64)"
key2="$(curl -s https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64)"
key3="$(curl -s https://letsencrypt.org/certs/isrgrootx1.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64)"
pkp="$(printf "add_header Public-Key-Pins 'pin-sha256=\"%s\"; pin-sha256=\"%s\"; pin-sha256=\"%s\"; max-age=2592000;';\n" $key1 $key2 $key3)"
cat << EOF > "/usr/local/etc/nginx/servers/$server_name.conf"
<>
EOF
unset argv
done
sudo launchctl load /Library/LaunchDaemons/org.nginx.nginx.plist
}
#+end_src
**** =/usr/local/etc/nginx/servers/server_name/server_name.conf=
#+begin_src conf :noweb-ref server_name.conf
server {
server_name $server_name;
location / {
proxy_pass $proxy_address;
}
ssl_certificate /etc/letsencrypt/live/$server_name/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/$server_name/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/$server_name/chain.pem;
$pkp
add_header Content-Security-Policy "upgrade-insecure-requests;";
add_header Referrer-Policy "strict-origin";
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains; preload" always;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header X-Robots-Tag none;
add_header X-XSS-Protection "1; mode=block";
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl_stapling on;
ssl_stapling_verify on;
# https://securityheaders.io/?q=https%3A%2F%2F$server_name&hide=on&followRedirects=on
# https://www.ssllabs.com/ssltest/analyze.html?d=$server_name&hideResults=on&latest
}
#+end_src
*** Configure Default Apps
#+begin_src sh
config_default_apps () {
true
}
#+end_src
*** Configure Desktop Picture
#+begin_src sh
config_desktop () {
sudo rm -f "/Library/Caches/com.apple.desktop.admin.png"
base64 -D << EOF > "/Library/Desktop Pictures/Solid Colors/Solid Black.png"
<>
EOF
}
#+end_src
**** =black.png.b64=
#+begin_src base64 :noweb-ref black.png.b64
iVBORw0KGgoAAAANSUhEUgAAAIAAAACAAQAAAADrRVxmAAAAGElEQVR4AWOgMxgFo2AUjIJRMApGwSgAAAiAAAH3bJXBAAAAAElFTkSuQmCC
#+end_src
*** Configure Dovecot
#+begin_src sh
config_dovecot () {
if which /usr/local/sbin/dovecot > /dev/null; then
if ! run "Configure Dovecot Email Server?" "Configure Server" "Cancel"; then
sudo tee "/usr/local/etc/dovecot/dovecot.conf" << EOF > /dev/null
<>
EOF
MAILADM="$(ask 'Email: Postmaster Email?' 'Set Email' "$(whoami)@$(hostname -f | cut -d. -f2-)")"
MAILSVR="$(ask 'Email: Server Hostname for DNS?' 'Set Hostname' "$(hostname -f)")"
sudo certbot certonly --domain $MAILSVR
printf "%s\n" \
"postmaster_address = '${MAILADM}'" \
"ssl_cert = /dev/null
if test ! -f "/usr/local/etc/dovecot/cram-md5.pwd"; then
while true; do
MAILUSR="$(ask 'New Email Account: User Name?' 'Create Account' "$(whoami)")"
test -n "${MAILUSR}" || break
doveadm pw | \
sed -e "s/^/${MAILUSR}:/" | \
sudo tee -a "/usr/local/etc/dovecot/cram-md5.pwd"
done
sudo chown _dovecot "/usr/local/etc/dovecot/cram-md5.pwd"
sudo chmod go= "/usr/local/etc/dovecot/cram-md5.pwd"
fi
sudo tee "/etc/pam.d/dovecot" << EOF > /dev/null
<>
EOF
sudo brew services start dovecot
cat << EOF > "/usr/local/bin/imaptimefix.py"
<>
EOF
chmod +x /usr/local/bin/imaptimefix.py
fi
fi
}
#+end_src
**** =/usr/local/etc/dovecot/dovecot.conf=
#+begin_src conf :noweb-ref dovecot.conf
auth_mechanisms = cram-md5
default_internal_user = _dovecot
default_login_user = _dovenull
log_path = /dev/stderr
mail_location = maildir:~/.mail:INBOX=~/.mail/Inbox:LAYOUT=fs
mail_plugins = zlib
maildir_copy_with_hardlinks = no
namespace {
inbox = yes
mailbox Drafts {
auto = subscribe
special_use = \Drafts
}
mailbox Junk {
auto = subscribe
special_use = \Junk
}
mailbox Sent {
auto = subscribe
special_use = \Sent
}
mailbox "Sent Messages" {
special_use = \Sent
}
mailbox Trash {
auto = subscribe
special_use = \Trash
}
separator = .
type = private
}
passdb {
args = scheme=cram-md5 /usr/local/etc/dovecot/cram-md5.pwd
driver = passwd-file
# driver = pam
# args = nopassword=y
# driver = static
}
plugin {
sieve = file:/Users/%u/.sieve
sieve_plugins = sieve_extprograms
zlib_save = bz2
zlib_save_level = 9
}
protocols = imap
service imap-login {
inet_listener imap {
port = 0
}
}
ssl = required
ssl_cipher_list = ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS:!AES128
ssl_dh_parameters_length = 4096
ssl_prefer_server_ciphers = yes
ssl_protocols = !SSLv2 !SSLv3
userdb {
driver = passwd
}
protocol lda {
mail_plugins = sieve zlib
}
# auth_debug = yes
# auth_debug_passwords = yes
# auth_verbose = yes
# auth_verbose_passwords = plain
# mail_debug = yes
# verbose_ssl = yes
#+end_src
**** =/etc/pam.d/dovecot=
#+begin_src conf :noweb-ref dovecot.pam
auth required pam_opendirectory.so try_first_pass
account required pam_nologin.so
account required pam_opendirectory.so
password required pam_opendirectory.so
#+end_src
**** =/usr/local/bin/imaptimefix.py=
#+begin_src python :noweb-ref imaptimefix.py
#!/usr/bin/env python
# Author: Zachary Cutlip <@zcutlip>
# http://shadow-file.blogspot.com/2012/06/parsing-email-and-fixing-timestamps-in.html
# Updated: Peter T Bosse II <@ptb>
# Purpose: A program to fix sorting of mail messages that have been POPed or
# IMAPed in the wrong order. Compares time stamp sent and timestamp
# received on an RFC822-formatted email message, and renames the
# message file using the most recent timestamp that is no more than
# 24 hours after the date sent. Updates the file's atime/mtime with
# the timestamp, as well. Does not modify the headers or contents of
# the message.
from bz2 import BZ2File
from email import message_from_string
from email.utils import mktime_tz, parsedate_tz
from os import rename, utime, walk
from os.path import abspath, isdir, isfile, join
from re import compile, match
from sys import argv
if isdir(argv[1]):
e = compile("([0-9]+)(\..*$)")
for a, b, c in walk(argv[1]):
for d in c:
if e.match(d):
f = message_from_string(BZ2File(join(a, d)).read())
g = mktime_tz(parsedate_tz(f.get("Date")))
h = 0
for i in f.get_all("Received", []):
j = i.split(";")[-1]
if parsedate_tz(j):
k = mktime_tz(parsedate_tz(j))
if (k - g) > (60*60*24):
continue
h = k
break
if (h < 1):
h = g
l = e.match(d)
if len(l.groups()) == 2:
m = str(int(h)) + l.groups()[1]
if not isfile(join(a, m)):
rename(join(a, d), join(a, m))
utime(join(a, m), (h, h))
#+end_src
*** Configure Emacs
#+begin_src sh
config_emacs () {
test -f "/usr/local/bin/vi" || \
cat << EOF > "/usr/local/bin/vi"
<>
EOF
chmod a+x /usr/local/bin/vi
rehash
}
#+end_src
**** =/usr/local/bin/vi=
#+begin_src sh :noweb-ref vi.sh :tangle no
#!/bin/sh
if [ -e "/Applications/Emacs.app" ]; then
t=()
if [ \${#@} -ne 0 ]; then
while IFS= read -r file; do
[ ! -f "\$file" ] && t+=("\$file") && /usr/bin/touch "\$file"
file=\$(echo \$(cd \$(dirname "\$file") && pwd -P)/\$(basename "\$file"))
\$(/usr/bin/osascript <<-END
if application "Emacs.app" is running then
tell application id (id of application "Emacs.app") to open POSIX file "\$file"
else
tell application ((path to applications folder as text) & "Emacs.app")
activate
open POSIX file "\$file"
end tell
end if
END
) & # Note: END on the previous line may be indented with tabs but not spaces
done <<<"\$(printf '%s\n' "\$@")"
fi
if [ ! -z "\$t" ]; then
\$(/bin/sleep 10; for file in "\${t[@]}"; do
[ ! -s "\$file" ] && /bin/rm "\$file";
done) &
fi
else
vim -No "\$@"
fi
#+end_src
*** Configure Environment Variables
#+begin_src sh :var _environment_defaults=_environment_defaults[3:-2,0:4]
config_environment () {
sudo tee "/etc/environment.sh" << 'EOF' > /dev/null
<>
EOF
sudo chmod a+x "/etc/environment.sh"
rehash
la="/Library/LaunchAgents/environment.user"
ld="/Library/LaunchDaemons/environment"
sudo mkdir -p "$(dirname $la)" "$(dirname $ld)"
sudo launchctl unload "${la}.plist" "${ld}.plist" 2> /dev/null
sudo rm -f "${la}.plist" "${ld}.plist"
config_defaults "$_environment_defaults" "sudo"
sudo plutil -convert xml1 "${la}.plist" "${ld}.plist"
sudo launchctl load "${la}.plist" "${ld}.plist" 2> /dev/null
}
#+end_src
**** =/etc/environment.sh=
#+begin_src sh :noweb-ref environment.sh :tangle no
#!/bin/sh
set -e
if test -x /usr/libexec/path_helper; then
export PATH=""
eval `/usr/libexec/path_helper -s`
launchctl setenv PATH $PATH
fi
osascript -e 'tell app "Dock" to quit'
#+end_src
**** _environment_defaults
#+name: _environment_defaults
|----------------------------------------+-------------+------------+---------------------+------|
| Domain | Key | Type | Value | Host |
|----------------------------------------+-------------+------------+---------------------+------|
| /Library/LaunchAgents/environment.user | KeepAlive | -bool | false | |
| /Library/LaunchAgents/environment.user | Label | -string | environment.user | |
| /Library/LaunchAgents/environment.user | ProcessType | -string | Background | |
| /Library/LaunchAgents/environment.user | Program | -string | /etc/environment.sh | |
| /Library/LaunchAgents/environment.user | RunAtLoad | -bool | true | |
| /Library/LaunchAgents/environment.user | WatchPaths | -array-add | /etc/environment.sh | |
| /Library/LaunchAgents/environment.user | WatchPaths | -array-add | /etc/paths | |
| /Library/LaunchAgents/environment.user | WatchPaths | -array-add | /etc/paths.d | |
| /Library/LaunchDaemons/environment | KeepAlive | -bool | false | |
| /Library/LaunchDaemons/environment | Label | -string | environment | |
| /Library/LaunchDaemons/environment | ProcessType | -string | Background | |
| /Library/LaunchDaemons/environment | Program | -string | /etc/environment.sh | |
| /Library/LaunchDaemons/environment | RunAtLoad | -bool | true | |
| /Library/LaunchDaemons/environment | WatchPaths | -array-add | /etc/environment.sh | |
| /Library/LaunchDaemons/environment | WatchPaths | -array-add | /etc/paths | |
| /Library/LaunchDaemons/environment | WatchPaths | -array-add | /etc/paths.d | |
|----------------------------------------+-------------+------------+---------------------+------|
*** Configure IPMenulet
#+begin_src sh
config_ipmenulet () {
_ipm="/Applications/IPMenulet.app/Contents/Resources"
if test -d "$_ipm"; then
rm "${_ipm}/icon-19x19-black.png"
ln "${_ipm}/icon-19x19-white.png" "${_ipm}/icon-19x19-black.png"
fi
}
#+end_src
*** Configure iStat Menus
#+begin_src sh
config_istatmenus () {
test -d "/Applications/iStat Menus.app" && \
open "/Applications/iStat Menus.app"
}
#+end_src
**** Notes
#+begin_example conf
client_max_body_size 0;
location / {
if ($http_x_plex_device_name = "") {
rewrite ^/$ https://$host/web/index.html permanent;
}
}
#+end_example
*** Configure nginx
#+begin_src sh :var _nginx_defaults=_nginx_defaults[3:-2,0:4]
config_nginx () {
cat << 'EOF' > /usr/local/etc/nginx/nginx.conf
<>
EOF
ld="/Library/LaunchDaemons/org.nginx.nginx"
sudo mkdir -p "$(dirname $ld)"
sudo launchctl unload "${ld}.plist" 2> /dev/null
sudo rm -f "${ld}.plist"
config_defaults "$_nginx_defaults" "sudo"
sudo plutil -convert xml1 "${ld}.plist"
sudo launchctl load "${ld}.plist" 2> /dev/null
}
#+end_src
**** =/usr/local/etc/nginx/nginx.conf=
#+begin_src conf :noweb-ref nginx.conf
daemon off;
events {
accept_mutex off;
worker_connections 8000;
}
http {
charset utf-8;
charset_types
application/javascript
application/json
application/rss+xml
application/xhtml+xml
application/xml
text/css
text/plain
text/vnd.wap.wml;
default_type application/octet-stream;
error_log /dev/stderr;
gzip on;
gzip_comp_level 9;
gzip_min_length 256;
gzip_proxied any;
gzip_static on;
gzip_vary on;
gzip_types
application/atom+xml
application/javascript
application/json
application/ld+json
application/manifest+json
application/rss+xml
application/vnd.geo+json
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/opentype
image/bmp
image/svg+xml
image/x-icon
text/cache-manifest
text/css
text/plain
text/vcard
text/vnd.rim.location.xloc
text/vtt
text/x-component
text/x-cross-domain-policy;
index index.html index.xhtml;
log_format default '$host $status $body_bytes_sent "$request" "$http_referer"\n'
' $remote_addr "$http_user_agent"';
map $http_upgrade $connection_upgrade {
default upgrade;
"" close;
}
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_buffering off;
proxy_redirect off;
sendfile on;
sendfile_max_chunk 512k;
server_tokens off;
resolver 8.8.8.8 8.8.4.4 [2001:4860:4860::8888] [2001:4860:4860::8844] valid=300s;
resolver_ti
本源码包内暂不包含可直接显示的源代码文件,请下载源码包。
English
