├── .github └── workflows │ └── test.yml ├── .gitignore ├── README.md ├── build.sbt ├── cloudbuild.yaml ├── project.toml ├── project ├── build.properties └── plugins.sbt ├── sbt ├── sbt.bat ├── shell.nix └── src ├── main ├── resources │ └── simplelogger.properties └── scala │ ├── App.scala │ └── UI.scala └── test └── scala └── AppSpec.scala /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | jobs: 4 | test: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v2 8 | 9 | - uses: actions/setup-java@v3 10 | with: 11 | distribution: 'temurin' 12 | java-version: 17 13 | cache: 'sbt' 14 | 15 | - run: | 16 | ./sbt test 17 | ./sbt clean 18 | 19 | - uses: buildpacks/github-actions/setup-pack@v5.0.0 20 | 21 | - run: | 22 | pack build --builder=paketobuildpacks/builder-jammy-base javadoccentral 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /project/target/ 3 | /project/project/ 4 | /.idea/ 5 | /.bsp/ 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | JavaDoc Central 2 | --------------- 3 | 4 | ![CloudBuild](https://badger-bdrmenfgcq-uc.a.run.app/build/status?project=jamesward&id=4097b960-a9af-4a61-b309-0e372889552e) 5 | 6 | Artifacts in Maven Central typically provide a JavaDoc Jar that contains the versioned documentation for the artifact. While IDEs use this to display the docs for a library, it is also sometimes nice to browse the docs in a web browser. This project is a simple web app that allows you to view the JavaDoc for any artifact in Maven Central. 7 | 8 | Usage Guide: 9 | 10 | Main page: [javadocs.dev](https://javadocs.dev/) 11 | 12 | URL Format: `https://javadocs.dev/GROUP_ID/ARTIFACT_ID/VERSION` 13 | 14 | You can specify the `GROUP_ID`, `ARTIFACT_ID`, and `VERSION`, like: 15 | `https://javadocs.dev/org.webjars/webjars-locator/0.32` 16 | 17 | Or the `GROUP_ID` and `ARTIFACT_ID`, like: 18 | `https://javadocs.dev/org.webjars/webjars-locator` 19 | 20 | Or just the `GROUP_ID`, like: 21 | `https://javadocs.dev/org.webjars` 22 | 23 | You can also specify `latest` for the version, like: 24 | `https://javadocs.dev/org.webjars/webjars-locator/latest` 25 | 26 | ## Dev Info 27 | 28 | Run with restart: 29 | ``` 30 | ./sbt ~reStart 31 | ``` 32 | 33 | Run and output GraalVM configs, with GraalVM: 34 | ``` 35 | # uncomment javaOptions in build.sbt 36 | ./sbt run 37 | ``` 38 | 39 | Build the container: 40 | ``` 41 | pack build --builder=paketobuildpacks/builder-jammy-base \ 42 | javadoccentral 43 | ``` 44 | 45 | Run the container: 46 | ``` 47 | docker run -p8080:8080 -m 512m javadoccentral 48 | ``` 49 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | enablePlugins(LauncherJarPlugin) 2 | 3 | // Hack Alert: This is the default when not in buildpacks (i.e. `default`) 4 | // In buildpacks it is javadoccentral which puts it alphabetically after dev.zio.zio-constraintless_3-0.3.1.jar 5 | // This causes the wrong Main-Class to get picked up. 6 | // https://github.com/paketo-buildpacks/executable-jar/issues/206 7 | organization := "default" 8 | 9 | name := "javadoccentral" 10 | 11 | // so we don't have to wait on Maven Central sync 12 | //resolvers += "OSS Staging" at "https://oss.sonatype.org/content/groups/staging" 13 | 14 | scalacOptions ++= Seq( 15 | //"-Yexplicit-nulls", // doesn't seem to work anymore 16 | "-language:strictEquality", 17 | // "-Xfatal-warnings", // doesn't seem to work anymore 18 | ) 19 | 20 | scalaVersion := "3.7.0" 21 | 22 | val zioVersion = "2.1.19" 23 | 24 | libraryDependencies ++= Seq( 25 | "dev.zio" %% "zio" % zioVersion, 26 | "dev.zio" %% "zio-concurrent" % zioVersion, 27 | "dev.zio" %% "zio-cache" % "0.2.4", 28 | "dev.zio" %% "zio-logging" % "2.5.0", 29 | "dev.zio" %% "zio-direct" % "1.0.0-RC7", 30 | "dev.zio" %% "zio-direct-streams" % "1.0.0-RC7", 31 | "dev.zio" %% "zio-http" % "3.3.3", 32 | "org.apache.commons" % "commons-compress" % "1.27.1", 33 | "org.slf4j" % "slf4j-simple" % "2.0.17", 34 | 35 | "com.jamesward" %% "zio-mavencentral" % "0.0.20", 36 | 37 | "dev.zio" %% "zio-test" % zioVersion % Test, 38 | "dev.zio" %% "zio-test-sbt" % zioVersion % Test, 39 | "dev.zio" %% "zio-test-magnolia" % zioVersion % Test, 40 | ) 41 | 42 | testFrameworks += new TestFramework("zio.test.sbt.ZTestFramework") 43 | 44 | Compile / packageDoc / publishArtifact := false 45 | 46 | Compile / doc / sources := Seq.empty 47 | 48 | fork := true 49 | 50 | javaOptions += "-Djava.net.preferIPv4Stack=true" 51 | 52 | //run / javaOptions += s"-agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image" 53 | //javaOptions += s"-agentlib:native-image-agent=trace-output=${(target in GraalVMNativeImage).value}/trace-output.json" 54 | -------------------------------------------------------------------------------- /cloudbuild.yaml: -------------------------------------------------------------------------------- 1 | steps: 2 | - name: 'adoptopenjdk/openjdk11' 3 | entrypoint: './sbt' 4 | args: ['test'] 5 | 6 | - name: 'adoptopenjdk/openjdk11' 7 | entrypoint: './sbt' 8 | args: ['clean'] 9 | 10 | - name: 'gcr.io/k8s-skaffold/pack' 11 | entrypoint: 'pack' 12 | args: ['build', '--builder=paketobuildpacks/builder-jammy-base', '--publish', 'gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA'] 13 | 14 | - name: 'gcr.io/cloud-builders/docker' 15 | args: ['pull', 'gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA'] 16 | 17 | - name: 'gcr.io/cloud-builders/docker' 18 | args: ['tag', 'gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA', 'gcr.io/$PROJECT_ID/$REPO_NAME:latest'] 19 | 20 | - name: 'gcr.io/cloud-builders/docker' 21 | args: ['push', 'gcr.io/$PROJECT_ID/$REPO_NAME:latest'] 22 | 23 | - name: 'ghcr.io/jamesward/easycloudrun' 24 | entrypoint: 'multiregion' 25 | env: 26 | - 'PROJECT_ID=$PROJECT_ID' 27 | - 'BUILD_ID=$BUILD_ID' 28 | - 'COMMIT_SHA=$COMMIT_SHA' 29 | - 'IMAGE_NAME=$REPO_NAME' 30 | - 'IMAGE_VERSION=$COMMIT_SHA' 31 | - 'DEPLOY_OPTS=--memory=512Mi --execution-environment=gen2' 32 | - 'DOMAINS=javadocs.dev' 33 | 34 | options: 35 | machineType: 'N1_HIGHCPU_32' 36 | -------------------------------------------------------------------------------- /project.toml: -------------------------------------------------------------------------------- 1 | name = "BP_JVM_VERSION" 2 | value = "21" 3 | 4 | [[build.env]] 5 | name = "BPE_OVERRIDE_BPL_JVM_THREAD_COUNT" 6 | value = "50" 7 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.11.0 2 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.11.1") 2 | addSbtPlugin("io.spray" % "sbt-revolver" % "0.10.0") 3 | -------------------------------------------------------------------------------- /sbt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set +e 4 | declare builtin_sbt_version="1.9.2" 5 | declare -a residual_args 6 | declare -a java_args 7 | declare -a scalac_args 8 | declare -a sbt_commands 9 | declare -a sbt_options 10 | declare -a print_version 11 | declare -a print_sbt_version 12 | declare -a print_sbt_script_version 13 | declare -a shutdownall 14 | declare -a original_args 15 | declare java_cmd=java 16 | declare java_version 17 | declare init_sbt_version=1.9.2 18 | declare sbt_default_mem=1024 19 | declare -r default_sbt_opts="" 20 | declare -r default_java_opts="-Dfile.encoding=UTF-8" 21 | declare sbt_verbose= 22 | declare sbt_debug= 23 | declare build_props_sbt_version= 24 | declare use_sbtn= 25 | declare no_server= 26 | declare sbtn_command="$SBTN_CMD" 27 | declare sbtn_version="1.9.0" 28 | 29 | ### ------------------------------- ### 30 | ### Helper methods for BASH scripts ### 31 | ### ------------------------------- ### 32 | 33 | # Bash reimplementation of realpath to return the absolute path 34 | realpathish () { 35 | ( 36 | TARGET_FILE="$1" 37 | FIX_CYGPATH="$2" 38 | 39 | cd "$(dirname "$TARGET_FILE")" 40 | TARGET_FILE=$(basename "$TARGET_FILE") 41 | 42 | COUNT=0 43 | while [ -L "$TARGET_FILE" -a $COUNT -lt 100 ] 44 | do 45 | TARGET_FILE=$(readlink "$TARGET_FILE") 46 | cd "$(dirname "$TARGET_FILE")" 47 | TARGET_FILE=$(basename "$TARGET_FILE") 48 | COUNT=$(($COUNT + 1)) 49 | done 50 | 51 | TARGET_DIR="$(pwd -P)" 52 | if [ "$TARGET_DIR" == "/" ]; then 53 | TARGET_FILE="/$TARGET_FILE" 54 | else 55 | TARGET_FILE="$TARGET_DIR/$TARGET_FILE" 56 | fi 57 | 58 | # make sure we grab the actual windows path, instead of cygwin's path. 59 | if [[ "x$FIX_CYGPATH" != "x" ]]; then 60 | echo "$(cygwinpath "$TARGET_FILE")" 61 | else 62 | echo "$TARGET_FILE" 63 | fi 64 | ) 65 | } 66 | 67 | # Uses uname to detect if we're in the odd cygwin environment. 68 | is_cygwin() { 69 | local os=$(uname -s) 70 | case "$os" in 71 | CYGWIN*) return 0 ;; 72 | MINGW*) return 0 ;; 73 | MSYS*) return 0 ;; 74 | *) return 1 ;; 75 | esac 76 | } 77 | 78 | # TODO - Use nicer bash-isms here. 79 | CYGWIN_FLAG=$(if is_cygwin; then echo true; else echo false; fi) 80 | 81 | # This can fix cygwin style /cygdrive paths so we get the 82 | # windows style paths. 83 | cygwinpath() { 84 | local file="$1" 85 | if [[ "$CYGWIN_FLAG" == "true" ]]; then #" 86 | echo $(cygpath -w $file) 87 | else 88 | echo $file 89 | fi 90 | } 91 | 92 | 93 | declare -r sbt_bin_dir="$(dirname "$(realpathish "$0")")" 94 | declare -r sbt_home="$(dirname "$sbt_bin_dir")" 95 | 96 | echoerr () { 97 | echo 1>&2 "$@" 98 | } 99 | vlog () { 100 | [[ $sbt_verbose || $sbt_debug ]] && echoerr "$@" 101 | } 102 | dlog () { 103 | [[ $sbt_debug ]] && echoerr "$@" 104 | } 105 | 106 | jar_file () { 107 | echo "$(cygwinpath "${sbt_home}/bin/sbt-launch.jar")" 108 | } 109 | 110 | jar_url () { 111 | local repo_base="$SBT_LAUNCH_REPO" 112 | if [[ $repo_base == "" ]]; then 113 | repo_base="https://repo1.maven.org/maven2" 114 | fi 115 | echo "$repo_base/org/scala-sbt/sbt-launch/$1/sbt-launch-$1.jar" 116 | } 117 | 118 | download_url () { 119 | local url="$1" 120 | local jar="$2" 121 | mkdir -p $(dirname "$jar") && { 122 | if command -v curl > /dev/null; then 123 | curl --silent -L "$url" --output "$jar" 124 | elif command -v wget > /dev/null; then 125 | wget --quiet -O "$jar" "$url" 126 | fi 127 | } && [[ -f "$jar" ]] 128 | } 129 | 130 | acquire_sbt_jar () { 131 | local launcher_sv="$1" 132 | if [[ "$launcher_sv" == "" ]]; then 133 | if [[ "$init_sbt_version" != "_to_be_replaced" ]]; then 134 | launcher_sv="$init_sbt_version" 135 | else 136 | launcher_sv="$builtin_sbt_version" 137 | fi 138 | fi 139 | local user_home && user_home=$(findProperty user.home) 140 | download_jar="${user_home:-$HOME}/.cache/sbt/boot/sbt-launch/$launcher_sv/sbt-launch-$launcher_sv.jar" 141 | if [[ -f "$download_jar" ]]; then 142 | sbt_jar="$download_jar" 143 | else 144 | sbt_url=$(jar_url "$launcher_sv") 145 | echoerr "downloading sbt launcher $launcher_sv" 146 | download_url "$sbt_url" "${download_jar}.temp" 147 | download_url "${sbt_url}.sha1" "${download_jar}.sha1" 148 | if command -v shasum > /dev/null; then 149 | if echo "$(cat "${download_jar}.sha1") ${download_jar}.temp" | shasum -c - > /dev/null; then 150 | mv "${download_jar}.temp" "${download_jar}" 151 | else 152 | echoerr "failed to download launcher jar: $sbt_url (shasum mismatch)" 153 | exit 2 154 | fi 155 | else 156 | mv "${download_jar}.temp" "${download_jar}" 157 | fi 158 | if [[ -f "$download_jar" ]]; then 159 | sbt_jar="$download_jar" 160 | else 161 | echoerr "failed to download launcher jar: $sbt_url" 162 | exit 2 163 | fi 164 | fi 165 | } 166 | 167 | acquire_sbtn () { 168 | local sbtn_v="$1" 169 | local user_home && user_home=$(findProperty user.home) 170 | local p="${user_home:-$HOME}/.cache/sbt/boot/sbtn/$sbtn_v" 171 | local target="$p/sbtn" 172 | local archive_target= 173 | local url= 174 | local arch="x86_64" 175 | if [[ "$OSTYPE" == "linux-gnu"* ]]; then 176 | arch=$(uname -m) 177 | if [[ "$arch" == "aarch64" ]] || [[ "$arch" == "x86_64" ]]; then 178 | archive_target="$p/sbtn-${arch}-pc-linux-${sbtn_v}.tar.gz" 179 | url="https://github.com/sbt/sbtn-dist/releases/download/v${sbtn_v}/sbtn-${arch}-pc-linux-${sbtn_v}.tar.gz" 180 | else 181 | echoerr "sbtn is not supported on $arch" 182 | exit 2 183 | fi 184 | elif [[ "$OSTYPE" == "darwin"* ]]; then 185 | archive_target="$p/sbtn-x86_64-apple-darwin-${sbtn_v}.tar.gz" 186 | url="https://github.com/sbt/sbtn-dist/releases/download/v${sbtn_v}/sbtn-x86_64-apple-darwin-${sbtn_v}.tar.gz" 187 | elif [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then 188 | target="$p/sbtn.exe" 189 | archive_target="$p/sbtn-x86_64-pc-win32-${sbtn_v}.zip" 190 | url="https://github.com/sbt/sbtn-dist/releases/download/v${sbtn_v}/sbtn-x86_64-pc-win32-${sbtn_v}.zip" 191 | else 192 | echoerr "sbtn is not supported on $OSTYPE" 193 | exit 2 194 | fi 195 | 196 | if [[ -f "$target" ]]; then 197 | sbtn_command="$target" 198 | else 199 | echoerr "downloading sbtn ${sbtn_v} for ${arch}" 200 | download_url "$url" "$archive_target" 201 | if [[ "$OSTYPE" == "linux-gnu"* ]] || [[ "$OSTYPE" == "darwin"* ]]; then 202 | tar zxf "$archive_target" --directory "$p" 203 | else 204 | unzip "$archive_target" -d "$p" 205 | fi 206 | sbtn_command="$target" 207 | fi 208 | } 209 | 210 | # execRunner should be called only once to give up control to java 211 | execRunner () { 212 | # print the arguments one to a line, quoting any containing spaces 213 | [[ $sbt_verbose || $sbt_debug ]] && echo "# Executing command line:" && { 214 | for arg; do 215 | if printf "%s\n" "$arg" | grep -q ' '; then 216 | printf "\"%s\"\n" "$arg" 217 | else 218 | printf "%s\n" "$arg" 219 | fi 220 | done 221 | echo "" 222 | } 223 | 224 | if [[ "$CYGWIN_FLAG" == "true" ]]; then 225 | # In cygwin we loose the ability to re-hook stty if exec is used 226 | # https://github.com/sbt/sbt-launcher-package/issues/53 227 | "$@" 228 | else 229 | exec "$@" 230 | fi 231 | } 232 | 233 | addJava () { 234 | dlog "[addJava] arg = '$1'" 235 | java_args=( "${java_args[@]}" "$1" ) 236 | } 237 | addSbt () { 238 | dlog "[addSbt] arg = '$1'" 239 | sbt_commands=( "${sbt_commands[@]}" "$1" ) 240 | } 241 | addResidual () { 242 | dlog "[residual] arg = '$1'" 243 | residual_args=( "${residual_args[@]}" "$1" ) 244 | } 245 | addDebugger () { 246 | addJava "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$1" 247 | } 248 | 249 | addMemory () { 250 | dlog "[addMemory] arg = '$1'" 251 | # evict memory related options 252 | local xs=("${java_args[@]}") 253 | java_args=() 254 | for i in "${xs[@]}"; do 255 | if ! [[ "${i}" == *-Xmx* ]] && ! [[ "${i}" == *-Xms* ]] && ! [[ "${i}" == *-Xss* ]] && ! [[ "${i}" == *-XX:MaxPermSize* ]] && ! [[ "${i}" == *-XX:MaxMetaspaceSize* ]] && ! [[ "${i}" == *-XX:ReservedCodeCacheSize* ]]; then 256 | java_args+=("${i}") 257 | fi 258 | done 259 | local ys=("${sbt_options[@]}") 260 | sbt_options=() 261 | for i in "${ys[@]}"; do 262 | if ! [[ "${i}" == *-Xmx* ]] && ! [[ "${i}" == *-Xms* ]] && ! [[ "${i}" == *-Xss* ]] && ! [[ "${i}" == *-XX:MaxPermSize* ]] && ! [[ "${i}" == *-XX:MaxMetaspaceSize* ]] && ! [[ "${i}" == *-XX:ReservedCodeCacheSize* ]]; then 263 | sbt_options+=("${i}") 264 | fi 265 | done 266 | # a ham-fisted attempt to move some memory settings in concert 267 | local mem=$1 268 | local codecache=$(( $mem / 8 )) 269 | (( $codecache > 128 )) || codecache=128 270 | (( $codecache < 512 )) || codecache=512 271 | local class_metadata_size=$(( $codecache * 2 )) 272 | if [[ -z $java_version ]]; then 273 | java_version=$(jdk_version) 274 | fi 275 | 276 | addJava "-Xms${mem}m" 277 | addJava "-Xmx${mem}m" 278 | addJava "-Xss4M" 279 | addJava "-XX:ReservedCodeCacheSize=${codecache}m" 280 | (( $java_version >= 8 )) || addJava "-XX:MaxPermSize=${class_metadata_size}m" 281 | } 282 | 283 | addDefaultMemory() { 284 | # if we detect any of these settings in ${JAVA_OPTS} or ${JAVA_TOOL_OPTIONS} we need to NOT output our settings. 285 | # The reason is the Xms/Xmx, if they don't line up, cause errors. 286 | if [[ "${java_args[@]}" == *-Xmx* ]] || \ 287 | [[ "${java_args[@]}" == *-Xms* ]] || \ 288 | [[ "${java_args[@]}" == *-Xss* ]] || \ 289 | [[ "${java_args[@]}" == *-XX:+UseCGroupMemoryLimitForHeap* ]] || \ 290 | [[ "${java_args[@]}" == *-XX:MaxRAM* ]] || \ 291 | [[ "${java_args[@]}" == *-XX:InitialRAMPercentage* ]] || \ 292 | [[ "${java_args[@]}" == *-XX:MaxRAMPercentage* ]] || \ 293 | [[ "${java_args[@]}" == *-XX:MinRAMPercentage* ]]; then 294 | : 295 | elif [[ "${JAVA_TOOL_OPTIONS}" == *-Xmx* ]] || \ 296 | [[ "${JAVA_TOOL_OPTIONS}" == *-Xms* ]] || \ 297 | [[ "${JAVA_TOOL_OPTIONS}" == *-Xss* ]] || \ 298 | [[ "${JAVA_TOOL_OPTIONS}" == *-XX:+UseCGroupMemoryLimitForHeap* ]] || \ 299 | [[ "${JAVA_TOOL_OPTIONS}" == *-XX:MaxRAM* ]] || \ 300 | [[ "${JAVA_TOOL_OPTIONS}" == *-XX:InitialRAMPercentage* ]] || \ 301 | [[ "${JAVA_TOOL_OPTIONS}" == *-XX:MaxRAMPercentage* ]] || \ 302 | [[ "${JAVA_TOOL_OPTIONS}" == *-XX:MinRAMPercentage* ]] ; then 303 | : 304 | elif [[ "${sbt_options[@]}" == *-Xmx* ]] || \ 305 | [[ "${sbt_options[@]}" == *-Xms* ]] || \ 306 | [[ "${sbt_options[@]}" == *-Xss* ]] || \ 307 | [[ "${sbt_options[@]}" == *-XX:+UseCGroupMemoryLimitForHeap* ]] || \ 308 | [[ "${sbt_options[@]}" == *-XX:MaxRAM* ]] || \ 309 | [[ "${sbt_options[@]}" == *-XX:InitialRAMPercentage* ]] || \ 310 | [[ "${sbt_options[@]}" == *-XX:MaxRAMPercentage* ]] || \ 311 | [[ "${sbt_options[@]}" == *-XX:MinRAMPercentage* ]] ; then 312 | : 313 | else 314 | addMemory $sbt_default_mem 315 | fi 316 | } 317 | 318 | addSbtScriptProperty () { 319 | if [[ "${java_args[@]}" == *-Dsbt.script=* ]]; then 320 | : 321 | else 322 | sbt_script=$0 323 | sbt_script=${sbt_script/ /%20} 324 | addJava "-Dsbt.script=$sbt_script" 325 | fi 326 | } 327 | 328 | require_arg () { 329 | local type="$1" 330 | local opt="$2" 331 | local arg="$3" 332 | if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then 333 | echo "$opt requires <$type> argument" 334 | exit 1 335 | fi 336 | } 337 | 338 | is_function_defined() { 339 | declare -f "$1" > /dev/null 340 | } 341 | 342 | # parses JDK version from the -version output line. 343 | # 8 for 1.8.0_nn, 9 for 9-ea etc, and "no_java" for undetected 344 | jdk_version() { 345 | local result 346 | local lines=$("$java_cmd" -Xms32M -Xmx32M -version 2>&1 | tr '\r' '\n') 347 | local IFS=$'\n' 348 | for line in $lines; do 349 | if [[ (-z $result) && ($line = *"version \""*) ]] 350 | then 351 | local ver=$(echo $line | sed -e 's/.*version "\(.*\)"\(.*\)/\1/; 1q') 352 | # on macOS sed doesn't support '?' 353 | if [[ $ver = "1."* ]] 354 | then 355 | result=$(echo $ver | sed -e 's/1\.\([0-9]*\)\(.*\)/\1/; 1q') 356 | else 357 | result=$(echo $ver | sed -e 's/\([0-9]*\)\(.*\)/\1/; 1q') 358 | fi 359 | fi 360 | done 361 | if [[ -z $result ]] 362 | then 363 | result=no_java 364 | fi 365 | echo "$result" 366 | } 367 | 368 | # Find the first occurrence of the given property name and returns its value by looking at: 369 | # - properties set by command-line options, 370 | # - JAVA_OPTS environment variable, 371 | # - SBT_OPTS environment variable, 372 | # - _JAVA_OPTIONS environment variable and 373 | # - JAVA_TOOL_OPTIONS environment variable 374 | # in that order. 375 | findProperty() { 376 | local -a java_opts_array 377 | local -a sbt_opts_array 378 | local -a _java_options_array 379 | local -a java_tool_options_array 380 | read -a java_opts_array <<< "$JAVA_OPTS" 381 | read -a sbt_opts_array <<< "$SBT_OPTS" 382 | read -a _java_options_array <<< "$_JAVA_OPTIONS" 383 | read -a java_tool_options_array <<< "$JAVA_TOOL_OPTIONS" 384 | 385 | local args_to_check=( 386 | "${java_args[@]}" 387 | "${java_opts_array[@]}" 388 | "${sbt_opts_array[@]}" 389 | "${_java_options_array[@]}" 390 | "${java_tool_options_array[@]}") 391 | 392 | for opt in "${args_to_check[@]}"; do 393 | if [[ "$opt" == -D$1=* ]]; then 394 | echo "${opt#-D$1=}" 395 | return 396 | fi 397 | done 398 | } 399 | 400 | # Extracts the preloaded directory from either -Dsbt.preloaded, -Dsbt.global.base or -Duser.home 401 | # in that order. 402 | getPreloaded() { 403 | local preloaded && preloaded=$(findProperty sbt.preloaded) 404 | [ "$preloaded" ] && echo "$preloaded" && return 405 | 406 | local global_base && global_base=$(findProperty sbt.global.base) 407 | [ "$global_base" ] && echo "$global_base/preloaded" && return 408 | 409 | local user_home && user_home=$(findProperty user.home) 410 | echo "${user_home:-$HOME}/.sbt/preloaded" 411 | } 412 | 413 | syncPreloaded() { 414 | local source_preloaded="$sbt_home/lib/local-preloaded/" 415 | local target_preloaded="$(getPreloaded)" 416 | if [[ "$init_sbt_version" == "" ]]; then 417 | # FIXME: better $init_sbt_version detection 418 | init_sbt_version="$(ls -1 "$source_preloaded/org/scala-sbt/sbt/")" 419 | fi 420 | [[ -f "$target_preloaded/org/scala-sbt/sbt/$init_sbt_version/" ]] || { 421 | # lib/local-preloaded exists (This is optional) 422 | [[ -d "$source_preloaded" ]] && { 423 | command -v rsync >/dev/null 2>&1 && { 424 | mkdir -p "$target_preloaded" 425 | rsync --recursive --links --perms --times --ignore-existing "$source_preloaded" "$target_preloaded" || true 426 | } 427 | } 428 | } 429 | } 430 | 431 | # Detect that we have java installed. 432 | checkJava() { 433 | local required_version="$1" 434 | # Now check to see if it's a good enough version 435 | local good_enough="$(expr $java_version ">=" $required_version)" 436 | if [[ "$java_version" == "" ]]; then 437 | echo 438 | echo "No Java Development Kit (JDK) installation was detected." 439 | echo Please go to http://www.oracle.com/technetwork/java/javase/downloads/ and download. 440 | echo 441 | exit 1 442 | elif [[ "$good_enough" != "1" ]]; then 443 | echo 444 | echo "The Java Development Kit (JDK) installation you have is not up to date." 445 | echo $script_name requires at least version $required_version+, you have 446 | echo version $java_version 447 | echo 448 | echo Please go to http://www.oracle.com/technetwork/java/javase/downloads/ and download 449 | echo a valid JDK and install before running $script_name. 450 | echo 451 | exit 1 452 | fi 453 | } 454 | 455 | copyRt() { 456 | local at_least_9="$(expr $java_version ">=" 9)" 457 | if [[ "$at_least_9" == "1" ]]; then 458 | # The grep for java9-rt-ext- matches the filename prefix printed in Export.java 459 | java9_ext=$("$java_cmd" "${sbt_options[@]}" "${java_args[@]}" \ 460 | -jar "$sbt_jar" --rt-ext-dir | grep java9-rt-ext- | tr -d '\r') 461 | java9_rt=$(echo "$java9_ext/rt.jar") 462 | vlog "[copyRt] java9_rt = '$java9_rt'" 463 | if [[ ! -f "$java9_rt" ]]; then 464 | echo copying runtime jar... 465 | mkdir -p "$java9_ext" 466 | "$java_cmd" \ 467 | "${sbt_options[@]}" \ 468 | "${java_args[@]}" \ 469 | -jar "$sbt_jar" \ 470 | --export-rt \ 471 | "${java9_rt}" 472 | fi 473 | addJava "-Dscala.ext.dirs=${java9_ext}" 474 | fi 475 | } 476 | 477 | run() { 478 | # Copy preloaded repo to user's preloaded directory 479 | syncPreloaded 480 | 481 | # no jar? download it. 482 | [[ -f "$sbt_jar" ]] || acquire_sbt_jar "$sbt_version" || { 483 | exit 1 484 | } 485 | 486 | # TODO - java check should be configurable... 487 | checkJava "6" 488 | 489 | # Java 9 support 490 | copyRt 491 | 492 | # If we're in cygwin, we should use the windows config, and terminal hacks 493 | if [[ "$CYGWIN_FLAG" == "true" ]]; then #" 494 | stty -icanon min 1 -echo > /dev/null 2>&1 495 | addJava "-Djline.terminal=jline.UnixTerminal" 496 | addJava "-Dsbt.cygwin=true" 497 | fi 498 | 499 | if [[ $print_sbt_version ]]; then 500 | execRunner "$java_cmd" -jar "$sbt_jar" "sbtVersion" | tail -1 | sed -e 's/\[info\]//g' 501 | elif [[ $print_sbt_script_version ]]; then 502 | echo "$init_sbt_version" 503 | elif [[ $print_version ]]; then 504 | execRunner "$java_cmd" -jar "$sbt_jar" "sbtVersion" | tail -1 | sed -e 's/\[info\]/sbt version in this project:/g' 505 | echo "sbt script version: $init_sbt_version" 506 | elif [[ $shutdownall ]]; then 507 | local sbt_processes=( $(jps -v | grep sbt-launch | cut -f1 -d ' ') ) 508 | for procId in "${sbt_processes[@]}"; do 509 | kill -9 $procId 510 | done 511 | echo "shutdown ${#sbt_processes[@]} sbt processes" 512 | else 513 | # run sbt 514 | execRunner "$java_cmd" \ 515 | "${java_args[@]}" \ 516 | "${sbt_options[@]}" \ 517 | -jar "$sbt_jar" \ 518 | "${sbt_commands[@]}" \ 519 | "${residual_args[@]}" 520 | fi 521 | 522 | exit_code=$? 523 | 524 | # Clean up the terminal from cygwin hacks. 525 | if [[ "$CYGWIN_FLAG" == "true" ]]; then #" 526 | stty icanon echo > /dev/null 2>&1 527 | fi 528 | exit $exit_code 529 | } 530 | 531 | declare -ra noshare_opts=(-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy) 532 | declare -r sbt_opts_file=".sbtopts" 533 | declare -r build_props_file="$(pwd)/project/build.properties" 534 | declare -r etc_sbt_opts_file="/etc/sbt/sbtopts" 535 | # this allows /etc/sbt/sbtopts location to be changed 536 | declare -r etc_file="${SBT_ETC_FILE:-$etc_sbt_opts_file}" 537 | declare -r dist_sbt_opts_file="${sbt_home}/conf/sbtopts" 538 | declare -r win_sbt_opts_file="${sbt_home}/conf/sbtconfig.txt" 539 | declare sbt_jar="$(jar_file)" 540 | 541 | usage() { 542 | cat < path to global settings/plugins directory (default: ~/.sbt) 563 | --sbt-boot path to shared boot directory (default: ~/.sbt/boot in 0.11 series) 564 | --sbt-cache path to global cache directory (default: operating system specific) 565 | --ivy path to local Ivy repository (default: ~/.ivy2) 566 | --mem set memory options (default: $sbt_default_mem) 567 | --no-share use all local caches; no sharing 568 | --no-global uses global caches, but does not use global ~/.sbt directory. 569 | --jvm-debug Turn on JVM debugging, open at the given port. 570 | --batch disable interactive mode 571 | 572 | # sbt version (default: from project/build.properties if present, else latest release) 573 | --sbt-version use the specified version of sbt 574 | --sbt-jar use the specified jar as the sbt launcher 575 | 576 | --java-home alternate JAVA_HOME 577 | 578 | # jvm options and output control 579 | JAVA_OPTS environment variable, if unset uses "$default_java_opts" 580 | .jvmopts if this file exists in the current directory, its contents 581 | are appended to JAVA_OPTS 582 | SBT_OPTS environment variable, if unset uses "$default_sbt_opts" 583 | .sbtopts if this file exists in the current directory, its contents 584 | are prepended to the runner args 585 | /etc/sbt/sbtopts if this file exists, it is prepended to the runner args 586 | -Dkey=val pass -Dkey=val directly to the java runtime 587 | -J-X pass option -X directly to the java runtime 588 | (-J is stripped) 589 | 590 | In the case of duplicated or conflicting options, the order above 591 | shows precedence: JAVA_OPTS lowest, command line options highest. 592 | EOM 593 | } 594 | 595 | process_my_args () { 596 | while [[ $# -gt 0 ]]; do 597 | case "$1" in 598 | -batch|--batch) exec 599 | 600 | -sbt-create|--sbt-create) sbt_create=true && shift ;; 601 | 602 | new) sbt_new=true && addResidual "$1" && shift ;; 603 | 604 | *) addResidual "$1" && shift ;; 605 | esac 606 | done 607 | 608 | # Now, ensure sbt version is used. 609 | [[ "${sbt_version}XXX" != "XXX" ]] && addJava "-Dsbt.version=$sbt_version" 610 | 611 | # Confirm a user's intent if the current directory does not look like an sbt 612 | # top-level directory and neither the -sbt-create option nor the "new" 613 | # command was given. 614 | [[ -f ./build.sbt || -d ./project || -n "$sbt_create" || -n "$sbt_new" ]] || { 615 | echo "[warn] Neither build.sbt nor a 'project' directory in the current directory: $(pwd)" 616 | while true; do 617 | echo 'c) continue' 618 | echo 'q) quit' 619 | 620 | read -p '? ' || exit 1 621 | case "$REPLY" in 622 | c|C) break ;; 623 | q|Q) exit 1 ;; 624 | esac 625 | done 626 | } 627 | } 628 | 629 | ## map over argument array. this is used to process both command line arguments and SBT_OPTS 630 | map_args () { 631 | local options=() 632 | local commands=() 633 | while [[ $# -gt 0 ]]; do 634 | case "$1" in 635 | -no-colors|--no-colors) options=( "${options[@]}" "-Dsbt.log.noformat=true" ) && shift ;; 636 | -timings|--timings) options=( "${options[@]}" "-Dsbt.task.timings=true" "-Dsbt.task.timings.on.shutdown=true" ) && shift ;; 637 | -traces|--traces) options=( "${options[@]}" "-Dsbt.traces=true" ) && shift ;; 638 | --supershell=*) options=( "${options[@]}" "-Dsbt.supershell=${1:13}" ) && shift ;; 639 | -supershell=*) options=( "${options[@]}" "-Dsbt.supershell=${1:12}" ) && shift ;; 640 | -no-server|--no-server) options=( "${options[@]}" "-Dsbt.io.virtual=false" "-Dsbt.server.autostart=false" ) && shift ;; 641 | --color=*) options=( "${options[@]}" "-Dsbt.color=${1:8}" ) && shift ;; 642 | -color=*) options=( "${options[@]}" "-Dsbt.color=${1:7}" ) && shift ;; 643 | -no-share|--no-share) options=( "${options[@]}" "${noshare_opts[@]}" ) && shift ;; 644 | -no-global|--no-global) options=( "${options[@]}" "-Dsbt.global.base=$(pwd)/project/.sbtboot" ) && shift ;; 645 | -ivy|--ivy) require_arg path "$1" "$2" && options=( "${options[@]}" "-Dsbt.ivy.home=$2" ) && shift 2 ;; 646 | -sbt-boot|--sbt-boot) require_arg path "$1" "$2" && options=( "${options[@]}" "-Dsbt.boot.directory=$2" ) && shift 2 ;; 647 | -sbt-dir|--sbt-dir) require_arg path "$1" "$2" && options=( "${options[@]}" "-Dsbt.global.base=$2" ) && shift 2 ;; 648 | -debug|--debug) commands=( "${commands[@]}" "-debug" ) && shift ;; 649 | -debug-inc|--debug-inc) options=( "${options[@]}" "-Dxsbt.inc.debug=true" ) && shift ;; 650 | *) options=( "${options[@]}" "$1" ) && shift ;; 651 | esac 652 | done 653 | declare -p options 654 | declare -p commands 655 | } 656 | 657 | process_args () { 658 | while [[ $# -gt 0 ]]; do 659 | case "$1" in 660 | -h|-help|--help) usage; exit 1 ;; 661 | -v|-verbose|--verbose) sbt_verbose=1 && shift ;; 662 | -V|-version|--version) print_version=1 && shift ;; 663 | --numeric-version) print_sbt_version=1 && shift ;; 664 | --script-version) print_sbt_script_version=1 && shift ;; 665 | shutdownall) shutdownall=1 && shift ;; 666 | -d|-debug|--debug) sbt_debug=1 && addSbt "-debug" && shift ;; 667 | -client|--client) use_sbtn=1 && shift ;; 668 | --server) use_sbtn=0 && shift ;; 669 | 670 | -mem|--mem) require_arg integer "$1" "$2" && addMemory "$2" && shift 2 ;; 671 | -jvm-debug|--jvm-debug) require_arg port "$1" "$2" && addDebugger $2 && shift 2 ;; 672 | -batch|--batch) exec = 2 )) || ( (( $sbtBinaryV_1 >= 1 )) && (( $sbtBinaryV_2 >= 4 )) ); then 740 | if [[ "$use_sbtn" == "1" ]]; then 741 | echo "true" 742 | else 743 | echo "false" 744 | fi 745 | else 746 | echo "false" 747 | fi 748 | } 749 | 750 | runNativeClient() { 751 | vlog "[debug] running native client" 752 | detectNativeClient 753 | [[ -f "$sbtn_command" ]] || acquire_sbtn "$sbtn_version" || { 754 | exit 1 755 | } 756 | for i in "${!original_args[@]}"; do 757 | if [[ "${original_args[i]}" = "--client" ]]; then 758 | unset 'original_args[i]' 759 | fi 760 | done 761 | sbt_script=$0 762 | sbt_script=${sbt_script/ /%20} 763 | execRunner "$sbtn_command" "--sbt-script=$sbt_script" "${original_args[@]}" 764 | } 765 | 766 | original_args=("$@") 767 | 768 | # Here we pull in the default settings configuration. 769 | [[ -f "$dist_sbt_opts_file" ]] && set -- $(loadConfigFile "$dist_sbt_opts_file") "$@" 770 | 771 | # Here we pull in the global settings configuration. 772 | [[ -f "$etc_file" ]] && set -- $(loadConfigFile "$etc_file") "$@" 773 | 774 | # Pull in the project-level config file, if it exists. 775 | [[ -f "$sbt_opts_file" ]] && set -- $(loadConfigFile "$sbt_opts_file") "$@" 776 | 777 | # Pull in the project-level java config, if it exists. 778 | [[ -f ".jvmopts" ]] && export JAVA_OPTS="$JAVA_OPTS $(loadConfigFile .jvmopts)" 779 | 780 | # Pull in default JAVA_OPTS 781 | [[ -z "${JAVA_OPTS// }" ]] && export JAVA_OPTS="$default_java_opts" 782 | 783 | [[ -f "$build_props_file" ]] && loadPropFile "$build_props_file" 784 | 785 | java_args=($JAVA_OPTS) 786 | sbt_options0=(${SBT_OPTS:-$default_sbt_opts}) 787 | if [[ "$SBT_NATIVE_CLIENT" == "true" ]]; then 788 | use_sbtn=1 789 | fi 790 | 791 | # Split SBT_OPTS into options/commands 792 | miniscript=$(map_args "${sbt_options0[@]}") && eval "${miniscript/options/sbt_options}" && \ 793 | eval "${miniscript/commands/sbt_additional_commands}" 794 | 795 | # Combine command line options/commands and commands from SBT_OPTS 796 | miniscript=$(map_args "$@") && eval "${miniscript/options/cli_options}" && eval "${miniscript/commands/cli_commands}" 797 | args1=( "${cli_options[@]}" "${cli_commands[@]}" "${sbt_additional_commands[@]}" ) 798 | 799 | # process the combined args, then reset "$@" to the residuals 800 | process_args "${args1[@]}" 801 | vlog "[sbt_options] $(declare -p sbt_options)" 802 | 803 | if [[ "$(isRunNativeClient)" == "true" ]]; then 804 | set -- "${residual_args[@]}" 805 | argumentCount=$# 806 | runNativeClient 807 | else 808 | java_version="$(jdk_version)" 809 | vlog "[process_args] java_version = '$java_version'" 810 | addDefaultMemory 811 | addSbtScriptProperty 812 | set -- "${residual_args[@]}" 813 | argumentCount=$# 814 | run 815 | fi 816 | -------------------------------------------------------------------------------- /sbt.bat: -------------------------------------------------------------------------------- 1 | @REM SBT launcher script 2 | @REM 3 | @REM Environment: 4 | @REM JAVA_HOME - location of a JDK home dir (mandatory) 5 | @REM SBT_OPTS - JVM options (optional) 6 | @REM Configuration: 7 | @REM sbtconfig.txt found in the SBT_HOME. 8 | 9 | @REM ZOMG! We need delayed expansion to build up CFG_OPTS later 10 | @setlocal enabledelayedexpansion 11 | 12 | @echo off 13 | set SBT_BIN_DIR=%~dp0 14 | if not defined SBT_HOME for %%I in ("!SBT_BIN_DIR!\..") do set "SBT_HOME=%%~fI" 15 | 16 | set SBT_ARGS= 17 | set _JAVACMD= 18 | set _SBT_OPTS= 19 | set _JAVA_OPTS= 20 | 21 | set init_sbt_version=1.9.2 22 | set sbt_default_mem=1024 23 | set default_sbt_opts= 24 | set default_java_opts=-Dfile.encoding=UTF-8 25 | set sbt_jar= 26 | set build_props_sbt_version= 27 | set run_native_client= 28 | set shutdownall= 29 | 30 | set sbt_args_print_version= 31 | set sbt_args_print_sbt_version= 32 | set sbt_args_print_sbt_script_version= 33 | set sbt_args_verbose= 34 | set sbt_args_debug= 35 | set sbt_args_debug_inc= 36 | set sbt_args_batch= 37 | set sbt_args_color= 38 | set sbt_args_no_colors= 39 | set sbt_args_no_global= 40 | set sbt_args_no_share= 41 | set sbt_args_sbt_jar= 42 | set sbt_args_ivy= 43 | set sbt_args_supershell= 44 | set sbt_args_timings= 45 | set sbt_args_traces= 46 | set sbt_args_sbt_boot= 47 | set sbt_args_sbt_cache= 48 | set sbt_args_sbt_create= 49 | set sbt_args_sbt_dir= 50 | set sbt_args_sbt_version= 51 | set sbt_args_mem= 52 | set sbt_args_client= 53 | set sbt_args_no_server= 54 | 55 | rem users can set SBT_OPTS via .sbtopts 56 | if exist .sbtopts for /F %%A in (.sbtopts) do ( 57 | set _sbtopts_line=%%A 58 | if not "!_sbtopts_line:~0,1!" == "#" ( 59 | if "!_sbtopts_line:~0,2!" == "-J" ( 60 | set _sbtopts_line=!_sbtopts_line:~2,1000! 61 | ) 62 | if defined _SBT_OPTS ( 63 | set _SBT_OPTS=!_SBT_OPTS! !_sbtopts_line! 64 | ) else ( 65 | set _SBT_OPTS=!_sbtopts_line! 66 | ) 67 | ) 68 | ) 69 | 70 | rem TODO: remove/deprecate sbtconfig.txt and parse the sbtopts files 71 | 72 | rem FIRST we load the config file of extra options. 73 | set SBT_CONFIG=!SBT_HOME!\conf\sbtconfig.txt 74 | set SBT_CFG_OPTS= 75 | for /F "tokens=* eol=# usebackq delims=" %%i in ("!SBT_CONFIG!") do ( 76 | set DO_NOT_REUSE_ME=%%i 77 | rem ZOMG (Part #2) WE use !! here to delay the expansion of 78 | rem SBT_CFG_OPTS, otherwise it remains "" for this loop. 79 | set SBT_CFG_OPTS=!SBT_CFG_OPTS! !DO_NOT_REUSE_ME! 80 | ) 81 | 82 | rem poor man's jenv (which is not available on Windows) 83 | if defined JAVA_HOMES ( 84 | if exist .java-version for /F %%A in (.java-version) do ( 85 | set JAVA_HOME=%JAVA_HOMES%\%%A 86 | set JDK_HOME=%JAVA_HOMES%\%%A 87 | ) 88 | ) 89 | 90 | if exist "project\build.properties" ( 91 | for /F "eol=# delims== tokens=1*" %%a in (project\build.properties) do ( 92 | if "%%a" == "sbt.version" if not "%%b" == "" ( 93 | set build_props_sbt_version=%%b 94 | ) 95 | ) 96 | ) 97 | 98 | rem must set PATH or wrong javac is used for java projects 99 | if defined JAVA_HOME set "PATH=%JAVA_HOME%\bin;%PATH%" 100 | 101 | rem We use the value of the JAVACMD environment variable if defined 102 | if defined JAVACMD set "_JAVACMD=%JAVACMD%" 103 | 104 | rem remove quotes 105 | if defined _JAVACMD set _JAVACMD=!_JAVACMD:"=! 106 | 107 | if not defined _JAVACMD ( 108 | if not "%JAVA_HOME%" == "" ( 109 | if exist "%JAVA_HOME%\bin\java.exe" set "_JAVACMD=%JAVA_HOME%\bin\java.exe" 110 | ) 111 | ) 112 | 113 | if not defined _JAVACMD set _JAVACMD=java 114 | 115 | rem users can set JAVA_OPTS via .jvmopts (sbt-extras style) 116 | if exist .jvmopts for /F %%A in (.jvmopts) do ( 117 | set _jvmopts_line=%%A 118 | if not "!_jvmopts_line:~0,1!" == "#" ( 119 | if defined _JAVA_OPTS ( 120 | set _JAVA_OPTS=!_JAVA_OPTS! %%A 121 | ) else ( 122 | set _JAVA_OPTS=%%A 123 | ) 124 | ) 125 | ) 126 | 127 | rem We use the value of the JAVA_OPTS environment variable if defined, rather than the config. 128 | if not defined _JAVA_OPTS if defined JAVA_OPTS set _JAVA_OPTS=%JAVA_OPTS% 129 | if not defined _JAVA_OPTS if defined default_java_opts set _JAVA_OPTS=!default_java_opts! 130 | 131 | rem We use the value of the SBT_OPTS environment variable if defined, rather than the config. 132 | if not defined _SBT_OPTS if defined SBT_OPTS set _SBT_OPTS=%SBT_OPTS% 133 | if not defined _SBT_OPTS if defined SBT_CFG_OPTS set _SBT_OPTS=!SBT_CFG_OPTS! 134 | if not defined _SBT_OPTS if defined default_sbt_opts set _SBT_OPTS=!default_sbt_opts! 135 | 136 | if defined SBT_NATIVE_CLIENT ( 137 | if "%SBT_NATIVE_CLIENT%" == "true" ( 138 | set sbt_args_client=1 139 | ) 140 | ) 141 | 142 | :args_loop 143 | shift 144 | 145 | if "%~0" == "" goto args_end 146 | set g=%~0 147 | 148 | rem make sure the sbt_args_debug gets set first incase any argument parsing uses :dlog 149 | if "%~0" == "-d" set _debug_arg=true 150 | if "%~0" == "--debug" set _debug_arg=true 151 | 152 | if defined _debug_arg ( 153 | set _debug_arg= 154 | set sbt_args_debug=1 155 | set SBT_ARGS=-debug !SBT_ARGS! 156 | goto args_loop 157 | ) 158 | 159 | if "%~0" == "-h" goto usage 160 | if "%~0" == "-help" goto usage 161 | if "%~0" == "--help" goto usage 162 | 163 | if "%~0" == "-v" set _verbose_arg=true 164 | if "%~0" == "-verbose" set _verbose_arg=true 165 | if "%~0" == "--verbose" set _verbose_arg=true 166 | 167 | if defined _verbose_arg ( 168 | set _verbose_arg= 169 | set sbt_args_verbose=1 170 | goto args_loop 171 | ) 172 | 173 | if "%~0" == "-V" set _version_arg=true 174 | if "%~0" == "-version" set _version_arg=true 175 | if "%~0" == "--version" set _version_arg=true 176 | 177 | if defined _version_arg ( 178 | set _version_arg= 179 | set sbt_args_print_version=1 180 | goto args_loop 181 | ) 182 | 183 | if "%~0" == "--client" set _client_arg=true 184 | 185 | if defined _client_arg ( 186 | set _client_arg= 187 | set sbt_args_client=1 188 | goto args_loop 189 | ) 190 | 191 | if "%~0" == "-batch" set _batch_arg=true 192 | if "%~0" == "--batch" set _batch_arg=true 193 | 194 | if defined _batch_arg ( 195 | set _batch_arg= 196 | set sbt_args_batch=1 197 | goto args_loop 198 | ) 199 | 200 | if "%~0" == "-no-colors" set _no_colors_arg=true 201 | if "%~0" == "--no-colors" set _no_colors_arg=true 202 | 203 | if defined _no_colors_arg ( 204 | set _no_colors_arg= 205 | set sbt_args_no_colors=1 206 | goto args_loop 207 | ) 208 | 209 | if "%~0" == "-no-server" set _no_server_arg=true 210 | if "%~0" == "--no-server" set _no_server_arg=true 211 | 212 | if defined _no_server_arg ( 213 | set _no_server_arg= 214 | set sbt_args_no_server=1 215 | goto args_loop 216 | ) 217 | 218 | if "%~0" == "-no-global" set _no_global_arg=true 219 | if "%~0" == "--no-global" set _no_global_arg=true 220 | 221 | if defined _no_global_arg ( 222 | set _no_global_arg= 223 | set sbt_args_no_global=1 224 | goto args_loop 225 | ) 226 | 227 | if "%~0" == "-traces" set _traces_arg=true 228 | if "%~0" == "--traces" set _traces_arg=true 229 | 230 | if defined _traces_arg ( 231 | set _traces_arg= 232 | set sbt_args_traces=1 233 | goto args_loop 234 | ) 235 | 236 | if "%~0" == "-sbt-create" set _sbt_create_arg=true 237 | if "%~0" == "--sbt-create" set _sbt_create_arg=true 238 | 239 | if defined _sbt_create_arg ( 240 | set _sbt_create_arg= 241 | set sbt_args_sbt_create=1 242 | goto args_loop 243 | ) 244 | 245 | if "%~0" == "-sbt-dir" set _sbt_dir_arg=true 246 | if "%~0" == "--sbt-dir" set _sbt_dir_arg=true 247 | 248 | if defined _sbt_dir_arg ( 249 | set _sbt_dir_arg= 250 | if not "%~1" == "" ( 251 | set sbt_args_sbt_dir=%1 252 | shift 253 | goto args_loop 254 | ) else ( 255 | echo "%~0" is missing a value 256 | goto error 257 | ) 258 | ) 259 | 260 | if "%~0" == "-sbt-boot" set _sbt_boot_arg=true 261 | if "%~0" == "--sbt-boot" set _sbt_boot_arg=true 262 | 263 | if defined _sbt_boot_arg ( 264 | set _sbt_boot_arg= 265 | if not "%~1" == "" ( 266 | set sbt_args_sbt_boot=%1 267 | shift 268 | goto args_loop 269 | ) else ( 270 | echo "%~0" is missing a value 271 | goto error 272 | ) 273 | ) 274 | 275 | if "%~0" == "-sbt-cache" set _sbt_cache_arg=true 276 | if "%~0" == "--sbt-cache" set _sbt_cache_arg=true 277 | 278 | if defined _sbt_cache_arg ( 279 | set _sbt_cache_arg= 280 | if not "%~1" == "" ( 281 | set sbt_args_sbt_cache=%1 282 | shift 283 | goto args_loop 284 | ) else ( 285 | echo "%~0" is missing a value 286 | goto error 287 | ) 288 | ) 289 | 290 | if "%~0" == "-sbt-jar" set _sbt_jar=true 291 | if "%~0" == "--sbt-jar" set _sbt_jar=true 292 | 293 | if defined _sbt_jar ( 294 | set _sbt_jar= 295 | if not "%~1" == "" ( 296 | if exist "%~1" ( 297 | set sbt_args_sbt_jar=%1 298 | shift 299 | goto args_loop 300 | ) else ( 301 | echo %~1 does not exist 302 | goto error 303 | ) 304 | ) else ( 305 | echo "%~0" is missing a value 306 | goto error 307 | ) 308 | ) 309 | 310 | if "%~0" == "-ivy" set _sbt_ivy_arg=true 311 | if "%~0" == "--ivy" set _sbt_ivy_arg=true 312 | 313 | if defined _sbt_ivy_arg ( 314 | set _sbt_ivy_arg= 315 | if not "%~1" == "" ( 316 | set sbt_args_ivy=%1 317 | shift 318 | goto args_loop 319 | ) else ( 320 | echo "%~0" is missing a value 321 | goto error 322 | ) 323 | ) 324 | 325 | if "%~0" == "-debug-inc" set _debug_inc_arg=true 326 | if "%~0" == "--debug-inc" set _debug_inc_arg=true 327 | 328 | if defined _debug_inc_arg ( 329 | set _debug_inc_arg= 330 | set sbt_args_debug_inc=1 331 | goto args_loop 332 | ) 333 | 334 | if "%~0" == "--sbt-version" set _sbt_version_arg=true 335 | if "%~0" == "-sbt-version" set _sbt_version_arg=true 336 | 337 | if defined _sbt_version_arg ( 338 | set _sbt_version_arg= 339 | if not "%~1" == "" ( 340 | set sbt_args_sbt_version=%~1 341 | shift 342 | goto args_loop 343 | ) else ( 344 | echo "%~0" is missing a value 345 | goto error 346 | ) 347 | ) 348 | 349 | if "%~0" == "--mem" set _sbt_mem_arg=true 350 | if "%~0" == "-mem" set _sbt_mem_arg=true 351 | 352 | if defined _sbt_mem_arg ( 353 | set _sbt_mem_arg= 354 | if not "%~1" == "" ( 355 | set sbt_args_mem=%~1 356 | shift 357 | goto args_loop 358 | ) else ( 359 | echo "%~0" is missing a value 360 | goto error 361 | ) 362 | ) 363 | 364 | if "%~0" == "--supershell" set _supershell_arg=true 365 | if "%~0" == "-supershell" set _supershell_arg=true 366 | 367 | if defined _supershell_arg ( 368 | set _supershell_arg= 369 | if not "%~1" == "" ( 370 | set sbt_args_supershell=%~1 371 | shift 372 | goto args_loop 373 | ) else ( 374 | echo "%~0" is missing a value 375 | goto error 376 | ) 377 | ) 378 | 379 | if "%~0" == "--color" set _color_arg=true 380 | if "%~0" == "-color" set _color_arg=true 381 | 382 | if defined _color_arg ( 383 | set _color_arg= 384 | if not "%~1" == "" ( 385 | set sbt_args_color=%~1 386 | shift 387 | goto args_loop 388 | ) else ( 389 | echo "%~0" is missing a value 390 | goto error 391 | ) 392 | goto args_loop 393 | ) 394 | 395 | if "%~0" == "--no-share" set _no_share_arg=true 396 | if "%~0" == "-no-share" set _no_share_arg=true 397 | 398 | if defined _no_share_arg ( 399 | set _no_share_arg= 400 | set sbt_args_no_share=1 401 | goto args_loop 402 | ) 403 | 404 | if "%~0" == "--timings" set _timings_arg=true 405 | if "%~0" == "-timings" set _timings_arg=true 406 | 407 | if defined _timings_arg ( 408 | set _timings_arg= 409 | set sbt_args_timings=1 410 | goto args_loop 411 | ) 412 | 413 | if "%~0" == "shutdownall" ( 414 | set shutdownall=1 415 | goto args_loop 416 | ) 417 | 418 | if "%~0" == "--script-version" ( 419 | set sbt_args_print_sbt_script_version=1 420 | goto args_loop 421 | ) 422 | 423 | if "%~0" == "--numeric-version" ( 424 | set sbt_args_print_sbt_version=1 425 | goto args_loop 426 | ) 427 | 428 | if "%~0" == "-jvm-debug" set _jvm_debug_arg=true 429 | if "%~0" == "--jvm-debug" set _jvm_debug_arg=true 430 | 431 | if defined _jvm_debug_arg ( 432 | set _jvm_debug_arg= 433 | if not "%~1" == "" ( 434 | set /a JVM_DEBUG_PORT=%~1 2>nul >nul 435 | if !JVM_DEBUG_PORT! EQU 0 ( 436 | rem next argument wasn't a port, set a default and process next arg 437 | set /A JVM_DEBUG_PORT=5005 438 | goto args_loop 439 | ) else ( 440 | shift 441 | goto args_loop 442 | ) 443 | ) 444 | ) 445 | 446 | if "%~0" == "-java-home" set _java_home_arg=true 447 | if "%~0" == "--java-home" set _java_home_arg=true 448 | 449 | if defined _java_home_arg ( 450 | set _java_home_arg= 451 | if not "%~1" == "" ( 452 | if exist "%~1\bin\java.exe" ( 453 | set "_JAVACMD=%~1\bin\java.exe" 454 | set "JAVA_HOME=%~1" 455 | set "JDK_HOME=%~1" 456 | shift 457 | goto args_loop 458 | ) else ( 459 | echo Directory "%~1" for JAVA_HOME is not valid 460 | goto error 461 | ) 462 | ) else ( 463 | echo Second argument for --java-home missing 464 | goto error 465 | ) 466 | ) 467 | 468 | if "%~0" == "new" ( 469 | if not defined SBT_ARGS ( 470 | set sbt_new=true 471 | ) 472 | ) 473 | 474 | if "%g:~0,2%" == "-D" ( 475 | rem special handling for -D since '=' gets parsed away 476 | for /F "tokens=1 delims==" %%a in ("%g%") do ( 477 | rem make sure it doesn't have the '=' already 478 | if "%g%" == "%%a" ( 479 | if not "%~1" == "" ( 480 | call :dlog [args_loop] -D argument %~0=%~1 481 | set "SBT_ARGS=!SBT_ARGS! %~0=%~1" 482 | shift 483 | goto args_loop 484 | ) else ( 485 | echo %g% is missing a value 486 | goto error 487 | ) 488 | ) else ( 489 | call :dlog [args_loop] -D argument %~0 490 | set "SBT_ARGS=!SBT_ARGS! %~0" 491 | goto args_loop 492 | ) 493 | ) 494 | ) 495 | 496 | if not "%g:~0,5%" == "-XX:+" if not "%g:~0,5%" == "-XX:-" if "%g:~0,3%" == "-XX" ( 497 | rem special handling for -XX since '=' gets parsed away 498 | for /F "tokens=1 delims==" %%a in ("%g%") do ( 499 | rem make sure it doesn't have the '=' already 500 | if "%g%" == "%%a" ( 501 | if not "%~1" == "" ( 502 | call :dlog [args_loop] -XX argument %~0=%~1 503 | set "SBT_ARGS=!SBT_ARGS! %~0=%~1" 504 | shift 505 | goto args_loop 506 | ) else ( 507 | echo %g% is missing a value 508 | goto error 509 | ) 510 | ) else ( 511 | call :dlog [args_loop] -XX argument %~0 512 | set "SBT_ARGS=!SBT_ARGS! %~0" 513 | goto args_loop 514 | ) 515 | ) 516 | ) 517 | 518 | rem the %0 (instead of %~0) preserves original argument quoting 519 | set SBT_ARGS=!SBT_ARGS! %0 520 | 521 | goto args_loop 522 | :args_end 523 | 524 | rem Confirm a user's intent if the current directory does not look like an sbt 525 | rem top-level directory and the "new" command was not given. 526 | 527 | if not defined sbt_args_sbt_create if not defined sbt_args_print_version if not defined sbt_args_print_sbt_version if not defined sbt_args_print_sbt_script_version if not defined shutdownall if not exist build.sbt ( 528 | if not exist project\ ( 529 | if not defined sbt_new ( 530 | echo [warn] Neither build.sbt nor a 'project' directory in the current directory: "%CD%" 531 | setlocal 532 | :confirm 533 | echo c^) continue 534 | echo q^) quit 535 | 536 | set /P reply=^? 537 | if /I "!reply!" == "c" ( 538 | goto confirm_end 539 | ) else if /I "!reply!" == "q" ( 540 | exit /B 1 541 | ) 542 | 543 | goto confirm 544 | :confirm_end 545 | endlocal 546 | ) 547 | ) 548 | ) 549 | 550 | call :process 551 | 552 | rem avoid bootstrapping/java version check for script version 553 | 554 | if !shutdownall! equ 1 ( 555 | set count=0 556 | for /f "tokens=1" %%i in ('jps -lv ^| findstr "xsbt.boot.Boot"') do ( 557 | taskkill /F /PID %%i 558 | set /a count=!count!+1 559 | ) 560 | echo shutdown !count! sbt processes 561 | goto :eof 562 | ) 563 | 564 | if !sbt_args_print_sbt_script_version! equ 1 ( 565 | echo !init_sbt_version! 566 | goto :eof 567 | ) 568 | 569 | if !run_native_client! equ 1 ( 570 | goto :runnative !SBT_ARGS! 571 | goto :eof 572 | ) 573 | 574 | call :checkjava 575 | 576 | if defined sbt_args_sbt_jar ( 577 | set "sbt_jar=!sbt_args_sbt_jar!" 578 | ) else ( 579 | set "sbt_jar=!SBT_HOME!\bin\sbt-launch.jar" 580 | ) 581 | 582 | set sbt_jar=!sbt_jar:"=! 583 | 584 | call :copyrt 585 | 586 | if defined JVM_DEBUG_PORT ( 587 | set _JAVA_OPTS=!_JAVA_OPTS! -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=!JVM_DEBUG_PORT! 588 | ) 589 | 590 | call :sync_preloaded 591 | 592 | call :run !SBT_ARGS! 593 | 594 | if ERRORLEVEL 1 goto error 595 | goto end 596 | 597 | :run 598 | 599 | rem set arguments 600 | 601 | if defined sbt_args_debug_inc ( 602 | set _SBT_OPTS=-Dxsbt.inc.debug=true !_SBT_OPTS! 603 | ) 604 | 605 | if defined sbt_args_no_colors ( 606 | set _SBT_OPTS=-Dsbt.log.noformat=true !_SBT_OPTS! 607 | ) 608 | 609 | if defined sbt_args_no_global ( 610 | set _SBT_OPTS=-Dsbt.global.base=project/.sbtboot !_SBT_OPTS! 611 | ) 612 | 613 | if defined sbt_args_no_share ( 614 | set _SBT_OPTS=-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy !_SBT_OPTS! 615 | ) 616 | 617 | if defined sbt_args_supershell ( 618 | set _SBT_OPTS=-Dsbt.supershell=!sbt_args_supershell! !_SBT_OPTS! 619 | ) 620 | 621 | if defined sbt_args_sbt_version ( 622 | set _SBT_OPTS=-Dsbt.version=!sbt_args_sbt_version! !_SBT_OPTS! 623 | ) 624 | 625 | if defined sbt_args_sbt_dir ( 626 | set _SBT_OPTS=-Dsbt.global.base=!sbt_args_sbt_dir! !_SBT_OPTS! 627 | ) 628 | 629 | if defined sbt_args_sbt_boot ( 630 | set _SBT_OPTS=-Dsbt.boot.directory=!sbt_args_sbt_boot! !_SBT_OPTS! 631 | ) 632 | 633 | if defined sbt_args_sbt_cache ( 634 | set _SBT_OPTS=-Dsbt.global.localcache=!sbt_args_sbt_cache! !_SBT_OPTS! 635 | ) 636 | 637 | if defined sbt_args_ivy ( 638 | set _SBT_OPTS=-Dsbt.ivy.home=!sbt_args_ivy! !_SBT_OPTS! 639 | ) 640 | 641 | if defined sbt_args_color ( 642 | set _SBT_OPTS=-Dsbt.color=!sbt_args_color! !_SBT_OPTS! 643 | ) 644 | 645 | if defined sbt_args_mem ( 646 | call :addMemory !sbt_args_mem! 647 | ) else ( 648 | call :addDefaultMemory 649 | ) 650 | 651 | if defined sbt_args_timings ( 652 | set _SBT_OPTS=-Dsbt.task.timings=true -Dsbt.task.timings.on.shutdown=true !_SBT_OPTS! 653 | ) 654 | 655 | if defined sbt_args_traces ( 656 | set _SBT_OPTS=-Dsbt.traces=true !_SBT_OPTS! 657 | ) 658 | 659 | if defined sbt_args_no_server ( 660 | set _SBT_OPTS=-Dsbt.io.virtual=false -Dsbt.server.autostart=false !_SBT_OPTS! 661 | ) 662 | 663 | rem TODO: _SBT_OPTS needs to be processed as args and diffed against SBT_ARGS 664 | 665 | if !sbt_args_print_sbt_version! equ 1 ( 666 | call :set_sbt_version 667 | echo !sbt_version! 668 | goto :eof 669 | ) 670 | 671 | if !sbt_args_print_version! equ 1 ( 672 | call :set_sbt_version 673 | echo sbt version in this project: !sbt_version! 674 | echo sbt script version: !init_sbt_version! 675 | goto :eof 676 | ) 677 | 678 | if defined sbt_args_verbose ( 679 | echo # Executing command line: 680 | echo "!_JAVACMD!" 681 | if defined _JAVA_OPTS ( call :echolist !_JAVA_OPTS! ) 682 | if defined _SBT_OPTS ( call :echolist !_SBT_OPTS! ) 683 | echo -cp 684 | echo "!sbt_jar!" 685 | echo xsbt.boot.Boot 686 | if not "%~1" == "" ( call :echolist %* ) 687 | echo. 688 | ) 689 | 690 | "!_JAVACMD!" !_JAVA_OPTS! !_SBT_OPTS! -cp "!sbt_jar!" xsbt.boot.Boot %* 691 | 692 | goto :eof 693 | 694 | :runnative 695 | 696 | set "_SBTNCMD=!SBT_BIN_DIR!sbtn-x86_64-pc-win32.exe" 697 | 698 | if defined sbt_args_verbose ( 699 | echo # running native client 700 | if not "%~1" == "" ( call :echolist %* ) 701 | set "SBT_ARGS=-v !SBT_ARGS!" 702 | ) 703 | 704 | set "SBT_SCRIPT=!SBT_BIN_DIR: =%%20!sbt.bat" 705 | set "SBT_ARGS=--sbt-script=!SBT_SCRIPT! %SBT_ARGS%" 706 | 707 | rem Microsoft Visual C++ 2010 SP1 Redistributable Package (x64) is required 708 | rem https://www.microsoft.com/en-us/download/details.aspx?id=13523 709 | "!_SBTNCMD!" %SBT_ARGS% 710 | 711 | goto :eof 712 | 713 | rem for expression tries to interpret files, so simply loop over %* instead 714 | rem fixes dealing with quotes after = args: -Dscala.ext.dirs="C:\Users\First Last\.sbt\0.13\java9-rt-ext-adoptopenjdk_11_0_3" 715 | :echolist 716 | rem call method is in first call of %0 717 | shift 718 | 719 | if "%~0" == "" goto echolist_end 720 | set "p=%~0" 721 | 722 | if "%p:~0,2%" == "-D" ( 723 | rem special handling for -D since '=' gets parsed away 724 | for /F "tokens=1 delims==" %%a in ("%p%") do ( 725 | rem make sure it doesn't have the '=' already 726 | if "%p%" == "%%a" if not "%~1" == "" ( 727 | echo %0=%1 728 | shift 729 | goto echolist 730 | ) 731 | ) 732 | ) 733 | 734 | if not "%p:~0,5%" == "-XX:+" if not "%p:~0,5%" == "-XX:-" if "%p:~0,3%" == "-XX" ( 735 | rem special handling for -XX since '=' gets parsed away 736 | for /F "tokens=1 delims==" %%a in ("%p%") do ( 737 | rem make sure it doesn't have the '=' already 738 | if "%p%" == "%%a" if not "%~1" == "" ( 739 | echo %0=%1 740 | shift 741 | goto echolist 742 | ) 743 | ) 744 | ) 745 | 746 | if "%p:~0,14%" == "-agentlib:jdwp" ( 747 | rem special handling for --jvm-debug since '=' and ',' gets parsed away 748 | for /F "tokens=1 delims==" %%a in ("%p%") do ( 749 | rem make sure it doesn't have the '=' already 750 | if "%p%" == "%%a" if not "%~1" == "" if not "%~2" == "" if not "%~3" == "" if not "%~4" == "" if not "%~5" == "" if not "%~6" == "" if not "%~7" == "" if not "%~8" == "" ( 751 | echo %0=%1=%2,%3=%4,%5=%6,%7=%8 752 | shift & shift & shift & shift & shift & shift & shift & shift 753 | goto echolist 754 | ) 755 | ) 756 | ) 757 | 758 | echo %0 759 | goto echolist 760 | 761 | :echolist_end 762 | 763 | exit /B 0 764 | 765 | :addJava 766 | call :dlog [addJava] arg = '%*' 767 | set "_JAVA_OPTS=!_JAVA_OPTS! %*" 768 | exit /B 0 769 | 770 | :addMemory 771 | call :dlog [addMemory] arg = '%*' 772 | 773 | rem evict memory related options 774 | set _new_java_opts= 775 | set _old_java_opts=!_JAVA_OPTS! 776 | :next_java_opt 777 | if "!_old_java_opts!" == "" goto :done_java_opt 778 | for /F "tokens=1,*" %%g in ("!_old_java_opts!") do ( 779 | set "p=%%g" 780 | if not "!p:~0,4!" == "-Xmx" if not "!p:~0,4!" == "-Xms" if not "!p:~0,4!" == "-Xss" if not "!p:~0,15!" == "-XX:MaxPermSize" if not "!p:~0,20!" == "-XX:MaxMetaspaceSize" if not "!p:~0,25!" == "-XX:ReservedCodeCacheSize" ( 781 | set _new_java_opts=!_new_java_opts! %%g 782 | ) 783 | set "_old_java_opts=%%h" 784 | ) 785 | goto :next_java_opt 786 | :done_java_opt 787 | set _JAVA_OPTS=!_new_java_opts! 788 | 789 | set _new_sbt_opts= 790 | set _old_sbt_opts=!_SBT_OPTS! 791 | :next_sbt_opt 792 | if "!_old_sbt_opts!" == "" goto :done_sbt_opt 793 | for /F "tokens=1,*" %%g in ("!_old_sbt_opts!") do ( 794 | set "p=%%g" 795 | if not "!p:~0,4!" == "-Xmx" if not "!p:~0,4!" == "-Xms" if not "!p:~0,4!" == "-Xss" if not "!p:~0,15!" == "-XX:MaxPermSize" if not "!p:~0,20!" == "-XX:MaxMetaspaceSize" if not "!p:~0,25!" == "-XX:ReservedCodeCacheSize" ( 796 | set _new_sbt_opts=!_new_sbt_opts! %%g 797 | ) 798 | set "_old_sbt_opts=%%h" 799 | ) 800 | goto :next_sbt_opt 801 | :done_sbt_opt 802 | set _SBT_OPTS=!_new_sbt_opts! 803 | 804 | rem a ham-fisted attempt to move some memory settings in concert 805 | set mem=%1 806 | set /a codecache=!mem! / 8 807 | if !codecache! GEQ 512 set /a codecache=512 808 | if !codecache! LEQ 128 set /a codecache=128 809 | 810 | set /a class_metadata_size=!codecache! * 2 811 | 812 | call :addJava -Xms!mem!m 813 | call :addJava -Xmx!mem!m 814 | call :addJava -Xss4M 815 | call :addJava -XX:ReservedCodeCacheSize=!codecache!m 816 | 817 | if /I !JAVA_VERSION! LSS 8 ( 818 | call :addJava -XX:MaxPermSize=!class_metadata_size!m 819 | ) 820 | 821 | exit /B 0 822 | 823 | :addDefaultMemory 824 | rem if we detect any of these settings in ${JAVA_OPTS} or ${JAVA_TOOL_OPTIONS} we need to NOT output our settings. 825 | rem The reason is the Xms/Xmx, if they don't line up, cause errors. 826 | 827 | set _has_memory_args= 828 | 829 | if defined _JAVA_OPTS for /F %%g in ("!_JAVA_OPTS!") do ( 830 | set "p=%%g" 831 | if "!p:~0,4!" == "-Xmx" set _has_memory_args=1 832 | if "!p:~0,4!" == "-Xms" set _has_memory_args=1 833 | if "!p:~0,4!" == "-Xss" set _has_memory_args=1 834 | ) 835 | 836 | if defined JAVA_TOOL_OPTIONS for /F %%g in ("%JAVA_TOOL_OPTIONS%") do ( 837 | set "p=%%g" 838 | if "!p:~0,4!" == "-Xmx" set _has_memory_args=1 839 | if "!p:~0,4!" == "-Xms" set _has_memory_args=1 840 | if "!p:~0,4!" == "-Xss" set _has_memory_args=1 841 | ) 842 | 843 | if defined _SBT_OPTS for /F %%g in ("!_SBT_OPTS!") do ( 844 | set "p=%%g" 845 | if "!p:~0,4!" == "-Xmx" set _has_memory_args=1 846 | if "!p:~0,4!" == "-Xms" set _has_memory_args=1 847 | if "!p:~0,4!" == "-Xss" set _has_memory_args=1 848 | ) 849 | 850 | if not defined _has_memory_args ( 851 | call :addMemory !sbt_default_mem! 852 | ) 853 | exit /B 0 854 | 855 | :dlog 856 | if defined sbt_args_debug ( 857 | echo %* 1>&2 858 | ) 859 | exit /B 0 860 | 861 | :process 862 | rem Parses x out of 1.x; for example 8 out of java version 1.8.0_xx 863 | rem Otherwise, parses the major version; 9 out of java version 9-ea 864 | set JAVA_VERSION=0 865 | 866 | for /f "tokens=3 usebackq" %%g in (`CALL "!_JAVACMD!" -Xms32M -Xmx32M -version 2^>^&1 ^| findstr /i version`) do ( 867 | set JAVA_VERSION=%%g 868 | ) 869 | 870 | rem removes all quotes from JAVA_VERSION 871 | set JAVA_VERSION=!JAVA_VERSION:"=! 872 | 873 | for /f "delims=.-_ tokens=1-2" %%v in ("!JAVA_VERSION!") do ( 874 | if /I "%%v" EQU "1" ( 875 | set JAVA_VERSION=%%w 876 | ) else ( 877 | set JAVA_VERSION=%%v 878 | ) 879 | ) 880 | 881 | rem parse the first two segments of sbt.version and set run_native_client to 882 | rem 1 if the user has also indicated they want to use native client. 883 | set sbtV=!build_props_sbt_version! 884 | set sbtBinaryV_1= 885 | set sbtBinaryV_2= 886 | for /F "delims=.-_ tokens=1-2" %%v in ("!sbtV!") do ( 887 | set sbtBinaryV_1=%%v 888 | set sbtBinaryV_2=%%w 889 | ) 890 | set native_client_ready= 891 | if !sbtBinaryV_1! geq 2 ( 892 | set native_client_ready=1 893 | ) else ( 894 | if !sbtBinaryV_1! geq 1 ( 895 | if !sbtBinaryV_2! geq 4 ( 896 | set native_client_ready=1 897 | ) 898 | ) 899 | ) 900 | if !native_client_ready! equ 1 ( 901 | if !sbt_args_client! equ 1 ( 902 | set run_native_client=1 903 | ) 904 | ) 905 | set native_client_ready= 906 | 907 | exit /B 0 908 | 909 | :checkjava 910 | set /a required_version=6 911 | if /I !JAVA_VERSION! GEQ !required_version! ( 912 | exit /B 0 913 | ) 914 | echo. 915 | echo The Java Development Kit ^(JDK^) installation you have is not up to date. 916 | echo sbt requires at least version !required_version!+, you have 917 | echo version "!JAVA_VERSION!" 918 | echo. 919 | echo Please go to http://www.oracle.com/technetwork/java/javase/downloads/ and download 920 | echo a valid JDK and install before running sbt. 921 | echo. 922 | exit /B 1 923 | 924 | :copyrt 925 | if /I !JAVA_VERSION! GEQ 9 ( 926 | "!_JAVACMD!" !_JAVA_OPTS! !_SBT_OPTS! -jar "!sbt_jar!" --rt-ext-dir > "%TEMP%.\rtext.txt" 927 | set /p java9_ext= < "%TEMP%.\rtext.txt" 928 | set "java9_rt=!java9_ext!\rt.jar" 929 | 930 | if not exist "!java9_rt!" ( 931 | mkdir "!java9_ext!" 932 | "!_JAVACMD!" !_JAVA_OPTS! !_SBT_OPTS! -jar "!sbt_jar!" --export-rt "!java9_rt!" 933 | ) 934 | set _JAVA_OPTS=!_JAVA_OPTS! -Dscala.ext.dirs="!java9_ext!" 935 | ) 936 | exit /B 0 937 | 938 | :sync_preloaded 939 | if not defined init_sbt_version ( 940 | rem FIXME: better !init_sbt_version! detection 941 | FOR /F "tokens=* usebackq" %%F IN (`dir /b "!SBT_HOME!\lib\local-preloaded\org\scala-sbt\sbt" /B`) DO ( 942 | SET init_sbt_version=%%F 943 | ) 944 | ) 945 | 946 | set PRELOAD_SBT_JAR="%UserProfile%\.sbt\preloaded\org\scala-sbt\sbt\!init_sbt_version!\" 947 | if /I !JAVA_VERSION! GEQ 8 ( 948 | where robocopy >nul 2>nul 949 | if %ERRORLEVEL% EQU 0 ( 950 | if not exist !PRELOAD_SBT_JAR! ( 951 | if exist "!SBT_HOME!\lib\local-preloaded\" ( 952 | robocopy "!SBT_HOME!\lib\local-preloaded" "%UserProfile%\.sbt\preloaded" /E >nul 2>nul 953 | ) 954 | ) 955 | ) 956 | ) 957 | exit /B 0 958 | 959 | :usage 960 | 961 | for /f "tokens=3 usebackq" %%g in (`CALL "!_JAVACMD!" -Xms32M -Xmx32M -version 2^>^&1 ^| findstr /i version`) do ( 962 | set FULL_JAVA_VERSION=%%g 963 | ) 964 | 965 | echo. 966 | echo Usage: %~n0 [options] 967 | echo. 968 | echo -h ^| --help print this message 969 | echo -v ^| --verbose this runner is chattier 970 | echo -V ^| --version print sbt version information 971 | echo --numeric-version print the numeric sbt version (sbt sbtVersion) 972 | echo --script-version print the version of sbt script 973 | echo -d ^| --debug set sbt log level to debug 974 | echo -debug-inc ^| --debug-inc 975 | echo enable extra debugging for the incremental debugger 976 | echo --no-colors disable ANSI color codes 977 | echo --color=auto^|always^|true^|false^|never 978 | echo enable or disable ANSI color codes ^(sbt 1.3 and above^) 979 | echo --supershell=auto^|always^|true^|false^|never 980 | echo enable or disable supershell ^(sbt 1.3 and above^) 981 | echo --traces generate Trace Event report on shutdown ^(sbt 1.3 and above^) 982 | echo --timings display task timings report on shutdown 983 | echo --sbt-create start sbt even if current directory contains no sbt project 984 | echo --sbt-dir ^ path to global settings/plugins directory ^(default: ~/.sbt^) 985 | echo --sbt-boot ^ path to shared boot directory ^(default: ~/.sbt/boot in 0.11 series^) 986 | echo --sbt-cache ^ path to global cache directory ^(default: operating system specific^) 987 | echo --ivy ^ path to local Ivy repository ^(default: ~/.ivy2^) 988 | echo --mem ^ set memory options ^(default: %sbt_default_mem%^) 989 | echo --no-share use all local caches; no sharing 990 | echo --no-global uses global caches, but does not use global ~/.sbt directory. 991 | echo --jvm-debug ^ enable on JVM debugging, open at the given port. 992 | rem echo --batch disable interactive mode 993 | echo. 994 | echo # sbt version ^(default: from project/build.properties if present, else latest release^) 995 | echo --sbt-version ^ use the specified version of sbt 996 | echo --sbt-jar ^ use the specified jar as the sbt launcher 997 | echo. 998 | echo # java version ^(default: java from PATH, currently !FULL_JAVA_VERSION!^) 999 | echo --java-home ^ alternate JAVA_HOME 1000 | echo. 1001 | echo # jvm options and output control 1002 | echo JAVA_OPTS environment variable, if unset uses "!default_java_opts!" 1003 | echo .jvmopts if this file exists in the current directory, its contents 1004 | echo are appended to JAVA_OPTS 1005 | echo SBT_OPTS environment variable, if unset uses "!default_sbt_opts!" 1006 | echo .sbtopts if this file exists in the current directory, its contents 1007 | echo are prepended to the runner args 1008 | echo !SBT_CONFIG! 1009 | echo if this file exists, it is prepended to the runner args 1010 | echo -Dkey=val pass -Dkey=val directly to the java runtime 1011 | rem echo -J-X pass option -X directly to the java runtime 1012 | rem echo ^(-J is stripped^) 1013 | rem echo -S-X add -X to sbt's scalacOptions ^(-S is stripped^) 1014 | echo. 1015 | echo In the case of duplicated or conflicting options, the order above 1016 | echo shows precedence: JAVA_OPTS lowest, command line options highest. 1017 | echo. 1018 | 1019 | @endlocal 1020 | exit /B 1 1021 | 1022 | :set_sbt_version 1023 | rem set project sbtVersion 1024 | for /F "usebackq tokens=2" %%G in (`CALL "!_JAVACMD!" -jar "!sbt_jar!" "sbtVersion" 2^>^&1`) do set "sbt_version=%%G" 1025 | exit /B 0 1026 | 1027 | :error 1028 | @endlocal 1029 | exit /B 1 1030 | 1031 | :end 1032 | @endlocal 1033 | exit /B 0 1034 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | with import {}; 2 | mkShell { 3 | buildInputs = [ 4 | pkgs.buildpack 5 | pkgs.graalvm19-ce 6 | ]; 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/simplelogger.properties: -------------------------------------------------------------------------------- 1 | org.slf4j.simpleLogger.defaultLogLevel=debug -------------------------------------------------------------------------------- /src/main/scala/App.scala: -------------------------------------------------------------------------------- 1 | import com.jamesward.zio_mavencentral.MavenCentral 2 | import com.jamesward.zio_mavencentral.MavenCentral.JavadocNotFoundError 3 | import zio.* 4 | import zio.cache.{Cache, Lookup} 5 | import zio.concurrent.ConcurrentMap 6 | import zio.direct.* 7 | import zio.http.* 8 | import zio.http.codec.PathCodec 9 | 10 | import java.io.{File, FileNotFoundException} 11 | import java.nio.file.Files 12 | import scala.annotation.unused 13 | 14 | 15 | object App extends ZIOAppDefault: 16 | // todo: maybe via env? 17 | private val tmpDir = Files.createTempDirectory("jars").nn.toFile 18 | 19 | given CanEqual[Path, Path] = CanEqual.derived 20 | given CanEqual[Method, Method] = CanEqual.derived 21 | 22 | def withGroupId(groupId: MavenCentral.GroupId, @unused request: Request): Handler[Client, Nothing, (MavenCentral.GroupId, Request), Response] = 23 | Handler.fromZIO: 24 | ZIO.scoped: 25 | MavenCentral.searchArtifacts(groupId) 26 | .flatMap: artifacts => 27 | Handler.template("javadocs.dev")(UI.needArtifactId(groupId, artifacts)) 28 | .catchAllCause: 29 | case Cause.Fail(_: MavenCentral.GroupIdNotFoundError, _) => 30 | Handler.notFound(groupId.toString) 31 | case cause => 32 | Handler.fromZIO: 33 | ZIO.logErrorCause(cause).as(Response.status(Status.InternalServerError)) 34 | 35 | def withArtifactId(groupId: MavenCentral.GroupId, artifactId: MavenCentral.ArtifactId, @unused request: Request): Handler[Client, Nothing, (MavenCentral.GroupId, MavenCentral.ArtifactId, Request), Response] = 36 | Handler.fromZIO: 37 | ZIO.scoped: 38 | defer: 39 | val isArtifact = MavenCentral.isArtifact(groupId, artifactId).run 40 | Option.when(isArtifact): 41 | MavenCentral.searchVersions(groupId, artifactId).run 42 | .flatMap: maybeVersions => 43 | maybeVersions.fold: 44 | // todo: better api? 45 | Handler.fromResponse(Response.redirect(URL(Path.root / (groupId.toString + "." + artifactId.toString)))) 46 | .apply: versions => 47 | Handler.template("javadocs.dev")(UI.needVersion(groupId, artifactId, versions)) 48 | .catchAllCause: 49 | case Cause.Fail(_: MavenCentral.GroupIdOrArtifactIdNotFoundError, _) => 50 | Handler.notFound(MavenCentral.GroupArtifact(groupId, artifactId).toString) 51 | case cause => 52 | Handler.fromZIO: 53 | ZIO.logErrorCause(cause).as(Response.status(Status.InternalServerError)) 54 | 55 | type LatestCache = Cache[MavenCentral.GroupArtifact, MavenCentral.GroupIdOrArtifactIdNotFoundError | Throwable, Path] 56 | type JavadocExistsCache = Cache[MavenCentral.GroupArtifactVersion, MavenCentral.JavadocNotFoundError | Throwable, Path] 57 | 58 | // todo: is the option handling here correct? 59 | def latest(groupArtifact: MavenCentral.GroupArtifact): ZIO[Client, MavenCentral.GroupIdOrArtifactIdNotFoundError | Throwable, Path] = 60 | ZIO.scoped: 61 | defer: 62 | val maybeLatest = MavenCentral.latest(groupArtifact.groupId, groupArtifact.artifactId).run 63 | maybeLatest.fold: 64 | groupArtifact.toPath 65 | .apply: latestVersion => 66 | groupArtifact / latestVersion 67 | 68 | def javadocExists(groupArtifactVersion: MavenCentral.GroupArtifactVersion): ZIO[Client, MavenCentral.JavadocNotFoundError | Throwable, Path] = 69 | ZIO.scoped: 70 | defer: 71 | MavenCentral.javadocUri(groupArtifactVersion.groupId, groupArtifactVersion.artifactId, groupArtifactVersion.version).run // javadoc exists 72 | groupArtifactVersion.toPath / "index.html" 73 | 74 | def withVersion(groupId: MavenCentral.GroupId, artifactId: MavenCentral.ArtifactId, version: MavenCentral.Version, @unused request: Request)(latestCache: LatestCache, javadocExistsCache: JavadocExistsCache): Handler[Client, Nothing, (MavenCentral.GroupId, MavenCentral.ArtifactId, MavenCentral.Version, Path, Request), Response] = 75 | val groupArtifactVersion = MavenCentral.GroupArtifactVersion(groupId, artifactId, version) 76 | val javadocPathZIO = 77 | if groupArtifactVersion.version == MavenCentral.Version.latest then 78 | latestCache.get(groupArtifactVersion.noVersion) 79 | else 80 | javadocExistsCache.get(groupArtifactVersion) 81 | 82 | Handler.fromZIO: 83 | javadocPathZIO.map: path => 84 | Response.redirect(URL(path)) // todo: perm when not latest 85 | .catchAllCause: 86 | case Cause.Fail(MavenCentral.JavadocNotFoundError(groupId, artifactId, version), _) => 87 | Handler.fromZIO: 88 | ZIO.scoped: 89 | MavenCentral.searchVersions(groupId, artifactId) 90 | .flatMap: versions => 91 | Handler.template("javadocs.dev")(UI.noJavadoc(groupId, artifactId, versions, version)) 92 | .catchAllCause: 93 | case Cause.Fail(MavenCentral.GroupIdOrArtifactIdNotFoundError(_, _), _) => 94 | Handler.notFound(groupArtifactVersion.toString) // todo: better handling 95 | case cause => 96 | Handler.fromZIO: 97 | ZIO.logErrorCause(cause).as(Response.status(Status.InternalServerError)) 98 | case cause => 99 | Handler.fromZIO: 100 | ZIO.logErrorCause(cause).as(Response.status(Status.InternalServerError)) 101 | 102 | type Blocker = ConcurrentMap[MavenCentral.GroupArtifactVersion, Promise[Nothing, Unit]] 103 | 104 | class JavadocNotFoundException(javadocNotFoundError: JavadocNotFoundError) extends Throwable 105 | 106 | object JavadocNotFoundException: 107 | val from: PartialFunction[JavadocNotFoundError | Throwable, Throwable] = 108 | case e: JavadocNotFoundError => JavadocNotFoundException(e) 109 | 110 | def withFile(groupId: MavenCentral.GroupId, artifactId: MavenCentral.ArtifactId, version: MavenCentral.Version, file: Path, @unused request: Request, blocker: Blocker): Handler[Client, Nothing, (MavenCentral.GroupId, MavenCentral.ArtifactId, MavenCentral.Version, Path, Request), Response] = 111 | val groupArtifactVersion = MavenCentral.GroupArtifactVersion(groupId, artifactId, version) 112 | val javadocFileZIO: ZIO[Client, Throwable, File] = 113 | ZIO.scoped: 114 | defer: 115 | val javadocDir = File(tmpDir, groupArtifactVersion.toString) 116 | val javadocFile = File(javadocDir, file.toString) 117 | 118 | // could be less racey 119 | if !javadocDir.exists() then 120 | val maybeBlock = blocker.get(groupArtifactVersion).run 121 | // note: fold doesn't work with defer here 122 | maybeBlock match 123 | case Some(promise) => 124 | promise.await.run 125 | case _ => 126 | val promise = Promise.make[Nothing, Unit].run 127 | blocker.put(groupArtifactVersion, promise).run 128 | val javadocUri = MavenCentral.javadocUri(groupArtifactVersion.groupId, groupArtifactVersion.artifactId, groupArtifactVersion.version).mapError(JavadocNotFoundException.from).run 129 | MavenCentral.downloadAndExtractZip(javadocUri, javadocDir).run 130 | promise.succeed(()).run 131 | 132 | javadocFile 133 | 134 | Handler.fromFileZIO(javadocFileZIO).catchAll: 135 | case _: JavadocNotFoundException => 136 | Response.redirect(URL(groupArtifactVersion.toPath)).toHandler 137 | case _: FileNotFoundException => 138 | Response.notFound((groupArtifactVersion.toPath ++ file).toString).toHandler 139 | case error => 140 | Handler.fromZIO: 141 | val message = Option(error.getMessage).getOrElse("Unknown Error") 142 | ZIO.logError(message).as(Response.status(Status.InternalServerError)) 143 | 144 | private def groupIdExtractor(groupId: String) = MavenCentral.GroupId.unapply(groupId).toRight(groupId) 145 | private val groupId: PathCodec[MavenCentral.GroupId] = 146 | string("groupId").transformOrFailLeft(groupIdExtractor)(_.toString) 147 | 148 | private def artifactIdExtractor(artifactId: String) = MavenCentral.ArtifactId.unapply(artifactId).toRight(artifactId) 149 | private val artifactId: PathCodec[MavenCentral.ArtifactId] = 150 | string("artifactId").transformOrFailLeft(artifactIdExtractor)(_.toString) 151 | 152 | private def versionExtractor(version: String) = MavenCentral.Version.unapply(version).toRight(version) 153 | private val version: PathCodec[MavenCentral.Version] = 154 | string("version").transformOrFailLeft(versionExtractor)(_.toString) 155 | 156 | def app(latestCache: LatestCache, javadocExistsCache: JavadocExistsCache, blocker: Blocker): Routes[Client, Nothing] = 157 | Routes[Client, Nothing]( 158 | Method.GET / "" -> Handler.template("javadocs.dev")(UI.index), 159 | Method.GET / "favicon.ico" -> Handler.notFound, 160 | Method.GET / "robots.txt" -> Handler.notFound, 161 | Method.GET / groupId -> Handler.fromFunctionHandler[(MavenCentral.GroupId, Request)](withGroupId), 162 | Method.GET / groupId / artifactId -> Handler.fromFunctionHandler[(MavenCentral.GroupId, MavenCentral.ArtifactId, Request)](withArtifactId), 163 | Method.GET / groupId / artifactId / version / trailing -> Handler.fromFunctionHandler[(MavenCentral.GroupId, MavenCentral.ArtifactId, MavenCentral.Version, Path, Request)] { 164 | (groupId, artifactId, version, file, request) => 165 | if (file.isEmpty) 166 | withVersion(groupId, artifactId, version, request)(latestCache, javadocExistsCache) 167 | else 168 | withFile(groupId, artifactId, version, file, request, blocker) 169 | }, 170 | ) 171 | 172 | private val redirectQueryParams = HandlerAspect.intercept: (request, response) => 173 | request.url.queryParam("groupId").map: groupId => 174 | request.url.path(Path.root / groupId).setQueryParams() 175 | .orElse: 176 | request.url.queryParam("artifactId").map: artifactId => 177 | request.url.path(request.path / artifactId).setQueryParams() 178 | .orElse: 179 | request.url.queryParam("version").map: version => 180 | request.url.path(request.path / version).setQueryParams() 181 | .fold( 182 | if request.url.path.hasTrailingSlash then 183 | Response.redirect(request.url.dropTrailingSlash) 184 | else 185 | response 186 | )(Response.redirect(_, true)) 187 | 188 | def appWithMiddleware(blocker: Blocker, latestCache: LatestCache, javadocExistsCache: JavadocExistsCache): Routes[Client, Nothing] = 189 | app(latestCache, javadocExistsCache, blocker) @@ redirectQueryParams @@ Middleware.requestLogging() 190 | 191 | def run = 192 | // todo: log filtering so they don't show up in tests / runtime config 193 | defer: 194 | val blocker = ConcurrentMap.empty[MavenCentral.GroupArtifactVersion, Promise[Nothing, Unit]].run 195 | val latestCache = Cache.makeWith(1_000, Lookup(latest)) { 196 | case Exit.Success(_) => 1.hour 197 | case Exit.Failure(_) => Duration.Zero 198 | }.run 199 | val javadocExistsCache = Cache.makeWith(1_000, Lookup(javadocExists)) { 200 | case Exit.Success(_) => Duration.Infinity 201 | case Exit.Failure(_) => Duration.Zero 202 | }.run 203 | val app = appWithMiddleware(blocker, latestCache, javadocExistsCache) 204 | Server.serve(app).run 205 | () 206 | .provide( 207 | Server.default, 208 | Client.default, 209 | ) 210 | -------------------------------------------------------------------------------- /src/main/scala/UI.scala: -------------------------------------------------------------------------------- 1 | import zio.http.template.* 2 | import com.jamesward.zio_mavencentral.MavenCentral 3 | 4 | object UI: 5 | 6 | val index: Html = 7 | form(actionAttr := "/", methodAttr := "get", 8 | label("GroupId (i.e. ", a(href := "/org.springframework", "org.springframework"), "): ", 9 | input(nameAttr := "groupId", requiredAttr := true) 10 | ), 11 | " ", 12 | input(valueAttr := "Go!", typeAttr := "submit"), 13 | ) 14 | 15 | def invalidGroupId(groupId: MavenCentral.GroupId): Html = 16 | form(actionAttr := "/", methodAttr := "get", 17 | label( 18 | "GroupId:", 19 | input( 20 | nameAttr := "groupId", 21 | valueAttr := groupId.toString, 22 | onFocusAttr := "this.setCustomValidity('GroupID is invalid'); this.reportValidity();", 23 | onInputAttr := "this.setCustomValidity(''); this.reportValidity()", 24 | autofocusAttr := "autofocus", 25 | requiredAttr := true, 26 | ) 27 | ), 28 | " ", 29 | input(valueAttr := "Go!", typeAttr := "submit"), 30 | ) 31 | 32 | def needArtifactId(groupId: MavenCentral.GroupId, artifactIds: Seq[MavenCentral.ArtifactId]): Html = 33 | form(actionAttr := s"/$groupId", methodAttr := "get", 34 | label( 35 | a( 36 | href := "/", 37 | "GroupId" 38 | ), 39 | ":", 40 | input(nameAttr := "groupId", valueAttr := groupId.toString, disabledAttr := "disabled") 41 | ), 42 | " ", 43 | label( 44 | "ArtifactId:", 45 | select( 46 | nameAttr := "artifactId", 47 | artifactIds.map: artifactId => 48 | option(artifactId.toString) 49 | ) 50 | ), 51 | " ", 52 | input(valueAttr := "Go!", typeAttr := "submit"), 53 | ) 54 | 55 | def needVersion(groupId: MavenCentral.GroupId, artifactId: MavenCentral.ArtifactId, versions: Seq[MavenCentral.Version]): Html = 56 | form(actionAttr := s"/$groupId/$artifactId", methodAttr := "get", 57 | label( 58 | a(hrefAttr := "/", "GroupId"), 59 | ":", 60 | input(nameAttr := "groupId", valueAttr := groupId.toString, disabledAttr := "disabled") 61 | ), 62 | " ", 63 | label( 64 | a(hrefAttr := s"/$groupId", "ArtifactId"), 65 | ":", 66 | input(nameAttr := "artifactId", valueAttr := artifactId.toString, disabledAttr := "disabled") 67 | ), 68 | " ", 69 | label( 70 | "Version:", 71 | select(nameAttr := "version", 72 | versions.map: version => 73 | option(version.toString) 74 | ) 75 | ), 76 | " ", 77 | input(valueAttr := "Go!", typeAttr := "submit") 78 | ) 79 | 80 | def noJavadoc(groupId: MavenCentral.GroupId, artifactId: MavenCentral.ArtifactId, versions: Seq[MavenCentral.Version], version: MavenCentral.Version): Html = 81 | div( 82 | p(s"Version $version of that artifact does not exist or does not have a JavaDoc jar."), 83 | needVersion(groupId, artifactId, versions), 84 | ) 85 | -------------------------------------------------------------------------------- /src/test/scala/AppSpec.scala: -------------------------------------------------------------------------------- 1 | import com.jamesward.zio_mavencentral.MavenCentral 2 | import com.jamesward.zio_mavencentral.MavenCentral.given 3 | import zio.cache.{Cache, Lookup} 4 | import zio.concurrent.ConcurrentMap 5 | import zio.direct.* 6 | import zio.http.* 7 | import zio.test.* 8 | import zio.test.Assertion.* 9 | import zio.* 10 | 11 | object AppSpec extends ZIOSpecDefault: 12 | 13 | def spec = suite("App")( 14 | test("routing"): 15 | defer: 16 | val blocker = ConcurrentMap.empty[MavenCentral.GroupArtifactVersion, Promise[Nothing, Unit]].run 17 | val latestCache = Cache.make(50, 60.minutes, Lookup(App.latest)).run 18 | val javadocExistsCache = Cache.make(50, 60.minutes, Lookup(App.javadocExists)).run 19 | 20 | val groupIdResp = App.appWithMiddleware(blocker, latestCache, javadocExistsCache).runZIO(Request.get(URL(Path.root, queryParams = QueryParams("groupId" -> "com.jamesward")))).run 21 | val artifactIdResp = App.appWithMiddleware(blocker, latestCache, javadocExistsCache).runZIO(Request.get(URL(Path.root / "com.jamesward", queryParams = QueryParams("artifactId" -> "travis-central-test")))).run 22 | val versionResp = App.appWithMiddleware(blocker, latestCache, javadocExistsCache).runZIO(Request.get(URL(Path.root / "com.jamesward" / "travis-central-test", queryParams = QueryParams("version" -> "0.0.15")))).run 23 | val latest = App.appWithMiddleware(blocker, latestCache, javadocExistsCache).runZIO(Request.get(URL(Path.root / "org.webjars" / "jquery" / "latest"))).run 24 | 25 | val groupIdRedir = App.appWithMiddleware(blocker, latestCache, javadocExistsCache).runZIO(Request.get(URL((Path.root / "com.jamesward").addTrailingSlash))).run 26 | val artifactIdRedir = App.appWithMiddleware(blocker, latestCache, javadocExistsCache).runZIO(Request.get(URL((Path.root / "com.jamesward" / "travis-central-test").addTrailingSlash))).run 27 | 28 | val indexPath = App.appWithMiddleware(blocker, latestCache, javadocExistsCache).runZIO(Request.get(URL(Path.root / "org.webjars" / "webjars-locator-core" / "0.52" / "index.html"))).run 29 | val filePath = App.appWithMiddleware(blocker, latestCache, javadocExistsCache).runZIO(Request.get(URL(Path.root / "org.webjars" / "webjars-locator-core" / "0.52" / "org" / "webjars" / "package-summary.html"))).run 30 | val notFoundFilePath = App.appWithMiddleware(blocker, latestCache, javadocExistsCache).runZIO(Request.get(URL(Path.root / "org.webjars" / "webjars-locator-core" / "0.52" / "asdf"))).run 31 | 32 | assertTrue( 33 | App.appWithMiddleware(blocker, latestCache, javadocExistsCache).runZIO(Request.get(URL(Path.empty))).run.status.isSuccess, 34 | App.appWithMiddleware(blocker, latestCache, javadocExistsCache).runZIO(Request.get(URL(Path.root))).run.status.isRedirection, 35 | groupIdResp.status.isRedirection, 36 | groupIdResp.headers.get(Header.Location).exists(_.url.path == Path.decode("/com.jamesward")), 37 | artifactIdResp.status.isRedirection, 38 | artifactIdResp.headers.get(Header.Location).exists(_.url.path == Path.decode("/com.jamesward/travis-central-test")), 39 | versionResp.status.isRedirection, 40 | versionResp.headers.get(Header.Location).exists(_.url.path == Path.decode("/com.jamesward/travis-central-test/0.0.15")), 41 | latest.status.isRedirection, 42 | latest.headers.get(Header.Location).exists(_.url.path == Path.decode("/org.webjars/jquery/3.7.1")), 43 | groupIdRedir.status.isRedirection, 44 | groupIdRedir.headers.get(Header.Location).exists(_.url.path == Path.decode("/com.jamesward")), 45 | artifactIdRedir.status.isRedirection, 46 | artifactIdRedir.headers.get(Header.Location).exists(_.url.path == Path.decode("/com.jamesward/travis-central-test")), 47 | indexPath.status.isSuccess, 48 | filePath.status.isSuccess, 49 | notFoundFilePath.status == Status.NotFound, 50 | ) 51 | ).provide(Client.default, Scope.default) 52 | --------------------------------------------------------------------------------