-
-
Save rubeniskov/79c6f105b4ab472472bdcbcb3bd7fde6 to your computer and use it in GitHub Desktop.
Linaro Toolchain Utils Standalone
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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