diff --git a/Cargo.lock b/Cargo.lock index 6c248fb9..9c9b8bf4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "amber" version = "0.3.1-alpha" @@ -10,6 +19,7 @@ dependencies = [ "colored", "heraclitus-compiler", "itertools", + "regex", "similar-string", ] @@ -234,6 +244,12 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + [[package]] name = "pad" version = "0.1.6" @@ -261,6 +277,35 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "regex" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + [[package]] name = "rustix" version = "0.38.10" diff --git a/Cargo.toml b/Cargo.toml index 55ed841d..e0585893 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ similar-string = "1.4.2" colored = "2.0.0" itertools = "0.11.0" clap = { version = "4.5.4", features = ["derive"] } +regex = "1.10.4" [profile.release] debug = true diff --git a/setup/install.sh b/setup/install.sh index 7ac24816..8538df05 100755 --- a/setup/install.sh +++ b/setup/install.sh @@ -1,254 +1,253 @@ -function has_failed__19_v0 { +#!/bin/bash +# Written in [Amber](https://amber-lang.com/) +# This is the runtime dependency checker. Please do not remove these lines. +AMBER_RDC_CD=('eval' 'exit' '[[' 'test' 'sudo' 'test' 'mkdir' 'curl' 'mv' 'chmod' 'ln' 'curl') +AMBER_RDC_MD=() +for d in "${AMBER_RDC_CD[@]}" +do + if ! command -v $d > /dev/null 2>&1; then + AMBER_RDC_MD+=($d) + fi +done + +if (( ${#AMBER_RDC_MD[@]} != 0 )); then + >&2 echo This program requires for these commands: \( $AMBER_RDC_MD \) to be present in \$PATH. + exit 1 +fi +unset $AMBER_RDC_CD +unset $AMBER_RDC_MD +# Dependencies are ok at this point + +function has_failed__20_v0 { local command=$1 eval ${command} > /dev/null 2>&1 -__AMBER_STATUS=$?; -if [ $__AMBER_STATUS != 0 ]; then -: -fi; - __AMBER_FUN_has_failed19_v0=$(echo $__AMBER_STATUS '!=' 0 | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//'); +__AS=$? + __AF_has_failed20_v0=$(echo $__AS '!=' 0 | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//'); return 0 -}; -function exit__20_v0 { +} +function exit__21_v0 { local code=$1 exit "${code}" -__AMBER_STATUS=$?; -if [ $__AMBER_STATUS != 0 ]; then -: -fi -}; -function includes__21_v0 { +__AS=$? +} +function includes__22_v0 { local arr=("${!1}") local value=$2 [[ "${arr[@]}" =~ "${value}" ]] -__AMBER_STATUS=$?; -if [ $__AMBER_STATUS != 0 ]; then -: -fi; - __AMBER_FUN_includes21_v0=$(echo $__AMBER_STATUS '==' 0 | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//'); +__AS=$? + __AF_includes22_v0=$(echo $__AS '==' 0 | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//'); return 0 } -function includes__21_v1 { +function includes__22_v1 { local arr=$1 local value=$2 [[ "${arr[@]}" =~ "${value}" ]] -__AMBER_STATUS=$?; -if [ $__AMBER_STATUS != 0 ]; then -: -fi; - __AMBER_FUN_includes21_v1=$(echo $__AMBER_STATUS '==' 0 | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//'); +__AS=$? + __AF_includes22_v1=$(echo $__AS '==' 0 | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//'); return 0 } -function get_os__28_v0 { +function get_os__29_v0 { __AMBER_VAL_0=$(uname -s); - __AMBER_STATUS=$?; -if [ $__AMBER_STATUS != 0 ]; then - echo "Failed to determine OS type."; - echo "Please try again or use another download method."; - exit__20_v0 1; - __AMBER_FUN_exit20_v0__8=${__AMBER_FUN_exit20_v0}; - echo ${__AMBER_FUN_exit20_v0__8} > /dev/null 2>&1 -fi; - local os_type="${__AMBER_VAL_0}"; - local os=$(if [ $([ "_${os_type}" != "_Darwin" ]; echo $?) != 0 ]; then echo "macos"; else echo "linux"; fi); - __AMBER_FUN_get_os28_v0="${os}"; + __AS=$?; +if [ $__AS != 0 ]; then + echo "Failed to determine OS type." + echo "Please try again or use another download method." + exit__21_v0 1; + __AF_exit21_v0__8=$__AF_exit21_v0; + echo $__AF_exit21_v0__8 > /dev/null 2>&1 +fi; + local os_type="${__AMBER_VAL_0}" + local os=$(if [ $([ "_${os_type}" != "_Darwin" ]; echo $?) != 0 ]; then echo "macos"; else echo "linux"; fi) + __AF_get_os29_v0="${os}"; return 0 -}; -function get_arch__29_v0 { +} +function get_arch__30_v0 { __AMBER_VAL_1=$(uname -m); - __AMBER_STATUS=$?; -if [ $__AMBER_STATUS != 0 ]; then - echo "Failed to determine architecture."; - echo "Please try again or use another download method."; - exit__20_v0 1; - __AMBER_FUN_exit20_v0__22=${__AMBER_FUN_exit20_v0}; - echo ${__AMBER_FUN_exit20_v0__22} > /dev/null 2>&1 -fi; - local arch_type="${__AMBER_VAL_1}"; + __AS=$?; +if [ $__AS != 0 ]; then + echo "Failed to determine architecture." + echo "Please try again or use another download method." + exit__21_v0 1; + __AF_exit21_v0__22=$__AF_exit21_v0; + echo $__AF_exit21_v0__22 > /dev/null 2>&1 +fi; + local arch_type="${__AMBER_VAL_1}" __AMBER_ARRAY_0=("arm64" "aarch64"); - includes__21_v0 __AMBER_ARRAY_0[@] "${arch_type}"; - __AMBER_FUN_includes21_v0__25=${__AMBER_FUN_includes21_v0}; - local arch=$(if [ ${__AMBER_FUN_includes21_v0__25} != 0 ]; then echo "aarch64"; else echo "x86_64"; fi); - __AMBER_FUN_get_arch29_v0="${arch}"; + includes__22_v0 __AMBER_ARRAY_0[@] "${arch_type}"; + __AF_includes22_v0__25=$__AF_includes22_v0; + local arch=$(if [ $__AF_includes22_v0__25 != 0 ]; then echo "aarch64"; else echo "x86_64"; fi) + __AF_get_arch30_v0="${arch}"; return 0 -}; -function get_home__30_v0 { +} +function get_home__31_v0 { __AMBER_VAL_2=$(echo $HOME); - __AMBER_STATUS=$?; -if [ $__AMBER_STATUS != 0 ]; then - echo "User installation requested, but unable to retrieve home directory from $HOME environment."; - exit__20_v0 1; - __AMBER_FUN_exit20_v0__35=${__AMBER_FUN_exit20_v0}; - echo ${__AMBER_FUN_exit20_v0__35} > /dev/null 2>&1 -fi; - local home="${__AMBER_VAL_2}"; + __AS=$?; +if [ $__AS != 0 ]; then + echo "User installation requested, but unable to retrieve home directory from $HOME environment." + exit__21_v0 1; + __AF_exit21_v0__35=$__AF_exit21_v0; + echo $__AF_exit21_v0__35 > /dev/null 2>&1 +fi; + local home="${__AMBER_VAL_2}" if [ $([ "_${home}" != "_" ]; echo $?) != 0 ]; then - echo "User installation requested, but unable to find home directory."; - exit__20_v0 1; - __AMBER_FUN_exit20_v0__39=${__AMBER_FUN_exit20_v0}; - echo ${__AMBER_FUN_exit20_v0__39} > /dev/null 2>&1 -fi; - __AMBER_FUN_get_home30_v0="${home}"; + echo "User installation requested, but unable to find home directory." + exit__21_v0 1; + __AF_exit21_v0__39=$__AF_exit21_v0; + echo $__AF_exit21_v0__39 > /dev/null 2>&1 +fi + __AF_get_home31_v0="${home}"; return 0 -}; -function get_bins_folder__31_v0 { +} +function get_bins_folder__32_v0 { local user_only=$1 if [ ${user_only} != 0 ]; then - get_home__30_v0 ; - __AMBER_FUN_get_home30_v0__46=${__AMBER_FUN_get_home30_v0}; - __AMBER_FUN_get_bins_folder31_v0="${__AMBER_FUN_get_home30_v0__46}/.local/bin"; + get_home__31_v0 ; + __AF_get_home31_v0__46="${__AF_get_home31_v0}"; + __AF_get_bins_folder32_v0="${__AF_get_home31_v0__46}/.local/bin"; return 0 else - local bins_folder="/usr/local/bin"; + local bins_folder="/usr/local/bin" test -d "${bins_folder}" -__AMBER_STATUS=$?; -if [ $__AMBER_STATUS != 0 ]; then +__AS=$?; +if [ $__AS != 0 ]; then sudo mkdir -p "${bins_folder}" > /dev/null 2>&1 -__AMBER_STATUS=$?; -if [ $__AMBER_STATUS != 0 ]; then - echo "Failed to create ${bins_folder} directory."; - exit__20_v0 1 > /dev/null 2>&1; - __AMBER_FUN_exit20_v0__53=${__AMBER_FUN_exit20_v0}; - echo ${__AMBER_FUN_exit20_v0__53} > /dev/null 2>&1 +__AS=$?; +if [ $__AS != 0 ]; then + echo "Failed to create ${bins_folder} directory." + exit__21_v0 1 > /dev/null 2>&1; + __AF_exit21_v0__53=$__AF_exit21_v0; + echo $__AF_exit21_v0__53 > /dev/null 2>&1 fi -fi; - __AMBER_FUN_get_bins_folder31_v0="${bins_folder}"; +fi + __AF_get_bins_folder32_v0="${bins_folder}"; return 0 fi -}; -function get_place__32_v0 { +} +function get_place__33_v0 { local user_only=$1 if [ ${user_only} != 0 ]; then - get_home__30_v0 ; - __AMBER_FUN_get_home30_v0__62=${__AMBER_FUN_get_home30_v0}; - get_arch__29_v0 ; - __AMBER_FUN_get_arch29_v0__62=${__AMBER_FUN_get_arch29_v0}; - __AMBER_FUN_get_place32_v0="${__AMBER_FUN_get_home30_v0__62}/.local/lib/${__AMBER_FUN_get_arch29_v0__62}/amber"; + get_home__31_v0 ; + __AF_get_home31_v0__62="${__AF_get_home31_v0}"; + get_arch__30_v0 ; + __AF_get_arch30_v0__62="${__AF_get_arch30_v0}"; + __AF_get_place33_v0="${__AF_get_home31_v0__62}/.local/lib/${__AF_get_arch30_v0__62}/amber"; return 0 else - __AMBER_FUN_get_place32_v0="/opt/amber"; + __AF_get_place33_v0="/opt/amber"; return 0 fi } -__0_name="AmberNative"; -__1_target="amber"; -__2_tag="0.3.1-alpha"; -has_failed__19_v0 "uname -a"; -__AMBER_FUN_has_failed19_v0__7=${__AMBER_FUN_has_failed19_v0}; +__0_name="AmberNative" +__1_target="amber" +__2_tag="0.3.1-alpha" +has_failed__20_v0 "uname -a"; +__AF_has_failed20_v0__7=$__AF_has_failed20_v0; __AMBER_VAL_3=$(uname -a); -__AMBER_STATUS=$?; -if [ $__AMBER_STATUS != 0 ]; then -: -fi; -__3_agent=$(if [ ${__AMBER_FUN_has_failed19_v0__7} != 0 ]; then echo "unknown"; else echo "${__AMBER_VAL_3}"; fi); -echo ""; +__AS=$?; +__3_agent=$(if [ $__AF_has_failed20_v0__7 != 0 ]; then echo "unknown"; else echo "${__AMBER_VAL_3}"; fi) +echo "" args=$1 - get_os__28_v0 ; - __AMBER_FUN_get_os28_v0__14=${__AMBER_FUN_get_os28_v0}; - os=${__AMBER_FUN_get_os28_v0__14}; - get_arch__29_v0 ; - __AMBER_FUN_get_arch29_v0__15=${__AMBER_FUN_get_arch29_v0}; - arch=${__AMBER_FUN_get_arch29_v0__15}; - includes__21_v1 "${args}" "--user"; - __AMBER_FUN_includes21_v1__17=${__AMBER_FUN_includes21_v1}; - user_only_install=${__AMBER_FUN_includes21_v1__17}; - get_place__32_v0 ${user_only_install}; - __AMBER_FUN_get_place32_v0__18=${__AMBER_FUN_get_place32_v0}; - place=${__AMBER_FUN_get_place32_v0__18}; - get_bins_folder__31_v0 ${user_only_install}; - __AMBER_FUN_get_bins_folder31_v0__19=${__AMBER_FUN_get_bins_folder31_v0}; - bins_folder=${__AMBER_FUN_get_bins_folder31_v0__19}; + get_os__29_v0 ; + __AF_get_os29_v0__14="${__AF_get_os29_v0}"; + os="${__AF_get_os29_v0__14}" + get_arch__30_v0 ; + __AF_get_arch30_v0__15="${__AF_get_arch30_v0}"; + arch="${__AF_get_arch30_v0__15}" + includes__22_v1 "${args}" "--user"; + __AF_includes22_v1__17=$__AF_includes22_v1; + user_only_install=$__AF_includes22_v1__17 + get_place__33_v0 ${user_only_install}; + __AF_get_place33_v0__18="${__AF_get_place33_v0}"; + place="${__AF_get_place33_v0__18}" + get_bins_folder__32_v0 ${user_only_install}; + __AF_get_bins_folder32_v0__19="${__AF_get_bins_folder32_v0}"; + bins_folder="${__AF_get_bins_folder32_v0__19}" test -d "${place}" -__AMBER_STATUS=$?; -if [ $__AMBER_STATUS != 0 ]; then -: -fi; - if [ $(echo $__AMBER_STATUS '==' 0 | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//') != 0 ]; then - echo "Amber already installed"; - echo "It seems that Amber is already installed on your system. (${place})"; - echo "If you want to reinstall Amber, uninstall it first."; - echo "(Find out more at https://docs.amber-lang.com/getting_started/installation#uninstallation)"; - exit__20_v0 2; - __AMBER_FUN_exit20_v0__29=${__AMBER_FUN_exit20_v0}; - echo ${__AMBER_FUN_exit20_v0__29} > /dev/null 2>&1 -fi; - has_failed__19_v0 "curl -V"; - __AMBER_FUN_has_failed19_v0__33=${__AMBER_FUN_has_failed19_v0}; - if [ ${__AMBER_FUN_has_failed19_v0__33} != 0 ]; then - echo "Curl is not installed on your system."; - echo "Please install \`curl\` and try again."; - exit__20_v0 1; - __AMBER_FUN_exit20_v0__36=${__AMBER_FUN_exit20_v0}; - echo ${__AMBER_FUN_exit20_v0__36} > /dev/null 2>&1 -fi; - echo "Installing Amber... 🚀"; - sudo=$(if [ ${user_only_install} != 0 ]; then echo ""; else echo "sudo"; fi); +__AS=$? + if [ $(echo $__AS '==' 0 | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//') != 0 ]; then + echo "Amber already installed" + echo "It seems that Amber is already installed on your system. (${place})" + echo "If you want to reinstall Amber, uninstall it first." + echo "(Find out more at https://docs.amber-lang.com/getting_started/installation#uninstallation)" + exit__21_v0 2; + __AF_exit21_v0__29=$__AF_exit21_v0; + echo $__AF_exit21_v0__29 > /dev/null 2>&1 +fi + has_failed__20_v0 "curl -V"; + __AF_has_failed20_v0__33=$__AF_has_failed20_v0; + if [ $__AF_has_failed20_v0__33 != 0 ]; then + echo "Curl is not installed on your system." + echo "Please install \`curl\` and try again." + exit__21_v0 1; + __AF_exit21_v0__36=$__AF_exit21_v0; + echo $__AF_exit21_v0__36 > /dev/null 2>&1 +fi + echo "Installing Amber... 🚀" + sudo=$(if [ ${user_only_install} != 0 ]; then echo ""; else echo "sudo"; fi) ${sudo} mkdir -p "${place}" > /dev/null 2>&1 -__AMBER_STATUS=$?; -if [ $__AMBER_STATUS != 0 ]; then - echo "Failed to create directory for amber."; +__AS=$?; +if [ $__AS != 0 ]; then + echo "Failed to create directory for amber." if [ ${user_only_install} != 0 ]; then echo "Please make sure that root user can access ${place} directory." else echo "Please make sure that your user can access ${place} directory." -fi; - exit__20_v0 1 > /dev/null 2>&1; - __AMBER_FUN_exit20_v0__52=${__AMBER_FUN_exit20_v0}; - echo ${__AMBER_FUN_exit20_v0__52} > /dev/null 2>&1 -fi; +fi + exit__21_v0 1 > /dev/null 2>&1; + __AF_exit21_v0__52=$__AF_exit21_v0; + echo $__AF_exit21_v0__52 > /dev/null 2>&1 +fi if [ ${user_only_install} != 0 ]; then mkdir -p "${bins_folder}" > /dev/null 2>&1 -__AMBER_STATUS=$?; -if [ $__AMBER_STATUS != 0 ]; then - echo "Failed to create directory for amber bin at ${bins_folder}."; - exit__20_v0 1 > /dev/null 2>&1; - __AMBER_FUN_exit20_v0__57=${__AMBER_FUN_exit20_v0}; - echo ${__AMBER_FUN_exit20_v0__57} > /dev/null 2>&1 +__AS=$?; +if [ $__AS != 0 ]; then + echo "Failed to create directory for amber bin at ${bins_folder}." + exit__21_v0 1 > /dev/null 2>&1; + __AF_exit21_v0__57=$__AF_exit21_v0; + echo $__AF_exit21_v0__57 > /dev/null 2>&1 fi -fi; - url="https://github.com/Ph0enixKM/${__0_name}/releases/download/${__2_tag}/amber_${os}_${arch}"; +fi + url="https://github.com/Ph0enixKM/${__0_name}/releases/download/${__2_tag}/amber_${os}_${arch}" curl -L -o "${__1_target}" "${url}" > /dev/null 2>&1 -__AMBER_STATUS=$?; -if [ $__AMBER_STATUS != 0 ]; then - echo "Curl failed to download amber."; - echo "Something went wrong. Please try again later."; - exit__20_v0 1 > /dev/null 2>&1; - __AMBER_FUN_exit20_v0__68=${__AMBER_FUN_exit20_v0}; - echo ${__AMBER_FUN_exit20_v0__68} > /dev/null 2>&1 -fi; +__AS=$?; +if [ $__AS != 0 ]; then + echo "Curl failed to download amber." + echo "Something went wrong. Please try again later." + exit__21_v0 1 > /dev/null 2>&1; + __AF_exit21_v0__68=$__AF_exit21_v0; + echo $__AF_exit21_v0__68 > /dev/null 2>&1 +fi ${sudo} mv "${__1_target}" "${place}/${__1_target}" -__AMBER_STATUS=$?; -if [ $__AMBER_STATUS != 0 ]; then - echo "Failed to move amber to the installation directory."; - echo "Please make sure that root user can access /opt directory."; - exit__20_v0 1; - __AMBER_FUN_exit20_v0__75=${__AMBER_FUN_exit20_v0}; - echo ${__AMBER_FUN_exit20_v0__75} > /dev/null 2>&1 -fi; +__AS=$?; +if [ $__AS != 0 ]; then + echo "Failed to move amber to the installation directory." + echo "Please make sure that root user can access /opt directory." + exit__21_v0 1; + __AF_exit21_v0__75=$__AF_exit21_v0; + echo $__AF_exit21_v0__75 > /dev/null 2>&1 +fi ${sudo} chmod +x "${place}/${__1_target}" -__AMBER_STATUS=$?; -if [ $__AMBER_STATUS != 0 ]; then - echo "Failed to give permissions to execute amber."; - echo "Please make sure that root user can access /opt directory."; - exit__20_v0 1; - __AMBER_FUN_exit20_v0__81=${__AMBER_FUN_exit20_v0}; - echo ${__AMBER_FUN_exit20_v0__81} > /dev/null 2>&1 -fi; +__AS=$?; +if [ $__AS != 0 ]; then + echo "Failed to give permissions to execute amber." + echo "Please make sure that root user can access /opt directory." + exit__21_v0 1; + __AF_exit21_v0__81=$__AF_exit21_v0; + echo $__AF_exit21_v0__81 > /dev/null 2>&1 +fi ${sudo} ln -s "${place}/${__1_target}" "${bins_folder}/${__1_target}" -__AMBER_STATUS=$?; -if [ $__AMBER_STATUS != 0 ]; then - echo "Failed to create amber symbol link."; - echo "Please make sure that root user can access /usr/local/bin directory."; - exit__20_v0 1; - __AMBER_FUN_exit20_v0__88=${__AMBER_FUN_exit20_v0}; - echo ${__AMBER_FUN_exit20_v0__88} > /dev/null 2>&1 -fi; +__AS=$?; +if [ $__AS != 0 ]; then + echo "Failed to create amber symbol link." + echo "Please make sure that root user can access /usr/local/bin directory." + exit__21_v0 1; + __AF_exit21_v0__88=$__AF_exit21_v0; + echo $__AF_exit21_v0__88 > /dev/null 2>&1 +fi curl -G --data-urlencode "agent=${__3_agent}" --data-urlencode "name=download" "https://amber-lang.com/api/visit" > /dev/null 2>&1 -__AMBER_STATUS=$?; -if [ $__AMBER_STATUS != 0 ]; then -: -fi; - echo "Amber has been installed successfully. 🎉"; - echo "> Now you can use amber by typing \`amber\` in your terminal."; +__AS=$? + echo "Amber has been installed successfully. 🎉" + echo "> Now you can use amber by typing \`amber\` in your terminal." if [ ${user_only_install} != 0 ]; then echo "> Since you requested a user only install with \`--user\` ensure that ~/.local/bin is in your \$PATH." fi \ No newline at end of file diff --git a/setup/uninstall.sh b/setup/uninstall.sh index c50a7c76..c49eb165 100755 --- a/setup/uninstall.sh +++ b/setup/uninstall.sh @@ -1,3 +1,23 @@ +#!/bin/bash +# Written in [Amber](https://amber-lang.com/) +# This is the runtime dependency checker. Please do not remove these lines. +AMBER_RDC_CD=('exit' '[[' 'test' 'sudo' 'test' 'rm') +AMBER_RDC_MD=() +for d in "${AMBER_RDC_CD[@]}" +do + if ! command -v $d > /dev/null 2>&1; then + AMBER_RDC_MD+=($d) + fi +done + +if (( ${#AMBER_RDC_MD[@]} != 0 )); then + >&2 echo This program requires for these commands: \( $AMBER_RDC_MD \) to be present in \$PATH. + exit 1 +fi +unset $AMBER_RDC_CD +unset $AMBER_RDC_MD +# Dependencies are ok at this point + function exit__21_v0 { local code=$1 exit "${code}" @@ -60,11 +80,24 @@ function get_bins_folder__30_v0 { local user_only=$1 if [ ${user_only} != 0 ]; then get_home__29_v0 ; - __AF_get_home29_v0__46=$__AF_get_home29_v0; - __AF_get_bins_folder30_v0="$__AF_get_home29_v0__46/.local/bin"; + __AF_get_home29_v0__46="${__AF_get_home29_v0}"; + __AF_get_bins_folder30_v0="${__AF_get_home29_v0__46}/.local/bin"; return 0 else - __AF_get_bins_folder30_v0="/usr/local/bin"; + local bins_folder="/usr/local/bin" + test -d "${bins_folder}" +__AS=$?; +if [ $__AS != 0 ]; then + sudo mkdir -p "${bins_folder}" > /dev/null 2>&1 +__AS=$?; +if [ $__AS != 0 ]; then + echo "Failed to create ${bins_folder} directory." + exit__21_v0 1 > /dev/null 2>&1; + __AF_exit21_v0__53=$__AF_exit21_v0; + echo $__AF_exit21_v0__53 > /dev/null 2>&1 +fi +fi + __AF_get_bins_folder30_v0="${bins_folder}"; return 0 fi } @@ -72,10 +105,10 @@ function get_place__31_v0 { local user_only=$1 if [ ${user_only} != 0 ]; then get_home__29_v0 ; - __AF_get_home29_v0__54=$__AF_get_home29_v0; + __AF_get_home29_v0__62="${__AF_get_home29_v0}"; get_arch__28_v0 ; - __AF_get_arch28_v0__54=$__AF_get_arch28_v0; - __AF_get_place31_v0="$__AF_get_home29_v0__54/.local/lib/$__AF_get_arch28_v0__54/amber"; + __AF_get_arch28_v0__62="${__AF_get_arch28_v0}"; + __AF_get_place31_v0="${__AF_get_home29_v0__62}/.local/lib/${__AF_get_arch28_v0__62}/amber"; return 0 else __AF_get_place31_v0="/opt/amber"; @@ -85,17 +118,17 @@ fi echo "" args=$1 get_arch__28_v0 ; - __AF_get_arch28_v0__8=$__AF_get_arch28_v0; - arch=$__AF_get_arch28_v0__8 + __AF_get_arch28_v0__8="${__AF_get_arch28_v0}"; + arch="${__AF_get_arch28_v0__8}" includes__22_v1 "${args}" "--user"; __AF_includes22_v1__10=$__AF_includes22_v1; user_only_install=$__AF_includes22_v1__10 get_place__31_v0 ${user_only_install}; - __AF_get_place31_v0__11=$__AF_get_place31_v0; - place=$__AF_get_place31_v0__11 + __AF_get_place31_v0__11="${__AF_get_place31_v0}"; + place="${__AF_get_place31_v0__11}" get_bins_folder__30_v0 ${user_only_install}; - __AF_get_bins_folder30_v0__12=$__AF_get_bins_folder30_v0; - bins_folder=$__AF_get_bins_folder30_v0__12 + __AF_get_bins_folder30_v0__12="${__AF_get_bins_folder30_v0}"; + bins_folder="${__AF_get_bins_folder30_v0__12}" test -d "${place}" > /dev/null __AS=$? if [ $(echo $__AS '==' 0 | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//') != 0 ]; then diff --git a/src/compiler.rs b/src/compiler.rs index 0bb5afd6..3705cb5f 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,5 +1,6 @@ use heraclitus_compiler::prelude::*; use crate::modules::block::Block; +use crate::modules::rdc; use crate::translate::check_all_blocks; use crate::utils::{ParserMetadata, TranslateMetadata}; use crate::translate::module::TranslateModule; @@ -15,14 +16,16 @@ const AMBER_DEBUG_TIME: &str = "AMBER_DEBUG_TIME"; pub struct AmberCompiler { pub cc: Compiler, - pub path: Option + pub path: Option, + pub rdc_disabled: bool } impl AmberCompiler { - pub fn new(code: String, path: Option) -> AmberCompiler { + pub fn new(code: String, path: Option, rdc_disabled: bool) -> AmberCompiler { AmberCompiler { cc: Compiler::new("Amber", rules::get_rules()), - path + path, + rdc_disabled }.load_code(code) } @@ -108,7 +111,16 @@ impl AmberCompiler { println!("[{}]\tin\t{}ms\t{pathname}", "Translate".magenta(), time.elapsed().as_millis()); } result.push(block.translate(&mut meta)); - result.join("\n") + let res = result.join("\n"); + let mut header = include_str!("header.sh").to_string(); + if ! self.rdc_disabled { + header += &rdc::generate(meta.externs); + } + format!( + "{}\n{}", + header, + res + ) } pub fn compile(&self) -> Result<(Vec, String), Message> { diff --git a/src/header.sh b/src/header.sh new file mode 100644 index 00000000..7d962fce --- /dev/null +++ b/src/header.sh @@ -0,0 +1,2 @@ +#!/bin/bash +# Written in [Amber](https://amber-lang.com/) diff --git a/src/main.rs b/src/main.rs index 7207ccb0..a4ebd8dd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,10 @@ struct Cli { /// Code to evaluate #[arg(short, long)] eval: Option, + + /// Disable Runtime Dependency Checker (not recommended) + #[arg(long)] + disable_rdc: bool } fn main() { @@ -32,7 +36,7 @@ fn main() { if let Some(code) = cli.eval { let code = format!("import * from \"std\"\n{code}"); - match AmberCompiler::new(code, None).compile() { + match AmberCompiler::new(code, None, cli.disable_rdc).compile() { Ok((messages, code)) => { messages.iter().for_each(|m| m.show()); (!messages.is_empty()).then(|| render_dash()); @@ -48,7 +52,7 @@ fn main() { match fs::read_to_string(&input) { Ok(code) => { - match AmberCompiler::new(code, Some(input)).compile() { + match AmberCompiler::new(code, Some(input), cli.disable_rdc).compile() { Ok((messages, code)) => { messages.iter().for_each(|m| m.show()); // Save to the output file diff --git a/src/modules/command/statement.rs b/src/modules/command/statement.rs index 61cfc262..050e4fd0 100644 --- a/src/modules/command/statement.rs +++ b/src/modules/command/statement.rs @@ -1,5 +1,5 @@ use heraclitus_compiler::prelude::*; -use crate::{utils::{ParserMetadata, TranslateMetadata}, modules::{types::{Type, Typed}, condition::failed::Failed}}; +use crate::{modules::{condition::failed::Failed, rdc::scan_append_externs, types::{Type, Typed}}, utils::{ParserMetadata, TranslateMetadata}}; use crate::modules::expression::expr::Expr; use crate::translate::module::TranslateModule; @@ -49,6 +49,9 @@ impl TranslateModule for CommandStatement { let interps = self.interps.iter() .map(|item| item.translate(meta)) .collect::>(); + + scan_append_externs(self.strings.clone(), meta); + let failed = self.failed.translate(meta); let mut translation = translate_interpolated_region(self.strings.clone(), interps, false); let silent = meta.gen_silent(); diff --git a/src/modules/expression/literal/range.rs b/src/modules/expression/literal/range.rs index adc29e9d..77c532d3 100644 --- a/src/modules/expression/literal/range.rs +++ b/src/modules/expression/literal/range.rs @@ -46,6 +46,7 @@ impl TranslateModule for Range { fn translate(&self, meta: &mut TranslateMetadata) -> String { let from = self.from.translate(meta); let to = self.to.translate(meta); + meta.externs.push("seq".into()); if self.neq { let to_neq = translate_computation(meta, ArithOp::Sub, Some(to), Some("1".to_string())); meta.gen_subprocess(&format!("seq {} {}", from, to_neq)) diff --git a/src/modules/imports/import.rs b/src/modules/imports/import.rs index 22640a80..1a4d4651 100644 --- a/src/modules/imports/import.rs +++ b/src/modules/imports/import.rs @@ -87,7 +87,8 @@ impl Import { } fn handle_compile_code(&mut self, meta: &mut ParserMetadata, imported_code: String) -> SyntaxResult { - match AmberCompiler::new(imported_code.clone(), Some(self.path.value.clone())).tokenize() { + // FIXME: Disable RDC here, if it is disabled for user code + match AmberCompiler::new(imported_code.clone(), Some(self.path.value.clone()), false).tokenize() { Ok(tokens) => { let mut block = Block::new(); // Save snapshot of current file diff --git a/src/modules/mod.rs b/src/modules/mod.rs index 45667813..aef33eed 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -11,6 +11,7 @@ pub mod types; pub mod imports; pub mod main; pub mod builtin; +pub mod rdc; #[macro_export] macro_rules! handle_types { diff --git a/src/modules/rdc.rs b/src/modules/rdc.rs new file mode 100644 index 00000000..b6db9a69 --- /dev/null +++ b/src/modules/rdc.rs @@ -0,0 +1,37 @@ +use itertools::Itertools; +use regex::Regex; + +use crate::utils::TranslateMetadata; + +/// RDC - Runtime dependency checker + +/// Generate the code +pub fn generate(externals: Vec) -> String { + if externals.len() == 0 { + return "".to_string(); + } + + let externals = externals.iter().dedup().map(|x| x.clone()).collect::>(); + let mut code = String::new(); + code += "# This is the runtime dependency checker. Please do not remove these lines.\n"; + code += format!("AMBER_RDC_CD=(\'{}\')\n", externals.join("\' \'")).as_str(); + code += include_str!("rdc.sh"); + code +} + +pub fn scan_append_externs(strings: Vec, meta: &mut TranslateMetadata) -> () { + // source: https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html + let bash_deps = vec![ "alias", "bind", "builtin", "caller", "command", "declare", "echo", "enable", "help", "let", "local", "logout", "mapfile", "printf", "read", "readarray", "source", "type", "typeset", "ulimit", "unalias" ]; + + let remove_prefix_var = Regex::new(r"^(\w+=\S+( \w+=\S+)*|) +").unwrap(); + let remove_all_non_cmd = Regex::new(r" .*$").unwrap(); + + for x in strings.iter() { + let parsed = remove_prefix_var.replace(x, "").to_string(); + let parsed = remove_all_non_cmd.replace(&parsed, "").to_string(); + if x.len() != 0 && bash_deps.iter().find(|y| x.to_string() == y.to_string()).is_none() { + meta.externs.push(parsed); + break; + } + } +} \ No newline at end of file diff --git a/src/modules/rdc.sh b/src/modules/rdc.sh new file mode 100644 index 00000000..810f04ff --- /dev/null +++ b/src/modules/rdc.sh @@ -0,0 +1,15 @@ +AMBER_RDC_MD=() +for d in "${AMBER_RDC_CD[@]}" +do + if ! command -v $d > /dev/null 2>&1; then + AMBER_RDC_MD+=($d) + fi +done + +if (( ${#AMBER_RDC_MD[@]} != 0 )); then + >&2 echo This program requires for these commands: \( $AMBER_RDC_MD \) to be present in \$PATH. + exit 1 +fi +unset $AMBER_RDC_CD +unset $AMBER_RDC_MD +# Dependencies are ok at this point diff --git a/src/tests/mod.rs b/src/tests/mod.rs index a0363a6d..51b80c2d 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1 +1,2 @@ -pub mod validity; \ No newline at end of file +pub mod validity; +pub mod rdc; \ No newline at end of file diff --git a/src/tests/rdc.rs b/src/tests/rdc.rs new file mode 100644 index 00000000..974be120 --- /dev/null +++ b/src/tests/rdc.rs @@ -0,0 +1,35 @@ +use std::process::{Command, Stdio}; + +use crate::compiler::AmberCompiler; + +#[test] +fn nonexistant_command() { + let compiler = AmberCompiler::new("unsafe $rfdhyikjeldrhfnjdkfmgdfk$".to_string(), None, false); + let compiled = compiler.compile().map_or_else(Err, |(_, code)| { + let child = Command::new("/bin/bash") + .arg("-c") + .arg(code.to_string()) + .stderr(Stdio::piped()) + .spawn().unwrap().wait_with_output().unwrap(); + assert_eq!(child.status.code(), Some(1)); + assert_eq!(String::from_utf8(child.stderr).unwrap(), "This program requires for these commands: ( rfdhyikjeldrhfnjdkfmgdfk ) to be present in $PATH.\n"); + Ok(()) + }); + compiled.unwrap(); +} + +#[test] +fn existant_command() { + let compiler = AmberCompiler::new("unsafe $bash -c 'echo ok'$".to_string(), None, false); + let compiled = compiler.compile().map_or_else(Err, |(_, code)| { + let child = Command::new("/bin/bash") + .arg("-c") + .arg(code.to_string()) + .stdout(Stdio::piped()) + .spawn().unwrap().wait_with_output().unwrap(); + assert_eq!(child.status.code(), Some(0)); + assert_eq!(String::from_utf8(child.stdout).unwrap(), "ok\n"); + Ok(()) + }); + compiled.unwrap(); +} \ No newline at end of file diff --git a/src/tests/validity.rs b/src/tests/validity.rs index ea663a7f..57e446e0 100644 --- a/src/tests/validity.rs +++ b/src/tests/validity.rs @@ -3,7 +3,8 @@ use crate::compiler::AmberCompiler; macro_rules! test_amber { ($code:expr, $result:expr) => { { - match AmberCompiler::new($code.to_string(), None).test_eval() { + // RDC is disabled in these tests because it will be tested later and could break things + match AmberCompiler::new($code.to_string(), None, false).test_eval() { Ok(result) => assert_eq!(result.trim(), $result), Err(err) => panic!("ERROR: {}", err.message.unwrap()) } diff --git a/src/translate/compute.rs b/src/translate/compute.rs index 4187cc26..aa17063b 100644 --- a/src/translate/compute.rs +++ b/src/translate/compute.rs @@ -21,7 +21,7 @@ pub enum ArithOp { Or } -pub fn translate_computation(meta: &TranslateMetadata, operation: ArithOp, left: Option, right: Option) -> String { +pub fn translate_computation(meta: &mut TranslateMetadata, operation: ArithOp, left: Option, right: Option) -> String { match meta.arith_module { ArithType::BcSed => { let (left, right) = (left.unwrap_or_default(), right.unwrap_or_default()); @@ -48,6 +48,8 @@ pub fn translate_computation(meta: &TranslateMetadata, operation: ArithOp, left: ArithOp::Or => "||" }; let math_lib_flag = if math_lib_flag { "-l" } else { "" }; + meta.externs.push("bc".into()); + meta.externs.push("sed".into()); meta.gen_subprocess(&format!("echo {left} '{op}' {right} | bc {math_lib_flag} | sed '{sed_regex}'")) } } diff --git a/src/utils/metadata/translate.rs b/src/utils/metadata/translate.rs index 2e414e9f..faf0c2ec 100644 --- a/src/utils/metadata/translate.rs +++ b/src/utils/metadata/translate.rs @@ -22,7 +22,9 @@ pub struct TranslateMetadata { /// Determines whether the current context should be silenced. pub silenced: bool, /// The current indentation level. - pub indent: i64 + pub indent: i64, + /// External commands used + pub externs: Vec } impl TranslateMetadata { @@ -36,7 +38,8 @@ impl TranslateMetadata { value_id: 0, eval_ctx: false, silenced: false, - indent: -1 + indent: -1, + externs: vec![] } }