#! /usr/bin/env bash # # Salt's bootstrap script # Copyrithgt (C) 2018 salt # # Distributed under terms of the MIT license # # shellcheck disable=1117 ## Helper functions log() { [ -z ${1+x} ] && return 1 out=1 [ -z ${2+x} ] || out="$2" col_message="\e[39m" [ "$out" -gt "1" ] && col_message="\e[31m" [ "$out" -lt "1" ] && out=1 && col_message="\e[37m" printf "\e[94m%s\e[0m: %b%s\e[0m\n" \ "$name" \ "$col_message" \ "$1" >&${out} } validatedep() { if ! command -v "$1" > /dev/null 2>&1; then return 1 fi return 0 } help() { cat << EOF Usage: $name [OPTION] Bootstrap a git repository as a bare repo, also perform some bootstrap tasks. -d Bootstrap directory. Defaults to ~. -r Target repository. Defaults to gitlab.com/rehashedsalt/home -l File to log command output to. Defaults to replicate.log EOF } cleanup() { [ -z ${tmpdir+x} ] || rm -rf -- "$tmpdir" } ## Core functions step_validate_logs() { # Rotate the logfile, if necessary if [ -f "$logfile" ]; then log "Found old logfile. Rotating" 0 mv "$logfile" "$logfile.old" fi } step_validate_deps() { # Ensure we have the proper dependencies log "Validating dependencies" for dep in $deps; do if ! validatedep "$dep"; then log "Could not find critical dependency \"$dep\"" 2 return 1 fi done } step_make_skeleton() { # Build Home folder skeleton log "Building skeleton folder layout" if ! mkdir Desktop Documents Downloads Games Music Pictures Projects Public ROMs System Templates Videos > /dev/null 2>&1; then log "Failed to build skeleton layout" 2 return 1 fi return 0 } step_repo_clone() { # Clone the dotfiles log "Cloning repository into \"$tmpdir\"" git clone --recursive --depth 50 --separate-git-dir="$gitdir" "$repo" "$tmpdir" >> "$logfile" 2>&1 error="$?" if ! [ "$error" -eq "0" ]; then log "Failed cloning repository \"$repo\": git returned $error" 2 log "See $logfile for details" log "Do you have the appropriate permissions? Does the remote host know your key?" return 1 fi } step_repo_move() { # Move them to where they should be log "Moving cloned repo from \"$tmpdir\" into \"$bootstrapdir\"" if ! rsync -rvl --exclude ".git" "$tmpdir/" "$bootstrapdir/" >> "$logfile"; then log "Failed to move from temp directory to bootstrap directory" 2 return 1 fi } step_dot_update() { # Finish syncing log "Updating submodules and performing basic configuration" { git --git-dir="$gitdir" --work-tree="$bootstrapdir" submodule update --init --recursive --remote --depth 50 git --git-dir="$gitdir" --work-tree="$bootstrapdir" submodule foreach 'git checkout master && git pull' git --git-dir="$gitdir" --work-tree="$bootstrapdir" config status.showUntrackedFiles no >> "$logfile" } >> "$logfile" 2>&1 } ## Main main() { # Set up some non-controlled variables name="$(basename "$0" .sh)" # Name of the program, used in logging deps="git rsync mktemp basename" # Critical dependencies tmpdir="$(mktemp -d "tmp.$USER.$name.XXXXXXXX" --tmpdir)" gitdir="$PWD/.dotfiles" # Parse out arguments while getopts ":d:r:lh\?" opt; do case $opt in d) if [ "$OPTARG" == "" ]; then log "Option -d requires an argument" 2 exit 1 fi bootstrapdir="$OPTARG" ;; r) if [ "$OPTARG" == "" ]; then log "Option -r requires an argument" 2 exit 1 fi repo="$OPTARG" ;; l) if [ "$OPTARG" == "" ]; then log "Option -l requires an argument" 2 exit 1 fi logfile="$OPTARG" ;; \?|h) help ;; *) log "Invalid option: \"$opt\"" 2 exit 1 ;; esac done # Set up some user-controllable variables if [ -z ${bootstrapdir+x} ]; then bootstrapdir="$PWD" log "Using default bootstrap dir \"$bootstrapdir\"" 0 fi if [ -z ${repo+x} ]; then repo='git@gitlab.com:rehashedsalt/home.git' 0 log "Using default repository \"$repo\"" fi if [ -z ${logfile+x} ]; then logfile="${PWD}/${name}.log" # Log file fi # Do the do trap cleanup EXIT step_validate_logs || exit $? step_validate_deps || exit $? step_make_skeleton || exit $? step_repo_clone || exit $? step_repo_move || exit $? step_dot_update || exit $? log "Dotfiles set up successfully" exit 0 } main "$@"