Fix some bugs on Windows

This commit is contained in:
Taiki Endo
2023-09-16 22:26:41 +09:00
parent b441885d30
commit 55b35a1b0d
2 changed files with 159 additions and 85 deletions

View File

@@ -10,6 +10,8 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com
## [Unreleased] ## [Unreleased]
- Fix some bugs on Windows.
## [2.18.11] - 2023-09-15 ## [2.18.11] - 2023-09-15
- Update `cargo-hack@latest` to 0.6.8. - Update `cargo-hack@latest` to 0.6.8.

242
main.sh
View File

@@ -58,18 +58,11 @@ download_and_extract() {
local checksum="$2" local checksum="$2"
local bin_dir="$3" local bin_dir="$3"
local bin_in_archive="$4" # path to bin in archive local bin_in_archive="$4" # path to bin in archive
if [[ "${bin_dir}" == "/usr/"* ]]; then if [[ "${bin_dir}" == "${install_action_dir}/bin" ]]; then
if [[ ! -d "${bin_dir}" ]]; then init_install_action_bin_dir
bin_dir="${HOME}/.install-action/bin"
if [[ ! -d "${bin_dir}" ]]; then
mkdir -p "${bin_dir}"
canonicalize_windows_path "${bin_dir}" >>"${GITHUB_PATH}"
export PATH="${PATH}:${bin_dir}"
fi
fi
fi fi
local installed_bin
local installed_bin
# xbuild's binary name is "x", as opposed to the usual crate name # xbuild's binary name is "x", as opposed to the usual crate name
case "${tool}" in case "${tool}" in
xbuild) installed_bin="${bin_dir}/x" ;; xbuild) installed_bin="${bin_dir}/x" ;;
@@ -157,17 +150,17 @@ read_manifest() {
local tool="$1" local tool="$1"
local version="$2" local version="$2"
local manifest local manifest
rust_crate=$(jq -r ".rust_crate" "${manifest_dir}/${tool}.json") rust_crate=$(call_jq -r ".rust_crate" "${manifest_dir}/${tool}.json")
manifest=$(jq -r ".\"${version}\"" "${manifest_dir}/${tool}.json") manifest=$(call_jq -r ".\"${version}\"" "${manifest_dir}/${tool}.json")
if [[ "${manifest}" == "null" ]]; then if [[ "${manifest}" == "null" ]]; then
download_info="null" download_info="null"
return 0 return 0
fi fi
exact_version=$(jq <<<"${manifest}" -r '.version') exact_version=$(call_jq <<<"${manifest}" -r '.version')
if [[ "${exact_version}" == "null" ]]; then if [[ "${exact_version}" == "null" ]]; then
exact_version="${version}" exact_version="${version}"
else else
manifest=$(jq -r ".\"${exact_version}\"" "${manifest_dir}/${tool}.json") manifest=$(call_jq -r ".\"${exact_version}\"" "${manifest_dir}/${tool}.json")
fi fi
case "${host_os}" in case "${host_os}" in
linux) linux)
@@ -175,24 +168,24 @@ read_manifest() {
# usually preferred over linux-gnu binaries because they can avoid glibc version issues. # usually preferred over linux-gnu binaries because they can avoid glibc version issues.
# (rustc enables statically linking for linux-musl by default, except for mips.) # (rustc enables statically linking for linux-musl by default, except for mips.)
host_platform="${host_arch}_linux_musl" host_platform="${host_arch}_linux_musl"
download_info=$(jq <<<"${manifest}" -r ".${host_platform}") download_info=$(call_jq <<<"${manifest}" -r ".${host_platform}")
if [[ "${download_info}" == "null" ]]; then if [[ "${download_info}" == "null" ]]; then
# Even if host_env is musl, we won't issue an error here because it seems that in # Even if host_env is musl, we won't issue an error here because it seems that in
# some cases linux-gnu binaries will work on linux-musl hosts. # some cases linux-gnu binaries will work on linux-musl hosts.
# https://wiki.alpinelinux.org/wiki/Running_glibc_programs # https://wiki.alpinelinux.org/wiki/Running_glibc_programs
# TODO: However, a warning may make sense. # TODO: However, a warning may make sense.
host_platform="${host_arch}_linux_gnu" host_platform="${host_arch}_linux_gnu"
download_info=$(jq <<<"${manifest}" -r ".${host_platform}") download_info=$(call_jq <<<"${manifest}" -r ".${host_platform}")
fi fi
;; ;;
macos | windows) macos | windows)
# Binaries compiled for x86_64 macOS will usually also work on aarch64 macOS. # Binaries compiled for x86_64 macOS will usually also work on aarch64 macOS.
# Binaries compiled for x86_64 Windows will usually also work on aarch64 Windows 11+. # Binaries compiled for x86_64 Windows will usually also work on aarch64 Windows 11+.
host_platform="${host_arch}_${host_os}" host_platform="${host_arch}_${host_os}"
download_info=$(jq <<<"${manifest}" -r ".${host_platform}") download_info=$(call_jq <<<"${manifest}" -r ".${host_platform}")
if [[ "${download_info}" == "null" ]] && [[ "${host_arch}" != "x86_64" ]]; then if [[ "${download_info}" == "null" ]] && [[ "${host_arch}" != "x86_64" ]]; then
host_platform="x86_64_${host_os}" host_platform="x86_64_${host_os}"
download_info=$(jq <<<"${manifest}" -r ".${host_platform}") download_info=$(call_jq <<<"${manifest}" -r ".${host_platform}")
fi fi
;; ;;
*) bail "unsupported OS type '${host_os}' for ${tool}" ;; *) bail "unsupported OS type '${host_os}' for ${tool}" ;;
@@ -204,20 +197,24 @@ read_download_info() {
if [[ "${download_info}" == "null" ]]; then if [[ "${download_info}" == "null" ]]; then
bail "${tool}@${version} for '${host_os}' is not supported" bail "${tool}@${version} for '${host_os}' is not supported"
fi fi
checksum=$(jq <<<"${download_info}" -r '.checksum') checksum=$(call_jq <<<"${download_info}" -r '.checksum')
url=$(jq <<<"${download_info}" -r '.url') url=$(call_jq <<<"${download_info}" -r '.url')
if [[ "${url}" == "null" ]]; then if [[ "${url}" == "null" ]]; then
local template local template
template=$(jq -r ".template.${host_platform}" "${manifest_dir}/${tool}.json") template=$(call_jq -r ".template.${host_platform}" "${manifest_dir}/${tool}.json")
url=$(jq <<<"${template}" -r '.url') url=$(call_jq <<<"${template}" -r '.url')
url="${url//\$\{version\}/${exact_version}}" url="${url//\$\{version\}/${exact_version}}"
bin_in_archive=$(jq <<<"${template}" -r '.bin') bin_in_archive=$(call_jq <<<"${template}" -r '.bin')
bin_in_archive="${bin_in_archive//\$\{version\}/${exact_version}}" bin_in_archive="${bin_in_archive//\$\{version\}/${exact_version}}"
else else
bin_in_archive=$(jq <<<"${download_info}" -r '.bin') bin_in_archive=$(call_jq <<<"${download_info}" -r '.bin')
fi fi
if [[ "${rust_crate}" == "null" ]]; then if [[ "${rust_crate}" == "null" ]]; then
bin_dir="/usr/local/bin" if [[ "${host_os}" == "windows" ]] || [[ ! -e /usr/local/bin ]]; then
bin_dir="${install_action_dir}/bin"
else
bin_dir=/usr/local/bin
fi
else else
bin_dir="${cargo_bin}" bin_dir="${cargo_bin}"
fi fi
@@ -235,10 +232,11 @@ download_from_download_info() {
} }
install_cargo_binstall() { install_cargo_binstall() {
local binstall_version local binstall_version
binstall_version=$(jq -r '.latest.version' "${manifest_dir}/cargo-binstall.json") binstall_version=$(call_jq -r '.latest.version' "${manifest_dir}/cargo-binstall.json")
local install_binstall='1' local install_binstall='1'
if [[ -f "${cargo_bin}/cargo-binstall${exe}" ]]; then _binstall_version=$("cargo-binstall${exe}" binstall -V 2>/dev/null || echo "")
if [[ "$(cargo binstall -V)" == "${binstall_version}" ]]; then if [[ -n "${_binstall_version}" ]]; then
if [[ "${_binstall_version}" == "${binstall_version}" ]]; then
info "cargo-binstall already installed at ${cargo_bin}/cargo-binstall${exe}" info "cargo-binstall already installed at ${cargo_bin}/cargo-binstall${exe}"
install_binstall='' install_binstall=''
else else
@@ -248,10 +246,15 @@ install_cargo_binstall() {
fi fi
if [[ -n "${install_binstall}" ]]; then if [[ -n "${install_binstall}" ]]; then
info "installing cargo-binstall" info "installing cargo-binstall@latest (${binstall_version})"
download_from_manifest "cargo-binstall" "latest" download_from_manifest "cargo-binstall" "latest"
info "cargo-binstall installed at $(type -P "cargo-binstall${exe}")" installed_at=$(type -P "cargo-binstall${exe}" || echo "")
rx cargo binstall -V if [[ -n "${installed_at}" ]]; then
info "cargo-binstall installed at ${installed_at}"
else
warn "cargo-binstall should be installed at ${bin_dir:-}/cargo-binstall${exe}; but cargo-binstall${exe} not found in path"
fi
rx "cargo-binstall${exe}" binstall -V
fi fi
} }
apt_update() { apt_update() {
@@ -307,9 +310,21 @@ sys_install() {
fedora) dnf_install "$@" ;; fedora) dnf_install "$@" ;;
esac esac
} }
init_install_action_bin_dir() {
if [[ -z "${init_install_action_bin:-}" ]]; then
init_install_action_bin=1
mkdir -p "${bin_dir}"
export PATH="${PATH}:${bin_dir}"
local _bin_dir
_bin_dir=$(canonicalize_windows_path "${bin_dir}")
# TODO: avoid this when already added
info "adding '${_bin_dir}' to PATH"
echo "${_bin_dir}" >>"${GITHUB_PATH}"
fi
}
canonicalize_windows_path() { canonicalize_windows_path() {
case "${host_os}" in case "${host_os}" in
windows) sed <<<"$1" 's/^\/c\//C:\\/' ;; windows) sed <<<"$1" 's/^\/c\//C:\\/; s/\//\\/g' ;;
*) echo "$1" ;; *) echo "$1" ;;
esac esac
} }
@@ -407,46 +422,101 @@ case "$(uname -m)" in
# So we can assume x86_64 unless it is aarch64 or arm. # So we can assume x86_64 unless it is aarch64 or arm.
*) host_arch="x86_64" ;; *) host_arch="x86_64" ;;
esac esac
info "host platform: ${host_arch}_${host_os}"
tmp_dir="${HOME}/.install-action/tmp" install_action_dir="${HOME}/.install-action"
tmp_dir="${install_action_dir}/tmp"
cargo_bin="${CARGO_HOME:-"${HOME}/.cargo"}/bin" cargo_bin="${CARGO_HOME:-"${HOME}/.cargo"}/bin"
# If $CARGO_HOME does not exist, or cargo installed outside of $CARGO_HOME/bin # If $CARGO_HOME does not exist, or cargo installed outside of $CARGO_HOME/bin
# is used ($CARGO_HOME/bin is most likely not included in the PATH), fallback to # is used ($CARGO_HOME/bin is most likely not included in the PATH), fallback to
# /usr/local/bin or $HOME/.install-action/bin. # /usr/local/bin or $install_action_dir/bin.
if [[ ! -d "${cargo_bin}" ]] || { [[ "${host_os}" != "windows" ]] && [[ "$(type -P cargo || true)" != "${cargo_bin}/cargo${exe}" ]]; }; then if [[ ! -e "${cargo_bin}" ]] || [[ "$(type -P cargo || true)" != "${cargo_bin}/cargo"* ]]; then
cargo_bin=/usr/local/bin if type -P cargo &>/dev/null; then
info "cargo is located at $(type -P cargo)"
fi
if [[ "${host_os}" == "windows" ]] || [[ ! -e /usr/local/bin ]]; then
cargo_bin="${install_action_dir}/bin"
else
cargo_bin=/usr/local/bin
fi
fi fi
if ! type -P jq &>/dev/null || ! type -P curl &>/dev/null || ! type -P tar &>/dev/null; then jq_use_b=''
case "${base_distro}" in case "${host_os}" in
debian | fedora | alpine) linux)
echo "::group::Install packages required for installation (jq, curl, and/or tar)" if ! type -P jq &>/dev/null || ! type -P curl &>/dev/null || ! type -P tar &>/dev/null; then
sys_packages=() case "${base_distro}" in
if ! type -P curl &>/dev/null; then debian | fedora | alpine)
sys_packages+=(ca-certificates curl) echo "::group::Install packages required for installation (jq, curl, and/or tar)"
fi sys_packages=()
if ! type -P tar &>/dev/null; then if ! type -P curl &>/dev/null; then
sys_packages+=(tar) sys_packages+=(ca-certificates curl)
fi fi
if [[ "${dnf:-}" == "yum" ]]; then if ! type -P tar &>/dev/null; then
# On RHEL7-based distribution jq requires EPEL sys_packages+=(tar)
if ! type -P jq &>/dev/null; then fi
sys_packages+=(epel-release) if [[ "${dnf:-}" == "yum" ]]; then
sys_install "${sys_packages[@]}" # On RHEL7-based distribution jq requires EPEL
sys_install jq --enablerepo=epel if ! type -P jq &>/dev/null; then
else sys_packages+=(epel-release)
sys_install "${sys_packages[@]}" sys_install "${sys_packages[@]}"
fi sys_install jq --enablerepo=epel
else else
if ! type -P jq &>/dev/null; then sys_install "${sys_packages[@]}"
sys_packages+=(jq) fi
fi else
sys_install "${sys_packages[@]}" if ! type -P jq &>/dev/null; then
fi sys_packages+=(jq)
echo "::endgroup::" fi
;; sys_install "${sys_packages[@]}"
esac fi
fi echo "::endgroup::"
;;
*) warn "install-action requires at least jq and curl on non-Debian/Fedora/Alpine-based Linux" ;;
esac
fi
;;
macos)
if ! type -P jq &>/dev/null || ! type -P curl &>/dev/null; then
warn "install-action requires at least jq and curl on macOS"
fi
;;
windows)
if ! type -P curl &>/dev/null; then
warn "install-action requires at least curl on Windows"
fi
# https://github.com/jqlang/jq/issues/1854
jq_use_b=1
jq="${install_action_dir}/jq/bin/jq.exe"
if [[ ! -f "${jq}" ]]; then
jq_version=$(jq --version || echo "")
case "${jq_version}" in
jq-1.[7-9]* | jq-1.[1-9][0-9]*) jq='' ;;
*)
info "old jq (${jq_version}) has bug on Windows; downloading jq 1.7 (will not be added to PATH)"
mkdir -p "${install_action_dir}/jq/bin"
url='https://github.com/jqlang/jq/releases/download/jq-1.7/jq-windows-amd64.exe'
checksum='2e9cc54d0a5d098e2007decec1dbb3c555ca2f5aabded7aec907fe0ffe401aab'
(
cd "${install_action_dir}/jq/bin"
download_and_checksum "${url}" "${checksum}"
mv tmp jq.exe
)
echo
;;
esac
fi
;;
*) bail "unsupported host OS '${host_os}'" ;;
esac
call_jq() {
# https://github.com/jqlang/jq/issues/1854
if [[ -n "${jq_use_b}" ]]; then
"${jq:-jq}" -b "$@"
else
"${jq:-jq}" "$@"
fi
}
unsupported_tools=() unsupported_tools=()
for tool in "${tools[@]}"; do for tool in "${tools[@]}"; do
@@ -468,13 +538,11 @@ for tool in "${tools[@]}"; do
read_manifest "protoc" "${version}" read_manifest "protoc" "${version}"
read_download_info "protoc" "${version}" read_download_info "protoc" "${version}"
# Copying files to /usr/local/include requires sudo, so do not use it. # Copying files to /usr/local/include requires sudo, so do not use it.
bin_dir="${HOME}/.install-action/bin" bin_dir="${install_action_dir}/bin"
include_dir="${HOME}/.install-action/include" include_dir="${install_action_dir}/include"
if [[ ! -d "${bin_dir}" ]]; then init_install_action_bin_dir
mkdir -p "${bin_dir}" if [[ ! -e "${include_dir}" ]]; then
mkdir -p "${include_dir}" mkdir -p "${include_dir}"
canonicalize_windows_path "${bin_dir}" >>"${GITHUB_PATH}"
export PATH="${PATH}:${bin_dir}"
fi fi
if ! type -P unzip &>/dev/null; then if ! type -P unzip &>/dev/null; then
case "${base_distro}" in case "${base_distro}" in
@@ -493,10 +561,10 @@ for tool in "${tools[@]}"; do
mv "bin/protoc${exe}" "${bin_dir}/" mv "bin/protoc${exe}" "${bin_dir}/"
mkdir -p "${include_dir}/" mkdir -p "${include_dir}/"
cp -r include/. "${include_dir}/" cp -r include/. "${include_dir}/"
bin_dir=$(canonicalize_windows_path "${bin_dir}")
if [[ -z "${PROTOC:-}" ]]; then if [[ -z "${PROTOC:-}" ]]; then
info "setting PROTOC environment variable" _bin_dir=$(canonicalize_windows_path "${bin_dir}")
echo "PROTOC=${bin_dir}/protoc${exe}" >>"${GITHUB_ENV}" info "setting PROTOC environment variable to '${_bin_dir}/protoc${exe}'"
echo "PROTOC=${_bin_dir}/protoc${exe}" >>"${GITHUB_ENV}"
fi fi
) )
rm -rf "${tmp_dir}" rm -rf "${tmp_dir}"
@@ -519,7 +587,6 @@ for tool in "${tools[@]}"; do
snap_install valgrind --classic snap_install valgrind --classic
;; ;;
cargo-binstall) cargo-binstall)
info "installing ${tool}@${version}"
case "${version}" in case "${version}" in
latest) ;; latest) ;;
*) warn "specifying the version of ${tool} is not supported by this action" ;; *) warn "specifying the version of ${tool} is not supported by this action" ;;
@@ -580,21 +647,26 @@ for tool in "${tools[@]}"; do
xbuild) tool_bin="x" ;; xbuild) tool_bin="x" ;;
*) tool_bin="${tool}" ;; *) tool_bin="${tool}" ;;
esac esac
info "${tool} installed at $(type -P "${tool_bin}${exe}")" installed_at=$(type -P "${tool_bin}${exe}" || echo "")
if [[ -n "${installed_at}" ]]; then
tool_bin="${tool_bin}${exe}"
else
installed_at=$(type -P "${tool_bin}" || echo "")
fi
if [[ -n "${installed_at}" ]]; then
info "${tool} installed at ${installed_at}"
else
warn "${tool} should be installed at ${bin_dir:+"${bin_dir}/"}${tool_bin}${exe}; but ${tool_bin}${exe} not found in path"
fi
# cargo-udeps 0.1.30 and wasm-pack 0.12.0 do not support --version option. # cargo-udeps 0.1.30 and wasm-pack 0.12.0 do not support --version option.
case "${tool}" in case "${tool}" in
cargo-careful | cargo-machete) ;; # cargo-careful 0.3.4 and cargo-machete 0.5.0 do not support neither --version nor --help option. cargo-careful | cargo-machete) ;; # cargo-careful 0.3.4 and cargo-machete 0.5.0 do not support neither --version nor --help option.
cargo-*) cargo-*)
if type -P cargo &>/dev/null; then
_cargo=cargo
else
_cargo="${tool}"
fi
case "${tool}" in case "${tool}" in
cargo-valgrind) rx "${_cargo}" "${tool#cargo-}" --help ;; # cargo-valgrind 2.1.0's --version option just calls cargo's --version option cargo-valgrind) rx "${tool_bin}" "${tool#cargo-}" --help ;; # cargo-valgrind 2.1.0's --version option just calls cargo's --version option
*) *)
if ! rx "${_cargo}" "${tool#cargo-}" --version; then if ! rx "${tool_bin}" "${tool#cargo-}" --version; then
rx "${_cargo}" "${tool#cargo-}" --help rx "${tool_bin}" "${tool#cargo-}" --help
fi fi
;; ;;
esac esac