Skip to content

Instantly share code, notes, and snippets.

@salewski
Created November 3, 2020 07:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save salewski/d85517f5e2eca6988872d5e60fa1759a to your computer and use it in GitHub Desktop.
Save salewski/d85517f5e2eca6988872d5e60fa1759a to your computer and use it in GitHub Desktop.
Print all rustup 'rustc' versions mapped to the corresponding "toolchain" name
#!/bin/bash -
# SPDX-FileCopyrightText: <text> © 2020 Alan D. Salewski <ads@salewski.email> </text>
# SPDX-License-Identifier: GPL-2.0-or-later
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,, USA.
# rustup-rustc-versions: Print all rustup 'rustc' versions mapped to
# the corresponding "toolchain".
#
# Uses 'rustup' and related commands to obtain the list of rustup
# "toolchain" names and their corresponding rustc(1) versions, for
# each toolchain the user has configured.
#
# This program is a more ergonomic version of the following command
# (from which it evolved):
#
# $ ( target=$(eval "$(rustc --print cfg | grep -E '^target_(arch|vendor|os|env)=')" && printf '%s-%s-%s-%s\n' "${target_arch}" "${target_vendor}" "${target_os}" "${target_env}" ) && rustup toolchain list | sed -e 's/[[:space:]]\{1,\}[(]default[)][[:space:]]*$//' -e 's/'"-${target}"'$//' | while read -r tc; do printf '%10s: %s\n' "$tc" "$(rustup run $tc rustc --version)"; done )
# stable: rustc 1.47.0 (18bf6b4f0 2020-10-07)
# beta: rustc 1.48.0-beta.5 (4c78178b1 2020-10-21)
# nightly: rustc 1.49.0-nightly (ffa2e7ae8 2020-10-24)
# system: rustc 1.46.0
#
# Usage:
# rustup-rustc-versions
#
#
# Example:
# $ rustup-rustc-versions
# stable: rustc 1.47.0 (18bf6b4f0 2020-10-07)
# beta: rustc 1.48.0-beta.5 (4c78178b1 2020-10-21)
# nightly: rustc 1.49.0-nightly (ffa2e7ae8 2020-10-24)
# system: rustc 1.46.0
#
#
# See also:
#
# * rustup
#
# * rustc(1)
#
declare -r PROG='rustup-rustc-versions'
DEBUGGING=false
# By default we'll use the external programs found on $PATH. But we
# allow the user to override any particular tool by setting an
# environment variable named after the tool (with hyphen chars
# changed to underscores).
#
SED_PROG="${SED:-sed}"
GREP_PROG="${GREP:-grep}"
RUSTC_PROG="${RUSTC:-rustc}"
RUSTUP_PROG="${RUSTUP:-rustup}"
declare -a NEEDED_EXTERNAL_PROGS=(
"${SED_PROG}"
"${GREP_PROG}"
"${RUSTC_PROG}"
"${RUSTUP_PROG}"
)
for ext_tool in "${NEEDED_EXTERNAL_PROGS[@]}"; do
t_path=$(builtin type -p "${ext_tool}")
if test $? -ne 0; then
printf "${PROG} (error): was unable to locate \"%s\" on PATH; bailing out\n" "${ext_tool}" 1>&2
exit 1
fi
if $DEBUGGING; then
printf "${PROG} (debug): path to external tool \"%s\": %s\n" "${ext_tool}" "${t_path}" 1>&2
fi
done
# We use the 'rustup toolchain list' command to enumerate all of the
# rustup "toolchains" that the user has configured.
#
# $ rustup toolchain list
# stable-x86_64-unknown-linux-gnu
# beta-x86_64-unknown-linux-gnu
# nightly-x86_64-unknown-linux-gnu
# system (default)
#
# There's currently no knob to prevent that " (default)" token from
# being emitted, so we'll slice it off manually:
#
# $ rustup toolchain list | sed -e 's/[[:space:]]\{1,\}[(]default[)][[:space:]]*$//'
# stable-x86_64-unknown-linux-gnu
# beta-x86_64-unknown-linux-gnu
# nightly-x86_64-unknown-linux-gnu
# system
#
# The list of "toolchain" names in the above output is specific, but
# that comprehensive spelling is not typically how users specify
# them on the rustup command line. Rather than,
# "nightly-x86_64-unknown-linux-gnu", the user would just type
# "nightly", at least in the common case of targetting the current
# host and a non-date-specific nightly.
#
# The 'x86_64-unknown-linux-gnu' value is in the form:
#
# <arch>-<vendor>-<os>-<env>
#
# and we can query for the correct values to use for those fields on
# the current host from the 'rustc --print cfg' command:
#
# $ rustc --print cfg
# debug_assertions
# target_arch="x86_64"
# target_endian="little"
# target_env="gnu"
# target_family="unix"
# target_feature="fxsr"
# target_feature="sse"
# target_feature="sse2"
# target_os="linux"
# target_pointer_width="64"
# target_vendor="unknown"
# unix
#
# We can pull out just the relevant settings like this:
#
# $ rustc --print cfg | grep -E '^target_(arch|vendor|os|env)='
# target_arch="x86_64"
# target_env="gnu"
# target_os="linux"
# target_vendor="unknown"
#
# Notice that those are legit shell statements, so if we do that in
# a subshell we can just use the 'target_*' variables directly:
#
# $ ( eval "$(rustc --print cfg | grep -E '^target_(arch|vendor|os|env)=')" && printf '%s-%s-%s-%s\n' "${target_arch}" "${target_vendor}" "${target_os}" "${target_env}" )
# x86_64-unknown-linux-gnu
#
target=$( eval "$("${RUSTC_PROG}" --print cfg \
| "${GREP_PROG}" -E '^target_(arch|vendor|os|env)=')" \
&& printf '%s-%s-%s-%s\n' \
"${target_arch}" \
"${target_vendor}" \
"${target_os}" \
"${target_env}" )
if test $? -ne 0 \
|| test -z "${target}"; then
printf "${PROG} (error): was unable to extract <arch>-<vendor>-<os>-<env> target spec; bailing out\n" 1>&2
exit 1
fi
# Gather "toolchain" names, slicing off the " (default)" label, and
# shortening the explicit toolchain names that match our default
# target host arch/vendor/os/env.
#
# We will note the length of the longest name as we go.
#
declare -a toolchain_names=()
largest=0
while read -r tc_name; do
toolchain_names+=( "${tc_name}" )
if test "${#tc_name}" -gt "${largest}"; then
largest=${#tc_name}
fi
done < <("${RUSTUP_PROG}" toolchain list \
| "${SED_PROG}" -e 's/[[:space:]]\{1,\}[(]default[)][[:space:]]*$//' \
-e 's/'"-${target}"'$//')
if test $? -ne 0; then
printf "${PROG} (error): was unable to obtain list of rustup \"toolchain\" names; bailing out\n" 1>&2
exit 1
fi
# We will use the $largest value to display the toolchain names in a
# fixed width field.
#
for one_tc_name in "${toolchain_names[@]}"; do
printf '%*s: %s\n' \
"${largest}" "${one_tc_name}" \
"$("${RUSTUP_PROG}" run "${one_tc_name}" rustc --version)"
if test $? -ne 0; then
printf "${PROG} (error): was unable to print rustc version for toolchain \"%s\"; bailing out\n" \
"${one_tc_name}" 1>&2
exit 1
fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment