#!/bin/sh # # Copyright (C) 2020, 2022 Jeffery To # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. # nl=" " log() { # shellcheck disable=SC2039 local IFS=" " printf '%s\n' "$*" } log_error() { # shellcheck disable=SC2039 local IFS=" " printf 'Error: %s\n' "$*" >&2 } link_contents() { # shellcheck disable=SC2039 local src="$1" dest="$2" IFS="$nl" dirs dir base if [ -n "$(find "$src" -mindepth 1 -maxdepth 1 -name "*.go" -not -type d)" ]; then log_error "$src is already a Go library" return 1 fi dirs="$(find "$src" -mindepth 1 -maxdepth 1 -type d)" for dir in $dirs; do base="${dir##*/}" if [ -d "$dest/$base" ]; then case "$dir" in *$GO_BUILD_DEPENDS_SRC/$GO_PKG) log "$GO_PKG is already installed. Please check for circular dependencies." ;; *) link_contents "$src/$base" "$dest/$base" ;; esac else log "...${src#$GO_BUILD_DEPENDS_SRC}/$base" ln -sf "$src/$base" "$dest/$base" fi done return 0 } configure() { # shellcheck disable=SC2039 local files code testdata gomod pattern extra IFS file dest cd "$BUILD_DIR" || return 1 files="$(find ./ -path "*/.*" -prune -o -not -type d -print)" if [ "$GO_INSTALL_ALL" != 1 ]; then code="$(printf '%s\n' "$files" | grep '\.\(c\|cc\|cpp\|go\|h\|hh\|hpp\|proto\|s\)$')" testdata="$(printf '%s\n' "$files" | grep '/testdata/')" gomod="$(printf '%s\n' "$files" | grep '/go\.\(mod\|sum\|work\)$')" for pattern in $GO_INSTALL_EXTRA; do extra="$(printf '%s\n' "$extra"; printf '%s\n' "$files" | grep -e "$pattern")" done files="$(printf '%s\n%s\n%s\n%s\n' "$code" "$testdata" "$gomod" "$extra" | grep -v '^[[:space:]]*$' | sort -u)" fi IFS="$nl" log "Copying files from $BUILD_DIR into $GO_BUILD_DIR/src/$GO_PKG" mkdir -p "$GO_BUILD_DIR/src" for file in $files; do log "${file#./}" dest="$GO_BUILD_DIR/src/$GO_PKG/${file#./}" mkdir -p "${dest%/*}" cp -fpR "$file" "$dest" done log if [ "$GO_SOURCE_ONLY" != 1 ]; then if [ -d "$GO_BUILD_DEPENDS_SRC" ]; then log "Symlinking directories from $GO_BUILD_DEPENDS_SRC into $GO_BUILD_DIR/src" link_contents "$GO_BUILD_DEPENDS_SRC" "$GO_BUILD_DIR/src" else log "$GO_BUILD_DEPENDS_SRC does not exist, skipping symlinks" fi else log "Not building binaries, skipping symlinks" fi log return 0 } build() { # shellcheck disable=SC2039 local modargs pattern targets retval cd "$GO_BUILD_DIR" || return 1 if [ -f "$BUILD_DIR/go.mod" ] ; then mkdir -p "$GO_MOD_CACHE_DIR" modargs="$GO_MOD_ARGS" fi log "Finding targets" # shellcheck disable=SC2086 targets="$(go list $modargs $GO_BUILD_PKG)" for pattern in $GO_EXCLUDES; do targets="$(printf '%s\n' "$targets" | grep -v "$pattern")" done log if [ "$GO_GO_GENERATE" = 1 ]; then log "Calling go generate" # shellcheck disable=SC2086 GOOS='' GOARCH='' GO386='' GOARM='' GOMIPS='' GOMIPS64='' \ go generate -v $targets log fi if [ "$GO_SOURCE_ONLY" = 1 ]; then return 0 fi log "Building targets" mkdir -p "$GO_BUILD_DIR/bin" "$GO_BUILD_CACHE_DIR" # shellcheck disable=SC2086 go install $modargs "$@" $targets retval="$?" log if [ "$retval" -eq 0 ] && [ -z "$(find "$GO_BUILD_BIN_DIR" -maxdepth 0 -type d -not -empty 2>/dev/null)" ]; then log_error "No binaries were built" retval=1 fi if [ "$retval" -ne 0 ]; then cache_cleanup fi return "$retval" } install_bin() { # shellcheck disable=SC2039 local dest="$1" install -d -m0755 "$dest/$GO_INSTALL_BIN_PATH" install -m0755 "$GO_BUILD_BIN_DIR"/* "$dest/$GO_INSTALL_BIN_PATH/" } install_src() { # shellcheck disable=SC2039 local dest="$1" dir="${GO_PKG%/*}" install -d -m0755 "$dest/$GO_BUILD_DEPENDS_PATH/src/$dir" cp -fpR "$GO_BUILD_DIR/src/$GO_PKG" "$dest/$GO_BUILD_DEPENDS_PATH/src/$dir/" } cache_cleanup() { if ! [ -d "$GO_MOD_CACHE_DIR" ]; then return 0 fi # in case go is called without -modcacherw find "$GO_MOD_CACHE_DIR" -type d -not -perm -u+w -exec chmod u+w '{}' + if [ -n "$CONFIG_GOLANG_MOD_CACHE_WORLD_READABLE" ]; then find "$GO_MOD_CACHE_DIR" -type d -not -perm -go+rx -exec chmod go+rx '{}' + find "$GO_MOD_CACHE_DIR" -not -type d -not -perm -go+r -exec chmod go+r '{}' + fi return 0 } if [ "$#" -lt 1 ]; then log_error "Missing command" exit 1 fi command="$1" shift 1 case "$command" in configure) configure ;; build) build "$@" ;; install_bin) install_bin "$@" ;; install_src) install_src "$@" ;; cache_cleanup) cache_cleanup ;; *) log_error "Invalid command \"$command\"" exit 1 ;; esac