mirror of https://github.com/knative/client.git
414 lines
11 KiB
Bash
Executable File
414 lines
11 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
|
||
# Copyright 2018 The Knative Authors
|
||
#
|
||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||
# you may not use this file except in compliance with the License.
|
||
# You may obtain a copy of the License at
|
||
#
|
||
# http://www.apache.org/licenses/LICENSE-2.0
|
||
#
|
||
# Unless required by applicable law or agreed to in writing, software
|
||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
# See the License for the specific language governing permissions and
|
||
# limitations under the License.
|
||
|
||
# shellcheck source=/dev/null
|
||
|
||
set -o pipefail
|
||
set -o errexit
|
||
set -o nounset
|
||
|
||
source_dirs="cmd pkg test tools"
|
||
|
||
# Store for later
|
||
if [ -z "${1-}" ]; then
|
||
ARGS=("")
|
||
else
|
||
ARGS=("$@")
|
||
fi
|
||
|
||
# Tool version
|
||
readonly GOIMPORTS_VERSION="v0.7.0"
|
||
readonly GOLINT_VERSION="v1.52.0"
|
||
|
||
# Run build
|
||
run() {
|
||
# Switch on modules unconditionally
|
||
export GO111MODULE=on
|
||
|
||
# Jump into project directory
|
||
pushd "$(basedir)" >/dev/null 2>&1
|
||
|
||
# Print help if requested
|
||
if has_flag --help -h; then
|
||
display_help "$@"
|
||
exit 0
|
||
fi
|
||
|
||
# Run linter if requested
|
||
if has_flag --lint; then
|
||
source_lint
|
||
exit 0
|
||
fi
|
||
|
||
if has_flag --watch -w; then
|
||
# Build and test first
|
||
go_build
|
||
|
||
if has_flag --test -t; then
|
||
go_test
|
||
fi
|
||
|
||
# Go in endless loop, to be stopped with CTRL-C
|
||
watch
|
||
fi
|
||
|
||
# Fast mode: Only compile and maybe run test
|
||
if has_flag --fast -f; then
|
||
go_build
|
||
|
||
if has_flag --test -t; then
|
||
go_test
|
||
fi
|
||
exit 0
|
||
fi
|
||
|
||
# platform mode: Only to build target platform for cross-compilation
|
||
if has_flag --platform -p; then
|
||
# Extract GOOS and GOARCH from command-line arguments
|
||
GOOS="${ARGS[1]}"
|
||
GOARCH="${ARGS[2]}"
|
||
go_build_with_goos_goarch "$GOOS" "$GOARCH"
|
||
exit 0
|
||
fi
|
||
|
||
# Run only tests
|
||
if has_flag --test -t; then
|
||
go_test
|
||
exit 0
|
||
fi
|
||
|
||
# Run only codegen
|
||
if has_flag --codegen -c; then
|
||
codegen
|
||
exit 0
|
||
fi
|
||
|
||
# Cross compile only
|
||
if has_flag --all -x; then
|
||
cross_build || (echo "✋ Cross platform build failed" && exit 1)
|
||
exit 0
|
||
fi
|
||
|
||
# Default flow
|
||
codegen
|
||
go_build
|
||
go_test
|
||
|
||
echo "────────────────────────────────────────────"
|
||
./kn version
|
||
}
|
||
|
||
|
||
codegen() {
|
||
# Update dependencies
|
||
update_deps
|
||
|
||
# Format source code and cleanup imports
|
||
source_format
|
||
|
||
# Check for license headers
|
||
check_license
|
||
|
||
# Auto generate cli docs
|
||
generate_docs
|
||
|
||
}
|
||
|
||
go_fmt() {
|
||
echo "🧹 ${S}Format"
|
||
find $(echo "$source_dirs") -name "*.go" -print0 | xargs -0 gofmt -s -w
|
||
}
|
||
|
||
source_format() {
|
||
set +e
|
||
go_run "golang.org/x/tools/cmd/goimports@${GOIMPORTS_VERSION}" -w $(echo "$source_dirs")
|
||
find $(echo "$source_dirs") -name "*.go" -print0 | xargs -0 gofmt -s -w
|
||
set -e
|
||
}
|
||
|
||
source_lint() {
|
||
echo "🔍 Lint"
|
||
go_run "github.com/golangci/golangci-lint/cmd/golangci-lint@${GOLINT_VERSION}" run || \
|
||
{ echo "--- FAIL: golangci-lint failed please fix the reported errors"; return 1; }
|
||
}
|
||
|
||
go_build() {
|
||
echo "🚧 Compile"
|
||
# Env var exported by hack/build-flags.sh
|
||
go build -ldflags "${KN_BUILD_LD_FLAGS:-}" -o kn ./cmd/...
|
||
|
||
if file kn | grep -q -i "Windows"; then
|
||
mv kn kn.exe
|
||
fi
|
||
}
|
||
|
||
go_build_with_goos_goarch() {
|
||
GOOS="${1:-}"
|
||
GOARCH="${2:-}"
|
||
|
||
if [ -z "${GOOS}" ] || [ -z "${GOARCH}" ]; then
|
||
echo "❌ Missing GOOS or GOARCH. Please provide both GOOS and GOARCH as arguments."
|
||
exit 1
|
||
fi
|
||
|
||
echo "🚧 Compile for GOOS=${GOOS} GOARCH=${GOARCH}"
|
||
|
||
# Env var exported by hack/build-flags.sh
|
||
GOOS="${GOOS}" GOARCH="${GOARCH}" go build -ldflags "${KN_BUILD_LD_FLAGS:-}" -o kn ./cmd/...
|
||
|
||
if $(file kn | grep -q -i "Windows"); then
|
||
mv kn kn.exe
|
||
fi
|
||
}
|
||
|
||
go_test() {
|
||
local test_output
|
||
test_output="$(mktemp /tmp/kn-client-test-output.XXXXXX)"
|
||
|
||
local red=""
|
||
local reset=""
|
||
# Use color only when a terminal is set
|
||
if [ -t 1 ]; then
|
||
red="[31m"
|
||
reset="[39m"
|
||
fi
|
||
|
||
echo "🧪 ${X}Test"
|
||
set +e
|
||
go test -v ./cmd/... ./pkg/... >$test_output 2>&1
|
||
local err=$?
|
||
if [ $err -ne 0 ]; then
|
||
echo "🔥 ${red}Failure${reset}"
|
||
cat $test_output | sed -e "s/^.*\(FAIL.*\)$/$red\1$reset/"
|
||
rm $test_output
|
||
exit $err
|
||
fi
|
||
rm $test_output
|
||
}
|
||
|
||
check_license() {
|
||
echo "⚖️ ${S}License"
|
||
local required_keywords=("Authors" "Apache License" "LICENSE-2.0")
|
||
local extensions_to_check=("sh" "go" "yaml" "yml" "json")
|
||
|
||
local check_output
|
||
check_output="$(mktemp /tmp/kn-client-licence-check.XXXXXX)"
|
||
for ext in "${extensions_to_check[@]}"; do
|
||
find . -name "*.$ext" -a \! -path "./.*" -a \! -path "./third_party/*" -print0 |
|
||
while IFS= read -r -d '' path; do
|
||
for rword in "${required_keywords[@]}"; do
|
||
if ! grep -q "$rword" "$path"; then
|
||
echo " $path" >> $check_output
|
||
fi
|
||
done
|
||
done
|
||
done
|
||
if [ -s $check_output ]; then
|
||
echo "🔥 No license header found in:"
|
||
cat $check_output | sort | uniq
|
||
echo "🔥 Please fix and retry."
|
||
rm $check_output
|
||
exit 1
|
||
fi
|
||
rm $check_output
|
||
}
|
||
|
||
|
||
update_deps() {
|
||
echo "🚒 Update"
|
||
if has_flag --verbose; then
|
||
"$(basedir)"/hack/update-deps.sh
|
||
else
|
||
"$(basedir)"/hack/update-deps.sh 1>/dev/null 2>&1
|
||
fi
|
||
}
|
||
|
||
generate_docs() {
|
||
echo "📖 Docs"
|
||
rm -rf "./docs/cmd"
|
||
mkdir -p "./docs/cmd"
|
||
go run "./hack/generate-docs.go" "."
|
||
}
|
||
|
||
watch() {
|
||
local command="./hack/build.sh --fast"
|
||
local fswatch_opts='-e "^\..*$" -o pkg cmd'
|
||
if has_flag --test -t; then
|
||
command="$command --test"
|
||
fi
|
||
if has_flag --verbose; then
|
||
fswatch_opts="$fswatch_opts -v"
|
||
fi
|
||
set +e
|
||
which fswatch >/dev/null 2>&1
|
||
if [ $? -ne 0 ]; then
|
||
local green="[32m"
|
||
local reset="[39m"
|
||
|
||
echo "🤷 Watch: Cannot find ${green}fswatch${reset}"
|
||
echo "🌏 Please see ${green}http://emcrisostomo.github.io/fswatch/${reset} for installation instructions"
|
||
exit 1
|
||
fi
|
||
set -e
|
||
|
||
echo "🔁 Watch"
|
||
fswatch "${fswatch_opts[@]}" | xargs -n1 -I{} sh -c "$command && echo 👌 OK"
|
||
}
|
||
|
||
# Dir where this script is located
|
||
basedir() {
|
||
# Default is current directory
|
||
local script=${BASH_SOURCE[0]}
|
||
|
||
# Resolve symbolic links
|
||
if [ -L $script ]; then
|
||
if readlink -f $script >/dev/null 2>&1; then
|
||
script=$(readlink -f $script)
|
||
elif readlink $script >/dev/null 2>&1; then
|
||
script=$(readlink $script)
|
||
elif realpath $script >/dev/null 2>&1; then
|
||
script=$(realpath $script)
|
||
else
|
||
echo "ERROR: Cannot resolve symbolic link $script"
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
local dir full_dir
|
||
dir=$(dirname "$script")
|
||
full_dir=$(cd "${dir}/.." && pwd)
|
||
echo "${full_dir}"
|
||
}
|
||
|
||
# Checks if a flag is present in the arguments.
|
||
has_flag() {
|
||
filters=("$@")
|
||
for var in "${ARGS[@]}"; do
|
||
for filter in "${filters[@]}"; do
|
||
if [ "$var" = "$filter" ]; then
|
||
return 0
|
||
fi
|
||
done
|
||
done
|
||
return 1
|
||
}
|
||
|
||
cross_build() {
|
||
# Env var exported by hack/build-flags.sh
|
||
local ld_flags="${KN_BUILD_LD_FLAGS:-}"
|
||
local failed=0
|
||
|
||
echo "⚔️ ${S}Compile"
|
||
|
||
export CGO_ENABLED=0
|
||
echo " 🐧 kn-linux-amd64"
|
||
GOOS=linux GOARCH=amd64 go build -ldflags "${ld_flags}" -o ./kn-linux-amd64 ./cmd/... || failed=1
|
||
echo " 💪 kn-linux-arm64"
|
||
GOOS=linux GOARCH=arm64 go build -ldflags "${ld_flags}" -o ./kn-linux-arm64 ./cmd/... || failed=1
|
||
echo " 🍏 kn-darwin-amd64"
|
||
GOOS=darwin GOARCH=amd64 go build -ldflags "${ld_flags}" -o ./kn-darwin-amd64 ./cmd/... || failed=1
|
||
echo " 🍎 kn-darwin-arm64"
|
||
GOOS=darwin GOARCH=arm64 go build -ldflags "${ld_flags}" -o ./kn-darwin-arm64 ./cmd/... || failed=1
|
||
echo " 🎠 kn-windows-amd64.exe"
|
||
GOOS=windows GOARCH=amd64 go build -ldflags "${ld_flags}" -o ./kn-windows-amd64.exe ./cmd/... || failed=1
|
||
echo " Z kn-linux-s390x"
|
||
GOOS=linux GOARCH=s390x go build -ldflags "${ld_flags}" -o ./kn-linux-s390x ./cmd/... || failed=1
|
||
echo " P kn-linux-ppc64le"
|
||
GOOS=linux GOARCH=ppc64le go build -ldflags "${ld_flags}" -o ./kn-linux-ppc64le ./cmd/... || failed=1
|
||
|
||
return ${failed}
|
||
}
|
||
|
||
# Spaced fillers needed for certain emojis in certain terminals
|
||
S=""
|
||
X=""
|
||
|
||
# Calculate space fixing variables S and X
|
||
apply_emoji_fixes() {
|
||
# Temporary fix for iTerm issue https://gitlab.com/gnachman/iterm2/issues/7901
|
||
if [ -n "${ITERM_PROFILE:-}" ]; then
|
||
S=" "
|
||
# This issue has been fixed with iTerm2 3.3.7, so let's check for this
|
||
# We can remove this code altogether if iTerm2 3.3.7 is in common usage everywhere
|
||
if [ -n "${TERM_PROGRAM_VERSION}" ]; then
|
||
args=$(echo $TERM_PROGRAM_VERSION | sed -e 's#[^0-9]*\([0-9]*\)[.]\([0-9]*\)[.]\([0-9]*\)\([0-9A-Za-z-]*\)#\1 \2 \3#')
|
||
expanded=$(printf '%03d%03d%03d' $args)
|
||
if [ $expanded -lt "003003007" ]; then
|
||
X=" "
|
||
fi
|
||
fi
|
||
fi
|
||
}
|
||
|
||
# Display a help message.
|
||
display_help() {
|
||
local command="${1:-}"
|
||
cat <<EOT
|
||
Knative client build script
|
||
|
||
Usage: $(basename "${BASH_SOURCE[0]}") [... options ...]
|
||
|
||
with the following options:
|
||
|
||
-f --fast Only compile (without dep update, formatting, testing, doc gen)
|
||
-p --platform Specify the target platform for cross-compilation (e.g., linux amd64, darwin amd64)"
|
||
-t --test Run tests when used with --fast or --watch
|
||
-c --codegen Runs formatting, doc gen and update without compiling/testing
|
||
-w --watch Watch for source changes and recompile in fast mode
|
||
-x --all Only build cross platform binaries without code-generation/testing
|
||
-h --help Display this help message
|
||
--lint Run the code linter
|
||
--verbose More output
|
||
--debug Debug information for this script (set -x)
|
||
|
||
You can add a symbolic link to this build script into your PATH so that it can be
|
||
called from everywhere. E.g.:
|
||
|
||
ln -s $(basedir)/hack/build.sh /usr/local/bin/kn_build.sh
|
||
|
||
Examples:
|
||
|
||
* Update deps, format, license check,
|
||
gen docs, compile, test: ........................ build.sh
|
||
* Compile only: ................................... build.sh --fast
|
||
* Build cross platform binaries for a platform: ... build.sh -p linux amd64
|
||
* Run only tests: ................................. build.sh --test
|
||
* Compile with tests: ............................. build.sh -f -t
|
||
* Automatic recompilation: ........................ build.sh --watch
|
||
* Build cross platform binaries: .................. build.sh --all
|
||
EOT
|
||
}
|
||
|
||
if has_flag --debug; then
|
||
export PS4='+($(basename ${BASH_SOURCE[0]}):${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
|
||
set -x
|
||
fi
|
||
|
||
# Shared funcs from hack repo
|
||
# shellcheck disable=SC1090
|
||
source "$(go run knative.dev/hack/cmd/script library.sh)"
|
||
|
||
# Shared funcs with CI
|
||
while IFS= read -r -d '' file; do
|
||
source "${file}"
|
||
done < <(find "$(basedir)/hack/build.sh.d" -name '*.sh' -print0)
|
||
source "$(basedir)"/hack/build-flags.sh
|
||
|
||
# Fixe emoji labels for certain terminals
|
||
apply_emoji_fixes
|
||
|
||
run "$@"
|