#!/bin/sh -eu print() { printf "%s" "$@" } matches() { value=$1 pattern=$2 print "$value" | grep --only-matching -E "$pattern" } replace() { value=$1 pattern=$2 print "$value" | sed -E "$pattern" } scpSyntaxURL() { matches "$1" "^[^:@/]+@[^:/]+:.*$" >/dev/null } scpSyntaxURLHost() { URL="$1" host=$(matches "$URL" '^[^:@/]+@[^:/]+:') host=${host#*@} host=${host%:} print "$host" } scpSyntaxURLPath() { URL="$1" prefix=$(matches "$URL" '^[^:]+:') path=${URL#$prefix} print "$path" } ensureDockerPathSet() { export DOCKERPATH=${DOCKERPATH:-$HOME/.docker-get} } ensureDockerPathExists() { mkdir -p "$DOCKERPATH" } ensureInsideDockerPath() { realDockerPath=$(cd "$DOCKERPATH"; pwd -P) realPwd=$(pwd -P) case "$realPwd" in "$realDockerPath"/*) true return ;; esac false } stripProtocol() { print "${1#*://}" } stripTrailingSlash() { print "${1%/}" } isRepository() { git ls-remote "$1" HEAD 2>/dev/null >/dev/null } ensureProtocol() { URL=$1 if scpSyntaxURL "$URL"; then print "$URL" return fi noProtocolURL=$(stripProtocol "$URL") protocol=${URL%$noProtocolURL} print "${protocol:-https://}$noProtocolURL" } tagOrDefault() { print "${1:-master}" } tagSuffix() { tagSuffix=$(matches "$taggedURL" ':[^/:]+$' || true) tagSuffix=${tagSuffix#:} print "$tagSuffix" } stripTagSuffix() { taggedURL=$1 tag=$(tagSuffix "$taggedURL") print "${taggedURL%:$tag}" } stripDotGit() { replace "$1" 's/\.git($|\/)/\1/' } inferPackageTagFromURL() { packageURL=$1 tag=$2 case $(packagePathOfPackageURL "$packageURL") in github.com*) pathTag=$(replace "$packageURL" 's/^.*tree\/([^\/]+)\/.*$/\1/') if [ -z "$tag" ] && [ ! "$pathTag" = "$packageURL" ]; then print "$pathTag" return fi ;; esac print "$tag" } applyFixesToPackageURL() { packageURL=$1 tag=$(tagOrDefault "$2") packageURL=$(stripTagSuffix "$packageURL") case $(packagePathOfPackageURL "$packageURL") in github.com*) replace "$packageURL" "s/\/tree\/$tag\//\//" return ;; esac print "$packageURL" } packagePathOfPackageURL() { packageURL=$1 if scpSyntaxURL "$packageURL"; then host=$(scpSyntaxURLHost "$packageURL") path=$(scpSyntaxURLPath "$packageURL") path=$(stripDotGit "$path") print "$host/$path" return fi packagePath=$(stripProtocol "$packageURL") packagePath=$(stripTrailingSlash "$packagePath") packagePath=$(stripDotGit "$packagePath") print "$packagePath" } repositoryURLOfPackageURL() { packageURL=$1 packageURL=$(ensureProtocol "$packageURL") while [ "${packageURL%/*}" != "$packageURL" ]; do if isRepository "$packageURL"; then print "$packageURL" return fi packageURL=${packageURL%/*} done false } refForTag() { repositoryURL=$1 tag=$2 git ls-remote "$repositoryURL" "$(tagOrDefault "$tag")" | sed 's/^.*refs\///' } inGitRepository() { ( exec 1> /dev/null exec 2> /dev/null git rev-parse --show-prefix && [ -z "$(git rev-parse --show-prefix)" ] ) } ensureRepositoryUpToDate() { repositoryPath=$1 repositoryURL=$2 pathInRepository=$3 tag=$4 ref=$(refForTag "$repositoryURL" "$tag") refspec=+refs/$ref:refs/remotes/origin/$ref if [ -z "$ref" ]; then # assume it's a commit hash ref=$tag refspec=$ref:refs/remotes/origin/$tag fi ( exec 2>&1 mkdir -p "$repositoryPath" cd "$repositoryPath" ensureInsideDockerPath if ! inGitRepository; then git init git remote add origin "$repositoryURL" fi git fetch -v --progress origin "$refspec" git checkout -f --progress "refs/remotes/origin/$ref" -- "$pathInRepository" ) } ensurePackagePresentForURL() { packageURL=$1 packageTag=$2 packagePath=$(packagePathOfPackageURL "$packageURL") repositoryURL=$(repositoryURLOfPackageURL "$packageURL") packageURL=$(ensureProtocol "$packageURL") pathInRepository=${packageURL#$repositoryURL} repositoryPath=$DOCKERPATH/${packagePath%$pathInRepository} printf "[docker-get] %s\n" "fetching .$pathInRepository ($(tagOrDefault "$packageTag")) from $repositoryURL ..." ensureRepositoryUpToDate \ "$repositoryPath" \ "$repositoryURL" \ ".$pathInRepository" \ "$packageTag" printf "[docker-get] %s\n" "done" } imageTagForPackagePath() { packagePath=$1 tag=$2 imageTag=$packagePath:$(tagOrDefault "$tag") print "$imageTag" | tr '[:upper:]' '[:lower:]' } dockerBuild() { imageTag=$1 shift ensureInsideDockerPath docker build -t "$imageTag" "$@" . } buildPackageForPath() { packagePath=$1 tag=$2 shift 2 buildDir=$DOCKERPATH/$packagePath imageTag=$(imageTagForPackagePath "$packagePath" "$tag") printf "[docker-get] %s\n" "building $imageTag..." ( cd "$buildDir" if [ "$(tagOrDefault "$tag")" = master ]; then dockerBuild "$imageTag" -t "$(imageTagForPackagePath "$packagePath" latest)" "$@" else dockerBuild "$imageTag" "$@" fi ) printf "[docker-get] %s\n" "done" } buildPackageForURL() { packageURL=$1 tag=$2 shift 2 packagePath=$(packagePathOfPackageURL "$packageURL") buildPackageForPath "$packagePath" "$tag" "$@" } buildPackageForTaggedURL() { taggedURL=$1 shift packageTag=$(inferPackageTagFromURL "$taggedURL" "$(tagSuffix "$taggedURL")") packageURL=$(applyFixesToPackageURL "$taggedURL" "$packageTag") ensurePackagePresentForURL "$packageURL" "$packageTag" buildPackageForURL "$packageURL" "$packageTag" "$@" } get() { taggedURL=$1 shift buildPackageForTaggedURL "$taggedURL" "$@" } ensureDockerPathSet ensureDockerPathExists get "$@"