|
#!/usr/bin/env bash |
|
# |
|
# steps: |
|
# 1. assume: $USER is primary on machine (eg: owner of a laptop) |
|
# 2. assume: system has been set to debian sid (eg: prefer bleeding edge) |
|
# 3. "$1" is a file listing desired apt-get installable packages |
|
# 4. "$2" is a fragile script for side-installing |
|
# (eg: delicate from-source installations, each likely project specific) |
|
# 5. *this* script should setup $HOME dir layout including bin & dotfiles |
|
# 6. "$3" is fragile script to custom-configure system |
|
# (eg: "natural scrolling" via Xorg confs, or disabling tap-to-click) |
|
set -euo pipefail |
|
(( BASH_VERSINFO[0] < 4 )) && exit 99 # panic and tear hair out |
|
|
|
setupSteps=( |
|
'ASSUMING this is primarily your machine' |
|
'ASSUMING this is a debian sid machine (bleeding edge software)' |
|
'setup $HOME dir layout, including bin/ and dotfiles' |
|
'apt-get install packages from DPKG_LIST listing one per line' |
|
'use SIDE_LOAD_SH to get other binaries (eg: compile from tarballs, use pip, cpan, etc.)' |
|
'use SYS_CONFIG_SH to custom-configure system settings (eg: periphs, groups, xor, etc.)' |
|
); declare -r setupSteps |
|
|
|
type git >/dev/null 2>&1 || { |
|
printf 'Error: `git` must be in $PATH to start\n' >&2 |
|
exit 1 |
|
} |
|
|
|
|
|
die() ( printf 'fatal error, see above.\n' >&2; exit 1; ) |
|
|
|
# commandline usage interaction |
|
[[ $# -eq 3 ]] || { |
|
printf \ |
|
'`usage: DPKG_LIST SIDE_LOAD_SH SYS_CONFIG_SH` will (in this order) do:\n%s\n\n' \ |
|
"$(printf '\t- "%s"\n' "${setupSteps[@]}")" >&2 |
|
exit 1 |
|
} |
|
dpkgList="$(readlink -f "$1")"; declare -r dpkgList; [[ -r "$dpkgList" ]] |
|
sideLoad="$(readlink -f "$2")"; declare -r sideLoad; [[ -x "$sideLoad" ]] |
|
sysConfig="$(readlink -f "$3")"; declare -r sysConfig; [[ -x "$sysConfig" ]] |
|
|
|
stepCompleted=0 |
|
reportProgress() ( |
|
(( stepCompleted == 6 )) && { |
|
printf 'SUCCESS: apparently achieved all %s steps\n' "${#setupSteps[@]}" >&2 |
|
return 0 |
|
} |
|
local step |
|
|
|
printf \ |
|
'WARNING: exiting EARLY; only finished step %s of %s; summary:\n' \ |
|
"$stepCompleted" "${#setupSteps[@]}" |
|
|
|
local stepStatus i=1 |
|
for step in "${setupSteps[@]}";do |
|
if (( i <= stepCompleted ));then |
|
stepStatus='[DONE]' |
|
else |
|
stepStatus='[FAILED]' |
|
fi |
|
|
|
printf '\t%.10s %s of %s:\t"%s"\n' \ |
|
"$stepStatus" "$i" "${#setupSteps[@]}" \ |
|
"${setupSteps[${i}-1]}" >&2 |
|
|
|
i=$(( i + 1 )) |
|
done |
|
) |
|
trap reportProgress exit |
|
|
|
logStep() ( |
|
set +x |
|
stepCompleted=$(( $1 - 1 )) |
|
if (( stepCompleted ));then |
|
printf '[FINISHED] %s of %s:\n\t%s\n\n' \ |
|
"$stepCompleted" "${#setupSteps[@]}" \ |
|
"${setupSteps[${stepCompleted}-1]}" >&2 |
|
sudo --remove-timestamp # clear previously earned creds |
|
fi |
|
|
|
printf '[STARTING] %s of %s:\n\t%s\n' \ |
|
"$1" "${#setupSteps[@]}" "${setupSteps[${1}-1]}" >&2 |
|
set -x |
|
) |
|
|
|
DEBUG=0 # change this value freely! |
|
if (( DEBUG ));then |
|
echo 'WARNING: this is debug mode!' >&2 |
|
mv() ( echo "[debug]mv" "$@"; ) |
|
rm() ( echo "[debug]rm" "$@"; ) |
|
mkdir() ( echo "[debug]mkdir" "$@"; ) |
|
ln() ( echo "[debug]ln" "$@"; ) |
|
sudo() ( echo "[debug]sudo" "$@"; ) |
|
crontab() ( echo "[debug]crontab" "$@"; ) |
|
fi |
|
|
|
|
|
logStep 1 # assume primary machine |
|
logStep 2 # assume debian sid |
|
|
|
|
|
logStep 3 # layout homedir |
|
# $1=github "username/repo" string to clone |
|
# $2=directory to clone into |
|
gitCloneOwnedGithub() ( |
|
git clone --quiet "https://github.com/$1" "$2" |
|
|
|
cd "$2" |
|
git remote set-url origin --push git@github.com:"$1" |
|
) |
|
cd # home |
|
privateDots=(.gnupg/* .ssh/config .aws/config); declare -r privateDots |
|
nonXdgDirs=(back/ .gnupg/ tmp/{build,src} usr/{log/arch,share{,/appimage},lib/{,go,sh,deno,rust/{cargo,rustup}}} .config/) |
|
declare -r nonXdgDirs |
|
mkdir -p ${nonXdgDirs[@]} # Unpack my bag o scripts... |
|
chmod 7777 tmp/ |
|
gitCloneOwnedGithub jzacsh/bin bin |
|
mkdir -p bin/local |
|
gitCloneOwnedGithub jzacsh/dotfiles back/dots |
|
gitCloneOwnedGithub jzacsh/yabashlib usr/lib/sh/yabashlib |
|
|
|
mvIfPwdOrig() ( |
|
local orig; orig="$(basename "$1")" |
|
[ -e "$orig" ] || return 0 |
|
|
|
printf '\tWARNING: moving existing file, "%s"\n' "${orig}" >&2 |
|
mv --verbose "$orig"{,.orig} |
|
) |
|
|
|
# delete the default ones |
|
rmdir ~/{Desktop,Pictures,Downloads,Music,Documents,Videos,Templates,Public}/ |
|
|
|
# organize furniture |
|
while read line; do |
|
[[ $line =~ ^XDG ]] || continue # skip; not a DIR configuration |
|
|
|
tmp="${line/XDG*=/}" # get the config value |
|
|
|
# strip surrounding quotes |
|
tmp="${tmp%\"}" |
|
tmp="${tmp#\"}" |
|
|
|
# eval vars. eg: tmp='$HOME/foo' -> '/home/jzacsh/foo' |
|
dir="$(eval echo -n "$tmp")" |
|
|
|
mkdir -p "$dir" |
|
done < ~/back/dots/.config/user-dirs.dirs |
|
|
|
# get my own source directory started |
|
mkdir ~/media/src/ |
|
|
|
# get my own reomte provider dir started |
|
mkdir -p ~/silos/{content,config} |
|
|
|
find ~/back/dots/ -maxdepth 1 -mindepth 1 -name '\.*' -print | while read dot; do |
|
f="$(basename "$dot")" |
|
|
|
[[ "$f" = .config ]] && continue # skip; see next section |
|
|
|
mvIfPwdOrig "$dot" |
|
|
|
ln --symbolic --verbose "$dot" |
|
done |
|
# deal w/manual imperfections of a simple dots directory.... |
|
rm .git # symlink to .git/ repo directory of ~/back/dots/ |
|
rm .gitignore # this is .gitignore for ~/back/dot/ *repo* |
|
mv .gitignore{_global,} # *this* is the gitignore for $HOME |
|
|
|
pushd ~/.config/ # map tracked ~/.config/ content to local .config dir on disk |
|
find ~/back/dots/.config/ -mindepth 1 -maxdepth 1 -print | while read configFile; do |
|
mvIfPwdOrig "$configFile" |
|
ln --symbolic --verbose "$configFile" |
|
done |
|
popd # from ~/.config/ |
|
|
|
chmod 700 .gnupg/ # should be rw (and executable) only to you |
|
pushd ~/.gnupg/ |
|
find ~/.config/ -mindepth 1 -maxdepth 1 -name 'gpg*.conf' -print | while read gpgconf; do |
|
mvIfPwdOrig "$gpgconf" |
|
ln --symbolic --verbose "$gpgconf" |
|
done |
|
popd # from ~/.gnupg/ |
|
|
|
# Finished; Now log stuff that can't be public or automated |
|
printf 'TODO(install): go install:\n\t%s\n' ${privateDots[@]} |
|
# printf 'TODO(install): run `opam init` once!' >&2 |
|
# printf 'TODO(install): run `opam install ocp-indent` once!' >&2 |
|
|
|
printf 'TODO(install): golang not installed; run then:\n' |
|
printf '\tmanually run ./laptop-post-golang.sh\n' |
|
printf '\tmanually run `:GoInstallBinaries` in vim\n' |
|
|
|
|
|
logStep 4 # install debian packages |
|
|
|
# as of 2021-04-09, this is the LTS release |
|
# Taken from |
|
# https://github.com/nodesource/distributions/blob/master/README.md#installation-instructions |
|
# According to |
|
# https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions |
|
printf 'preparing apt repos so nodejs is available...\n' |
|
sudo apt install curl |
|
sudo bash -c 'curl -fsSL https://deb.nodesource.com/setup_14.x | bash -' || die |
|
|
|
pkgList() ( |
|
grep --invert-match --extended-regexp '^#' "$dpkgList" | |
|
sed -e 's|\s*#.*$||g' | |
|
sed '/^\s*$/'d | |
|
sort | |
|
uniq |
|
) |
|
|
|
finalList="$(readlink -f "$(mktemp --tmpdir=. 'dpkg_list.XXXXXX.txt')")" |
|
printf 'writing install list to\n\t%s\n' "$finalList" |
|
pkgList > "$finalList" |
|
sudo apt update |
|
sudo apt install $(printf ' %s ' "$(pkgList)") # no quotes; multi-arg passing to apt-get |
|
sudo apt update |
|
|
|
|
|
|
|
logStep 5 # side load software |
|
"$sideLoad" |
|
|
|
|
|
logStep 6 # general system configuration prefs |
|
sudo "$sysConfig" "$USER" |
|
|
|
stepCompleted=0 |