Skip to content

Instantly share code, notes, and snippets.

@rubeniskov
Last active April 29, 2018 14:47
Show Gist options
  • Save rubeniskov/79c6f105b4ab472472bdcbcb3bd7fde6 to your computer and use it in GitHub Desktop.
Save rubeniskov/79c6f105b4ab472472bdcbcb3bd7fde6 to your computer and use it in GitHub Desktop.
Linaro Toolchain Utils Standalone
#!/usr/bin/env bash
VERSION=""
LTU_VERSION=${VERSION:="TESTING"}
LTU_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
LTU_PATH=${LTU_PATH:="$LTU_DIR"}
LTU_DEST_DIR=${LTU_DEST_DIR:="$LTU_PATH/toolchains"}
LTU_CACHE_DIR=${LTU_CACHE_DIR:="$LTU_PATH/cache"}
LTU_RELEASE_LINKS_URL=${LTU_RELEASE_LINKS_URL:="https://gist.githubusercontent.com/rubeniskov/d5c04095c41076c4dfe5273015c9a871/raw"}
LTU_GNU_BINARIES=( "getopt" )
LTU_BASH_BINARIES=( "sort" "awk" "cut" "grep" "cut" "head" "tail")
LTU_THIRD_PARTY_BINARIES=( "curl" )
ltu_filter_version(){
awk '/^[0-9]/{ print $0 }'
}
ltu_filter_brief(){
[[ $* = *"--brief"* ]] && (awk '{print $1" "$4}' | sort | uniq) || cat -
}
ltu_filter_host_arch(){
[[ $* = *"--host-arch"* ]] && grep -w "$(uname -m)" || cat -
}
ltu_filter_grep(){
local pattern=$(echo "$*"|sed -e 's/--[0-9a-z\-]*//g'|sed -e 's/[[:space:]]*$//')
#echo >&2 ".*${pattern// /.*\s.*}.*"
#local pattern=$(echo ${*//-*/}|sed -e 's/^[[:space:]]*//')
[[ -n $pattern ]] && grep ".*${pattern// /.*\s.*}.*" || cat -
}
ltu_filter_latest(){
[[ $* = *"--latest"* ]] && (sort | awk '
BEGIN {
# initialize numeric cursor better than use an object
len=0
}
NR>1{
cur_ver=$1
cur_rev=$2
# if versions changes print the stored results
if(prev_ver && cur_ver != prev_ver) {
for (i = 1; i<len; i++) {
print(arr[i]);
}
len=0;
}
# if not revision could change then reset the cursor to store the new data
else if (prev_rev && cur_rev != prev_rev) {
len=0;
}
# store result
else
{
arr[len++]=$0
}
# save prev state
prev_ver=cur_ver
prev_rev=cur_rev
}
END {
# print the rest of the data
for (i = 1; i<len; i++) {
print(arr[i]);
}
}') || cat -
}
ltu_parse_html_links(){
grep "<a" |\
sed -n 's/.*href="\([^"]*\).*/\1/p'
}
ltu_parse_basename(){
awk 'function basename(file, a, n) {
n = split(file, a, "/")
return a[n]
}
{print basename($1)}'
}
ltu_parse_toolchain(){
awk 'function basename(file, a, n) {
n = split(file, a, "/")
return a[n]
}
{print basename($1)" "$1}' |\
sed -n -E 's/gcc-linaro-(([0-9]+\.)+([0-9]))-([0-9]{4}(\.[0-9]{2})+(-[0-9]+)?)-([a-z0-9-]+(_64)?)_([a-z0-9-]+)(.*) /\1 \4 \7 \9 /p'
}
ltu_parse_group_by(){
awk -F, 'NR>1{arr[$1]++}END{for (a in arr) print a, arr[a]}'
}
ltu_format_table(){
awk -v argv="$*" '
function max(a, b){
return (a > b) ? a : b;
}
function draw_splitter(column_sizes){
for(i = 1; i <= length(column_sizes); i++) {
str_splitter=sprintf("%"column_sizes[i]"s", "");
gsub(/ /, "-", str_splitter);
printf("%s",("|"str_splitter));
}
print("|");
}
function draw_header(column_names, column_sizes) {
col_len = length(column_sizes)
for(i = 1; i <= col_len; i++) {
for(j = col_len + 1; col_len == i && j <= length(column_names); j ++) {
column_names[i] = column_names[i]" "column_names[j];
}
printf("| %"(i == 1 ? "": "-")(column_sizes[i] - 2)"s ", column_names[i]);
}
print("|");
}
function draw_row(column_values, column_sizes) {
split(column_values, column_values, " ");
draw_header(column_values, column_sizes);
}
function parse_argv(argv){
split(argv, args, " ");
for (i = 1; i <= length(args); i++) {
split(args[i], column, "%");
if (length(column[2]) == 0) {
column[2] = length(column[1]) + 2;
} else {
column[2] = max(column[2], length(column[1]) + 2);
}
column_names[i] = column[1];
column_sizes[i] = column[2];
}
}
BEGIN {
nores = 1;
parse_argv(argv);
draw_splitter(column_sizes);
draw_header(column_names, column_sizes);
draw_splitter(column_sizes);
}
END {
if (nores)
draw_row("No Results", column_sizes);
draw_splitter(column_sizes);
}
{
nores=0;
draw_row($0, column_sizes);
}'
}
ltu_format_local_toolchain(){
awk '{
printf("gcc-linaro-%s-%s-%s_%s\n", $1, $2, $3, $4)
}'
}
ltu_format_remote_toolchain(){
awk -v url_base="$LTU_RELEASES_URL" '{
split($1, version, ".")
printf("%s/%s-%s/%s/gcc-linaro-%s-%s-%s_%s.tar.xz\n", url_base, version[1]"."version[2], $2, $4, $1, $2, $3, $4)
}'
}
ltu_get_platform(){
unameOut="$(uname -s)"
case "${unameOut}" in
Linux*) platform=Linux;;
Darwin*) platform=Mac;;
CYGWIN*) platform=Cygwin;;
MINGW*) platform=MinGw;;
*) platform="UNKNOWN:${unameOut}"
esac
echo ${platform}
}
ESC_SEQ="\x1b["
COL_RESET=$ESC_SEQ"39;49;00m"
COL_RED=$ESC_SEQ"31;01m"
COL_GREEN=$ESC_SEQ"32;01m"
COL_YELLOW=$ESC_SEQ"33;01m"
COL_BLUE=$ESC_SEQ"34;01m"
COL_MAGENTA=$ESC_SEQ"35;01m"
COL_CYAN=$ESC_SEQ"36;01m"
ltu_log() {
local ret
local label=$1
local color=$COL_GREEN
local msg=$2
local detail=$3
local cols=$(tput cols)
case $1 in
err)
label="error"
color=$COL_RED
;;
prg)
ret=1
label=$3
detail=$4
;;
wrn)
label="warn"
color=$COL_YELLOW
;;
info)
label="o.k."
;;
*)
label="..."
msg="$1"
detail="$2"
;;
esac
msg="[ $color$(printf "%5s" $label)$COL_RESET ] $msg"
if [[ -n "$detail" ]]; then
#msg="$msg ( $COL_BLUE${detail:0:$(($cols-${#msg}))}$COL_RESET )"
msg="$msg ( $COL_BLUE$detail$COL_RESET )"
fi
# msg="$msg"
echo -en >&2 "$(printf '%*s\n' "${COLUMNS:-$(($cols))}" '')\r"
if [[ -n $ret ]]; then
echo -en >&2 "$msg\r"
else
echo -e >&2 "$msg"
fi
# log function parameters to install.log
#[[ -n $DEST ]] && echo "Displaying message: $@" >> $DEST/debug/output.log
}
ltu_exec(){
$(ltu_find_command $1) "${@:2}"
}
ltu_check_command(){
echo $1
command -v "${1}" >/dev/null 2>&1 || {
toolchain_display_alert "Missing command or not installed Aborting." "${1}" "wrn";
echo >&2;
exit 1;
}
return 0
}
ltu_find_command(){
local cmd_path
local cmd_name="${1}"
local cmd_stored_path=$(echo $LTU_CMD_STORE|tr ' ' '\n'|grep "${cmd_name}:"|awk -F':' '{print $2}'|head -n 1)
if [ -n "$cmd_stored_path" ]; then
echo $cmd_stored_path
return 0
fi
case "$(ltu_get_platform)" in
Linux*)
cmd_path=$(which $1)
;;
Mac)
if [ $(ltu_check_command brew) ]; then
cmd_path=$(brew --prefix "gnu-${cmd_name}" 2>/dev/null||brew --prefix "${cmd_name}" 2>/dev/null)
if [ $cmd_path ] && [ -f "${cmd_path}/bin/${cmd_name}" ]; then
cmd_path="${cmd_path}/bin/${cmd_name}"
else
cmd_path=$(which ${cmd_name})
fi
fi
;;
esac
if [ -z $cmd_path ]; then
toolchain_display_alert "Command not found" "${cmd_name}" "wrn"
return 1
fi
LTU_CMD_STORE="$LTU_CMD_STORE $cmd_name:$cmd_path"
echo $cmd_path
return 0
}
ltu_time_since_file_modified(){
if [ -f "${1}" ]; then
echo "$(($(date +%s) - $(date -r "${1}" +"%s")))"
else
echo "$(((2**31)-1))"
fi
}
ltu_cache_results(){
if [ -n "${1}" ]; then
if [ ! $(mkdir -p "$(dirname $cache_file)") ]; then
cat - > $cache_file
fi
fi
cat $cache_file
}
ltu_get_from_url(){
ltu_exec curl \
--header "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36" \
$*
}
ltu_each() {
while read -r args; do
while read -r res; do
echo "$args"|awk -v res="$res" '{print $0" "res}'
done <<< "$($* $args)"
done
}
ltu_ls_remote() {
ltu_get_remote_toolchains |\
ltu_filter_host_arch $* |\
ltu_filter_latest $* |\
ltu_filter_brief $* |\
ltu_filter_grep $*
}
ltu_get_remote_toolchains() {
local cache_file="${LTU_CACHE_DIR}/.ltu_cache_remote"
local time_since_modify=$(ltu_time_since_file_modified ${cache_file})
([[ $time_since_modify -lt $((86400 * 7)) ]] &&
(cat "${cache_file}") ||
(ltu_get_from_url -s "$LTU_RELEASE_LINKS_URL" | ltu_cache_results "${cache_file}")) |\
ltu_parse_toolchain
}
ltu_ls_local(){
ltu_get_local_toolchains |\
ltu_filter_host_arch $* |\
ltu_filter_latest $* |\
ltu_filter_brief $* |\
ltu_filter_grep $*
}
ltu_get_local_files() {
mkdir -p $LTU_DEST_DIR && ls $LTU_DEST_DIR |\
awk -v base_uri=$LTU_DEST_DIR '{print base_uri"/"$0}'
}
ltu_get_local_toolchains(){
ltu_get_local_files |\
ltu_parse_toolchain
}
ltu_ls_usage(){
local app_name=$(basename $0)
cat <<EOF
Usage: $app_name ls <search> <options>
Example
$app_name ls 7.2 elf
$app_name ls 4.9 x86_64
Options
$app_name ls -q|--quiet Supress formats and colors usefull to parse the data
$app_name ls -a|--all Show all data
$app_name ls -l|--latest Match only with the latest revision of each version
$app_name ls --no-color Disable output color
$app_name ls --no-table Disable output table format
$app_name ls --no-host-arch Disable host architecture filter
$app_name ls --local Display only the installed toolchain packages
$app_name ls --remote Display only the remote toolchain packages
$app_name ls --help Display this usage
EOF
}
ltu_ls_remote_checking_locals(){
while read -r line; do
if [[ $(ltu_ls_local $* | grep -w "${line}") ]]; then
printf "%s %s\n" "☑" "${line}"
else
printf "%s %s\n" "☐" "${line}"
fi
done <<< "$(ltu_ls_remote $*)"
}
ltu_ls() {
local flags=("--brief --color --table --host-arch")
local pattern
local table_headers=("I Version%5" "Target%25")
local opts=$(ltu_exec getopt \
--options :qal \
--long quiet,all,latest,no-color,no-table,no-host-arch,local,remote,help \
--name 'ltu_ls' -- "$@")
eval set -- "$opts"
while true; do
case "${1}" in
--)
pattern="${@:2}"
break
;;
-q|--quiet)
flags=(${flags[@]//'--table'})
flags=(${flags[@]//'--color'})
shift 1
;;
-a|--all)
flags=(${flags[@]//'--brief'})
table_headers=("I Version%5" "Revision%15" "Host%15" "Target%25")
shift 1
;;
-l|--latest)
flags+=("--latest")
shift 1
;;
--local|--remote)
flags+=("${1}")
shift 1
;;
--no-color|--no-table|--no-host-arch)
local flag=${1//no-}
flags=(${flags[@]//$flag})
shift 1
;;
--help|*)
ltu_ls_usage
return 1
;;
esac
done
if [[ "${flags[*]}" = *"--local"* ]] || [[ "${flags[*]}" = *"--remote"* ]]; then
table_headers=(${table_headers[@]//'I'})
fi
([[ "${flags[*]}" = *"--local"* ]] && \
ltu_ls_local $pattern ${flags[*]}|| \
([[ "${flags[*]}" = *"--remote"* ]] && \
ltu_ls_remote $pattern ${flags[*]} || \
ltu_ls_remote_checking_locals $pattern ${flags[*]} )) |\
([[ "${flags[*]}" = *"--color"* ]] && awk '{ if ($1 ~ /^☑/) { printf("\033[1m\033[32m%s\033[0m\n", $0) } else { $6 = ""; print $0; } }' || cat -) |\
([[ "${flags[*]}" = *"--table"* ]] && ltu_format_table "${table_headers[@]}" || cat -)
}
ltu_download_usage() {
local app_name=$(basename $0)
cat <<EOF
Usage: $app_name download [version/s] <options>
Example
$app_name download 7.2 elf
$app_name download 4.9 elf
Options
$app_name download -d|--destination Destination folder
$app_name download -l|--latest Match only with the latest revision of each version
$app_name download -h|--help Display this usage
Versions
Arch Types
EOF
}
ltu_download() {
local pattern destination flags
local destination="/tmp"
local opts=$(ltu_exec getopt \
--options :d:lh \
--long destination:,latest,help \
--name 'ltu_download' -- "$@")
eval set -- "$opts"
while true; do
case "${1}" in
--)
pattern="${@:2}"
break
;;
--destination)
destination="$2"
shift 2
;;
--latest)
flags+=("$1")
shift 1
;;
-h|--help|*)
ltu_download_usage
exit 1
;;
esac
done
ltu_ls --remote -q -a ${pattern} |\
while read -r row; do
echo $row | ltu_format_remote_toolchain |\
while read -r url; do
local filename=${url##*/}
local path="${destination}/${filename}"
if [ ! -f "${path}" ]; then
mkdir -p "${destination}/"
ltu_get_from_url -Lf "${url}" --progress-bar -o "${path}" 2>&1 |\
while IFS= read -d $'\r' -r progress; do
ltu_log "prg" "Downloading" "${progress##* }" "$url"
done
if [[ $? != 0 ]];then
ltu_log "err" "Download failed" "${row}"
return 1
fi
ltu_log "info" "Downloaded" "${destination}/${filename}"
fi
printf "%s %s %s\n" "${row}" "${url}" "${path}"
done
done
return 0
}
ltu_unpack() {
local file=$1
local destination="${@: -1}"
local filename="${file##*/}"
local compression_type="${filename##*.}"
local dirname=${filename//.tar.$compression_type}
local total=0
mkdir -p "$destination"
tar xvpf $file "${dirname}/bin" "${dirname}/lib" -C $destination 2>&1 |\
while read filepath; do
total=$((total+1))
ltu_log "prg" "Unpacking" "$total" "$file ${filepath##*/}"
done
ltu_log "info" "Unpacked" "$file"
}
ltu_install_usage() {
local app_name=$(basename $0)
cat <<EOF
Usage: $app_name install [version/s] <options>
Example
$app_name install 7.2 elf
$app_name install 4.9 elf
Options
$app_name install --help: Display this usage
Versions
Arch Types
EOF
}
ltu_install() {
local destination="${LTU_DEST_DIR}"
local opts=$(ltu_exec getopt \
--options :h \
--long help \
--name 'toolchain install' -- "$@")
eval set -- "$opts"
while true; do
case "${1}" in
--)
pattern="${@:2}"
break
;;
-h|--help|*)
ltu_install_usage install
exit 1
;;
esac
done
ltu_download ${pattern} --latest |\
while read -r file; do
ltu_unpack $(echo $file | awk '{print $6}') ${destination}
done
return 0
}
ltu_use() {
local target=$(ltu_ls --local -q -a $@)
local count=$(echo "${target}"|wc -l)
if [[ -z "$target" ]];then
ltu_log "err" "No matches for this pattern" "$1"
return 1
fi
if [ "$count" -gt 1 ]; then
ltu_log "wrn" "Multiple choices for this pattern" "$1"
echo "$target"|awk '{printf(" -> %s\n", $0)}'
return 1
fi
ltu_log "info" "Using" "$target)"
LTU_TARGET=$(echo "${target}"|ltu_format_local_toolchain)
LTU_CROSS_COMPILE="$(echo "${target}"|awk '{print $4}')-"
# store original PATH and LD_LIBRARY_PATH
if [[ -z ${PATH_ORIGIN+x} ]]; then export PATH_ORIGIN=${PATH}; fi
if [[ -z ${LD_LIBRARY_PATH_ORIGIN+x} ]]; then export LD_LIBRARY_PATH_ORIGIN=${LD_LIBRARY_PATH}; fi
# configure environment
if [[ -n "${LTU_TARGET}" ]]; then
export ARCH=arm
export CROSS_COMPILE=${LTU_CROSS_COMPILE}
export LTU_ROOT="${LTU_DEST_DIR}/${LTU_TARGET}"
export PATH="${LTU_ROOT}/bin:${PATH_ORIGIN}"
export LD_LIBRARY_PATH="${LTU_ROOT}/lib:${LD_LIBRARY_PATH_ORIGIN}"
printenv | grep --color -E -w 'ARCH|CROSS_COMPILE|LTU_ROOT|PATH|LD_LIBRARY_PATH'
fi
}
ltu_usage() {
local app_name=$(basename $0)
cat <<EOF
Usage: $app_name [install|use|ls|ls-remote...] <options>
Version
$LTU_VERSION
Example
$app_name install 7.2 elf
$app_name use 7.2 elf
Commands
$app_name i/install <version/s> Extract and install toolchain
$app_name uninstall <version/s> Uninstall a version
$app_name use <version> [<target>] Modify the enviroment vars to use <version>.
$app_name which <version> Display path to installed toolchain version.
$app_name ls List remote versions checking installed
$app_name ls <version> List remote versions checking installed, matching a given <version>
$app_name ls-local List installed versions
$app_name ls-local <version> List installed versions, matching a given <version>
$app_name ls-remote List remote versions available for install
$app_name ls-remote <version> List remote versions available for install, matching a given <version>
$app_name download Download toolchain binaries
$app_name help Display this usage
Options:
$app_name --version: Display the toolchain utility version
$app_name -?|-h|--help: Display this usage
EOF
}
ltu() {
case "$1" in
ls)
shift
ltu_ls $@
;;
ls-remote)
shift
ltu_ls --remote $@
;;
ls-local)
shift
ltu_ls --local $@
;;
download)
shift
ltu_download $@
;;
install)
shift
ltu_install $@
;;
use)
shift
ltu_use $@
;;
--version)
echo $LTU_VERSION
;;
-h|--help|help|?|*)
ltu_usage
;;
esac
}
if [[ $_ != $0 ]]; then
ltu $@
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment