golang.org/x/build@v0.0.0-20240506185731-218518f32b70/env/wasip1-wasm-wasmtime/install.sh (about)

     1  #!/usr/bin/env bash
     2  
     3  # Copied from
     4  # https://github.com/volta-cli/volta/blob/master/dev/unix/volta-install.sh
     5  
     6  # LICENSE:
     7  
     8  # BSD 2-CLAUSE LICENSE
     9  #
    10  # Copyright (c) 2017, The Wasmtime Contributors.
    11  # All rights reserved.
    12  #
    13  # This product includes:
    14  #
    15  # Contributions from LinkedIn Corporation
    16  # Copyright (c) 2017, LinkedIn Corporation.
    17  #
    18  # Redistribution and use in source and binary forms, with or without
    19  # modification, are permitted provided that the following conditions are met:
    20  #
    21  # 1. Redistributions of source code must retain the above copyright notice, this
    22  #    list of conditions and the following disclaimer.
    23  # 2. Redistributions in binary form must reproduce the above copyright notice,
    24  #    this list of conditions and the following disclaimer in the documentation
    25  #    and/or other materials provided with the distribution.
    26  #
    27  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    28  # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    29  # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    30  # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
    31  # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    32  # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    33  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    34  # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    35  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    36  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    37  #
    38  # The views and conclusions contained in the software and documentation are those
    39  # of the authors and should not be interpreted as representing official policies,
    40  # either expressed or implied, of the FreeBSD Project.
    41  
    42  get_latest_release() {
    43    curl --silent "https://api.github.com/repos/bytecodealliance/wasmtime/releases/latest" | \
    44      grep tag_name | \
    45      cut -d '"' -f 4
    46  }
    47  
    48  release_url() {
    49    echo "https://github.com/bytecodealliance/wasmtime/releases"
    50  }
    51  
    52  download_release_from_repo() {
    53    local version="$1"
    54    local arch="$2"
    55    local os_info="$3"
    56    local tmpdir="$4"
    57  
    58    local filename="wasmtime-$version-$arch-$os_info.tar.xz"
    59    local download_file="$tmpdir/$filename"
    60    local archive_url="$(release_url)/download/$version/$filename"
    61    info $archive_url
    62  
    63    curl --progress-bar --show-error --location --fail "$archive_url" \
    64         --output "$download_file" && echo "$download_file"
    65  }
    66  
    67  usage() {
    68      cat >&2 <<END_USAGE
    69  wasmtime-install: The installer for Wasmtime
    70  
    71  USAGE:
    72      wasmtime-install [FLAGS] [OPTIONS]
    73  
    74  FLAGS:
    75      -h, --help                  Prints help information
    76  
    77  OPTIONS:
    78          --dev                   Compile and install Wasmtime locally, using the dev target
    79          --release               Compile and install Wasmtime locally, using the release target
    80          --version <version>     Install a specific release version of Wasmtime
    81  END_USAGE
    82  }
    83  
    84  info() {
    85    local action="$1"
    86    local details="$2"
    87    command printf '\033[1;32m%12s\033[0m %s\n' "$action" "$details" 1>&2
    88  }
    89  
    90  error() {
    91    command printf '\033[1;31mError\033[0m: %s\n\n' "$1" 1>&2
    92  }
    93  
    94  warning() {
    95    command printf '\033[1;33mWarning\033[0m: %s\n\n' "$1" 1>&2
    96  }
    97  
    98  request() {
    99    command printf '\033[1m%s\033[0m\n' "$1" 1>&2
   100  }
   101  
   102  eprintf() {
   103    command printf '%s\n' "$1" 1>&2
   104  }
   105  
   106  bold() {
   107    command printf '\033[1m%s\033[0m' "$1"
   108  }
   109  
   110  # If file exists, echo it
   111  echo_fexists() {
   112    [ -f "$1" ] && echo "$1"
   113  }
   114  
   115  detect_profile() {
   116    local shellname="$1"
   117    local uname="$2"
   118  
   119    if [ -f "$PROFILE" ]; then
   120      echo "$PROFILE"
   121      return
   122    fi
   123  
   124    # try to detect the current shell
   125    case "$shellname" in
   126      bash)
   127        # Shells on macOS default to opening with a login shell, while Linuxes
   128        # default to a *non*-login shell, so if this is macOS we look for
   129        # `.bash_profile` first; if it's Linux, we look for `.bashrc` first. The
   130        # `*` fallthrough covers more than just Linux: it's everything that is not
   131        # macOS (Darwin). It can be made narrower later if need be.
   132        case $uname in
   133          Darwin)
   134            echo_fexists "$HOME/.bash_profile" || echo_fexists "$HOME/.bashrc"
   135          ;;
   136          *)
   137            echo_fexists "$HOME/.bashrc" || echo_fexists "$HOME/.bash_profile"
   138          ;;
   139        esac
   140        ;;
   141      zsh)
   142        echo "$HOME/.zshrc"
   143        ;;
   144      fish)
   145        echo "$HOME/.config/fish/config.fish"
   146        ;;
   147      *)
   148        # Fall back to checking for profile file existence. Once again, the order
   149        # differs between macOS and everything else.
   150        local profiles
   151        case $uname in
   152          Darwin)
   153            profiles=( .profile .bash_profile .bashrc .zshrc .config/fish/config.fish )
   154            ;;
   155          *)
   156            profiles=( .profile .bashrc .bash_profile .zshrc .config/fish/config.fish )
   157            ;;
   158        esac
   159  
   160        for profile in "${profiles[@]}"; do
   161          echo_fexists "$HOME/$profile" && break
   162        done
   163        ;;
   164    esac
   165  }
   166  
   167  # generate shell code to source the loading script and modify the path for the input profile
   168  build_path_str() {
   169    local profile="$1"
   170    local profile_install_dir="$2"
   171  
   172    if [[ $profile =~ \.fish$ ]]; then
   173      # fish uses a little different syntax to modify the PATH
   174      cat <<END_FISH_SCRIPT
   175  
   176  set -gx WASMTIME_HOME "$profile_install_dir"
   177  
   178  string match -r ".wasmtime" "\$PATH" > /dev/null; or set -gx PATH "\$WASMTIME_HOME/bin" \$PATH
   179  END_FISH_SCRIPT
   180    else
   181      # bash and zsh
   182      cat <<END_BASH_SCRIPT
   183  
   184  export WASMTIME_HOME="$profile_install_dir"
   185  
   186  export PATH="\$WASMTIME_HOME/bin:\$PATH"
   187  END_BASH_SCRIPT
   188    fi
   189  }
   190  
   191  # check for issue with WASMTIME_HOME
   192  # if it is set, and exists, but is not a directory, the install will fail
   193  wasmtime_home_is_ok() {
   194    if [ -n "${WASMTIME_HOME-}" ] && [ -e "$WASMTIME_HOME" ] && ! [ -d "$WASMTIME_HOME" ]; then
   195      error "\$WASMTIME_HOME is set but is not a directory ($WASMTIME_HOME)."
   196      eprintf "Please check your profile scripts and environment."
   197      return 1
   198    fi
   199    return 0
   200  }
   201  
   202  update_profile() {
   203    local install_dir="$1"
   204  
   205    local profile_install_dir=$(echo "$install_dir" | sed "s:^$HOME:\$HOME:")
   206    local detected_profile="$(detect_profile $(basename "/$SHELL") $(uname -s) )"
   207    local path_str="$(build_path_str "$detected_profile" "$profile_install_dir")"
   208    info 'Editing' "user profile ($detected_profile)"
   209  
   210    if [ -z "${detected_profile-}" ] ; then
   211      error "No user profile found."
   212      eprintf "Tried \$PROFILE ($PROFILE), ~/.bashrc, ~/.bash_profile, ~/.zshrc, ~/.profile, and ~/.config/fish/config.fish."
   213      eprintf ''
   214      eprintf "You can either create one of these and try again or add this to the appropriate file:"
   215      eprintf "$path_str"
   216      return 1
   217    else
   218      if ! command grep -qc 'WASMTIME_HOME' "$detected_profile"; then
   219        command printf "$path_str" >> "$detected_profile"
   220      else
   221        warning "Your profile ($detected_profile) already mentions Wasmtime and has not been changed."
   222      fi
   223    fi
   224  }
   225  
   226  # Check if it is OK to upgrade to the new version
   227  upgrade_is_ok() {
   228    local will_install_version="$1"
   229    local install_dir="$2"
   230    local is_dev_install="$3"
   231  
   232    local wasmtime_bin="$install_dir/wasmtime"
   233  
   234    if [[ -n "$install_dir" && -x "$wasmtime_bin" ]]; then
   235      local prev_version="$( ($wasmtime_bin --version 2>/dev/null || echo 0.1) | sed -E 's/^.*([0-9]+\.[0-9]+\.[0-9]+).*$/\1/')"
   236      # if this is a local dev install, skip the equality check
   237      # if installing the same version, this is a no-op
   238      if [ "$is_dev_install" != "true" ] && [ "$prev_version" == "$will_install_version" ]; then
   239        eprintf "Version $will_install_version already installed"
   240        return 1
   241      fi
   242      # in the future, check $prev_version for incompatible upgrades
   243    fi
   244    return 0
   245  }
   246  
   247  # returns the os name to be used in the packaged release,
   248  # including the openssl info if necessary
   249  parse_os_info() {
   250    local uname_str="$1"
   251    local openssl_version="$2"
   252  
   253    case "$uname_str" in
   254      Linux)
   255        echo "linux"
   256        ;;
   257      Darwin)
   258        echo "macos"
   259        ;;
   260      *)
   261        return 1
   262    esac
   263    return 0
   264  }
   265  
   266  parse_os_pretty() {
   267    local uname_str="$1"
   268  
   269    case "$uname_str" in
   270      Linux)
   271        echo "Linux"
   272        ;;
   273      Darwin)
   274        echo "macOS"
   275        ;;
   276      *)
   277        echo "$uname_str"
   278    esac
   279  }
   280  
   281  # return true(0) if the element is contained in the input arguments
   282  # called like:
   283  #  if element_in "foo" "${array[@]}"; then ...
   284  element_in() {
   285    local match="$1";
   286    shift
   287  
   288    local element;
   289    # loop over the input arguments and return when a match is found
   290    for element in "$@"; do
   291      [ "$element" == "$match" ] && return 0
   292    done
   293    return 1
   294  }
   295  
   296  create_tree() {
   297    local install_dir="$1"
   298  
   299    info 'Creating' "directory layout"
   300  
   301    # .wasmtime/
   302    #     bin/
   303  
   304    mkdir -p "$install_dir"
   305    mkdir -p "$install_dir"/bin
   306  }
   307  
   308  install_version() {
   309    local version_to_install="$1"
   310    local install_dir="$2"
   311  
   312    if ! wasmtime_home_is_ok; then
   313      exit 1
   314    fi
   315  
   316    case "$version_to_install" in
   317      latest)
   318        local latest_version="$(get_latest_release)"
   319        info 'Installing' "latest version of Wasmtime ($latest_version)"
   320        install_release "$latest_version" "$install_dir"
   321        ;;
   322      local-dev)
   323        info 'Installing' "Wasmtime locally after compiling"
   324        install_local "dev" "$install_dir"
   325        ;;
   326      local-release)
   327        info 'Installing' "Wasmtime locally after compiling with '--release'"
   328        install_local "release" "$install_dir"
   329        ;;
   330      *)
   331        # assume anything else is a specific version
   332        info 'Installing' "Wasmtime version $version_to_install"
   333        install_release "$version_to_install" "$install_dir"
   334        ;;
   335    esac
   336  
   337    if [ "$?" == 0 ]
   338    then
   339        update_profile "$install_dir" &&
   340        info "Finished" 'installation. Open a new terminal to start using Wasmtime!'
   341    fi
   342  }
   343  
   344  # parse the 'version = "X.Y.Z"' line from the input Cargo.toml contents
   345  # and return the version string
   346  parse_cargo_version() {
   347    local contents="$1"
   348  
   349    while read -r line
   350    do
   351      if [[ "$line" =~ ^version\ =\ \"(.*)\" ]]
   352      then
   353        echo "${BASH_REMATCH[1]}"
   354        return 0
   355      fi
   356    done <<< "$contents"
   357  
   358    error "Could not determine the current version from Cargo.toml"
   359    return 1
   360  }
   361  
   362  install_release() {
   363    local version="$1"
   364    local install_dir="$2"
   365    local is_dev_install="false"
   366  
   367    info 'Checking' "for existing Wasmtime installation"
   368    if upgrade_is_ok "$version" "$install_dir" "$is_dev_install"
   369    then
   370      download_archive="$(download_release "$version"; exit "$?")"
   371      exit_status="$?"
   372      if [ "$exit_status" != 0 ]
   373      then
   374        error "Could not download Wasmtime version '$version'. See $(release_url) for a list of available releases"
   375        return "$exit_status"
   376      fi
   377  
   378      install_from_file "$download_archive" "$install_dir"
   379    else
   380      # existing legacy install, or upgrade problem
   381      return 1
   382    fi
   383  }
   384  
   385  install_local() {
   386    local dev_or_release="$1"
   387    local install_dir="$2"
   388    # this is a local install, so skip the version equality check
   389    local is_dev_install="true"
   390  
   391    info 'Checking' "for existing Wasmtime installation"
   392    install_version="$(parse_cargo_version "$(<Cargo.toml)" )" || return 1
   393    if no_legacy_install && upgrade_is_ok "$install_version" "$install_dir" "$is_dev_install"
   394    then
   395      # compile and package the binaries, then install from that local archive
   396      compiled_archive="$(compile_and_package "$dev_or_release")" &&
   397        install_from_file "$compiled_archive" "$install_dir"
   398    else
   399      # existing legacy install, or upgrade problem
   400      return 1
   401    fi
   402  }
   403  
   404  compile_and_package() {
   405    local dev_or_release="$1"
   406  
   407    local release_output
   408  
   409    # get the directory of this script
   410    # (from https://stackoverflow.com/a/246128)
   411    DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
   412  
   413    # call the release script to create the packaged archive file
   414    # '2> >(tee /dev/stderr)' copies stderr to stdout, to collect it and parse the filename
   415    release_output="$( "$DIR/release.sh" "--$dev_or_release" 2> >(tee /dev/stderr) )"
   416    [ "$?" != 0 ] && return 1
   417  
   418    # parse the release filename and return that
   419    if [[ "$release_output" =~ release\ in\ file\ (target[^\ ]+) ]]; then
   420      echo "${BASH_REMATCH[1]}"
   421    else
   422      error "Could not determine output filename"
   423      return 1
   424    fi
   425  }
   426  
   427  download_release() {
   428    local version="$1"
   429  
   430    local arch="$(get_architecture)"
   431    local uname_str="$(uname -s)"
   432    local os_info
   433    os_info="$(parse_os_info "$uname_str")"
   434    if [ "$?" != 0 ]; then
   435      error "The current operating system ($uname_str) does not appear to be supported by Wasmtime."
   436      return 1
   437    fi
   438    local pretty_os_name="$(parse_os_pretty "$uname_str")"
   439  
   440    info 'Fetching' "archive for $pretty_os_name, version $version"
   441    # store the downloaded archive in a temporary directory
   442    local download_dir="$(mktemp -d)"
   443    download_release_from_repo "$version" "$arch" "$os_info" "$download_dir"
   444  }
   445  
   446  install_from_file() {
   447    local archive="$1"
   448    local copy_to="$2"
   449    local extract_to="$(dirname $archive)"
   450    local extracted_path="$extract_to/$(basename $archive .tar.xz)"
   451  
   452    create_tree "$copy_to"
   453  
   454    info 'Extracting' "Wasmtime binaries"
   455    # extract the files to the temp directory
   456    tar -xvf "$archive" -C "$extract_to"
   457  
   458    # copy the files to the specified directory
   459    # binaries go into the bin folder
   460    cp "$extracted_path/wasmtime" "$copy_to/bin"
   461  
   462    # the others directly into the specified folder
   463    cp "$extracted_path/LICENSE" "$extracted_path/README.md" "$copy_to"
   464  }
   465  
   466  get_architecture() {
   467      local arch="$(uname -m)"
   468      case "$arch" in
   469          # macOS on aarch64 says "arm64" instead.
   470          arm64)
   471              arch=aarch64
   472              ;;
   473      esac
   474      echo "$arch"
   475  }
   476  
   477  check_architecture() {
   478    local version="$1"
   479    local arch="$2"
   480    local os="$3"
   481  
   482    # Local version always allowed.
   483    if [[ "$version" == "local"* ]]; then
   484        return 0
   485    fi
   486  
   487    # Otherwise, check the matrix of OS/architecture support.
   488    case "$arch/$os" in
   489        aarch64/Linux)
   490            return 0
   491            ;;
   492        aarch64/Darwin)
   493            return 0
   494            ;;
   495        s390x/Linux)
   496            return 0
   497            ;;
   498        x86_64/*)
   499            return 0
   500            ;;
   501    esac
   502  
   503    error "Sorry! Wasmtime currently only provides pre-built binaries for x86_64 (Linux, macOS, Windows), aarch64 (Linux, macOS), and s390x (Linux)."
   504    return 1
   505  }
   506  
   507  
   508  # return if sourced (for testing the functions above)
   509  return 0 2>/dev/null
   510  
   511  # default to installing the latest available version
   512  version_to_install="latest"
   513  
   514  # install to WASMTIME_HOME, defaulting to ~/.wasmtime
   515  install_dir="${WASMTIME_HOME:-"$HOME/.wasmtime"}"
   516  
   517  # parse command line options
   518  while [ $# -gt 0 ]
   519  do
   520    arg="$1"
   521  
   522    case "$arg" in
   523      -h|--help)
   524        usage
   525        exit 0
   526        ;;
   527      --dev)
   528        shift # shift off the argument
   529        version_to_install="local-dev"
   530        ;;
   531      --release)
   532        shift # shift off the argument
   533        version_to_install="local-release"
   534        ;;
   535      --version)
   536        shift # shift off the argument
   537        version_to_install="$1"
   538        shift # shift off the value
   539        ;;
   540      *)
   541        error "unknown option: '$arg'"
   542        usage
   543        exit 1
   544        ;;
   545    esac
   546  done
   547  
   548  check_architecture "$version_to_install" "$(get_architecture)" "$(uname)" || exit 1
   549  
   550  install_version "$version_to_install" "$install_dir"