blob: 604cc7c8ec3fe128330b8f80de6287e5017a5bad [file] [log] [blame]
#!/bin/bash
# shellcheck disable=2311
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
set -eo pipefail
set +o posix
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
DORIS_HOME="$(
cd "${SCRIPT_DIR}/.." &>/dev/null
pwd
)"
DORIS_THIRDPARTY="$(
source "${DORIS_HOME}/env.sh" &>/dev/null
echo "${DORIS_THIRDPARTY}"
)"
INSTALL_PATH="${DORIS_THIRDPARTY}/installed/bin"
SHELLCHECK=''
SHFMT=''
log() {
local level="${1}"
local message="${2}"
local date
date="$(date +'%Y-%m-%d %H:%M:%S')"
if [[ "${level}" == 'INFO' ]]; then
level="[\033[32;1m ${level} \033[0m]"
elif [[ "${level}" == 'WARNING' ]]; then
level="[\033[33;1m${level}\033[0m]"
elif [[ "${level}" == 'ERROR' ]]; then
level="[\033[31;1m ${level} \033[0m]"
fi
echo -e "${level} ${date} - ${message}"
}
log_info() {
local message="${1}"
log 'INFO' "${message}"
}
log_warning() {
local message="${1}"
log 'WARNING' "${message}"
}
log_error() {
local message="${1}"
log 'ERROR' "${message}"
exit 1
}
get_version() {
local program="${1}"
local tool="${program##*/}"
case "${tool}" in
'shellcheck') "${program}" --version | sed -n 's/version: \(.*\)/\1/p' ;;
'shfmt') "${program}" --version ;;
*) ;;
esac
}
check_tool() {
local tool="${1}"
local version="${2}"
local program
if program="$(command -v "${tool}" 2>/dev/null)" && [[ ! "$(get_version "${program}")" < "${version}" ]]; then
echo "${program}"
return 0
fi
program="${INSTALL_PATH}/${tool}"
if [[ -f "${program}" && ! "$(get_version "${program}")" < "${version}" ]]; then
echo "${program}"
return 0
fi
return 255
}
get_url() {
local tool="${1}"
local os
local arch
os="$(uname -s | awk '{ print tolower($0) }')"
arch="$(uname -m | awk '{ print tolower($0) }')"
if [[ "${tool}" == 'shellcheck' ]]; then
if [[ "${arch}" == 'arm64' ]]; then
arch='aarch64'
fi
echo "https://github.com/koalaman/shellcheck/releases/download/v0.8.0/shellcheck-v0.8.0.${os}.${arch}.tar.xz"
return 0
elif [[ "${tool}" == 'shfmt' ]]; then
if [[ "${arch}" == 'x86_64' ]]; then
arch='amd64'
elif [[ "${arch}" == 'aarch64' ]]; then
arch='arm64'
fi
echo "https://github.com/mvdan/sh/releases/download/v3.5.1/shfmt_v3.5.1_${os}_${arch}"
return 0
fi
return 255
}
get_md5() {
local tool="${1}"
local os
local arch
os="$(uname -s | awk '{ print tolower($0) }')"
arch="$(uname -m | awk '{ print tolower($0) }')"
case "${tool}" in
'shellcheck')
case "${os}" in
'linux')
case "${arch}" in
'x86_64') echo '86ee889b1e771bc8292a7043df4b962a' ;;
'arm64' | 'aarch64') echo 'a0338c733d1283a51777b27edf9ccc96' ;;
*) ;;
esac
;;
'darwin')
case "${arch}" in
'x86_64') echo 'e744840256a77a1a277e81a3032f7bf4' ;;
*) ;;
esac
;;
*) ;;
esac
;;
'shfmt')
case "${os}" in
'linux')
case "${arch}" in
'x86_64') echo '1d234f204e249bf1c524015ce842b117' ;;
'arm64' | 'aarch64') echo '5c8494fd257d5cd9db1eef48af967e47' ;;
*) ;;
esac
;;
'darwin')
case "${arch}" in
'x86_64') echo '42f14325207a47f3177c96683c5085a4' ;;
'arm64' | 'aarch64') echo 'a9c51e5d4aeebfa2c8cc70af3006bc4e' ;;
*) ;;
esac
;;
*) ;;
esac
;;
*) ;;
esac
}
download_tool() {
local url="${1}"
local package="${2}"
local md5="${3}"
log_info "Download ${tool} from ${url}"
if [[ -f "${package}" && "$(md5sum "${package}" | awk '{print $1}')" == "${md5}" ]]; then
log_info "${tool} has been downloaded succesfully!"
return 0
fi
for i in {0..2}; do
if [[ "${i}" -gt 0 ]]; then
log_warning "Retry #${i}..."
fi
if curl --connect-timeout 5 --speed-limit 1000 --speed-time 30 -L "${url}" -o "${package}" &&
[[ "$(md5sum "${package}" | awk '{print $1}')" == "${md5}" ]]; then
log_info "${tool} has been downloaded succesfully!"
return 0
fi
done
return 255
}
install_shellcheck() {
local tool="shellcheck"
local url
local package
local md5
local dir
SYSTEM_NAME="$(uname -s)"
if [[ "${SYSTEM_NAME}" == 'Darwin' ]] && command -v 'brew' &>/dev/null; then
brew install "${tool}"
else
url="$(get_url "${tool}")"
package="${url##*/}"
md5="$(get_md5 "${tool}")"
download_tool "${url}" "${package}" "${md5}"
log_info "Set ${tool} up."
dir="$(mktemp -d)"
tar -xf "${package}" -C "${dir}" --strip-component=1
mkdir -p "${INSTALL_PATH}"
mv "${dir}/${tool}" "${INSTALL_PATH}"
fi
}
install_shfmt() {
local tool='shfmt'
local url
local package
local md5
local dir
SYSTEM_NAME="$(uname -s)"
if [[ "${SYSTEM_NAME}" == 'Darwin' ]] && command -v 'brew' &>/dev/null; then
brew install "${tool}"
else
url="$(get_url "${tool}")"
package="${url##*/}"
md5="$(get_md5 "${tool}")"
download_tool "${url}" "${package}" "${md5}"
log_info "Set ${tool} up."
mkdir -p "${INSTALL_PATH}"
cp "${package}" "${INSTALL_PATH}/shfmt"
chmod a+x "${INSTALL_PATH}/shfmt"
fi
}
install_tools_if_neccessary() {
while ! SHELLCHECK="$(check_tool 'shellcheck' '0.8.0')"; do
log_warning 'shellcheck was not found.'
install_shellcheck
done
log_info "shellcheck found: ${SHELLCHECK}"
while ! SHFMT="$(check_tool 'shfmt' '3.5.1')"; do
log_warning 'shfmt was not found.'
install_shfmt
done
log_info "shfmt found: ${SHFMT}"
}
find_shell_scripts() {
local path="${1}"
local exclude_patterns
local content
local files=()
content="$(grep 'sh_checker_exclude:' "${DORIS_HOME}/.github/workflows/shellcheck.yml")"
read -r -a exclude_patterns <<<"${content#*sh_checker_exclude: }"
while read -r file; do
local matched=false
for pattern in "${exclude_patterns[@]}"; do
if echo "${file:((${#DORIS_HOME} + 1))}" | grep -E "${pattern}" &>/dev/null; then
matched=true
break
fi
done
if ! "${matched}"; then
files+=("${file}")
fi
done < <(find "${path}" -type f -name '*.sh')
echo "${files[@]}"
}
run_tool() {
set +e
local tool="${1}"
local opt="${2}"
local status
shift 2
pushd "${DORIS_HOME}" >/dev/null
log_info "Run tool: ${tool}"
"${tool}" ${opt+${opt}} "${@}"
status="${?}"
popd >/dev/null
return "${status}"
}
run_shellcheck() {
run_tool "${SHELLCHECK}" '' "${@}"
}
run_shfmt() {
run_tool "${SHFMT}" '-d' "${@}"
}
main() {
local files
local shellcheck_result=0
local shfmt_result=0
install_tools_if_neccessary
read -r -a files < <(find_shell_scripts "${DORIS_HOME}")
run_shellcheck "${files[@]}" || shellcheck_result="${?}"
run_shfmt "${files[@]}" || shfmt_result="${?}"
if [[ "${shellcheck_result}" -ne 0 || "${shfmt_result}" -ne 0 ]]; then
echo
log_error 'Some issues were detected!'
else
log_info 'Success!'
fi
}
main "${@}"