From 42ee700e0c750e2c721cdc31306f7186254f465a Mon Sep 17 00:00:00 2001 From: mdeboercw Date: Tue, 3 May 2016 14:17:03 -0700 Subject: [PATCH] Added MAIN_PATH and DOCKER_BUILD_CONTEXT customizable parameters Updated README for new special options --- README.md | 33 +++++++++++++++++++++++++++++---- builder/build.sh | 30 +++++++++++++++++++++++------- builder/build_environment.sh | 25 +++++++++++++++++-------- 3 files changed, 69 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index e8094ab..1ca1f05 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,26 @@ The *golang-builder* assumes that your "main" package (the package containing yo In the example above, the `hello.go` source file defines the "main" package for this project and lives at the root of the project directory structure. This project defines other packages ("api" and "greeting") but those are subdirectories off the root. -This convention is in place so that the *golang-builder* knows where to find the "main" package in the project structure. In a future release, we may make this a configurable option in order to support projects with different directory structures. +This convention is in place so that the *golang-builder* knows where to find the "main" package in the project structure. + +If your "main" package does not reside at the root of your project structure, you can accomodate this by specifying the `MAIN_PATH` environment variable which references the relative path to your main package. + +For example, suppose your structure is like the following (slightly modified from above so that your "main" package resides in the "cli" subfolder): + + . + ├─Dockerfile + ├─api + | ├─api.go + | └─api_test.go + ├─greeting + | ├─greeting.go + | └─greeting_test.go + └─cli + ├─hello.go + └─hello_test.go + +You would then add `MAIN_PATH=cli` to your environment specification. + ### Canonical Import Path In addition to knowing where to find the "main" package, the *golang-builder* also needs to know the fully-qualified package name for your application. For the "hello" application shown above, the fully-qualified package name for the executable is "github.com/CenturyLink/hello" but there is no way to determine that just by looking at the project directory structure (during the development, the project directory would likely be mounted at `$GOPATH/src/github.com/CenturyLink/hello` so that the Go tools can determine the package name). @@ -63,9 +82,13 @@ The problem with doing a `go get` with each build is that *golang-builder* may e If you are using Godep to manage your dependencies *golang-builder* will reference the packages in your `Godeps/_workspace` directory instead of downloading them via `go get`. ### Dockerfile -If you would like to have *golang-builder* package your compiled Go application into a Docker image automatically then the final requirement is that your Dockerfile be placed at the root of your project directory structure. After compiling your Go application, *golang-builder* will execute a `docker build` with your Dockerfile. +If you would like to have *golang-builder* package your compiled Go application into a Docker image automatically then the final requirement is that your Dockerfile be placed at the root of your project directory structure. + +If your Dockerfile resides somewhere else, you can acommodate this by specifying the `DOCKER_BUILD_CONTEXT` env var. This will be used to override the default value of `"."`. + +After compiling your Go application, *golang-builder* will execute a `docker build` with your Dockerfile. -The compiled binary will be placed in the root of your project directory so your Dockerfile can be written with the assumption that the application binary is in the same directory as the Dockerfile itself: +The compiled binary will be placed (by default) in the root of your project directory so your Dockerfile can be written with the assumption that the application binary is in the same directory as the Dockerfile itself: FROM scratch EXPOSE 3000 @@ -74,7 +97,7 @@ The compiled binary will be placed in the root of your project directory so your In this case, the *hello* binary will be copied right to the root of the image and used as the entrypoint. Since we're using the empty *scratch* image as our base, there is no need to set-up any sort of directory structure inside the image. -If *golang-builder* does **NOT** see a Dockerfile in your project directory it will simply stop after compiling your application. +If *golang-builder* does **NOT** see a Dockerfile in your project directory (or `DOCKER_BUILD_CONTEXT` directory) it will simply stop after compiling your application. ## Usage @@ -112,6 +135,8 @@ If you just want to compile your application without packaging it in a Docker im * LDFLAGS - flags to pass to the linker (defaults to '-s') * COMPRESS_BINARY - if set to true, will use UPX to compress the final binary (defaults to false) * OUTPUT - if set, will use the `-o` option with `go build` to output the final binary to the value of this env var +* MAIN_PATH - if set, this (relative) path will be used as the location of the "main" package +* DOCKER_BUILD_CONTEXT - if set, this (relative) path will be used as the build context location (where the Dockerfile should reside) The above are environment variables to be passed to the docker run command: diff --git a/builder/build.sh b/builder/build.sh index d5061cd..ff14ec4 100755 --- a/builder/build.sh +++ b/builder/build.sh @@ -11,13 +11,23 @@ name=${pkgName##*/} # to the named output file # output="" +outputFile="" if [[ ! -z "${OUTPUT}" ]]; then - output="-o ${OUTPUT}" + outputFile="${OUTPUT}" + # + # If OUTPUT env var ends with "/", assume an output directory + # was specified, and we should append the executable name. + # + if [[ "$outputFile" == *"/" ]]; + then + outputFile="${outputFile}${name}" + fi + output="-o ${outputFile}" fi # Compile statically linked version of package -echo "Building $pkgName" +echo "Building $pkgName => ${outputFile}" ( CGO_ENABLED=${CGO_ENABLED:-0} \ go build \ @@ -30,19 +40,25 @@ echo "Building $pkgName" if [[ "$COMPRESS_BINARY" == "true" ]]; then - if [[ ! -z "${OUTPUT}" ]]; + if [[ ! -z "${outputFile}" ]]; then - goupx ${OUTPUT} + goupx "${outputFile}" else goupx $name fi fi -if [[ -e "/var/run/docker.sock" && -e "./Dockerfile" ]]; +dockerContextPath="." +if [ ! -z "${DOCKER_BUILD_CONTEXT}" ]; +then + dockerContextPath="${DOCKER_BUILD_CONTEXT}" +fi + +if [[ -e "/var/run/docker.sock" && -e "${dockerContextPath}/Dockerfile" ]]; then # Default TAG_NAME to package name if not set explicitly tagName=${tagName:-"$name":latest} # Build the image from the Dockerfile in the package directory - docker build -t $tagName . -fi + docker build -t $tagName "$dockerContextPath" +fi \ No newline at end of file diff --git a/builder/build_environment.sh b/builder/build_environment.sh index f505fbb..c9cb58d 100755 --- a/builder/build_environment.sh +++ b/builder/build_environment.sh @@ -8,20 +8,29 @@ then exit 990 fi -# Grab Go package name -pkgName="$(go list -e -f '{{.ImportComment}}' 2>/dev/null || true)" +# Construct Go package path +if [ ! -z "${MAIN_PATH}" ]; +then + pkgName="$(go list -e -f '{{.ImportComment}}' ./... 2>/dev/null | grep ${MAIN_PATH} || true)" + path=$(cd /src && ls -d -1 ${MAIN_PATH}) + pkgBase=${pkgName%/$path} +else + pkgName="$(go list -e -f '{{.ImportComment}}' 2>/dev/null || true)" + pkgBase="$pkgName" +fi + +echo "using pkgName: $pkgName, pkgBase: $pkgBase" if [ -z "$pkgName" ]; then - echo "Error: Must add canonical import path to root package" + echo "Error: Must add canonical import path to root package, or specify the MAIN_PATH env var" exit 992 fi # Grab just first path listed in GOPATH goPath="${GOPATH%%:*}" -# Construct Go package path -pkgPath="$goPath/src/$pkgName" +pkgPath="$goPath/src/$pkgBase" # Set-up src directory tree in GOPATH mkdir -p "$(dirname "$pkgPath")" @@ -31,8 +40,8 @@ ln -sf /src "$pkgPath" if [ -e "$pkgPath/vendor" ]; then - # Enable vendor experiment - export GO15VENDOREXPERIMENT=1 + # Enable vendor experiment + export GO15VENDOREXPERIMENT=1 elif [ -e "$pkgPath/Godeps/_workspace" ]; then # Add local godeps dir to GOPATH @@ -40,4 +49,4 @@ then else # Get all package dependencies go get -t -d -v ./... -fi +fi \ No newline at end of file