├── LICENSE ├── README_CN.md ├── README.md ├── install.sh └── gvm.sh /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Jetsung Chan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # Go 语言 2 | 3 | - 支持 **Linux / MacOS / FreeBSD** 等系统 4 | 5 | [English](./README.md) | 简体中文 6 | 7 | - **Golang Version Manager:** [gvm.sh](#go-语言版本管理) 8 | - **Golang Install:** [install.sh](#go-语言安装) 9 | 10 | --- 11 | 12 | # Go 语言版本管理 13 | 14 | ## 安装 15 | 16 | ```bash 17 | curl -fsL https://raw.gitcode.com/jetsung/golang-install/raw/main/gvm.sh | bash 18 | 19 | # 或者 20 | git clone https://gitcode.com/jetsung/golang-install.git 21 | cd golang-install 22 | ./gvm.sh -i 23 | 24 | # source $HOME/.zshrc 25 | # source $HOME/.bashrc 26 | 27 | gvm version 28 | ``` 29 | 30 | ## 帮助 31 | 32 | ```bash 33 | # gvm -h 34 | 35 | gvm 1.1.1 36 | 37 | Golang Version Manager 38 | 39 | Usage: gvm [OPTIONS] [COMMAND] 40 | 41 | Commands: 42 | use [VERSION|latest] Change Go version 43 | install [VERSION|latest] Install a new go version 44 | uninstall Uninstall a Go version 45 | list List all locally installed go versions 46 | remote List all remote go versions 47 | version Print the current go version 48 | 49 | Options: 50 | -i, --install 51 | Install Golang Version Manager 52 | 53 | -u, --update 54 | Update Golang Version Manager 55 | 56 | -h, --help 57 | Print help information 58 | 59 | -v, --version 60 | Print Gvm version information 61 | ``` 62 | 63 | # Go 语言安装 64 | 65 | 最新版 Go 语言一键安装脚本。 66 | 67 | - 支持自定义**版本** 68 | - 支持自定义**GOPATH** 69 | 70 | **注意** 71 | 72 | - GOROOT: `$HOME/.go` 73 | - 默认安装最新版本的 **go version**, **GOPATH** 目录为 `$HOME/go` 74 | 75 | ## 安装 76 | 77 | ### 在线安装 78 | 79 | #### 默认安装 80 | 81 | ```sh 82 | curl -fsL https://raw.gitcode.com/jetsung/golang-install/raw/main/install.sh | bash 83 | ``` 84 | 85 | #### 自定义安装 86 | 87 | - **MY_DIY_GO_VERSION** 是自定义版本号, 例如: `1.12.8` 88 | - **MY_DIY_GO_PATH** 是自定义版本号, 例如: `/home/myhome/go` 89 | 90 | ```sh 91 | curl -fsL https://raw.gitcode.com/jetsung/golang-install/raw/main/install.sh | bash -s -- -v MY_DIY_GO_VERSION -p MY_DIY_GO_PATH 92 | ``` 93 | 94 | ### 离线执行 95 | 96 | 保存脚本并且命名为 **install.sh** 97 | 98 | ```sh 99 | # 默认配置 100 | bash install.sh 101 | 102 | # 自定义 103 | bash install.sh -v 1.12.8 -p /home/myhome/go 104 | ``` 105 | 106 | 脚本可执行权限,那么同时可以自定义 Go 版本和 GOPATH。 107 | 108 | ```sh 109 | # 添加可执行权限 110 | chmod +x install.sh 111 | 112 | # 默认配置 113 | ./install.sh 114 | 115 | # 自定义 116 | ./install.sh -v 1.12.8 -p /home/myhome/go 117 | ``` 118 | 119 | **使用说明** 120 | 121 | ```sh 122 | Go install 123 | 124 | USAGE: 125 | install.sh [OPTIONS] 126 | 127 | OPTIONS: 128 | -p, --path 129 | Set GOPATH. (default: $HOME/go) 130 | 131 | -r, --root 132 | Set GOROOT. (default: $HOME/.go) 133 | 134 | -v, --version 135 | Set golang version. 136 | 137 | -h, --help 138 | Print help information. 139 | ``` 140 | 141 | ## License 142 | 143 | This project is licensed under the [MIT license](./LICENSE). 144 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Golang 2 | 3 | - Support **Linux / MacOS / FreeBSD** 4 | 5 | English | [简体中文](./README_CN.md) 6 | 7 | - **Golang Version Manager:** [gvm.sh](#golang-version-manager) 8 | - **Golang Install:** [install.sh](#golang-install) 9 | 10 | --- 11 | 12 | # Golang Version Manager 13 | 14 | ## Install 15 | 16 | ```bash 17 | curl -fsL https://github.com/jetsung/golang-install/raw/main/gvm.sh | bash 18 | 19 | # or 20 | git clone https://github.com/jetsung/golang-install.git 21 | cd golang-install 22 | ./gvm.sh -i 23 | 24 | # source $HOME/.zshrc 25 | # source $HOME/.bashrc 26 | 27 | gvm version 28 | ``` 29 | 30 | ## Help 31 | 32 | ```bash 33 | # gvm -h 34 | 35 | gvm 1.1.1 36 | 37 | Golang Version Manager 38 | 39 | Usage: gvm [OPTIONS] [COMMAND] 40 | 41 | Commands: 42 | use [VERSION|latest] Change Go version 43 | install [VERSION|latest] Install a new go version 44 | uninstall Uninstall a Go version 45 | list List all locally installed go versions 46 | remote List all remote go versions 47 | version Print the current go version 48 | 49 | Options: 50 | -i, --install 51 | Install Golang Version Manager 52 | 53 | -u, --update 54 | Update Golang Version Manager 55 | 56 | -h, --help 57 | Print help information 58 | 59 | -v, --version 60 | Print Gvm version information 61 | ``` 62 | 63 | # Golang Install 64 | 65 | The latest version of the golang is installed. 66 | 67 | - Support custom **version** 68 | - Support custom **GOPATH** 69 | 70 | **Notice** 71 | 72 | - GOROOT: `$HOME/.go` 73 | - By default, the latest version of **go version** is installed, and the **GOPATH** directory is `$HOME/go` 74 | 75 | ## Installation 76 | 77 | ### Online 78 | 79 | #### Default install 80 | 81 | ```sh 82 | curl -fsL https://raw.githubusercontent.com/jetsung/golang-install/main/install.sh | bash 83 | ``` 84 | 85 | #### Custom version 86 | 87 | - **MY_DIY_GO_VERSION** is a custom golang version, such as: `1.12.8` 88 | - **MY_DIY_GO_PATH** is a custom gopath, such as: `/home/myhome/go` 89 | 90 | ```sh 91 | curl -fsL https://raw.githubusercontent.com/jetsung/golang-install/main/install.sh | bash -s -- -v MY_DIY_GO_VERSION -p MY_DIY_GO_PATH 92 | ``` 93 | 94 | ### Offline 95 | 96 | Save the script as a file name **install.sh** 97 | 98 | ```sh 99 | # default install 100 | bash install.sh 101 | 102 | # customize 103 | bash install.sh -v 1.12.8 -p /home/myhome/go 104 | ``` 105 | 106 | When you add executable permissions, you can customize the version and gopath. 107 | 108 | ```sh 109 | # add executable 110 | chmod +x install.sh 111 | 112 | # default install 113 | ./install.sh 114 | 115 | # customize 116 | ./install.sh -v 1.12.8 -p /home/myhome/go 117 | ``` 118 | 119 | **Usage** 120 | ./install.sh -h 121 | 122 | ```sh 123 | Go install 124 | 125 | USAGE: 126 | install.sh [OPTIONS] 127 | 128 | OPTIONS: 129 | -p, --path 130 | Set GOPATH. (default: $HOME/go) 131 | 132 | -r, --root 133 | Set GOROOT. (default: $HOME/.go) 134 | 135 | -v, --version 136 | Set golang version. 137 | 138 | -h, --help 139 | Print help information. 140 | ``` 141 | 142 | ## License 143 | 144 | This project is licensed under the [MIT license](./LICENSE). 145 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Golang-Install 4 | # Project Home Page: 5 | # https://github.com/jetsung/golang-install 6 | # https://gitcode.com/jetsung/golang-install 7 | # 8 | # Author: Jetsung Chan 9 | 10 | if [[ -n "${DEBUG:-}" ]]; then 11 | set -eux 12 | else 13 | set -euo pipefail 14 | fi 15 | 16 | # Downlaod URL 17 | DOWNLOAD_URL="https://dl.google.com/go/" 18 | DOWNLOAD_CN_URL="https://golang.google.cn/dl/" 19 | 20 | script_name=$(basename "$0") 21 | script_dir_name="${script_name##*/}" 22 | 23 | if [ -t 1 ] && command -v tput >/dev/null; then 24 | ncolors=$(tput colors || echo 0) 25 | if [ -n "$ncolors" ] && [ "$ncolors" -ge 8 ]; then 26 | bold="$(tput bold || echo)" 27 | normal="$(tput sgr0 || echo)" 28 | black="$(tput setaf 0 || echo)" 29 | red="$(tput setaf 1 || echo)" 30 | green="$(tput setaf 2 || echo)" 31 | yellow="$(tput setaf 3 || echo)" 32 | blue="$(tput setaf 4 || echo)" 33 | magenta="$(tput setaf 5 || echo)" 34 | cyan="$(tput setaf 6 || echo)" 35 | white="$(tput setaf 7 || echo)" 36 | fi 37 | fi 38 | 39 | say_warning() { 40 | printf "%b\n" "${yellow:-}${script_name}: Warning: $1${normal:-}" >&3 41 | } 42 | 43 | say_err() { 44 | printf "%b\n" "${red:-}${script_name}: Error: $1${normal:-}" >&2 45 | exit 1 46 | } 47 | 48 | say() { 49 | printf "%b\n" "${cyan:-}${script_name}:${normal:-} $1" >&3 50 | } 51 | 52 | # try profile 53 | try_profile() { 54 | if [ -z "${1:-}" ] || [ ! -f "$1" ]; then 55 | return 1 56 | fi 57 | sh_echo "$1" 58 | } 59 | 60 | # sh echo 61 | sh_echo() { 62 | command printf %s\\n "$*" 2>/dev/null 63 | } 64 | 65 | # Get PROFILE 66 | detect_profile() { 67 | local DETECTED_PROFILE="" 68 | 69 | if [ -z "${SHELL:-}" ]; then 70 | SHELL="$(grep "^$(whoami):" /etc/passwd | cut -d: -f7)" 71 | fi 72 | 73 | BASENAME_SHELL=$(basename "$SHELL") 74 | case "$BASENAME_SHELL" in 75 | 'sh') 76 | DETECTED_PROFILE="$HOME/.profile" 77 | ;; 78 | 'zsh') 79 | DETECTED_PROFILE="$HOME/.zshrc" 80 | ;; 81 | 'bash') 82 | DETECTED_PROFILE="$HOME/.bashrc" 83 | ;; 84 | 'fish') 85 | DETECTED_PROFILE="$HOME/.config/fish/config.fish" 86 | ;; 87 | *) 88 | return 89 | ;; 90 | esac 91 | 92 | if [ ! -f "$DETECTED_PROFILE" ]; then 93 | touch "$DETECTED_PROFILE" 94 | fi 95 | 96 | if [ -f "$DETECTED_PROFILE" ]; then 97 | sh_echo "$DETECTED_PROFILE" 98 | fi 99 | } 100 | 101 | # fix macos 102 | sedi() { 103 | if [ "$OS" = "darwin" ]; then 104 | sed -i "" "$@" 105 | else 106 | sed -i "$@" 107 | fi 108 | } 109 | 110 | # custom version 111 | custom_version() { 112 | if [ -n "$1" ]; then 113 | RELEASE_TAG="go$1" 114 | fi 115 | } 116 | 117 | # check in china 118 | check_in_china() { 119 | if [[ -n "${CN:-}" ]]; then 120 | return 0 # 手动指定 121 | fi 122 | if [[ "$(curl -s -m 3 -o /dev/null -w "%{http_code}" https://www.google.com)" == "000" ]]; then 123 | return 0 # 中国网络 124 | fi 125 | return 1 # 非中国网络 126 | } 127 | 128 | # Get OS bit 129 | init_arch() { 130 | ARCH=$(uname -m) 131 | BIT="$ARCH" 132 | 133 | case "$ARCH" in 134 | amd64) ARCH="amd64" ;; 135 | x86_64) ARCH="amd64" ;; 136 | i386) ARCH="386" ;; 137 | armv6l) ARCH="armv6l" ;; 138 | armv7l) ARCH="armv6l" ;; 139 | aarch64) ARCH="arm64" ;; 140 | *) 141 | say_err "Architecture $ARCH is not supported by this installation script\n" 142 | ;; 143 | esac 144 | } 145 | 146 | # Get OS version 147 | init_os() { 148 | OS=$(uname | tr '[:upper:]' '[:lower:]') 149 | 150 | case "$OS" in 151 | darwin) OS='darwin' ;; 152 | linux) OS='linux' ;; 153 | freebsd) OS='freebsd' ;; 154 | # mingw*) OS='windows';; 155 | # msys*) OS='windows';; 156 | *) 157 | say_err "OS $OS is not supported by this installation script\n" 158 | ;; 159 | esac 160 | } 161 | 162 | # install curl command 163 | install_curl_command() { 164 | if ! test -x "$(command -v curl)"; then 165 | if test -x "$(command -v yum)"; then 166 | yum install -y curl 167 | elif test -x "$(command -v apt)"; then 168 | apt install -y curl 169 | else 170 | say_err "You must pre-install the curl tool\n" 171 | fi 172 | fi 173 | } 174 | 175 | # if RELEASE_TAG was not provided, assume latest 176 | latest_version() { 177 | if [ -z "$RELEASE_TAG" ]; then 178 | RELEASE_TAG="$(curl -sL --retry 5 --max-time 30 "$RELEASE_URL" | sed -n '/toggleVisible/p' | head -n 1 | cut -d '"' -f 4)" 179 | fi 180 | } 181 | 182 | # compare version 183 | compare_version() { 184 | OLD_VERSION="none" 185 | NEW_VERSION="$RELEASE_TAG" 186 | 187 | _gobin="${GOROOT:-}/bin/go" 188 | if [ -f "$_gobin" ]; then 189 | OLD_VERSION=$("$_gobin" version | awk '{print $3}') 190 | fi 191 | 192 | if [ "$OLD_VERSION" = "$NEW_VERSION" ]; then 193 | say_err "You have installed this version: $OLD_VERSION" 194 | fi 195 | 196 | printf " 197 | Current version: \e[1;33m %s \e[0m 198 | Target version: \e[1;33m %s \e[0m 199 | " "$OLD_VERSION" "$NEW_VERSION" 200 | } 201 | 202 | check_gvm() { 203 | # shellcheck disable=SC2016 204 | if grep -q '$HOME/.gvm/env' "$PROFILE"; then 205 | IS_GVM=1 206 | fi 207 | } 208 | 209 | # Download file and unpack 210 | download_unpack() { 211 | local downurl="$1" 212 | local savepath="$2" 213 | 214 | if [ -z "$downurl" ] || [ -z "$savepath" ]; then 215 | say_err "not found downurl or savepath" 216 | fi 217 | 218 | printf "Fetching %s \n\n" "$downurl" 219 | 220 | _tempdir=$(mktemp -d -t goroot.XXXXXX) 221 | curl -Lk --connect-timeout 30 --retry 5 --retry-max-time 360 --max-time 300 "$downurl" | gunzip | tar xf - --strip-components=1 -C "$_tempdir" || { 222 | say_err "download and unpack failed" 223 | } 224 | if [ -d "$savepath" ]; then 225 | rm -rf "$savepath" 226 | fi 227 | mv "$_tempdir" "$savepath" 228 | } 229 | 230 | # compare version size 231 | version_ge() { [ "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1" ]; } 232 | 233 | # set golang environment 234 | set_environment() { 235 | if [ -n "$IS_GVM" ]; then 236 | return 237 | fi 238 | 239 | # shellcheck disable=SC2016 240 | sedi '/## GOLANG/,/export PATH="$PATH:$GOROOT"/d' "$PROFILE" 241 | 242 | # shellcheck disable=SC2001 243 | _goroot=$(echo "$GO_ROOT" | sed "s|$HOME|\\\$HOME|g") 244 | # shellcheck disable=SC2001 245 | _gopath=$(echo "$GO_PATH" | sed "s|$HOME|\\\$HOME|g") 246 | { 247 | echo 248 | echo '## GOLANG' 249 | echo "export GOROOT=\"$_goroot\"" 250 | echo "export GOPATH=\"$_gopath\"" 251 | # shellcheck disable=SC2016 252 | echo 'export GOBIN="$GOPATH/bin"' 253 | echo 'GOPROXY="https://goproxy.cn,https://goproxy.io,direct"' 254 | # shellcheck disable=SC2016 255 | echo 'export PATH="$PATH:$GOROOT/bin:$GOBIN"' 256 | } >>"$PROFILE" 257 | 258 | if [ -z "$IN_CHINA" ]; then 259 | sedi '/GOPROXY/d' "$PROFILE" 260 | fi 261 | } 262 | 263 | # show copyright 264 | show_copyright() { 265 | clear 266 | 267 | printf " 268 | ############################################################### 269 | ### Golang Install 270 | ### 271 | ### Author: Jetsung Chan 272 | ### Link: https://jetsung.com 273 | ### Project: %s 274 | ############################################################### 275 | \n" "$PROJECT_URL" 276 | } 277 | 278 | # show system information 279 | show_system_information() { 280 | printf " 281 | ############################################################### 282 | ### System: %s 283 | ### Bit: %s 284 | ### Version: %s 285 | ############################################################### 286 | \n" "$OS" "$BIT" "$RELEASE_TAG" 287 | } 288 | 289 | # Show success message 290 | show_success_message() { 291 | printf " 292 | ############################################################### 293 | # Installation successful, please execute again \e[1;33msource %s\e[0m 294 | ############################################################### 295 | \n" "$PROFILE" 296 | } 297 | 298 | # show help message 299 | show_help_message() { 300 | printf "Go install 301 | 302 | \e[1;33mUSAGE:\e[m 303 | \e[1;32m%s\e[m [OPTIONS] 304 | 305 | \e[1;33mOPTIONS:\e[m 306 | \e[1;32m-p, --path\e[m 307 | Set GOPATH. (default: \$HOME/go) 308 | 309 | \e[1;32m-r, --root\e[m 310 | Set GOROOT. (default: \$HOME/.go) 311 | 312 | \e[1;32m-v, --version\e[m 313 | Set golang version. 314 | 315 | \e[1;32m-h, --help\e[m 316 | Print help information. 317 | \n" "$script_dir_name" 318 | exit 319 | } 320 | 321 | # 处理参数信息 322 | judgment_parameters() { 323 | while [ $# -gt 0 ]; do 324 | case "$1" in 325 | 326 | '-p' | '--path') 327 | if [ -z "${2:-}" ]; then 328 | say_err "Missing go path argument. \n Example: $script_name --path [GOPATH]\n" 329 | fi 330 | if [[ "$2" == -* ]]; then 331 | shift 332 | continue 333 | fi 334 | GO_PATH="${2:-}" 335 | shift 336 | ;; 337 | 338 | '-r' | '--root') 339 | if [ -z "${2:-}" ]; then 340 | say_err "Missing go root argument. \n Example: $script_name --root [GOROOT]\n" 341 | fi 342 | if [[ "$2" == -* ]]; then 343 | shift 344 | continue 345 | fi 346 | GO_ROOT="${2:-}" 347 | shift 348 | ;; 349 | 350 | '-v' | '--version') 351 | if [ -z "${2:-}" ]; then 352 | say_err "Missing go version argument. \n Example: $script_name --version [VERSION]\n" 353 | fi 354 | if [[ "$2" == -* ]]; then 355 | shift 356 | continue 357 | fi 358 | custom_version "${2:-}" 359 | shift 360 | ;; 361 | 362 | # 帮助 363 | '-h' | '--help') 364 | show_help_message 365 | ;; 366 | 367 | # 未知参数 368 | *) 369 | say_err "$script_dir_name: unknown option - $1" 370 | ;; 371 | 372 | esac 373 | shift 374 | done 375 | } 376 | 377 | do_action() { 378 | echo 379 | } 380 | 381 | set_project_url() { 382 | # Release URL 383 | RELEASE_URL="https://go.dev/dl/" 384 | RELEASE_CN_URL="https://golang.google.cn/dl/" 385 | 386 | # Project URL 387 | PROJECT_URL="https://github.com/jetsung/golang-install" 388 | PROJECT_CN_URL="https://gitcode.com/jetsung/golang-install" 389 | 390 | if [ -n "$IN_CHINA" ]; then 391 | RELEASE_URL="$RELEASE_CN_URL" 392 | PROJECT_URL="$PROJECT_CN_URL" 393 | DOWNLOAD_URL="$DOWNLOAD_CN_URL" 394 | fi 395 | } 396 | 397 | main() { 398 | # GVM 399 | IS_GVM="" 400 | GVMPATH=${GVMPATH:-$HOME/.gvm} 401 | 402 | # GOPATH 403 | # shellcheck disable=SC2016 404 | GO_PATH="$HOME/go" 405 | 406 | # GOROOT 407 | GO_ROOT="$HOME/.go" 408 | 409 | # Release tag / go version 410 | RELEASE_TAG="" 411 | 412 | BASENAME_SHELL="" 413 | PROFILE="$(detect_profile)" 414 | 415 | if [ -z "$PROFILE" ]; then 416 | say_err "Error: can not find profile" 417 | fi 418 | 419 | # 提取参数和值 420 | judgment_parameters "$@" 421 | 422 | check_gvm 423 | if [ -n "$IS_GVM" ]; then 424 | if [ ! -d "$GVMPATH/packages" ]; then 425 | mkdir -p "$GVMPATH/packages" 426 | fi 427 | GO_ROOT="$GVMPATH/packages/$RELEASE_TAG" 428 | fi 429 | 430 | IN_CHINA="" 431 | if check_in_china; then 432 | IN_CHINA=1 433 | fi 434 | 435 | set_project_url 436 | 437 | show_copyright 438 | 439 | init_arch 440 | 441 | init_os 442 | 443 | install_curl_command 444 | 445 | latest_version 446 | 447 | compare_version 448 | 449 | show_system_information 450 | 451 | # Download File 452 | BINARY_URL="$DOWNLOAD_URL$RELEASE_TAG.$OS-$ARCH.tar.gz" 453 | 454 | # Download and unpack 455 | download_unpack "$BINARY_URL" "$GO_ROOT" 456 | 457 | # Set ENV 458 | set_environment || say_err "set environment error" 459 | 460 | show_success_message 461 | } 462 | 463 | main "$@" || exit 1 464 | -------------------------------------------------------------------------------- /gvm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Golang Version Manager 4 | # Project Home Page: 5 | # https://github.com/jetsung/golang-install 6 | # https://gitcode.com/jetsung/golang-install 7 | # 8 | # Author: Jetsung Chan 9 | 10 | if [[ -n "${DEBUG:-}" ]]; then 11 | set -eux 12 | else 13 | set -euo pipefail 14 | fi 15 | 16 | exec 3>&1 17 | 18 | GVM_VERSION="1.1.2" 19 | 20 | script_name=$(basename "$0") 21 | script_dir_name="${script_name##*/}" 22 | 23 | if [ -t 1 ] && command -v tput >/dev/null; then 24 | ncolors=$(tput colors || echo 0) 25 | if [ -n "$ncolors" ] && [ "$ncolors" -ge 8 ]; then 26 | bold="$(tput bold || echo)" 27 | normal="$(tput sgr0 || echo)" 28 | black="$(tput setaf 0 || echo)" 29 | red="$(tput setaf 1 || echo)" 30 | green="$(tput setaf 2 || echo)" 31 | yellow="$(tput setaf 3 || echo)" 32 | blue="$(tput setaf 4 || echo)" 33 | magenta="$(tput setaf 5 || echo)" 34 | cyan="$(tput setaf 6 || echo)" 35 | white="$(tput setaf 7 || echo)" 36 | fi 37 | fi 38 | 39 | say_warning() { 40 | printf "%b\n" "${yellow:-}$script_name: Warning: $1${normal:-}" >&3 41 | } 42 | 43 | say_err() { 44 | printf "%b\n" "${red:-}$script_name: Error: $1${normal:-}" >&2 45 | exit 1 46 | } 47 | 48 | say() { 49 | printf "%b\n" "${cyan:-}$script_name:${normal:-} $1" >&3 50 | } 51 | 52 | # try profile 53 | try_profile() { 54 | if [ -z "${1:-}" ] || [ ! -f "$1" ]; then 55 | return 1 56 | fi 57 | sh_echo "$1" 58 | } 59 | 60 | # sh echo 61 | sh_echo() { 62 | command printf %s\\n "$*" 2>/dev/null 63 | } 64 | 65 | # Get PROFILE 66 | detect_profile() { 67 | local DETECTED_PROFILE="" 68 | 69 | if [ -z "${SHELL:-}" ]; then 70 | SHELL="$(grep "^$(whoami):" /etc/passwd | cut -d: -f7)" 71 | fi 72 | 73 | BASENAME_SHELL=$(basename "$SHELL") 74 | case "$BASENAME_SHELL" in 75 | 'sh') 76 | DETECTED_PROFILE="$HOME/.profile" 77 | ;; 78 | 'zsh') 79 | DETECTED_PROFILE="$HOME/.zshrc" 80 | ;; 81 | 'bash') 82 | DETECTED_PROFILE="$HOME/.bashrc" 83 | ;; 84 | 'fish') 85 | DETECTED_PROFILE="$HOME/.config/fish/config.fish" 86 | ;; 87 | *) 88 | return 89 | ;; 90 | esac 91 | 92 | if [ ! -f "$DETECTED_PROFILE" ]; then 93 | touch "$DETECTED_PROFILE" 94 | fi 95 | 96 | if [ -f "$DETECTED_PROFILE" ]; then 97 | sh_echo "$DETECTED_PROFILE" 98 | fi 99 | } 100 | 101 | # fix macos 102 | sedi() { 103 | if [ "$OS" = "darwin" ]; then 104 | sed -i "" "$@" 105 | else 106 | sed -i "$@" 107 | fi 108 | } 109 | 110 | # check in china 111 | check_in_china() { 112 | if [[ -n "${CN:-}" ]]; then 113 | return 0 # 手动指定 114 | fi 115 | if [[ "$(curl -s -m 3 -o /dev/null -w "%{http_code}" https://www.google.com)" == "000" ]]; then 116 | return 0 # 中国网络 117 | fi 118 | return 1 # 非中国网络 119 | } 120 | 121 | # Get OS version 122 | init_os() { 123 | OS=$(uname | tr '[:upper:]' '[:lower:]') 124 | case "$OS" in 125 | darwin) OS='darwin' ;; 126 | linux) OS='linux' ;; 127 | freebsd) OS='freebsd' ;; 128 | # mingw*) OS='windows';; 129 | # msys*) OS='windows';; 130 | *) 131 | say_err "OS $OS is not supported by this installation script\n" 132 | ;; 133 | esac 134 | } 135 | 136 | # install curl command 137 | install_curl_command() { 138 | if ! test -x "$(command -v curl)"; then 139 | if test -x "$(command -v yum)"; then 140 | yum install -y curl 141 | elif test -x "$(command -v apt)"; then 142 | apt install -y curl 143 | else 144 | say_err "You must pre-install the curl tool\n" 145 | fi 146 | fi 147 | } 148 | 149 | # set gvm environment 150 | set_environment() { 151 | # shellcheck disable=SC2016 152 | if ! grep -q '$HOME/.gvm/env' "$PROFILE"; then 153 | { 154 | printf '\n## GVM\n. "$HOME/.gvm/env"\n' 155 | } >>"$PROFILE" 156 | else 157 | sedi 's@^. "$HOME/.gvm/.*@. "$HOME/.gvm/env"@' "$PROFILE" 158 | fi 159 | 160 | cat > "$GVM_ENV_PATH" <<-'EOF' 161 | #!/usr/bin/env sh 162 | 163 | export GVMPATH="$HOME/.gvm" 164 | 165 | case ":${PATH}:" in 166 | *:"$GVMPATH/bin":*) ;; 167 | *) export PATH="$GVMPATH/bin:$PATH" ;; 168 | esac 169 | 170 | ## GOLANG 171 | export GOROOT="$HOME/.gvm/go" 172 | export GOPATH="$HOME/go" 173 | export GOBIN="$GOPATH/bin" 174 | export GOPROXY="https://goproxy.cn,https://goproxy.io,direct" 175 | export PATH="$PATH:$GOROOT/bin:$GOBIN" 176 | EOF 177 | 178 | if [ -z "$IN_CHINA" ]; then 179 | sedi '/GOPROXY/d' "$GVM_ENV_PATH" 180 | fi 181 | 182 | # shellcheck disable=SC2016 183 | sedi '/## GOLANG/,/export PATH="$PATH:$GOROOT"/d' "$PROFILE" 184 | } 185 | 186 | # update gvm.sh 187 | gvm_script() { 188 | [ -d "$GVM_BIN_PATH" ] || mkdir -p "$GVM_BIN_PATH" 189 | 190 | CURRENT_GVM_PATH="$(pwd)/gvm" 191 | local GVM_SCRIPT_PATH="$GVM_BIN_PATH/gvm" 192 | 193 | # locally update 194 | if [ -f "$CURRENT_GVM_PATH.sh" ]; then 195 | cp "$CURRENT_GVM_PATH.sh" "$GVM_SCRIPT_PATH" 196 | else # git update 197 | if [ -n "$IN_CHINA" ]; then 198 | PRO_URL="$PRO_CN_URL" 199 | fi 200 | curl -sSL -m 5 -o "$GVM_SCRIPT_PATH" "$PRO_URL/gvm.sh" 201 | fi 202 | 203 | if [ ! -f "$GVM_SCRIPT_PATH" ]; then 204 | say_err "GVM(gvm.sh) download failed\n" 205 | fi 206 | chmod +x "$GVM_SCRIPT_PATH" 207 | } 208 | 209 | # download go install.sh 210 | dl_goinstall_script() { 211 | # force update 212 | if [ -n "${1:-}" ]; then 213 | rm -rf "$GO_INSTALL_SCRIPT" 214 | fi 215 | 216 | if [ ! -f "$GO_INSTALL_SCRIPT" ]; then 217 | # locally update 218 | if [ -f "./install.sh" ]; then 219 | cp -f "./install.sh" "$GO_INSTALL_SCRIPT" 220 | else # git update 221 | if [ -n "$IN_CHINA" ]; then 222 | PRO_URL="$PRO_CN_URL" 223 | fi 224 | curl -fsSL -m 5 -o "$GO_INSTALL_SCRIPT" "$PRO_URL/install.sh" 225 | fi 226 | fi 227 | 228 | if [ ! -f "$GO_INSTALL_SCRIPT" ]; then 229 | say_err "GVM go-install.sh download failed\n" 230 | fi 231 | chmod +x "$GO_INSTALL_SCRIPT" 232 | } 233 | 234 | # gvm script install 235 | install_script() { 236 | gvm_script 237 | dl_goinstall_script 238 | 239 | say "GVM successfully installed\n" 240 | 241 | if ! command -v gvm >/dev/null; then 242 | printf "You need to execute: \n\e[1;33msource %s\e[m\n" "$PROFILE" 243 | fi 244 | } 245 | 246 | # gvm script upgrade 247 | update_script() { 248 | gvm_script 249 | dl_goinstall_script "force" 250 | 251 | say "GVM successfully updated\n" 252 | } 253 | 254 | # Get a list of locally installed Go versions. 255 | go_list_locale() { 256 | if ! find "$GO_VERSIONS_PATH"/go*/bin/go -maxdepth 1 -type f >/dev/null 2>&1; then 257 | if [ -z "${1:-}" ]; then 258 | say_err "No go version list found\n" 259 | fi 260 | return 261 | fi 262 | 263 | # GO_VERSION_LIST=$(find "${GO_VERSIONS_PATH}" -maxdepth 1 -name "go*" -type d | cut -d '/' -f 6 | sed 's/..//') 264 | while IFS= read -r _V; do 265 | GO_VERSION_LIST[${#GO_VERSION_LIST[@]}]=$(${_V} version | awk '{print $3}' | sed 's/..//') 266 | done < <(find "$GO_VERSIONS_PATH"/go*/bin/go -maxdepth 1 -type f) 267 | } 268 | 269 | # Obtain a list of versions from the Go official website. 270 | go_list_remote() { 271 | IN_CHINA="" 272 | if check_in_china; then 273 | IN_CHINA=1 274 | fi 275 | local GO_DL_URL="https://go.dev/dl/" 276 | if [ -n "$IN_CHINA" ]; then 277 | GO_DL_URL="https://golang.google.cn/dl/" 278 | fi 279 | 280 | RELEASE_TAGS=$(curl -sL -m 5 "$GO_DL_URL" | sed -n '/toggle/p' | cut -d '"' -f 4 | grep go | grep -Ev 'rc|beta') 281 | 282 | while IFS=$'\n' read -r -d ' ' _V; do 283 | REMOTE_GO_LIST[${#REMOTE_GO_LIST[@]}]="$_V" 284 | done < <(echo "$RELEASE_TAGS" | tr -s '\n' ' ') 285 | } 286 | 287 | # Install Go 288 | install_go() { 289 | go_list_locale "install" 290 | for _V in "${GO_VERSION_LIST[@]:-}"; do 291 | if [ "$_V" = "$GO_VERSION" ]; then 292 | say_err "Go $GO_VERSION already exists\n" 293 | fi 294 | done 295 | 296 | go_list_remote 297 | local REMOTE_HAS_VERSION="" 298 | for _V in "${REMOTE_GO_LIST[@]:-}"; do 299 | if [ "$_V" = "go$GO_VERSION" ]; then 300 | REMOTE_HAS_VERSION=1 301 | break 302 | fi 303 | done 304 | 305 | if [ -z "$REMOTE_HAS_VERSION" ]; then 306 | say_err "There is no such version(go$GO_VERSION)\n" 307 | fi 308 | 309 | printf "\e[1;33mInstalling go %s\e[m\n" "$GO_VERSION" 310 | 311 | PARAMS="--version $GO_VERSION --root $GO_VERSIONS_PATH/go$GO_VERSION" 312 | # echo "${GO_INSTALL_SCRIPT} ${PARAMS}" 313 | 314 | # shellcheck disable=SC2086 315 | $SHELL $GO_INSTALL_SCRIPT $PARAMS >"$HOME/.gvm.log" 2>&1 316 | # shellcheck disable=SC1090,SC2086 317 | CURRENT_GO_BINARY="$GO_VERSIONS_PATH/go$GO_VERSION/bin/go" 318 | 319 | if [ ! -d "$GVM_GO_ROOT" ]; then 320 | ln -s "$GO_VERSIONS_PATH/go$GO_VERSION" "$GVM_GO_ROOT" 321 | fi 322 | 323 | if [ -f "$CURRENT_GO_BINARY" ]; then 324 | $CURRENT_GO_BINARY version 325 | else 326 | say_err "Go $GO_VERSION installation failed\n" 327 | fi 328 | } 329 | 330 | # List all locally installed go versions 331 | show_list() { 332 | go_list_locale 333 | 334 | for _V in "${GO_VERSION_LIST[@]:-}"; do 335 | if [ -z "$_V" ]; then 336 | continue 337 | fi 338 | printf "go%s\n" "$_V" 339 | done 340 | } 341 | 342 | # List all remote go versions 343 | show_remote_list() { 344 | go_list_remote 345 | 346 | local SHOW_ALL="" 347 | SHOW_ALL="${1:-}" 348 | 349 | local __INDEX=1 350 | for _V in "${REMOTE_GO_LIST[@]:-}"; do 351 | if [ $__INDEX -ge 10 ] && [ -z "$SHOW_ALL" ]; then 352 | break 353 | fi 354 | 355 | printf "%s\n" "$_V" 356 | ((__INDEX++)) 357 | done 358 | } 359 | 360 | # Remove custom go version from locally 361 | uninstall_go() { 362 | if command -v go > /dev/null; then 363 | if [ "$(go version | awk '{print $3}')" = "go$GO_VERSION" ]; then 364 | say_err "The current version(go${GO_VERSION}) is in use\n" 365 | fi 366 | fi 367 | 368 | 369 | if [ -d "$GO_VERSIONS_PATH/go$GO_VERSION" ]; then 370 | rm -rf "$GO_VERSIONS_PATH/go$GO_VERSION" 371 | say "go$GO_VERSION uninstalled successfully\n" 372 | else 373 | say "go$GO_VERSION does not exist\n" 374 | fi 375 | } 376 | 377 | # Use custom go version 378 | use_go() { 379 | CURRENT_GO_BINARY="$GO_VERSIONS_PATH/go$GO_VERSION/bin/go" 380 | if [ ! -f "$CURRENT_GO_BINARY" ]; then 381 | install_go 382 | else 383 | $CURRENT_GO_BINARY version 384 | fi 385 | 386 | if [ -f "$CURRENT_GO_BINARY" ]; then 387 | rm -rf "$GVM_GO_ROOT" 388 | ln -s "$GO_VERSIONS_PATH/go$GO_VERSION" "$GVM_GO_ROOT" 389 | 390 | if ! command -v go >/dev/null 2>&1 || [ "$(go version | awk '{print $3}')" != "go$GO_VERSION" ]; then 391 | printf "\nYou need to execute: \n\e[1;33msource %s\e[m\n" "$PROFILE" 392 | fi 393 | fi 394 | } 395 | 396 | # Get go latest version 397 | get_latest_version() { 398 | _VERSION="${1:-}" 399 | if [ "$_VERSION" = "latest" ]; then 400 | _VERSION=$(show_remote_list | sort -rV | head -n 1) 401 | fi 402 | } 403 | 404 | # show help message 405 | show_help_message() { 406 | printf "\e[1;32mgvm\e[m %s 407 | 408 | Golang Version Manager 409 | 410 | \e[1;33mUsage:\e[m %s [OPTIONS] [COMMAND] 411 | 412 | \e[1;33mCommands:\e[m 413 | \e[1;32muse\e[m [VERSION|latest] Change Go version 414 | \e[1;32minstall\e[m [VERSION|latest] Install a new go version 415 | \e[1;32muninstall\e[m Uninstall a Go version 416 | \e[1;32mlist\e[m List all locally installed go versions 417 | \e[1;32mremote\e[m List all remote go versions 418 | \e[1;32mversion\e[m Print the current go version 419 | 420 | \e[1;33mOptions:\e[m 421 | \e[1;32m-i, --install\e[m 422 | Install Golang Version Manager 423 | 424 | \e[1;32m-u, --update\e[m 425 | Update Golang Version Manager 426 | 427 | \e[1;32m-h, --help\e[m 428 | Print help information 429 | 430 | \e[1;32m-v, --version\e[m 431 | Print Gvm version information 432 | \n" "$GVM_VERSION" "$script_dir_name" 433 | exit 0 434 | } 435 | 436 | # 处理参数信息 437 | judgment_parameters() { 438 | # 参数带帮助 439 | if [ $# -eq 0 ]; then 440 | if [ "$0" == "bash" ] || [ "$0" == "-bash" ]; then # 无参数,远程,安装 441 | DO_ACTION="--install" 442 | else # 无参数,本地 443 | DO_ACTION="--help" 444 | fi 445 | return 446 | fi 447 | 448 | while [ $# -gt 0 ]; do 449 | case "$1" in 450 | 451 | # 切换 Go 452 | 'use') 453 | if [ -z "${2:-}" ]; then 454 | say_err "Missing go version argument. \n Example: $script_name use [VERSION]\n" 455 | fi 456 | 457 | DO_ACTION="use" 458 | DO_PARAMETER="${2:-}" 459 | shift 460 | ;; 461 | 462 | # 安装 Go 463 | 'install') 464 | if [ -z "${2:-}" ]; then 465 | say_err "Missing go version argument. \n Example: $script_name install [VERSION]\n" 466 | fi 467 | 468 | DO_ACTION="install" 469 | DO_PARAMETER="${2:-}" 470 | shift 471 | ;; 472 | 473 | 'uninstall') 474 | if [ -z "${2:-}" ]; then 475 | say_err "Missing go version argument. \n Example: $script_name uninstall [VERSION]\n" 476 | fi 477 | 478 | DO_ACTION="uninstall" 479 | DO_PARAMETER="${2:-}" 480 | shift 481 | ;; 482 | 483 | # 显示本地已安装的 Go 版本 484 | 'list') 485 | DO_ACTION="list" 486 | ;; 487 | 488 | # 显示远程已安装的 Go 版本 489 | 'remote') 490 | DO_ACTION="remote" 491 | DO_PARAMETER="${2:-}" 492 | if [ -n "$DO_PARAMETER" ]; then 493 | shift 494 | fi 495 | ;; 496 | 497 | # 显示 Go 版本 498 | 'version') 499 | DO_ACTION="version" 500 | ;; 501 | 502 | # 安装此项目 503 | '-i' | '--install') 504 | DO_ACTION="--install" 505 | ;; 506 | 507 | # 更新此项目 508 | '-u' | '--update') 509 | DO_ACTION="--update" 510 | ;; 511 | 512 | # 显示脚本版本 513 | '-v' | '--version') 514 | DO_ACTION="--version" 515 | ;; 516 | 517 | 518 | # 帮助 519 | '-h' | '--help') 520 | DO_ACTION="--help" 521 | ;; 522 | 523 | # 未知参数 524 | *) 525 | echo "$script_dir_name: unknown option -- $1" 526 | exit 1 527 | ;; 528 | 529 | esac 530 | shift 531 | done 532 | } 533 | 534 | do_action() { 535 | case "${DO_ACTION:-}" in 536 | 537 | # 切换 Go 538 | 'use') 539 | get_latest_version "${DO_PARAMETER:-}" 540 | GO_VERSION="${_VERSION#go}" 541 | use_go 542 | ;; 543 | 544 | # 安装 Go 545 | 'install') 546 | get_latest_version "${DO_PARAMETER:-}" 547 | GO_VERSION="${_VERSION#go}" 548 | install_go 549 | ;; 550 | 551 | 'uninstall') 552 | _VERSION="${DO_PARAMETER:-}" 553 | GO_VERSION="${_VERSION#go}" 554 | uninstall_go 555 | ;; 556 | 557 | # 显示本地已安装的 Go 版本 558 | 'list') 559 | show_list 560 | ;; 561 | 562 | # 显示远程已安装的 Go 版本 563 | 'remote') 564 | _MODE="${DO_PARAMETER:-}" 565 | show_remote_list "$_MODE" 566 | ;; 567 | 568 | # 显示 Go 版本 569 | 'version') 570 | if ! command -v go >/dev/null 2>&1; then 571 | _msg=$(printf "Go is not installed\nPlease execute: \e[1;33m%s install latest\e[0m\n" "$script_dir_name") 572 | say_err "$_msg" 573 | else 574 | go version 575 | fi 576 | ;; 577 | 578 | # 安装此项目 579 | '-i' | '--install') 580 | install_script 581 | ;; 582 | 583 | 584 | # 更新此项目 585 | '-u' | '--update') 586 | update_script 587 | ;; 588 | 589 | # 显示脚本版本 590 | '-v' | '--version') 591 | printf "gvm version: %s\n" "$GVM_VERSION" 592 | ;; 593 | 594 | # 帮助 595 | '-h' | '--help') 596 | show_help_message 597 | ;; 598 | 599 | # 未知参数 600 | *) 601 | ;; 602 | esac 603 | } 604 | 605 | set_project_url() { 606 | PRO_URL="https://raw.githubusercontent.com/jetsung/golang-install/main/" 607 | PRO_CN_URL="https://raw.gitcode.com/jetsung/golang-install/raw/main/" 608 | 609 | # DEBUG 610 | if [ -n "$DEBUG" ]; then 611 | PRO_CN_URL="https://git.envs.net/jetsung/learn/raw/branch/dev/" 612 | fi 613 | } 614 | 615 | main() { 616 | GVM_PATH="$HOME/.gvm" 617 | GVM_BIN_PATH="$GVM_PATH/bin" 618 | GVM_ENV_PATH="$GVM_PATH/env" 619 | GVM_GO_ROOT="$GVM_PATH/go" 620 | 621 | GO_INSTALL_SCRIPT="$GVM_PATH/install.sh" 622 | GO_VERSIONS_PATH="$GVM_PATH/packages" 623 | 624 | DEBUG="" 625 | 626 | BASENAME_SHELL="" 627 | PROFILE="$(detect_profile)" 628 | 629 | if [ -z "$PROFILE" ]; then 630 | say_err "Error: can not find profile" 631 | fi 632 | 633 | IN_CHINA="" 634 | if check_in_china; then 635 | IN_CHINA=1 636 | fi 637 | 638 | REMOTE_GO_LIST=() 639 | GO_VERSION_LIST=() 640 | 641 | # 动作 642 | DO_ACTION="" 643 | # 参数 644 | DO_PARAMETER="" 645 | 646 | if [ ! -d "$GO_VERSIONS_PATH" ]; then 647 | mkdir -p "$GO_VERSIONS_PATH" 648 | fi 649 | 650 | # 检测系统 651 | init_os 652 | 653 | # 安装必要的依赖 654 | install_curl_command 655 | 656 | # 设置环境变量 657 | set_environment 658 | 659 | # 设置项目地址 660 | set_project_url 661 | 662 | # 提取参数和值 663 | judgment_parameters "$@" 664 | 665 | # 执行命令 666 | do_action 667 | } 668 | 669 | main "$@" || exit 1 670 | --------------------------------------------------------------------------------