425 lines
14 KiB
Bash
Executable File
425 lines
14 KiB
Bash
Executable File
#!/bin/bash
|
|
# Copyright 2025 Huawei Technologies Co., Ltd
|
|
#
|
|
# 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.
|
|
|
|
set -euo pipefail # Exit on error, undefined variables, and pipe failures
|
|
|
|
# Get OS information
|
|
readonly OS_NAME=$(uname -s)
|
|
readonly ARCH=$(uname -m)
|
|
|
|
# Default shellcheck version
|
|
SHELLCHECK_VERSION="v0.7.1"
|
|
|
|
# Color output
|
|
readonly RED='\033[0;31m'
|
|
readonly GREEN='\033[0;32m'
|
|
readonly YELLOW='\033[1;33m'
|
|
readonly BLUE='\033[0;34m'
|
|
readonly NC='\033[0m' # No Color
|
|
|
|
# Logging functions
|
|
log_info() {
|
|
echo -e "${BLUE}[INFO]${NC} $*"
|
|
}
|
|
|
|
log_warning() {
|
|
echo -e "${YELLOW}[WARNING]${NC} $*" >&2
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}[ERROR]${NC} $*" >&2
|
|
}
|
|
|
|
log_success() {
|
|
echo -e "${GREEN}[SUCCESS]${NC} $*"
|
|
}
|
|
|
|
# Show help information
|
|
show_help() {
|
|
cat << EOF
|
|
Usage: $0 [OPTIONS]
|
|
|
|
Install codecheck tools for different platforms.
|
|
|
|
On Windows: Only install Ruby gems (chef-utils, mdl) - ShellCheck is skipped
|
|
On Linux/macOS: Install shellcheck and optionally Ruby gems
|
|
|
|
Options:
|
|
-v, --version VERSION Specify shellcheck version (default: $SHELLCHECK_VERSION) - Linux/macOS only
|
|
-h, --help Show this help message
|
|
--install-dir DIR Custom installation directory - Linux only
|
|
--install-gems Install Ruby gems (chef-utils, mdl)
|
|
|
|
Examples:
|
|
$0 # Install with default settings
|
|
$0 --install-gems # Install Ruby gems on all platforms
|
|
$0 -v v0.9.0 # Install specific shellcheck version (Linux/macOS)
|
|
$0 --install-dir /usr/local # Install to custom directory (Linux)
|
|
|
|
Platform-specific behavior:
|
|
- Windows: Only installs Ruby gems (ShellCheck is intentionally skipped as it has no reference value on Windows)
|
|
- Linux: Installs shellcheck and optionally Ruby gems
|
|
- macOS: Installs shellcheck via Homebrew and optionally Ruby gems
|
|
|
|
EOF
|
|
}
|
|
|
|
# Check if command exists
|
|
command_exists() {
|
|
command -v "$1" >/dev/null 2>&1
|
|
}
|
|
|
|
# Check prerequisites for Linux installation
|
|
check_linux_prerequisites() {
|
|
local missing_tools=()
|
|
|
|
if ! command_exists xz && ! command_exists tar; then
|
|
missing_tools+=("xz or tar")
|
|
fi
|
|
|
|
if ! command_exists curl && ! command_exists wget; then
|
|
missing_tools+=("curl or wget")
|
|
fi
|
|
|
|
if [[ ${#missing_tools[@]} -gt 0 ]]; then
|
|
log_error "Missing required tools: ${missing_tools[*]}"
|
|
log_info "Please install them using your package manager:"
|
|
log_info " Ubuntu/Debian: sudo apt-get install ${missing_tools[*]}"
|
|
log_info " CentOS/RHEL: sudo yum install ${missing_tools[*]}"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Download file with curl or wget
|
|
download_file() {
|
|
local url="$1"
|
|
local output="$2"
|
|
|
|
if command_exists wget; then
|
|
wget -O "$output" "$url" "--no-check-certificate"
|
|
elif command_exists curl; then
|
|
curl --ssl-no-revoke -k -f -L -o "$output" "$url"
|
|
else
|
|
log_error "Neither curl nor wget is available"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
install_linux_codecheck_tool() {
|
|
# Check system architecture
|
|
case "$ARCH" in
|
|
x86_64|aarch64)
|
|
log_info "Supported architecture detected: $ARCH"
|
|
;;
|
|
*)
|
|
log_error "Unsupported architecture: $ARCH"
|
|
log_info "Supported architectures: x86_64 aarch64"
|
|
log_info "For other architectures, please install shellcheck manually from your package manager"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
log_info "System architecture: $ARCH, starting installation..."
|
|
|
|
# Check sudo privileges for regular users
|
|
if [[ $EUID -ne 0 ]]; then
|
|
log_info "Checking sudo privileges..."
|
|
if ! command_exists sudo; then
|
|
log_error "sudo command not found. Regular user installation requires sudo privileges."
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
check_linux_prerequisites
|
|
|
|
local package_shellcheck_name="shellcheck-${SHELLCHECK_VERSION}"
|
|
local temp_dir="/tmp"
|
|
|
|
log_info "Installing shellcheck version: $SHELLCHECK_VERSION"
|
|
|
|
# Determine installation directory
|
|
local install_dir="${INSTALL_DIR:-/usr/bin}"
|
|
if [[ ! -w "$install_dir" && $EUID -ne 0 ]]; then
|
|
log_info "Installation directory $install_dir requires root access"
|
|
if ! sudo -v >/dev/null 2>&1; then
|
|
log_error "Regular user installation requires sudo privileges. Please run with a user that has sudo access."
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Unified URL building logic
|
|
local filename
|
|
local download_url
|
|
|
|
case "$ARCH" in
|
|
x86_64)
|
|
filename="${package_shellcheck_name}.linux.x86_64.tar.xz"
|
|
download_url="https://tools.mindspore.cn/tools/check/shellcheck/${package_shellcheck_name}/$filename"
|
|
;;
|
|
aarch64)
|
|
filename="${package_shellcheck_name}.linux.aarch64.tar.xz"
|
|
download_url="https://tools.mindspore.cn/tools/check/shellcheck/${package_shellcheck_name}/$filename"
|
|
;;
|
|
*)
|
|
log_error "Unsupported architecture: $ARCH"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
# Download
|
|
cd "$temp_dir" || {
|
|
log_error "Cannot change to temp directory: $temp_dir"
|
|
exit 1
|
|
}
|
|
|
|
log_info "Downloading shellcheck from: $download_url"
|
|
if ! download_file "$download_url" "$filename"; then
|
|
log_error "Failed to download shellcheck"
|
|
log_info "Please check:"
|
|
log_info "1. Network connectivity"
|
|
log_info "2. Version $SHELLCHECK_VERSION availability"
|
|
log_info "3. URL: $download_url"
|
|
exit 1
|
|
fi
|
|
|
|
# Verify downloaded file
|
|
if [[ ! -f "$filename" ]]; then
|
|
log_error "Downloaded file not found: $filename"
|
|
exit 1
|
|
fi
|
|
|
|
# Extract
|
|
log_info "Extracting shellcheck package..."
|
|
if command_exists tar; then
|
|
if ! tar -xf "$filename"; then
|
|
log_error "Failed to extract shellcheck package"
|
|
exit 1
|
|
fi
|
|
else
|
|
log_error "tar command not found, cannot extract package"
|
|
exit 1
|
|
fi
|
|
|
|
# Find the shellcheck binary in the extracted directory
|
|
local shellcheck_binary
|
|
if [[ -f "${package_shellcheck_name}/shellcheck" ]]; then
|
|
shellcheck_binary="${package_shellcheck_name}/shellcheck"
|
|
elif [[ -f "shellcheck" ]]; then
|
|
shellcheck_binary="shellcheck"
|
|
else
|
|
# Try to find it in any subdirectory
|
|
shellcheck_binary=$(find "/tmp/${package_shellcheck_name}" -name "shellcheck" -type f 2>/dev/null | head -1)
|
|
if [[ -z "$shellcheck_binary" ]]; then
|
|
log_error "Could not find shellcheck binary in extracted files"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Install
|
|
log_info "Installing shellcheck to $install_dir/shellcheck"
|
|
if [[ $EUID -eq 0 ]]; then
|
|
# Running as root
|
|
mv "$shellcheck_binary" "$install_dir/shellcheck"
|
|
chmod 755 "$install_dir/shellcheck"
|
|
else
|
|
# Running as regular user, use sudo
|
|
sudo mv "$shellcheck_binary" "$install_dir/shellcheck"
|
|
sudo chmod 755 "$install_dir/shellcheck"
|
|
fi
|
|
|
|
# Cleanup
|
|
log_info "Cleaning up temporary files..."
|
|
rm -rf "/tmp/${package_shellcheck_name}" 2>/dev/null || true
|
|
rm -f "/tmp/${filename}" 2>/dev/null || true
|
|
|
|
log_success "Shellcheck installed successfully to $install_dir/shellcheck"
|
|
}
|
|
|
|
install_windows_codecheck_tools() {
|
|
log_info "Installing Windows codecheck tools..."
|
|
log_warning "================================================================"
|
|
log_warning "ShellCheck intentionally skipped on Windows"
|
|
log_warning "Reason: ShellCheck has no reference value in Windows environment"
|
|
log_warning "Windows shell environments differ significantly from Linux/macOS"
|
|
log_warning "================================================================"
|
|
|
|
# Install Ruby gems if available and requested
|
|
if command_exists gem && [[ "$INSTALL_GEMS" == "true" ]]; then
|
|
log_info "Installing Ruby gems..."
|
|
gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/
|
|
gem install chef-utils -v 16.6.14
|
|
gem install mdl
|
|
log_success "Ruby gems installed successfully"
|
|
else
|
|
log_info "Skipping Ruby gems installation (gem not found or not requested)"
|
|
log_info "To install Ruby gems, use the --install-gems flag"
|
|
fi
|
|
|
|
log_success "Windows codecheck tools installation completed"
|
|
log_info "Note: ShellCheck was intentionally not installed as it has no reference value on Windows"
|
|
}
|
|
|
|
install_mac_codecheck_tools() {
|
|
log_info "Installing macOS codecheck tools..."
|
|
|
|
if ! command_exists brew; then
|
|
log_error "Homebrew is required but not installed. Please install Homebrew first."
|
|
log_info "You can install Homebrew from: https://brew.sh/"
|
|
log_info "Install command:"
|
|
log_info ' /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"'
|
|
exit 1
|
|
fi
|
|
|
|
log_info "Installing shellcheck via Homebrew..."
|
|
brew install shellcheck
|
|
brew link --overwrite shellcheck
|
|
|
|
# Install Ruby gems if needed
|
|
if command_exists gem && [[ "$INSTALL_GEMS" == "true" ]]; then
|
|
log_info "Installing Ruby gems..."
|
|
gem install chef-utils -v 16.6.14
|
|
gem install mdl
|
|
fi
|
|
|
|
log_success "macOS codecheck tools installed successfully"
|
|
}
|
|
|
|
check_shellcheck_version() {
|
|
# Skip version check on Windows
|
|
if [[ "$OS_NAME" == MINGW* || "$OS_NAME" == MSYS* || "$OS_NAME" == CYGWIN* ]]; then
|
|
log_info "Skipping shellcheck version check on Windows (ShellCheck has no reference value on Windows)"
|
|
return 0
|
|
fi
|
|
|
|
log_info "Checking shellcheck version..."
|
|
|
|
if ! command_exists shellcheck; then
|
|
log_warning "shellcheck is not installed or not in PATH"
|
|
return 1
|
|
fi
|
|
|
|
local version_output
|
|
if ! version_output=$(shellcheck -V 2>/dev/null); then
|
|
log_warning "Failed to get shellcheck version"
|
|
return 1
|
|
fi
|
|
|
|
# Robust version parsing
|
|
local version_str
|
|
if [[ "$version_output" =~ [Vv]ersion[[:space:]]*([0-9]+\.[0-9]+\.[0-9]+) ]]; then
|
|
version_str="${BASH_REMATCH[1]}"
|
|
else
|
|
version_str=$(echo "$version_output" | grep -i version | head -1 | awk '{print $2}')
|
|
fi
|
|
|
|
if [[ -z "$version_str" ]]; then
|
|
log_warning "Could not parse shellcheck version"
|
|
return 1
|
|
fi
|
|
|
|
log_info "Installed shellcheck version: $version_str"
|
|
|
|
# Version comparison (extract version number from SHELLCHECK_VERSION if it has 'v' prefix)
|
|
local required_version="${SHELLCHECK_VERSION#v}"
|
|
|
|
# Use sort -V for version comparison
|
|
if printf '%s\n' "$required_version" "$version_str" | sort -V -C ; then
|
|
log_success "shellcheck version meets requirement (>= $required_version)"
|
|
return 0
|
|
else
|
|
log_warning "shellcheck version $version_str is less than $required_version"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Parse command line arguments
|
|
parse_arguments() {
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
-v|--version)
|
|
if [[ -n "${2:-}" ]]; then
|
|
SHELLCHECK_VERSION="$2"
|
|
shift 2
|
|
else
|
|
log_error "'--version' requires a non-empty argument"
|
|
exit 1
|
|
fi
|
|
;;
|
|
-h|--help)
|
|
show_help
|
|
exit 0
|
|
;;
|
|
--install-dir)
|
|
if [[ -n "${2:-}" ]]; then
|
|
INSTALL_DIR="$2"
|
|
shift 2
|
|
else
|
|
log_error "'--install-dir' requires a non-empty argument"
|
|
exit 1
|
|
fi
|
|
;;
|
|
--install-gems)
|
|
INSTALL_GEMS="true"
|
|
shift
|
|
;;
|
|
*)
|
|
log_error "Unknown option: $1"
|
|
show_help
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
main() {
|
|
log_info "Detected OS: $OS_NAME, Architecture: $ARCH"
|
|
|
|
parse_arguments "$@"
|
|
|
|
case "$OS_NAME" in
|
|
MINGW*|MSYS*|CYGWIN*)
|
|
log_info "Windows environment detected"
|
|
install_windows_codecheck_tools
|
|
;;
|
|
Linux)
|
|
log_info "GNU/Linux detected"
|
|
install_linux_codecheck_tool
|
|
;;
|
|
Darwin)
|
|
log_info "macOS detected"
|
|
install_mac_codecheck_tools
|
|
;;
|
|
*)
|
|
log_error "Unsupported operating system: $OS_NAME"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
if check_shellcheck_version; then
|
|
log_success "Codecheck tools installation completed successfully"
|
|
else
|
|
log_warning "Installation completed with some warnings"
|
|
if [[ "$OS_NAME" == MINGW* || "$OS_NAME" == MSYS* || "$OS_NAME" == CYGWIN* ]]; then
|
|
log_info "On Windows, only Ruby gems were installed (ShellCheck was intentionally skipped as it has no reference value on Windows)"
|
|
else
|
|
log_info "Please verify the installation manually"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Initialize default values
|
|
INSTALL_GEMS="false"
|
|
|
|
main "$@" |