mill 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. #!/usr/bin/env sh
  2. # This is a wrapper script, that automatically download mill from GitHub release pages
  3. # You can give the required mill version with --mill-version parameter
  4. # If no version is given, it falls back to the value of DEFAULT_MILL_VERSION
  5. #
  6. # Original Project page: https://github.com/lefou/millw
  7. # Script Version: 0.4.12
  8. #
  9. # If you want to improve this script, please also contribute your changes back!
  10. #
  11. # Licensed under the Apache License, Version 2.0
  12. set -e
  13. if [ -z "${DEFAULT_MILL_VERSION}" ] ; then
  14. DEFAULT_MILL_VERSION="0.11.4"
  15. fi
  16. if [ -z "${GITHUB_RELEASE_CDN}" ] ; then
  17. GITHUB_RELEASE_CDN=""
  18. fi
  19. MILL_REPO_URL="https://github.com/com-lihaoyi/mill"
  20. if [ -z "${CURL_CMD}" ] ; then
  21. CURL_CMD=curl
  22. fi
  23. # Explicit commandline argument takes precedence over all other methods
  24. if [ "$1" = "--mill-version" ] ; then
  25. shift
  26. if [ "x$1" != "x" ] ; then
  27. MILL_VERSION="$1"
  28. shift
  29. else
  30. echo "You specified --mill-version without a version." 1>&2
  31. echo "Please provide a version that matches one provided on" 1>&2
  32. echo "${MILL_REPO_URL}/releases" 1>&2
  33. false
  34. fi
  35. fi
  36. # Please note, that if a MILL_VERSION is already set in the environment,
  37. # We reuse it's value and skip searching for a value.
  38. # If not already set, read .mill-version file
  39. if [ -z "${MILL_VERSION}" ] ; then
  40. if [ -f ".mill-version" ] ; then
  41. MILL_VERSION="$(tr '\r' '\n' < .mill-version | head -n 1 2> /dev/null)"
  42. elif [ -f ".config/mill-version" ] ; then
  43. MILL_VERSION="$(tr '\r' '\n' < .config/mill-version | head -n 1 2> /dev/null)"
  44. fi
  45. fi
  46. MILL_USER_CACHE_DIR="${XDG_CACHE_HOME:-${HOME}/.cache}/mill"
  47. if [ -z "${MILL_DOWNLOAD_PATH}" ] ; then
  48. MILL_DOWNLOAD_PATH="${MILL_USER_CACHE_DIR}/download"
  49. fi
  50. # If not already set, try to fetch newest from Github
  51. if [ -z "${MILL_VERSION}" ] ; then
  52. # TODO: try to load latest version from release page
  53. echo "No mill version specified." 1>&2
  54. echo "You should provide a version via '.mill-version' file or --mill-version option." 1>&2
  55. mkdir -p "${MILL_DOWNLOAD_PATH}"
  56. LANG=C touch -d '1 hour ago' "${MILL_DOWNLOAD_PATH}/.expire_latest" 2>/dev/null || (
  57. # we might be on OSX or BSD which don't have -d option for touch
  58. # but probably a -A [-][[hh]mm]SS
  59. touch "${MILL_DOWNLOAD_PATH}/.expire_latest"; touch -A -010000 "${MILL_DOWNLOAD_PATH}/.expire_latest"
  60. ) || (
  61. # in case we still failed, we retry the first touch command with the intention
  62. # to show the (previously suppressed) error message
  63. LANG=C touch -d '1 hour ago' "${MILL_DOWNLOAD_PATH}/.expire_latest"
  64. )
  65. # POSIX shell variant of bash's -nt operator, see https://unix.stackexchange.com/a/449744/6993
  66. # if [ "${MILL_DOWNLOAD_PATH}/.latest" -nt "${MILL_DOWNLOAD_PATH}/.expire_latest" ] ; then
  67. if [ -n "$(find -L "${MILL_DOWNLOAD_PATH}/.latest" -prune -newer "${MILL_DOWNLOAD_PATH}/.expire_latest")" ]; then
  68. # we know a current latest version
  69. MILL_VERSION=$(head -n 1 "${MILL_DOWNLOAD_PATH}"/.latest 2> /dev/null)
  70. fi
  71. if [ -z "${MILL_VERSION}" ] ; then
  72. # we don't know a current latest version
  73. echo "Retrieving latest mill version ..." 1>&2
  74. LANG=C ${CURL_CMD} -s -i -f -I ${MILL_REPO_URL}/releases/latest 2> /dev/null | grep --ignore-case Location: | sed s'/^.*tag\///' | tr -d '\r\n' > "${MILL_DOWNLOAD_PATH}/.latest"
  75. MILL_VERSION=$(head -n 1 "${MILL_DOWNLOAD_PATH}"/.latest 2> /dev/null)
  76. fi
  77. if [ -z "${MILL_VERSION}" ] ; then
  78. # Last resort
  79. MILL_VERSION="${DEFAULT_MILL_VERSION}"
  80. echo "Falling back to hardcoded mill version ${MILL_VERSION}" 1>&2
  81. else
  82. echo "Using mill version ${MILL_VERSION}" 1>&2
  83. fi
  84. fi
  85. MILL_NATIVE_SUFFIX="-native"
  86. FULL_MILL_VERSION=$MILL_VERSION
  87. ARTIFACT_SUFFIX=""
  88. case "$MILL_VERSION" in
  89. *"$MILL_NATIVE_SUFFIX")
  90. MILL_VERSION=${MILL_VERSION%"$MILL_NATIVE_SUFFIX"}
  91. if [ "$(expr substr $(uname -s) 1 5 2>/dev/null)" = "Linux" ]; then
  92. if [ "$(uname -m)" = "aarch64" ]; then
  93. ARTIFACT_SUFFIX="-native-linux-aarch64"
  94. else
  95. ARTIFACT_SUFFIX="-native-linux-amd64"
  96. fi
  97. elif [ "$(uname)" = "Darwin" ]; then
  98. if [ "$(uname -m)" = "arm64" ]; then
  99. ARTIFACT_SUFFIX="-native-mac-aarch64"
  100. else
  101. ARTIFACT_SUFFIX="-native-mac-amd64"
  102. fi
  103. else
  104. echo "This native mill launcher supports only Linux and macOS." 1>&2
  105. exit 1
  106. fi
  107. esac
  108. MILL="${MILL_DOWNLOAD_PATH}/${FULL_MILL_VERSION}"
  109. try_to_use_system_mill() {
  110. if [ "$(uname)" != "Linux" ]; then
  111. return 0
  112. fi
  113. MILL_IN_PATH="$(command -v mill || true)"
  114. if [ -z "${MILL_IN_PATH}" ]; then
  115. return 0
  116. fi
  117. SYSTEM_MILL_FIRST_TWO_BYTES=$(head --bytes=2 "${MILL_IN_PATH}")
  118. if [ "${SYSTEM_MILL_FIRST_TWO_BYTES}" = "#!" ]; then
  119. # MILL_IN_PATH is (very likely) a shell script and not the mill
  120. # executable, ignore it.
  121. return 0
  122. fi
  123. SYSTEM_MILL_PATH=$(readlink -e "${MILL_IN_PATH}")
  124. SYSTEM_MILL_SIZE=$(stat --format=%s "${SYSTEM_MILL_PATH}")
  125. SYSTEM_MILL_MTIME=$(stat --format=%y "${SYSTEM_MILL_PATH}")
  126. if [ ! -d "${MILL_USER_CACHE_DIR}" ]; then
  127. mkdir -p "${MILL_USER_CACHE_DIR}"
  128. fi
  129. SYSTEM_MILL_INFO_FILE="${MILL_USER_CACHE_DIR}/system-mill-info"
  130. if [ -f "${SYSTEM_MILL_INFO_FILE}" ]; then
  131. parseSystemMillInfo() {
  132. LINE_NUMBER="${1}"
  133. # Select the line number of the SYSTEM_MILL_INFO_FILE, cut the
  134. # variable definition in that line in two halves and return
  135. # the value, and finally remove the quotes.
  136. sed -n "${LINE_NUMBER}p" "${SYSTEM_MILL_INFO_FILE}" |\
  137. cut -d= -f2 |\
  138. sed 's/"\(.*\)"/\1/'
  139. }
  140. CACHED_SYSTEM_MILL_PATH=$(parseSystemMillInfo 1)
  141. CACHED_SYSTEM_MILL_VERSION=$(parseSystemMillInfo 2)
  142. CACHED_SYSTEM_MILL_SIZE=$(parseSystemMillInfo 3)
  143. CACHED_SYSTEM_MILL_MTIME=$(parseSystemMillInfo 4)
  144. if [ "${SYSTEM_MILL_PATH}" = "${CACHED_SYSTEM_MILL_PATH}" ] \
  145. && [ "${SYSTEM_MILL_SIZE}" = "${CACHED_SYSTEM_MILL_SIZE}" ] \
  146. && [ "${SYSTEM_MILL_MTIME}" = "${CACHED_SYSTEM_MILL_MTIME}" ]; then
  147. if [ "${CACHED_SYSTEM_MILL_VERSION}" = "${MILL_VERSION}" ]; then
  148. MILL="${SYSTEM_MILL_PATH}"
  149. return 0
  150. else
  151. return 0
  152. fi
  153. fi
  154. fi
  155. SYSTEM_MILL_VERSION=$(${SYSTEM_MILL_PATH} --version | head -n1 | sed -n 's/^Mill.*version \(.*\)/\1/p')
  156. cat <<EOF > "${SYSTEM_MILL_INFO_FILE}"
  157. CACHED_SYSTEM_MILL_PATH="${SYSTEM_MILL_PATH}"
  158. CACHED_SYSTEM_MILL_VERSION="${SYSTEM_MILL_VERSION}"
  159. CACHED_SYSTEM_MILL_SIZE="${SYSTEM_MILL_SIZE}"
  160. CACHED_SYSTEM_MILL_MTIME="${SYSTEM_MILL_MTIME}"
  161. EOF
  162. if [ "${SYSTEM_MILL_VERSION}" = "${MILL_VERSION}" ]; then
  163. MILL="${SYSTEM_MILL_PATH}"
  164. fi
  165. }
  166. try_to_use_system_mill
  167. # If not already downloaded, download it
  168. if [ ! -s "${MILL}" ] ; then
  169. # support old non-XDG download dir
  170. MILL_OLD_DOWNLOAD_PATH="${HOME}/.mill/download"
  171. OLD_MILL="${MILL_OLD_DOWNLOAD_PATH}/${MILL_VERSION}"
  172. if [ -x "${OLD_MILL}" ] ; then
  173. MILL="${OLD_MILL}"
  174. else
  175. case $MILL_VERSION in
  176. 0.0.* | 0.1.* | 0.2.* | 0.3.* | 0.4.* )
  177. DOWNLOAD_SUFFIX=""
  178. DOWNLOAD_FROM_MAVEN=0
  179. ;;
  180. 0.5.* | 0.6.* | 0.7.* | 0.8.* | 0.9.* | 0.10.* | 0.11.0-M* )
  181. DOWNLOAD_SUFFIX="-assembly"
  182. DOWNLOAD_FROM_MAVEN=0
  183. ;;
  184. *)
  185. DOWNLOAD_SUFFIX="-assembly"
  186. DOWNLOAD_FROM_MAVEN=1
  187. ;;
  188. esac
  189. DOWNLOAD_FILE=$(mktemp mill.XXXXXX)
  190. if [ "$DOWNLOAD_FROM_MAVEN" = "1" ] ; then
  191. DOWNLOAD_URL="https://repo1.maven.org/maven2/com/lihaoyi/mill-dist${ARTIFACT_SUFFIX}/${MILL_VERSION}/mill-dist${ARTIFACT_SUFFIX}-${MILL_VERSION}.jar"
  192. else
  193. MILL_VERSION_TAG=$(echo "$MILL_VERSION" | sed -E 's/([^-]+)(-M[0-9]+)?(-.*)?/\1\2/')
  194. DOWNLOAD_URL="${GITHUB_RELEASE_CDN}${MILL_REPO_URL}/releases/download/${MILL_VERSION_TAG}/${MILL_VERSION}${DOWNLOAD_SUFFIX}"
  195. unset MILL_VERSION_TAG
  196. fi
  197. # TODO: handle command not found
  198. echo "Downloading mill ${MILL_VERSION} from ${DOWNLOAD_URL} ..." 1>&2
  199. ${CURL_CMD} -f -L -o "${DOWNLOAD_FILE}" "${DOWNLOAD_URL}"
  200. chmod +x "${DOWNLOAD_FILE}"
  201. mkdir -p "${MILL_DOWNLOAD_PATH}"
  202. mv "${DOWNLOAD_FILE}" "${MILL}"
  203. unset DOWNLOAD_FILE
  204. unset DOWNLOAD_SUFFIX
  205. fi
  206. fi
  207. if [ -z "$MILL_MAIN_CLI" ] ; then
  208. MILL_MAIN_CLI="${0}"
  209. fi
  210. MILL_FIRST_ARG=""
  211. if [ "$1" = "--bsp" ] || [ "$1" = "-i" ] || [ "$1" = "--interactive" ] || [ "$1" = "--no-server" ] || [ "$1" = "--repl" ] || [ "$1" = "--help" ] ; then
  212. # Need to preserve the first position of those listed options
  213. MILL_FIRST_ARG=$1
  214. shift
  215. fi
  216. unset MILL_DOWNLOAD_PATH
  217. unset MILL_OLD_DOWNLOAD_PATH
  218. unset OLD_MILL
  219. unset MILL_VERSION
  220. unset MILL_REPO_URL
  221. # We don't quote MILL_FIRST_ARG on purpose, so we can expand the empty value without quotes
  222. # shellcheck disable=SC2086
  223. exec "${MILL}" $MILL_FIRST_ARG -D "mill.main.cli=${MILL_MAIN_CLI}" "$@"