run.sh 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #!/usr/bin/env bash
  2. set -euo pipefail
  3. #
  4. # variables
  5. #
  6. RESET="\033[0m"
  7. RED="\033[0;31m"
  8. YELLOW="\033[0;33m"
  9. MAGENTA="\033[0;95m"
  10. DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
  11. [ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet"
  12. verbose=false
  13. update=false
  14. repo_path="$DIR"
  15. channel=''
  16. tools_source=''
  17. #
  18. # Functions
  19. #
  20. __usage() {
  21. echo "Usage: $(basename "${BASH_SOURCE[0]}") command [options] [[--] <Arguments>...]"
  22. echo ""
  23. echo "Arguments:"
  24. echo " command The command to be run."
  25. echo " <Arguments>... Arguments passed to the command. Variable number of arguments allowed."
  26. echo ""
  27. echo "Options:"
  28. echo " --verbose Show verbose output."
  29. echo " -c|--channel <CHANNEL> The channel of KoreBuild to download. Overrides the value from the config file.."
  30. echo " --config-file <FILE> The path to the configuration file that stores values. Defaults to korebuild.json."
  31. echo " -d|--dotnet-home <DIR> The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet."
  32. echo " --path <PATH> The directory to build. Defaults to the directory containing the script."
  33. echo " -s|--tools-source|-ToolsSource <URL> The base url where build tools can be downloaded. Overrides the value from the config file."
  34. echo " -u|--update Update to the latest KoreBuild even if the lock file is present."
  35. echo ""
  36. echo "Description:"
  37. echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be."
  38. echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel."
  39. if [[ "${1:-}" != '--no-exit' ]]; then
  40. exit 2
  41. fi
  42. }
  43. get_korebuild() {
  44. local version
  45. local lock_file="$repo_path/korebuild-lock.txt"
  46. if [ ! -f "$lock_file" ] || [ "$update" = true ]; then
  47. __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file"
  48. fi
  49. version="$(grep 'version:*' -m 1 "$lock_file")"
  50. if [[ "$version" == '' ]]; then
  51. __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'"
  52. return 1
  53. fi
  54. version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
  55. local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version"
  56. {
  57. if [ ! -d "$korebuild_path" ]; then
  58. mkdir -p "$korebuild_path"
  59. local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip"
  60. tmpfile="$(mktemp)"
  61. echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}"
  62. if __get_remote_file "$remote_path" "$tmpfile"; then
  63. unzip -q -d "$korebuild_path" "$tmpfile"
  64. fi
  65. rm "$tmpfile" || true
  66. fi
  67. source "$korebuild_path/KoreBuild.sh"
  68. } || {
  69. if [ -d "$korebuild_path" ]; then
  70. echo "Cleaning up after failed installation"
  71. rm -rf "$korebuild_path" || true
  72. fi
  73. return 1
  74. }
  75. }
  76. __error() {
  77. echo -e "${RED}error: $*${RESET}" 1>&2
  78. }
  79. __warn() {
  80. echo -e "${YELLOW}warning: $*${RESET}"
  81. }
  82. __machine_has() {
  83. hash "$1" > /dev/null 2>&1
  84. return $?
  85. }
  86. __get_remote_file() {
  87. local remote_path=$1
  88. local local_path=$2
  89. if [[ "$remote_path" != 'http'* ]]; then
  90. cp "$remote_path" "$local_path"
  91. return 0
  92. fi
  93. local failed=false
  94. if __machine_has wget; then
  95. wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true
  96. else
  97. failed=true
  98. fi
  99. if [ "$failed" = true ] && __machine_has curl; then
  100. failed=false
  101. curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true
  102. fi
  103. if [ "$failed" = true ]; then
  104. __error "Download failed: $remote_path" 1>&2
  105. return 1
  106. fi
  107. }
  108. #
  109. # main
  110. #
  111. command="${1:-}"
  112. shift
  113. while [[ $# -gt 0 ]]; do
  114. case $1 in
  115. -\?|-h|--help)
  116. __usage --no-exit
  117. exit 0
  118. ;;
  119. -c|--channel|-Channel)
  120. shift
  121. channel="${1:-}"
  122. [ -z "$channel" ] && __usage
  123. ;;
  124. --config-file|-ConfigFile)
  125. shift
  126. config_file="${1:-}"
  127. [ -z "$config_file" ] && __usage
  128. if [ ! -f "$config_file" ]; then
  129. __error "Invalid value for --config-file. $config_file does not exist."
  130. exit 1
  131. fi
  132. ;;
  133. -d|--dotnet-home|-DotNetHome)
  134. shift
  135. DOTNET_HOME="${1:-}"
  136. [ -z "$DOTNET_HOME" ] && __usage
  137. ;;
  138. --path|-Path)
  139. shift
  140. repo_path="${1:-}"
  141. [ -z "$repo_path" ] && __usage
  142. ;;
  143. -s|--tools-source|-ToolsSource)
  144. shift
  145. tools_source="${1:-}"
  146. [ -z "$tools_source" ] && __usage
  147. ;;
  148. -u|--update|-Update)
  149. update=true
  150. ;;
  151. --verbose|-Verbose)
  152. verbose=true
  153. ;;
  154. --)
  155. shift
  156. break
  157. ;;
  158. *)
  159. break
  160. ;;
  161. esac
  162. shift
  163. done
  164. if ! __machine_has unzip; then
  165. __error 'Missing required command: unzip'
  166. exit 1
  167. fi
  168. if ! __machine_has curl && ! __machine_has wget; then
  169. __error 'Missing required command. Either wget or curl is required.'
  170. exit 1
  171. fi
  172. [ -z "${config_file:-}" ] && config_file="$repo_path/korebuild.json"
  173. if [ -f "$config_file" ]; then
  174. if __machine_has jq ; then
  175. if jq '.' "$config_file" >/dev/null ; then
  176. config_channel="$(jq -r 'select(.channel!=null) | .channel' "$config_file")"
  177. config_tools_source="$(jq -r 'select(.toolsSource!=null) | .toolsSource' "$config_file")"
  178. else
  179. __warn "$config_file is invalid JSON. Its settings will be ignored."
  180. fi
  181. elif __machine_has python ; then
  182. if python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'))" >/dev/null ; then
  183. config_channel="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")"
  184. config_tools_source="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")"
  185. else
  186. __warn "$config_file is invalid JSON. Its settings will be ignored."
  187. fi
  188. else
  189. __warn 'Missing required command: jq or pyton. Could not parse the JSON file. Its settings will be ignored.'
  190. fi
  191. [ ! -z "${config_channel:-}" ] && channel="$config_channel"
  192. [ ! -z "${config_tools_source:-}" ] && tools_source="$config_tools_source"
  193. fi
  194. [ -z "$channel" ] && channel='dev'
  195. [ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools'
  196. get_korebuild
  197. set_korebuildsettings "$tools_source" "$DOTNET_HOME" "$repo_path" "$config_file"
  198. invoke_korebuild_command "$command" "$@"