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 +# +# 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