diff --git a/marlintool.sh b/marlintool.sh index 4990b81..898a124 100755 --- a/marlintool.sh +++ b/marlintool.sh @@ -3,16 +3,21 @@ # by mmone with contribution by jhol, tssva # on github at https://github.com/mmone/marlintool +set -e +set -u + # The default config file to look for defaultParametersFile="marlintool.params" +cacheDir=$PWD/.cache + scriptName=$0 ## Checks that the tools listed in arguments are all installed. checkTools() { for cmd in "$@"; do - type -p $cmd >/dev/null || [ -x /usr/bin/$cmd ] || [ -x /bin/$cmd ] || [ -x /sbin/$cmd ] || { + command -v $cmd >/dev/null || { >&2 echo "The following tools must be installed:" >&2 echo " $@" >&2 echo " Failed to find $cmd" @@ -22,104 +27,219 @@ checkTools() done } +checkCurlWget() +{ + if ! curl=$(command -v curl) && ! wget=$(command -v wget); then + >&2 echo "Neither curl nor wget were found installed" + >&2 echo + exit 1 + fi +} + +checkToolChain() +{ + if [ ! -f $arduinoExecutable ]; then + >&2 echo "Arduino tool-chain has not been set up. Run $0 setup" + >&2 echo + exit 1 + fi +} + +checkMarlin() +{ + if [ ! -f $marlinDir/Marlin/Marlin.ino ]; then + >&2 echo "Marlin has not been set up. Run $0 get-marlin" + >&2 echo + exit 1 + fi +} + +gitRepoName() +{ + basename "$1" ".${1##*.}" +} + +getFile() +{ + local url=$1 + local file=$2 + local cacheFile=$cacheDir/$file + + if [ ! -f $cacheFile ]; then + >&$l echo " Downloading from $url..." + + local downloadTmpFile=$tmpDir/download + if [ "$curl" != "" ]; then + >&$o $curl -o "$downloadTmpFile" "$url" + else + >&$o $wget -O "$downloadTmpFile" "$url" + fi + + mkdir -p $cacheDir + mv $downloadTmpFile $cacheFile + else + >&$l echo " Retrieving $(basename $file) from cache..." + fi + + echo $cacheFile +} + +getGitRepo() +{ + local url=$1 + local branch=$2 + + local repoName=$(gitRepoName $url) + local repoDir=$tmpDir/$repoName + local cacheRepo=$cacheDir/$repoName + + if [ -d $cacheRepo ]; then + >&$l echo " Updating repository from $url..." + (cd $cacheRepo; 2>&$o git fetch -p origin) + else + >&$l echo " Cloning repository from $url..." + >&$o git clone --bare $url $cacheRepo 2>&1 + fi + + >&$l echo " Copying from cache..." + if [ "$marlinRepositoryBranch" != "" ]; then + >&$o git clone -b "$branch" --single-branch $cacheRepo $repoDir 2>&1 + else + >&$o git clone $cacheRepo $repoDir 2>&1 + fi + + echo $repoDir +} + +unpackArchive() +{ + local archive=$1 + local dir=$2 + + case $archive in + *.zip) + >&$o unzip -q "$archive" -d "$dir" + ;; + *.tar.*) + >&$o tar -xf "$archive" -C "$dir" --strip 1 + ;; + esac +} + ## Download the toolchain and unpack it getArduinoToolchain() { - echo -e "\nDownloading Arduino environment ...\n" - if [ "$os" == "Darwin" ]; then - curl -o "$arduinoToolchainArchive" http://downloads-02.arduino.cc/"$arduinoToolchainArchive" - else - wget http://downloads-02.arduino.cc/"$arduinoToolchainArchive" - fi - mkdir -p "$arduinoDir/portable" - echo -e "\nUnpacking Arduino environment. This might take a while ...\n" - if [ "$os" == "Darwin" ]; then - unzip -q "$arduinoToolchainArchive" -d "$arduinoDir" - else - tar -xf "$arduinoToolchainArchive" -C "$arduinoDir" --strip 1 - fi - rm -R "$arduinoToolchainArchive" + >&$l echo "Getting Arduino environment..." + + local archive=$(getFile http://downloads-02.arduino.cc/"$arduinoToolchainArchive" $arduinoToolchainArchive) + rm -rf "$arduinoDir" + mkdir -p "$arduinoDir/portable" + >&$l echo " Unpacking (this might take a while)..." + if [ "$os" == "Darwin" ]; then + >&$o unzip -q "$archive" -d "$arduinoDir" + else + >&$o tar -xf "$archive" -C "$arduinoDir" --strip 1 + fi } ## Get dependencies and move them in place getDependencies() { - echo -e "\nDownloading libraries ...\n" - - for library in ${marlinDependencies[@]}; do - IFS=',' read libName libUrl libDir <<< "$library" - git clone "$libUrl" "$libName" - rm -rf "$arduinoLibrariesDir"/"$libName" - mv -f "$libName"/"$libDir" "$arduinoLibrariesDir"/"$libName" - rm -rf "$libName" - done + >&$l echo -e "\nGetting libraries..." + + for library in ${marlinDependencies[@]}; do + local libName= + local libUrl= + local libDir= + + IFS=',' read libName libUrl libDir <<< "$library" + local libRepo=$(getGitRepo "$libUrl" "") + mv -f "$libRepo/$libDir" "$arduinoLibrariesDir/$libName" + rm -rf "$libRepo" + done } ## Clone Marlin getMarlin() { - echo -e "\nCloning Marlin \"$marlinRepositoryUrl\" ...\n" - - if [ "$marlinRepositoryBranch" != "" ]; then - git clone -b "$marlinRepositoryBranch" --single-branch "$marlinRepositoryUrl" "$marlinDir" - else - git clone "$marlinRepositoryUrl" "$marlinDir" - fi - - exit + >&$l echo -e "\nGetting Marlin..." + local repoDir=$(getGitRepo "$marlinRepositoryUrl" "$marlinRepositoryBranch") + rm -rf "$marlinDir" + mv "$repoDir" "$marlinDir" } ## Update an existing Marlin clone -checkoutMarlin() +updateMarlin() { - date=`date +%Y-%m-%d-%H-%M-%S` - - # backup configuration - backupMarlinConfiguration $date - - cd $marlinDir + local cacheRepo=$cacheDir/Marlin - echo -e "\nFetching most recent Marlin from \"$marlinRepositoryUrl\" ...\n" + backupName=`date +%Y-%m-%d-%H-%M-%S` + doBackup $backupName - git fetch - git checkout - git reset origin/`git rev-parse --abbrev-ref HEAD` --hard + >&$l echo "Fetching most recent Marlin from \"$marlinRepositoryUrl\"..." - echo -e "\n" + ( + cd $cacheRepo + 2>&$o git fetch -p origin + ) + ( + cd $marlinDir + >&$o git fetch -p origin + >&$o git checkout + >&$o git reset origin/`git rev-parse --abbrev-ref HEAD` --hard + ) - cd .. - - restoreMarlinConfiguration $date - exit + doRestore $backupName } ## Get the toolchain and Marlin, install board definition setupEnvironment() { - echo -e "\nSetting up build environment in \"$arduinoDir\" ...\n" - getArduinoToolchain - getDependencies - getHardwareDefinition - exit + >&$l echo -e "\nSetting up build environment in \"$arduinoDir\" ...\n" + getArduinoToolchain + getDependencies + getHardwareDefinition } ## Fetch and install anet board hardware definition getHardwareDefinition() { - if [ "$hardwareDefinitionRepo" != "" ]; then - - echo -e "\nCloning board hardware definition from \"$hardwareDefinitionRepo\" ... \n" - git clone "$hardwareDefinitionRepo" - - echo -e "\nMoving board hardware definition into arduino directory ... \n" - - repoName=$(basename "$hardwareDefinitionRepo" ".${hardwareDefinitionRepo##*.}") - - mv -f $repoName/hardware/* "$arduinoHardwareDir" - rm -rf $repoName - fi + if [ "$hardwareDefinitionRepo" != "" ]; then + >&$l echo -e "\nGetting board hardware definition..." + local repoPath=$(getGitRepo "$hardwareDefinitionRepo" "") + + >&$l echo " Moving board hardware definition into arduino directory..." + + mv -f $repoPath/hardware/* "$arduinoHardwareDir" + rm -rf $repoPath + fi +} + +## Reports the backup paths +reportBackupFiles() +{ + >&$l echo " \"Configuration.h\"" + >&$l echo " \"Configuration_adv.h\"" + >&$l echo "$1 \"./configuration/$backupName/\"" + >&$l echo +} + +## Performs the backup operation +doBackup() +{ + >&$l echo "Saving Marlin configuration..." + mkdir -p configuration/$0 + cp "$marlinDir"/Marlin/Configuration.h configuration/"$0" + cp "$marlinDir"/Marlin/Configuration_adv.h configuration/"$0" +} + +doRestore() +{ + >&$l echo "Restoring Marlin configuration..." + cp configuration/"$0"/Configuration.h "$marlinDir"/Marlin/ + cp configuration/"$0"/Configuration_adv.h "$marlinDir"/Marlin/ } @@ -127,104 +247,130 @@ getHardwareDefinition() ## param #1 backup name backupMarlinConfiguration() { - echo -e "\nSaving Marlin configuration\n" - echo -e " \"Configuration.h\"" - echo -e " \"Configuration_adv.h\"" - echo -e "\nto \"./configuration/$1/\"\n" - - mkdir -p configuration/$1 - - cp "$marlinDir"/Marlin/Configuration.h configuration/"$1" - cp "$marlinDir"/Marlin/Configuration_adv.h configuration/"$1" + doBackup $backupName + reportBackupFiles 'to' } ## Restore Marlin Configuration from backup ## param #1 backup name restoreMarlinConfiguration() { - if [ -d "configuration/$1" ]; then - echo -e "Restoring Marlin configuration\n" - echo -e " \"Configuration.h\"" - echo -e " \"Configuration_adv.h\"" - echo -e "\nfrom \"./configuration/$1/\"\n" - - cp configuration/"$1"/Configuration.h "$marlinDir"/Marlin/ - cp configuration/"$1"/Configuration_adv.h "$marlinDir"/Marlin/ - else - echo -e "\nBackup configuration/$1 not found!\n" - fi - exit + if [ -d "configuration/$backupName" ]; then + doRestore $backupName + reportBackupFiles 'from' + else + >&2 echo "Backup configuration/$backupName not found!" + fi } ## Build Marlin -verifyBuild() +build() { - echo -e "\nVerifying build ...\n" + >&$l echo "Building Marlin...\n" + + checkToolChain + checkMarlin - "$arduinoExecutable" --verify --verbose --board "$boardString" "$marlinDir"/Marlin/Marlin.ino --pref build.path="$buildDir" - exit + if >&$o "$arduinoExecutable" --verify --verbose --board "$boardString" "$marlinDir"/Marlin/Marlin.ino \ + --pref build.path="$buildDir" 2>&1 ; then + >&$l echo "Build successful." + else + >&2 echo "Build failed." + >&2 echo + exit 1 + fi } ## Build Marlin and upload buildAndUpload() { - echo -e "\nBuilding and uploading Marlin build from \"$buildDir\" ...\n" + echo "Building and uploading Marlin..." - "$arduinoExecutable" --upload --port "$port" --verbose --board "$boardString" "$marlinDir"/Marlin/Marlin.ino --pref build.path="$buildDir" - exit + checkToolChain + checkMarlin + + if >&$o "$arduinoExecutable" --upload --port "$port" --verbose --board "$boardString" \ + "$marlinDir"/Marlin/Marlin.ino --pref build.path="$buildDir" 2>&1 ; then + >&$l echo "Build and upload successful." + else + >&2 echo "Build and upload failed." + >&2 echo + exit 1 + fi } ## Delete everything that was downloaded cleanEverything() { - rm -Rf "$arduinoDir" - rm -Rf "$marlinDir" - rm -Rf "$buildDir" + rm -Rf "$arduinoDir" + rm -Rf "$marlinDir" + rm -Rf "$buildDir" +} + +## Delete everything that was downloaded +cleanCache() +{ + rm -Rf "$cacheDir" } ## Print help -printDocu() +printUsage() { - echo "Usage:" - echo " $scriptName ARGS" - echo - echo "Builds an installs Marlin 3D printer firmware." - echo - echo "Options:" - echo - echo " -s, --setup Download and configure the toolchain and the" - echo " necessary libraries for building Marlin." - echo " -m, --marlin Download Marlin sources." - echo " -f, --fetch Update an existing Marlin clone." - echo " -v, --verify Build without uploading." - echo " -u, --upload Build and upload Marlin." - echo " -b, --backupConfig [name] Backup the Marlin configuration to the named backup." - echo " -r, --restoreConfig [name] Restore the given configuration into the Marlin directory." - echo " Rename to Configuration.h implicitly." - echo " -c, --clean Cleanup everything. Remove Marlin sources and Arduino toolchain" - echo " -p, --port [port] Set the serialport for uploading the firmware." - echo " Overrides the default in the script." - echo " -h, --help Show this doc." - echo - exit + echo "Usage:" + echo " $scriptName [-q] []" + echo + echo "Builds an installs Marlin 3D printer firmware." + echo + echo "Options:" + echo " -q, --quiet Don't print status messages." + echo " -v, --verbose Print the output of sub-processes." + echo + echo "Commands:" + echo " setup Download and configure the toolchain and the" + echo " necessary libraries for building Marlin." + echo " get-marlin Download Marlin sources." + echo " update-marlin Update existing Marlin source." + echo + echo " build Build Marlin without uploading." + echo " build-upload Build Marlin and upload." + echo " -p, --port [port] Set the device serial port." + echo + echo " backup-config Backup the Marlin configuration to a named backup." + echo " restore-config Restore the Marlin given configuration." + echo + echo " clean Remove Arduino tool-chain and Marlin sources." + echo " clean-cache Clean up the download cache." + echo + echo " help Show help." + echo + exit +} + +onExit() +{ + rm -rf $tmpDir } # Check for parameters file and source it if available if [ -f $defaultParametersFile ]; then - source "$defaultParametersFile" + source "$defaultParametersFile" else - echo -e "\n ===================================================================" - echo -e "\n Can't find $defaultParametersFile!" - echo -e "\n Please rename the \"$defaultParametersFile.example\" file placed in the" - echo -e " same directory as this script to \"$defaultParametersFile\" and edit" - echo -e " if neccessary.\n" - echo -e " ===================================================================\n\n" - exit 1 + echo -e "\n ===================================================================" + echo -e "\n Can't find $defaultParametersFile!" + echo -e "\n Please rename the \"$defaultParametersFile.example\" file placed in the" + echo -e " same directory as this script to \"$defaultParametersFile\" and edit" + echo -e " if neccessary.\n" + echo -e " ===================================================================\n\n" + exit 1 fi +# Temporary directory +tmpDir=$(mktemp -d "${TMPDIR:-/tmp}/marlintool.XXXXXX") +trap "onExit" EXIT + # Toolchain architecture arch=$(uname -m) case $arch in @@ -240,13 +386,11 @@ esac # Operating system specific values os=$(uname -s) if [ "$os" == "Darwin" ]; then - tools="git unzip curl" arduinoToolchainArchive="arduino-$arduinoToolchainVersion-macosx.zip" arduinoExecutable="$arduinoDir/Arduino.app/Contents/MacOS/Arduino" arduinoHardwareDir="$arduinoDir/Arduino.app/Contents/Java/hardware" arduinoLibrariesDir="$arduinoDir/Arduino.app/Contents/Java/libraries" else - tools="git tar wget" arduinoToolchainArchive="arduino-$arduinoToolchainVersion-$arduinoToolchainArchitecture.tar.xz" arduinoExecutable="$arduinoDir/arduino" arduinoHardwareDir="$arduinoDir/hardware" @@ -254,38 +398,90 @@ else fi -checkTools "$tools" - -if [ "$1" = "" ]; then printDocu; exit 1; fi - -while [ "$1" != "" ]; do - case $1 in - -p | --port ) shift - port=$1 - ;; - -s | --setup ) setupEnvironment - ;; - -m | --marlin ) getMarlin - ;; - -f | --fetch ) checkoutMarlin - ;; - -v | --verify ) verifyBuild - ;; - -u | --upload ) buildAndUpload - ;; - -b | --backupConfig ) shift - backupMarlinConfiguration $1 exit - ;; - -r | --restoreConfig ) shift - restoreMarlinConfiguration $1 - ;; - -c | --clean ) shift - cleanEverything - ;; - -h | --help ) printDocu - ;; - * ) printDocu - exit 1 - esac - shift +checkTools git tar unzip +checkCurlWget + +if [ $# -lt 1 ]; then + printUsage >&2 + exit 1 +fi + +parseBackupRestoreArgument() { + if [ $# -eq 0 ]; then + >&2 echo "No backup path given" + >&2 echo + exit 1 + else + echo $1 + fi +} + +quiet= +verbose= +verb='' + +while [ "x$verb" = "x" ]; do + case $1 in + setup) verb=setupEnvironment;; + get-marlin) verb=getMarlin;; + update-marlin) verb=updateMarlin;; + build) verb=build;; + build-upload) verb=buildAndUpload;; + backup-config) + verb=backupMarlinConfiguration + shift + backupName=$(parseBackupRestoreArgument $@) + ;; + restore-config) + verb=restoreMarlinConfiguration + shift + backupName=$(parseBackupRestoreArgument $@) + ;; + clean) verb=cleanEverything;; + clean-cache) verb=cleanCache;; + help|-h|--help) verb=printUsage;; + -q|--quiet) quiet=y;; + -v|--verbose) verbose=y;; + *) + printUsage >&2 + exit 1 + ;; + esac + shift done + +case $verb in + buildAndUpload) + while [ $# -gt 0 ]; do + case $1 in + -p|--port) + shift + port=$1 + ;; + -q|--quiet) quiet=y;; + -v|--verbose) verbose=y;; + *) + printUsage >&2 + exit 1 + esac + shift + done + ;; + *) + while [ $# -gt 0 ]; do + case $1 in + -q|--quiet) quiet=y;; + -v|--verbose) verbose=y;; + *) + printUsage >&2 + exit 1 + esac + shift + done + ;; +esac + +[ "x$quiet" = "xy" ] && exec {l}>/dev/null || exec {l}>&1 +[ "x$verbose" = "xy" ] && exec {o}>&1 || exec {o}>/dev/null + +$verb