From 064edc95b9abff7378e29491a248d99f5e4f53a7 Mon Sep 17 00:00:00 2001
From: Salt <rehashedsalt@cock.li>
Date: Fri, 19 Oct 2018 21:01:30 -0500
Subject: [PATCH] Modularize replicate.sh, update README

---
 README.md    |  10 +--
 replicate.sh | 191 +++++++++++++++++++++++++++++++++++++--------------
 2 files changed, 146 insertions(+), 55 deletions(-)

diff --git a/README.md b/README.md
index 9c08cd0..602ac43 100644
--- a/README.md
+++ b/README.md
@@ -4,11 +4,13 @@
 Download and run the latest `replicate.sh`:
 
     cd
-    curl https://gitlab.com/rehashedsalt/bootstrap/raw/master/replicate.sh -o replicate.sh
-    chmod +x replicate.sh
-    ./replicate.sh
+    git clone https://gitlab.com/rehashedsalt/bootstrap
+    ./bootstrap/replicate.sh $HOME
+
+In the event that you want to simply test `replicate.sh`, simply pass a different argument to it:
+
+    ./bootstrap/replicate.sh /path/to/directory
 
 ## Notes
-* The script assumes that you want to bootstrap `$PWD` as `$HOME`. Don't run it out of your Downloads folder.
 * By default, the repository will attempt to clone with SSH. Either generate those keys and add them to GitLab or change the repository URI to HTTP.
 * Ideally, this will be called via Ansible or some other automation tool. It may, in the future, contain specific code for this purpose.
diff --git a/replicate.sh b/replicate.sh
index 35b09e6..27ecc77 100755
--- a/replicate.sh
+++ b/replicate.sh
@@ -1,68 +1,157 @@
 #!/bin/sh
+#
+# Salt's bootstrap script
+# Copyrithgt (C) 2018 salt <salt@lap-th-e560-0>
+#
+# Distributed under terms of the MIT license
+#
 
-## Set up some variables
-name="$(basename "$0" .sh)"
-deps="git rsync mktemp basename"
-
-logfile="${PWD}/${name}.log"
-tempfolder="$(mktemp -d tmp.replicate.XXXXXXXX --tmpdir)"
-gitdir="$PWD/.dotfiles"
-homedir="$PWD"
-repo='git@gitlab.com:rehashedsalt/home.git'
-
-## Define some functions
+## Helper functions
 log() {
 	[ -z ${1+x} ] && return 1
 	printf "\e[94m${name}\e[0m: $1\n"
 }
-
 validatedep() {
 	if ! which $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"
+}
 
-## Do the do
-# Rotate the logfile, if necessary
-if [ -f "$logfile" ]; then
-	log "Found old logfile. Rotating"
-	mv "$logfile" "$logfile.old"
-fi
-# 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\""
-		exit 1
+## Core functions
+step_validate_logs() {
+	# Rotate the logfile, if necessary
+	if [ -f "$logfile" ]; then
+		log "Found old logfile. Rotating"
+		mv "$logfile" "$logfile.old"
 	fi
-done
+}
+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\""
+			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"
+		return 1
+	fi
+	return 0
+}
+step_repo_clone() {
+	# Clone the dotfiles
+	log "Cloning repository into \"$tmpdir\""
+	git clone --recursive --depth 100 --separate-git-dir="$gitdir" "$repo" "$tmpdir" >> "$logfile" 2>&1
+	error="$?"
+	if ! [ "$error" -eq "0" ]; then
+		log "Failed cloning repository \"$repo\": git returned $error"
+		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"
+		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 >> "$logfile" 2>&1
+	git --git-dir="$gitdir" --work-tree="$bootstrapdir" submodule foreach 'git checkout master && git pull' >> "$logfile" 2>&1
+	git --git-dir="$gitdir" --work-tree="$bootstrapdir" config status.showUntrackedFiles no >> "$logfile" 2>&1
+}
 
-# Build Home folder skeleton
-log "Building skeleton folder layout"
-mkdir Desktop Documents Downloads Games Music Pictures Projects Public ROMs System Templates Videos
+## 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"
 
-# Clone the dotfiles
-log "Cloning repository"
-git clone --recursive --depth 100 --separate-git-dir="$gitdir" "$repo" "$tempfolder" >> "$logfile" 2>&1
-error="$?"
-if ! [ "$error" -eq "0" ]; then
-	log "Failed cloning repository \"$repo\": git returned $error"
-	log "See $logfile for details"
-	log "Do you have the appropriate permissions? Does the remote host know your key?"
-	exit 2
-fi
-# Move them to where they should be
-log "Moving cloned repo from \"$tempfolder\" into \"$homedir\""
-rsync -rvl --exclude ".git" "$tempfolder/" "$homedir/" >> "$logfile"
-rm -rf "$tempfolder"
-# Finish syncing
-log "Updating submodules and performing basic configuration"
-git --git-dir="$gitdir" --work-tree="$homedir" submodule update --init --recursive --remote --depth 50 >> "$logfile" 2>&1
-git --git-dir="$gitdir" --work-tree="$homedir" submodule foreach 'git checkout master && git pull' >> "$logfile" 2>&1
-git --git-dir="$gitdir" --work-tree="$homedir" config status.showUntrackedFiles no >> "$logfile" 2>&1
+	# Parse out arguments
+	while getopts ":d:r:h\?" opt; do
+		case $opt in
+			d)
+				if [ "$OPTARG" == "" ]; then
+					log "Option -d requires an argument"
+					exit 1
+				fi
+				bootstrapdir="$OPTARG"
+				;;
+			r)
+				if [ "$OPTARG" == "" ]; then
+					log "Option -r requires an argument"
+					exit 1
+				fi
+				repo="$OPTARG"
+				;;
+			l)
+				if [ "$OPTARG" == "" ]; then
+					log "Option -l requires an argument"
+					exit 1
+				fi
+				logfile="$OPTARG"
+				;;
+			\?|h)
+				help
+				;;
+			*)
+				log "Invalid option: \"$opt\""
+				exit 1
+				;;
+		esac
+	done
+	# Set up some user-controllable variables
+	if [ -z ${bootstrapdir+x} ]; then
+		bootstrapdir="$PWD"
+		log "Bootstrapping to $bootstrapdir"
+	fi
+	if [ -z ${repo+x} ]; then
+		repo='git@gitlab.com:rehashedsalt/home.git'
+		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 $@
 
-# Print some post-install instructions
-log "Dotfiles set up successfully"
-log "You may now delete the script"
-exit 0