├── .github ├── CODEOWNERS ├── auto_assign.yml └── workflows │ ├── pr.yml │ └── release.yml ├── .gitignore ├── .scalafmt.conf ├── .sdkmanrc ├── LICENSE ├── README.md ├── app ├── assets │ ├── css │ │ └── main.css │ └── js │ │ ├── swiper-settings.js │ │ └── switch-theme.js ├── controllers │ ├── ContextualController.scala │ └── HealthController.scala ├── handlers │ └── ErrorHandler.scala ├── models │ └── Contributor.scala ├── services │ └── OpenCollectiveService.scala ├── support │ └── MongoConnection.scala ├── views │ ├── contributors.scala.html │ ├── includes │ │ ├── advertisement.scala.html │ │ ├── browserhappy.scala.html │ │ ├── footer.scala.html │ │ ├── forkme.scala.html │ │ ├── header.scala.html │ │ ├── individual_card.scala.html │ │ ├── navigation.scala.html │ │ ├── opencollective.scala.html │ │ ├── organization_card.scala.html │ │ ├── scripts.scala.html │ │ └── statuspage.scala.html │ ├── index.scala.html │ ├── install.scala.html │ ├── jdks.scala.html │ ├── main.scala.html │ ├── notfound.scala.html │ ├── sdks.scala.html │ ├── usage.scala.html │ └── vendors.scala.html └── wrappers │ ├── OpenCollectiveWebApi.scala │ └── package.scala ├── build.sbt ├── conf ├── application.conf ├── jdks.conf ├── logback.xml └── routes ├── libexec └── sbt-launch.jar ├── project ├── build.properties ├── metals.sbt └── plugins.sbt ├── public ├── css │ ├── bootstrap.min.css │ ├── carbon.css │ ├── prism-dark.min.css │ └── prism.min.css ├── img │ ├── bubble-logo-sdkman-groovy-color.png │ ├── bubble-logo-sdkman-groovy-color.svg │ ├── chain-web.png │ ├── city.png │ ├── crypton-web.png │ ├── duke-thumbsup-comic.png │ ├── favicon.ico │ ├── icons-comic-colset-red.png │ ├── icons-comic-colset.png │ ├── logo-sdkman.png │ ├── logo.png │ ├── sdk-man-small-pattern.jpg │ ├── sdk-man-small-pattern.png │ ├── sdk-man-small-pattern.svg │ └── sdkman-web.png └── js │ ├── plugins.js │ └── vendor │ ├── bootstrap.bundle.min.js │ └── prism.min.js └── sbt /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @sdkman/sdkman-website 2 | -------------------------------------------------------------------------------- /.github/auto_assign.yml: -------------------------------------------------------------------------------- 1 | --- 2 | addReviewers: true 3 | addAssignees: author 4 | 5 | reviewers: 6 | - marc0der 7 | - helpermethod 8 | - eddumelendez 9 | 10 | numberOfReviewers: 0 11 | -------------------------------------------------------------------------------- /.github/workflows/pr.yml: -------------------------------------------------------------------------------- 1 | name: Pull Requests 2 | on: pull_request_target 3 | jobs: 4 | test: 5 | runs-on: ubuntu-latest 6 | services: 7 | mongodb: 8 | image: mongo:3.2 9 | ports: 10 | - 27017:27017 11 | steps: 12 | - name: Checkout source code 13 | uses: actions/checkout@v2 14 | with: 15 | ref: ${{ github.event.pull_request.head.sha }} 16 | - name: Set up JDK 11.0.11 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: 11.0.11 20 | - name: Run tests 21 | run: ./sbt test 22 | - uses: kentaro-m/auto-assign-action@v1.1.2 23 | with: 24 | configuration-path: ".github/auto_assign.yml" 25 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | branches: 5 | - master 6 | 7 | jobs: 8 | build: 9 | name: "Release" 10 | runs-on: ubuntu-latest 11 | environment: production 12 | services: 13 | mongodb: 14 | image: mongo:3.2 15 | ports: 16 | - 27017:27017 17 | steps: 18 | - uses: actions/checkout@v3 19 | with: 20 | fetch-depth: 0 21 | - name: Install doctl 22 | uses: digitalocean/action-doctl@v2 23 | with: 24 | token: ${{ secrets.DIGITALOCEAN_TOKEN }} 25 | - name: Log in to DigitalOcean Docker Registry 26 | run: | 27 | doctl registry login --expiry-seconds=300 28 | - name: Publish local Docker image 29 | run: ./sbt docker:publishLocal 30 | - name: Push image to DO registry 31 | run: | 32 | version=$(git rev-parse --short HEAD) 33 | docker push registry.digitalocean.com/sdkman/sdkman-website:$version 34 | docker push registry.digitalocean.com/sdkman/sdkman-website:latest 35 | 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/sbt,scala,bloop,metals,intellij+all,playframework 3 | # Edit at https://www.gitignore.io/?templates=sbt,scala,bloop,metals,intellij+all,playframework 4 | 5 | ### Bloop ### 6 | .bloop/ 7 | .bsp/ 8 | 9 | ### Intellij+all ### 10 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 11 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 12 | 13 | # User-specific stuff 14 | .idea/**/workspace.xml 15 | .idea/**/tasks.xml 16 | .idea/**/usage.statistics.xml 17 | .idea/**/dictionaries 18 | .idea/**/shelf 19 | 20 | # Generated files 21 | .idea/**/contentModel.xml 22 | 23 | # Sensitive or high-churn files 24 | .idea/**/dataSources/ 25 | .idea/**/dataSources.ids 26 | .idea/**/dataSources.local.xml 27 | .idea/**/sqlDataSources.xml 28 | .idea/**/dynamic.xml 29 | .idea/**/uiDesigner.xml 30 | .idea/**/dbnavigator.xml 31 | 32 | # Gradle 33 | .idea/**/gradle.xml 34 | .idea/**/libraries 35 | 36 | # Gradle and Maven with auto-import 37 | # When using Gradle or Maven with auto-import, you should exclude module files, 38 | # since they will be recreated, and may cause churn. Uncomment if using 39 | # auto-import. 40 | # .idea/modules.xml 41 | # .idea/*.iml 42 | # .idea/modules 43 | # *.iml 44 | # *.ipr 45 | 46 | # CMake 47 | cmake-build-*/ 48 | 49 | # Mongo Explorer plugin 50 | .idea/**/mongoSettings.xml 51 | 52 | # File-based project format 53 | *.iws 54 | 55 | # IntelliJ 56 | out/ 57 | 58 | # mpeltonen/sbt-idea plugin 59 | .idea_modules/ 60 | 61 | # JIRA plugin 62 | atlassian-ide-plugin.xml 63 | 64 | # Cursive Clojure plugin 65 | .idea/replstate.xml 66 | 67 | # Crashlytics plugin (for Android Studio and IntelliJ) 68 | com_crashlytics_export_strings.xml 69 | crashlytics.properties 70 | crashlytics-build.properties 71 | fabric.properties 72 | 73 | # Editor-based Rest Client 74 | .idea/httpRequests 75 | 76 | # Android studio 3.1+ serialized cache file 77 | .idea/caches/build_file_checksums.ser 78 | 79 | ### Intellij+all Patch ### 80 | # Ignores the whole .idea folder and all .iml files 81 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 82 | 83 | .idea/ 84 | 85 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 86 | 87 | *.iml 88 | modules.xml 89 | .idea/misc.xml 90 | *.ipr 91 | 92 | # Sonarlint plugin 93 | .idea/sonarlint 94 | 95 | ### Metals ### 96 | .metals/ 97 | 98 | ### PlayFramework ### 99 | # Ignore Play! working directory # 100 | bin/ 101 | /db 102 | .eclipse 103 | /lib/ 104 | /logs/ 105 | /modules 106 | /project/project 107 | /project/target 108 | /target 109 | tmp/ 110 | test-result 111 | server.pid 112 | *.eml 113 | /dist/ 114 | .cache 115 | 116 | ### SBT ### 117 | # Simple Build Tool 118 | # http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control 119 | 120 | dist/* 121 | target/ 122 | lib_managed/ 123 | src_managed/ 124 | project/boot/ 125 | project/plugins/project/ 126 | .history 127 | .lib/ 128 | 129 | ### Scala ### 130 | *.class 131 | *.log 132 | *.metals 133 | 134 | ### VSCODE ### 135 | .vscode/ 136 | 137 | ### Mac OS ### 138 | .DS_Store 139 | 140 | # End of https://www.gitignore.io/api/sbt,scala,bloop,metals,intellij+all,playframework 141 | -------------------------------------------------------------------------------- /.scalafmt.conf: -------------------------------------------------------------------------------- 1 | version = "3.7.10" 2 | runner.dialect = scala213 -------------------------------------------------------------------------------- /.sdkmanrc: -------------------------------------------------------------------------------- 1 | # Enable auto-env through the sdkman_auto_env config 2 | # Add key=value pairs of SDKs to use below 3 | java=11.0.19-tem 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SDKMAN! website 2 | 3 | ![Build status](https://github.com/sdkman/sdkman-website/actions/workflows/release.yml/badge.svg) 4 | 5 | This is the service backing the SDKMAN! website at https://sdkman.io 6 | 7 | ## Run local 8 | 9 | Make sure you have mongodb running locally or in a Docker Container: 10 | 11 | $ docker run -d --net=host --name mongo mongo:3.2 12 | 13 | Start the app: 14 | 15 | $ ./sbt run 16 | -------------------------------------------------------------------------------- /app/assets/css/main.css: -------------------------------------------------------------------------------- 1 | :root, [data-bs-theme=light] { 2 | --bs-primary: #0276c6; 3 | --bs-secondary: #343f52; 4 | --bs-secondary-rgb: 70, 86, 111; 5 | --bs-success: #16a34a; 6 | --bs-success-rgb: 22, 163, 74; 7 | --bs-emphasis-color-rgb: 25, 33, 46; 8 | 9 | /* Custom */ 10 | --card-bg: #f3f6fc; 11 | --footer-bg: #f3f6fc; 12 | --swiper-btn-bg-rgb: 224, 229, 237; 13 | --swiper-btn-text: #000000; 14 | } 15 | 16 | [data-bs-theme=dark] { 17 | --bs-secondary: #8094b6; 18 | --bs-body-bg: #151f32; 19 | --bs-emphasis-color-rgb: 154, 171, 202; 20 | 21 | /* Custom */ 22 | --card-bg: #18273f; 23 | --footer-bg: #0c1421; 24 | --swiper-btn-bg-rgb: 12, 20, 33; 25 | --swiper-btn-text: #ffffff; 26 | } 27 | 28 | .btn-outline-primary { 29 | --bs-btn-color: #0276c6; 30 | --bs-btn-border-color: #0276c6; 31 | --bs-btn-hover-bg: #0276c6; 32 | --bs-btn-hover-border-color: #0276c6; 33 | --bs-btn-active-bg: #0276c6; 34 | --bs-btn-active-border-color: #0276c6; 35 | --bs-btn-disabled-color: #0276c6; 36 | --bs-btn-disabled-border-color: #0276c6; 37 | } 38 | 39 | *, html { 40 | font-family: "Inter", sans-serif; 41 | } 42 | 43 | body { 44 | overflow-x: hidden; 45 | } 46 | 47 | pre { 48 | background-color: var(--card-bg) !important; 49 | border-radius: 8px; 50 | margin: 1rem 0 !important; 51 | } 52 | 53 | .swiper-button-prev, .swiper-button-next { 54 | width: 2.5rem !important; 55 | height: 2.5rem !important; 56 | border-radius: 100%; 57 | display: flex; 58 | align-items: center; 59 | justify-content: center; 60 | background-color: rgba(var(--swiper-btn-bg-rgb), 40%); 61 | color: var(--swiper-btn-text) !important; 62 | padding: .5rem; 63 | } 64 | 65 | .swiper-button-prev:after, .swiper-button-next:after { 66 | content: "" !important; 67 | } 68 | 69 | .swiper-button-prev { 70 | left: -.75rem !important; 71 | } 72 | 73 | .swiper-button-next { 74 | right: -.75rem !important; 75 | } 76 | 77 | .page-wrapper { 78 | padding-top: 80px; 79 | padding-bottom: 80px; 80 | } 81 | 82 | .h-20 { 83 | height: 80px; 84 | } 85 | 86 | .bg-page { 87 | position: absolute; 88 | left: -50vw; 89 | top: -50vw; 90 | width: 100vw; 91 | height: 100vw; 92 | background: radial-gradient( 93 | ellipse at center, 94 | rgba(2, 118, 198, 30%) 0%, 95 | transparent 50% 96 | ); 97 | } 98 | 99 | .bg-footer { 100 | background-color: var(--footer-bg); 101 | } 102 | 103 | .navbar { 104 | height: 64px; 105 | backdrop-filter: blur(10px); 106 | -webkit-backdrop-filter: blur(10px); 107 | } 108 | 109 | .nav-link > svg { 110 | height: 18px; 111 | width: 18px; 112 | } 113 | 114 | .nav-sidebar { 115 | max-height: calc(100vh - 160px); 116 | overflow-y: auto; 117 | position: sticky; 118 | top: 144px; 119 | } 120 | 121 | .nav-sidebar > .nav { 122 | color: var(--bs-secondary); 123 | } 124 | 125 | .nav-sidebar .nav-link { 126 | color: var(--bs-secondary); 127 | } 128 | 129 | .nav-sidebar .active { 130 | color: var(--bs-nav-link-color); 131 | font-weight: 500; 132 | border-left: solid 2px var(--bs-nav-link-color); 133 | } 134 | 135 | /* Sections */ 136 | .home-section { 137 | padding: 80px 0; 138 | } 139 | 140 | .hero-section-top { 141 | display: flex; 142 | flex-direction: column; 143 | align-items: center; 144 | } 145 | 146 | .hero-section-top-img { 147 | width: 250px; 148 | margin: 80px auto 0; 149 | } 150 | 151 | .hero-section-top-title { 152 | font-size: 48px; 153 | font-weight: 700; 154 | letter-spacing: 1.2; 155 | text-transform: capitalize; 156 | margin: 24px 0 16px 0; 157 | text-align: center; 158 | } 159 | 160 | .hero-section-top-text { 161 | font-size: 18px; 162 | width: 100%; 163 | max-width: 768px; 164 | text-align: center; 165 | color: var(--bs-secondary); 166 | } 167 | 168 | .hero-section-bottom { 169 | display: flex; 170 | flex-direction: column; 171 | align-items: center; 172 | margin: 1rem 0; 173 | } 174 | 175 | .hero-section-bottom-title { 176 | font-size: 24px; 177 | font-weight: 700; 178 | letter-spacing: 1.2; 179 | text-transform: capitalize; 180 | } 181 | 182 | .hero-section-bottom-text { 183 | text-align: center; 184 | color: var(--bs-secondary); 185 | } 186 | 187 | .open-collective-section-title { 188 | font-size: 24px; 189 | font-weight: 700; 190 | letter-spacing: 1.2; 191 | } 192 | 193 | .open-collective-section-subtitle { 194 | font-size: 20px; 195 | font-weight: 500; 196 | letter-spacing: 1.2; 197 | } 198 | 199 | /* Cards */ 200 | .card { 201 | height: 100%; 202 | border-radius: 16px; 203 | border: none; 204 | background-color: var(--card-bg); 205 | } 206 | 207 | .card .card-icon { 208 | height: 3.5rem; 209 | width: 3.5rem; 210 | display: flex; 211 | align-items: center; 212 | justify-content: center; 213 | color: var(--bs-primary); 214 | margin-bottom: 1.5rem; 215 | } 216 | 217 | .card .card-icon > svg { 218 | height: inherit; 219 | width: inherit; 220 | } 221 | 222 | .card .card-avatar { 223 | height: 4rem; 224 | width: 4rem; 225 | border-radius: 100%; 226 | overflow: hidden; 227 | margin-bottom: 1.5rem; 228 | } 229 | 230 | .card .card-avatar img { 231 | height: inherit; 232 | width: inherit; 233 | object-fit: cover; 234 | } 235 | 236 | .card .card-title { 237 | font-size: 20px; 238 | margin-bottom: 12px; 239 | } 240 | 241 | .card .card-text { 242 | font-size: 14px; 243 | color: var(--bs-secondary); 244 | } 245 | 246 | .open-collective-card { 247 | text-decoration: none; 248 | } 249 | 250 | .open-collective-card .card-title { 251 | font-size: 16px; 252 | font-weight: 500; 253 | } 254 | 255 | .open-collective-card-date { 256 | color: var(--bs-secondary); 257 | } 258 | 259 | .fs-7 { 260 | font-size: 14px; 261 | line-height: 24px; 262 | } 263 | 264 | .scroll-offset { 265 | scroll-margin: 80px 0; 266 | } 267 | 268 | /* Media queries */ 269 | @media (min-width: 576px) { 270 | .swiper-button-prev { 271 | left: -1.25rem !important; 272 | } 273 | 274 | .swiper-button-next { 275 | right: -1.25rem !important; 276 | } 277 | } 278 | 279 | @media (min-width: 992px) { 280 | .hero-section-top-img { 281 | margin: 0 auto; 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /app/assets/js/swiper-settings.js: -------------------------------------------------------------------------------- 1 | new Swiper('#swiper-organization', { 2 | loop: true, 3 | slidesPerView: 1, 4 | spaceBetween: 16, 5 | breakpointsBase: 'container', 6 | breakpoints: { 7 | 696: { 8 | slidesPerView: 2 9 | }, 10 | 936: { 11 | slidesPerView: 3 12 | }, 13 | 1296: { 14 | slidesPerView: 4 15 | } 16 | }, 17 | navigation: { 18 | nextEl: '#swiper-next-organization', 19 | prevEl: '#swiper-prev-organization', 20 | } 21 | }); 22 | 23 | new Swiper('#swiper-individual', { 24 | loop: true, 25 | slidesPerView: 1, 26 | spaceBetween: 16, 27 | breakpointsBase: 'container', 28 | breakpoints: { 29 | 516: { 30 | slidesPerView: 2 31 | }, 32 | 696: { 33 | slidesPerView: 3 34 | }, 35 | 936: { 36 | slidesPerView: 4 37 | }, 38 | 1296: { 39 | slidesPerView: 6 40 | } 41 | }, 42 | navigation: { 43 | nextEl: '#swiper-next-individual', 44 | prevEl: '#swiper-prev-individual', 45 | } 46 | }); 47 | -------------------------------------------------------------------------------- /app/assets/js/switch-theme.js: -------------------------------------------------------------------------------- 1 | (() => { 2 | 'use strict' 3 | 4 | const THEME_STORAGE_NAME = 'theme'; 5 | const getStoredTheme = () => localStorage.getItem(THEME_STORAGE_NAME) 6 | const setStoredTheme = theme => localStorage.setItem(THEME_STORAGE_NAME, theme) 7 | 8 | const getPreferredTheme = () => { 9 | const storedTheme = getStoredTheme() 10 | 11 | if (storedTheme) { 12 | return storedTheme 13 | } 14 | 15 | return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' 16 | } 17 | 18 | const setPrismjsTheme = theme => { 19 | const link = document.getElementById('prism-theme') 20 | 21 | if (link) { 22 | const href = `/assets/css/prism${theme === 'dark' ? '-dark' : ''}.min.css` 23 | 24 | link.setAttribute('href', href) 25 | } 26 | } 27 | 28 | const setTheme = theme => { 29 | if (theme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches) { 30 | document.documentElement.setAttribute('data-bs-theme', 'dark') 31 | setPrismjsTheme('dark') 32 | } else { 33 | document.documentElement.setAttribute('data-bs-theme', theme) 34 | setPrismjsTheme(theme) 35 | } 36 | } 37 | 38 | setTheme(getPreferredTheme()) 39 | 40 | const showActiveTheme = theme => { 41 | const activeThemeIcon = document.querySelector(`[data-bs-theme-value="${theme}"]`) 42 | 43 | document.querySelectorAll('[data-bs-theme-value]').forEach(element => { 44 | element.classList.add('d-none') 45 | }) 46 | 47 | activeThemeIcon.classList.remove('d-none') 48 | } 49 | 50 | window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { 51 | const storedTheme = getStoredTheme() 52 | 53 | if (storedTheme !== 'light' && storedTheme !== 'dark') { 54 | setTheme(getPreferredTheme()) 55 | } 56 | }) 57 | 58 | window.addEventListener('DOMContentLoaded', () => { 59 | const themeSwitcher = document.querySelector('#bd-theme') 60 | 61 | if (!themeSwitcher) { 62 | return 63 | } 64 | 65 | showActiveTheme(getPreferredTheme()) 66 | 67 | themeSwitcher.addEventListener('click', () => { 68 | const theme = getStoredTheme() === 'light' ? 'dark' : 'light' 69 | 70 | setStoredTheme(theme) 71 | setTheme(theme) 72 | showActiveTheme(theme) 73 | }) 74 | }) 75 | })() 76 | -------------------------------------------------------------------------------- /app/controllers/ContextualController.scala: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import com.typesafe.config.Config 4 | import io.sdkman.repos.{CandidatesRepo => ICandidatesRepo} 5 | import net.ceedubs.ficus.Ficus._ 6 | import net.ceedubs.ficus.readers.ArbitraryTypeReader._ 7 | import play.api.mvc._ 8 | import support.MongoConnection 9 | 10 | import javax.inject._ 11 | import scala.concurrent.ExecutionContext.Implicits.global 12 | import scala.concurrent.Future 13 | 14 | import services.OpenCollectiveService 15 | import models.Contributor 16 | 17 | @Singleton 18 | class ContextualController @Inject() ( 19 | cc: ControllerComponents, 20 | applicationRepo: ApplicationRepo, 21 | candidatesRepo: CandidatesRepo, 22 | conf: Config, 23 | openCollectiveService: OpenCollectiveService 24 | ) extends AbstractController(cc) { 25 | 26 | val index = Action.async { implicit request: Request[AnyContent] => 27 | openCollectiveService.getContributors().map { result => 28 | val data = result.groupBy(_.`type`) 29 | val organizationContributors = data.getOrElse("ORGANIZATION", Seq[Contributor]()) 30 | val individualContributors = data.getOrElse("USER", Seq[Contributor]()) 31 | 32 | Ok(views.html.index(organizationContributors, individualContributors)) 33 | } 34 | } 35 | 36 | val install = Action.async { implicit request: Request[AnyContent] => 37 | applicationRepo.findApplication().map { app => 38 | val scriptCliVersion = app.map(_.stableCliVersion).getOrElse("6.0.0") 39 | val nativeCliVersion = app.map(_.stableNativeCliVersion).getOrElse("1.0.0") 40 | Ok(views.html.install(scriptCliVersion, nativeCliVersion)) 41 | } 42 | } 43 | 44 | val usage = Action.async { implicit request: Request[AnyContent] => 45 | candidatesRepo.findAllCandidates().map { candidates => 46 | val candidateVersions = candidates 47 | .map(c => Tuple2(c.candidate, c.default.getOrElse("x.y.z"))) 48 | .toMap 49 | Ok(views.html.usage(candidateVersions)) 50 | } 51 | } 52 | 53 | val vendors = Action { implicit request: Request[AnyContent] => 54 | Ok(views.html.vendors()) 55 | } 56 | 57 | def jdks = Action.async { implicit request: Request[AnyContent] => 58 | Future.successful( 59 | Ok( 60 | views.html.jdks( 61 | conf.as[Seq[Jdk]]("jdks.vendors").sortBy(_.distribution) 62 | ) 63 | ) 64 | ) 65 | } 66 | 67 | def sdks = Action.async { implicit request: Request[AnyContent] => 68 | candidatesRepo.findAllCandidates().map { candidates => 69 | val sanitisedCandidates = 70 | candidates.filter(c => !Seq("java", "test").contains(c.candidate)) 71 | Ok(views.html.sdks(sanitisedCandidates)) 72 | } 73 | } 74 | 75 | def contributors = Action.async { implicit request: Request[AnyContent] => 76 | openCollectiveService.getContributors().map { result => 77 | val data = result.groupBy(_.`type`) 78 | val organizationContributors = data.getOrElse("ORGANIZATION", Seq[Contributor]()) 79 | val individualContributors = data.getOrElse("USER", Seq[Contributor]()) 80 | 81 | Ok(views.html.contributors(organizationContributors, individualContributors)) 82 | } 83 | } 84 | } 85 | 86 | case class Jdk( 87 | id: String, 88 | vendor: String, 89 | distribution: String, 90 | url: String, 91 | description: String 92 | ) 93 | 94 | @Singleton 95 | class CandidatesRepo extends ICandidatesRepo with MongoConnection 96 | -------------------------------------------------------------------------------- /app/controllers/HealthController.scala: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import com.typesafe.scalalogging.LazyLogging 4 | import io.sdkman.repos.{ApplicationRepo => IApplicationRepo} 5 | import javax.inject._ 6 | import play.api.libs.json.Json 7 | import play.api.mvc._ 8 | import support.MongoConnection 9 | 10 | import scala.concurrent.ExecutionContext.Implicits.global 11 | 12 | @Singleton 13 | class HealthController @Inject() ( 14 | cc: ControllerComponents, 15 | applicationRepo: ApplicationRepo 16 | ) extends AbstractController(cc) 17 | with LazyLogging { 18 | 19 | def alive = Action.async { _ => 20 | applicationRepo 21 | .findApplication() 22 | .map { maybeApp => 23 | maybeApp.fold(NotFound(statusMessage("KO"))) { app => 24 | val message = statusMessage(app.alive) 25 | logger.info(s"/alive 200 response: $message") 26 | Ok(message) 27 | } 28 | } 29 | .recover { case e => 30 | val message = errorMessage(e) 31 | logger.error(s"/alive 503 response $message") 32 | ServiceUnavailable(message) 33 | } 34 | } 35 | 36 | private def statusMessage(s: String) = Json.obj("status" -> s) 37 | 38 | private def errorMessage(e: Throwable) = 39 | Json.obj("status" -> "KO", "error" -> e.getMessage) 40 | } 41 | 42 | class ApplicationRepo extends IApplicationRepo with MongoConnection 43 | -------------------------------------------------------------------------------- /app/handlers/ErrorHandler.scala: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import javax.inject.Singleton 4 | import play.api.http.HttpErrorHandler 5 | import play.api.mvc.Results._ 6 | import play.api.mvc._ 7 | 8 | import scala.concurrent._ 9 | 10 | @Singleton 11 | class ErrorHandler extends HttpErrorHandler { 12 | 13 | def onClientError( 14 | requestHeader: RequestHeader, 15 | statusCode: Int, 16 | message: String 17 | ) = 18 | statusCode match { 19 | case 404 => 20 | Future.successful( 21 | NotFound(views.html.notfound(Request(requestHeader, AnyContent()))) 22 | ) 23 | case _ => 24 | Future.successful( 25 | Status(statusCode)("A client error occurred: " + message) 26 | ) 27 | } 28 | 29 | def onServerError(requestHeader: RequestHeader, exception: Throwable) = 30 | Future.successful( 31 | InternalServerError("A server error occurred: " + exception.getMessage) 32 | ) 33 | 34 | } 35 | -------------------------------------------------------------------------------- /app/models/Contributor.scala: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import java.util.Date 4 | import play.api.libs.json._ 5 | import java.time.LocalDateTime 6 | 7 | case class Contributor( 8 | name: String, 9 | since: LocalDateTime, 10 | totalAmountDonated: Int, 11 | `type`: String, 12 | description: Option[String], 13 | collectiveSlug: Option[String], 14 | image: String 15 | ) 16 | 17 | object Contributor { 18 | implicit val format: OFormat[Contributor] = Json.format[Contributor] 19 | } 20 | -------------------------------------------------------------------------------- /app/services/OpenCollectiveService.scala: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import javax.inject.Inject 4 | import play.api.cache.AsyncCacheApi 5 | import play.api.libs.json.JsValue 6 | 7 | import scala.concurrent.duration.{Duration, HOURS} 8 | import scala.concurrent.{ExecutionContext, Future} 9 | 10 | import wrappers.OpenCollectiveWebApi 11 | import models.Contributor 12 | 13 | class OpenCollectiveService @Inject() ( 14 | openCollectiveWebApi: OpenCollectiveWebApi, 15 | cache: AsyncCacheApi, 16 | implicit val ec: ExecutionContext 17 | ) { 18 | val cacheExpiry: Duration = Duration(1, HOURS) 19 | 20 | def getContributors(): Future[Seq[Contributor]] = { 21 | cache.getOrElseUpdate[JsValue]("open-collective-cache", cacheExpiry) { 22 | openCollectiveWebApi.getContributors() 23 | } 24 | .map(_.as[Seq[Contributor]].filter(_.totalAmountDonated > 0)) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/support/MongoConnection.scala: -------------------------------------------------------------------------------- 1 | package support 2 | 3 | import com.typesafe.config.{Config, ConfigFactory} 4 | import io.sdkman.db.{MongoConfiguration, MongoConnectivity} 5 | 6 | trait MongoConnection extends MongoConnectivity with MongoConfiguration { 7 | override lazy val config: Config = ConfigFactory.load() 8 | } 9 | -------------------------------------------------------------------------------- /app/views/contributors.scala.html: -------------------------------------------------------------------------------- 1 | @(organizationContributors: Seq[Contributor], individualContributors: Seq[Contributor])(implicit request: Request[AnyContent]) 2 | @main(title = "Contributors", request) { 3 |
4 |
5 | 6 | 7 | 8 |

Open Collective

9 |
10 | 11 | 12 |
13 |

@organizationContributors.size Organizations

14 |

15 | Contribute to our collective 16 |

17 |
18 | 19 |
20 | @for(organizationContributor <- organizationContributors) { 21 |
22 | @includes.organization_card(organizationContributor) 23 |
24 | } 25 |
26 | 27 | 28 |
29 |

@individualContributors.size People

30 |

31 | Contribute to our collective 32 |

33 |
34 | 35 |
36 | @for(individualContributor <- individualContributors) { 37 |
38 | @includes.individual_card(individualContributor) 39 |
40 | } 41 |
42 | 43 |
44 | 45 | Contribute to our collective 46 | 47 |
48 |
49 | } 50 | -------------------------------------------------------------------------------- /app/views/includes/advertisement.scala.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /app/views/includes/browserhappy.scala.html: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /app/views/includes/footer.scala.html: -------------------------------------------------------------------------------- 1 | @import java.time.format.DateTimeFormatter 2 | @import java.time.LocalDate 3 | 17 | -------------------------------------------------------------------------------- /app/views/includes/forkme.scala.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | Fork me on GitHub 7 | 8 |
9 | -------------------------------------------------------------------------------- /app/views/includes/header.scala.html: -------------------------------------------------------------------------------- 1 | @(title: String, request: Request[AnyContent]) 2 | 3 | 4 | 5 | 6 | @title - SDKMAN! the Software Development Kit Manager 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/views/includes/individual_card.scala.html: -------------------------------------------------------------------------------- 1 | @(contributor: Contributor) 2 | 3 |
4 |
5 |
6 | logo 7 |
8 | 9 |

@contributor.name

10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /app/views/includes/navigation.scala.html: -------------------------------------------------------------------------------- 1 | 75 | 76 |
77 |
78 |
Menu
79 | 80 |
81 |
82 | 90 |
91 |
92 | -------------------------------------------------------------------------------- /app/views/includes/opencollective.scala.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
5 | -------------------------------------------------------------------------------- /app/views/includes/organization_card.scala.html: -------------------------------------------------------------------------------- 1 | @import java.time.format.DateTimeFormatter 2 | @(contributor: Contributor) 3 | 4 |
5 |
6 |
7 |
8 | logo 9 |
10 | 11 | @if(contributor.description.nonEmpty) { 12 | @contributor.description 13 | } 14 |
15 | 16 |

@contributor.name

17 | 18 |
19 | $ @Math.round(contributor.totalAmountDonated / 100) 20 | since @contributor.since.format(DateTimeFormatter.ofPattern("MMM YYYY")) 21 |
22 |
23 |
24 |
25 | -------------------------------------------------------------------------------- /app/views/includes/scripts.scala.html: -------------------------------------------------------------------------------- 1 | @() 2 | 3 | 4 | 5 | 6 | 7 | 8 | @includes.statuspage() 9 | 18 | -------------------------------------------------------------------------------- /app/views/includes/statuspage.scala.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/index.scala.html: -------------------------------------------------------------------------------- 1 | @(organizationContributors: Seq[Contributor], individualContributors: Seq[Contributor])(implicit request: Request[AnyContent]) 2 | @main(title = "Home", request) { 3 |
4 |
5 | @includes.advertisement() 6 |
7 | 8 |
9 |
10 |
11 | SDKMAN! logo 12 | 13 |

The Software Development Kit Manager

14 | 15 |

16 | Meet SDKMAN! – your reliable companion for effortlessly managing multiple Software 17 | Development Kits on Unix systems. Imagine having different versions of SDKs and needing a 18 | stress-free 19 | way to switch between them. SDKMAN! steps in with its easy-to-use Command Line Interface (CLI) and 20 | API. 21 | 22 | Formerly known as GVM, the Groovy enVironment Manager, SDKMAN! draws inspiration from familiar tools 23 | like 24 | apt, pip, RVM, and rbenv and even Git. Think of it as your helpful toolkit friend, ready to 25 | streamline SDK 26 | management for you. 🛠️ 27 |

28 |
29 | 30 |
31 |

Get started now! 32 | 33 |

34 | Go on then, paste and run the following in a terminal: 35 |
36 | curl -s "https://get.sdkman.io" | bash 37 |

38 |
39 |
40 |
41 | 42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | 51 | 53 | 54 |
55 | 56 |

By Developers, for Developers

57 |

58 | Simplifying life. No more hunting for downloads, extracting archives, or tinkering with 59 | HOME and PATH environment variables. 60 |

61 |
62 |
63 |
64 | 65 |
66 |
67 |
68 |
69 | 71 | 73 | 74 |
75 | 76 |

Java all the way down

77 |

78 | Install Software Development Kits for the JVM such as Java, Scala, 79 | Kotlin and Groovy. 80 | Ant, Gradle, Grails, Maven, SBT, Spark, Spring Boot, Vert.x and many others 81 | also supported. 82 |

83 |
84 |
85 |
86 | 87 |
88 |
89 |
90 |
91 | 93 | 95 | 97 | 98 |
99 | 100 |

Lightweight

101 |

102 | Written in Rust and bash and only requires curl, zip, and 103 | unzip dependencies to be present on your system. Even works with 104 | ZSH too. 105 |

106 |
107 |
108 |
109 | 110 |
111 |
112 |
113 |
114 | 116 | 118 | 119 |
120 | 121 |

Multi-platform

122 |

123 | Operates seamlessly across various UNIX-based platforms, including macOS, Linux, and Windows 124 | Subsystem for Linux (WSL) on Windows. 125 |

126 |
127 |
128 |
129 | 130 |
131 |
132 |
133 |
134 | 136 | 138 | 139 |
140 | 141 |

APIs

142 |

143 | New Clients can easily be written by consuming our open Broker API. 144 | Vendors can publish and announce their own releases through a secure Vendor API. 145 |

146 |
147 |
148 |
149 | 150 |
151 |
152 |
153 |
154 | 156 | 158 | 159 |
160 | 161 |

Open Source

162 |

163 | Backed by a global community of developers. 164 |
165 | Licensed under Apache 2.0 166 |

167 |
168 |
169 |
170 |
171 |
172 |
173 | 174 |
175 |
176 |
177 | 178 | 179 | 180 |

Open Collective

181 |
182 | 183 | 184 |
185 |

@organizationContributors.size Organizations

186 |

187 | Contribute to our collective 188 |

189 |
190 | 191 |
192 |
193 |
194 | @for(organizationContributor <- organizationContributors.slice(0, 8)) { 195 |
196 | @includes.organization_card(organizationContributor) 197 |
198 | } 199 |
200 |
201 | 202 | 203 |
204 | 205 | 206 | 207 |
208 |
209 | 210 | 211 | 212 |
213 |
214 | 215 | 216 |
217 |

@individualContributors.size People

218 |

219 | Contribute to our collective 220 |

221 |
222 | 223 |
224 |
225 |
226 | @for(individualContributor <- individualContributors.slice(0, 12)) { 227 |
228 | @includes.individual_card(individualContributor) 229 |
230 | } 231 |
232 |
233 | 234 | 235 |
236 | 237 | 238 | 239 |
240 |
241 | 242 | 243 | 244 |
245 |
246 | 247 | 256 |
257 |
258 | 259 |
260 | 261 | 262 |
263 |
264 | } 265 | -------------------------------------------------------------------------------- /app/views/install.scala.html: -------------------------------------------------------------------------------- 1 | @(scriptCliVersion: String, nativeCliVersion: String)(implicit request: Request[AnyContent]) 2 | @main(title = "Installation", request) { 3 |
4 |

Installation

5 | @includes.advertisement() 6 | 7 |

Installing SDKMAN! on UNIX is a breeze. It effortlessly sets up on macOS, Linux and Windows (with 8 | WSL). 9 | Plus, it's compatible with both Bash and ZSH shells.

10 |

Just launch a new terminal and type in:

11 |
$ curl -s "https://get.sdkman.io" | bash
12 |

Follow the on-screen instructions to wrap up the installation. Afterward, open a new terminal or run 13 | the following in the same shell:

14 |
$ source "$HOME/.sdkman/bin/sdkman-init.sh"
15 |

Lastly, run the following snippet to confirm the installation's success:

16 |
$ sdk version
17 |

You should see output containing the latest script and native versions:

18 |
SDKMAN!
19 | script: @scriptCliVersion
20 | native: @nativeCliVersion
21 | 22 |

Windows installation

23 |

For Windows, there are two installation routes:

24 |
    25 |
  1. WSL Approach: Install Windows Subsystem for Linux (WSL) before attempting 26 | SDKMAN installation. A basic toolset (bash, zip, unzip, curl) is necessary. Most times, it works 27 | out of the box.
  2. 28 |
  3. Git Bash Solution: If you use Git Bash for Windows, you'll need to supplement 29 | it with MinGW to have the required toolset for SDKMAN. There are some issues with this approach, 30 | but it works for the most part.
  4. 31 |
32 |

Remember, SDKMAN requires a bash environment to run. On Windows, it can't be natively installed; 33 | you need WSL or MSYS+MinGW. We no longer support Cygwin.

34 | 35 |

Beta channel

36 |

Feeling adventurous? We've got a beta channel. New CLI features hit this channel first for trial. You 37 | can join by installing it directly:

38 |
$ curl -s "https://beta.sdkman.io" | bash
39 |

To leave the beta channel, simply set sdkman_beta_channel to false in 40 | ~/.sdkman/etc/config, then run: 41 |

42 |
$ sdk selfupdate force
43 | 44 |

Uninstallation

45 |

Here is how you go about removing SDKMAN! from your system:

46 |
    47 |
  1. Optionally backup and then remove the installation:
  2. 48 |
    $ tar zcvf ~/sdkman-backup_$(date +%F-%kh%M).tar.gz -C ~/ .sdkman
    49 | $ rm -rf ~/.sdkman
    50 |
  3. Remove initialization snippet from your shell configs.
  4. 51 | Edit and remove the initialisation snippet from your 52 | .bashrc, .bash_profile and/or .profile 53 | files. If you use ZSH, remove it from the .zshrc file. The snippet 54 | of code to be removed looks something like this: 55 |
    #THIS MUST BE AT THE END OF THE FILE FOR SDKMAN TO WORK!!!
    56 | [[ -s "/home/dudette/.sdkman/bin/sdkman-init.sh" ]] && source "/home/dudette/.sdkman/bin/sdkman-init.sh"
    57 | Once removed, you have successfully uninstalled SDKMAN! from your machine. 58 |
59 | 60 |

Install to a custom location

61 |

Lastly, if you want to install SDKMAN! in a custom location, like /usr/local/sdkman, 62 | make sure you have full access rights and that the folder doesn't exist. Export 63 | SDKMAN_DIR before installing: 64 |

65 |
$ export SDKMAN_DIR="/usr/local/sdkman" && curl -s "https://get.sdkman.io" | bash
66 | 67 |

Install without modifying shell config

68 |

And for installs on CI where shell config modification isn't appropriate, add 69 | rcupdate=false 70 | as a parameter when downloading the installer:

71 |
$ curl -s "https://get.sdkman.io?rcupdate=false" | bash
72 | 73 |

That's all there is to it! Now let's dive into Usage.

74 | } 75 | -------------------------------------------------------------------------------- /app/views/jdks.scala.html: -------------------------------------------------------------------------------- 1 | @(jdks: Seq[Jdk])(implicit request: Request[AnyContent]) 2 | @main(title = "JDK Distributions", request) { 3 |
4 |
5 |
6 | 14 |
15 | 16 |
17 |

JDK Distributions

18 | @includes.advertisement() 19 | 20 |
    21 | @for(jdk <- jdks) { 22 |
  • 23 |

    @jdk.distribution (@jdk.vendor)

    24 |

    @jdk.description

    25 | $ sdk install java x.y.z-@jdk.id 26 |
    27 |
  • 28 | } 29 |
30 |
31 |
32 |
33 | } 34 | -------------------------------------------------------------------------------- /app/views/main.scala.html: -------------------------------------------------------------------------------- 1 | @(title: String, request: Request[AnyContent])(content: Html) 2 | 3 | 5 | 7 | 9 | 10 | 11 | @includes.header(title, request) 12 | 13 | @includes.scripts() 14 | 15 |
16 |
17 | @includes.browserhappy() 18 | @includes.navigation() 19 |
20 | @content 21 |
22 | @includes.footer() 23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /app/views/notfound.scala.html: -------------------------------------------------------------------------------- 1 | @(request: Request[AnyContent]) 2 | @main(title = "Not Found!", request) { 3 |
4 |
5 |

Oops!

6 |

The page you are looking for does not exist!

7 |

We could not find the page you are looking for. Maybe you are looking for one of these?

8 | 16 |
17 |
18 | } 19 | -------------------------------------------------------------------------------- /app/views/sdks.scala.html: -------------------------------------------------------------------------------- 1 | @import io.sdkman.model.Candidate 2 | @(candidates: Seq[Candidate])(implicit request: Request[AnyContent]) 3 | @main(title = "Available SDKs", request) { 4 |
5 |
6 |
7 | 15 |
16 | 17 |
18 |

SDK Installation Candidates

19 | @includes.advertisement() 20 |
    21 | @for(c <- candidates) { 22 |
  • 23 |

    @c.name (@c.default.getOrElse("Coming soon!"))

    24 | @c.websiteUrl
    25 |

    @c.description

    26 | $ sdk install @c.candidate 27 |
    28 |
  • 29 | } 30 |
31 |
32 |
33 |
34 | } 35 | -------------------------------------------------------------------------------- /app/views/usage.scala.html: -------------------------------------------------------------------------------- 1 | @(candidates: Map[String, String])(implicit request: Request[AnyContent]) 2 | @groovyVersion = @{candidates.getOrElse("groovy", "x.y.z")} 3 | @gradleVersion = @{candidates.getOrElse("gradle", "x.y.z")} 4 | @grailsVersion = @{candidates.getOrElse("grails", "x.y.z")} 5 | @javaVersion = @{candidates.getOrElse("java", "x.y.z")} 6 | @scalaVersion = @{candidates.getOrElse("scala", "x.y.z")} 7 | @springbootVersion = @{candidates.getOrElse("springboot", "x.y.z")} 8 | @main(title = "Usage", request) { 9 |
10 |
11 | 37 | 38 |
39 |

Usage

40 | @includes.advertisement() 41 | 42 |
43 |

Installing an SDK

44 |
45 | 46 |

Latest Stable

47 |

48 | Install the latest stable version of your SDK of choice 49 | (say, Java JDK) by running the following command: 50 |

51 |
$ sdk install java
52 |

You will see something like the following output:

53 |
Downloading: java @javaVersion
 54 | 
 55 | In progress...
 56 | 
 57 | ######################################################################## 100.0%
 58 | 
 59 | Installing: java @javaVersion
 60 | Done installing!
 61 | 
62 |

Now you will be prompted if you want this version to be set asdefault.

63 |
Do you want java @javaVersion to be set as default? (Y/n):
64 |

65 | Answering yes (or hitting enter) will ensure that all 66 | subsequent shells opened will have this version of the SDK in use by default. 67 |

68 |
Setting java @javaVersion as default.
69 |
70 | 71 |

Specific Version

72 |

73 | Need a specific version of an SDK? Simply qualify the 74 | version you require: 75 |

76 |
$ sdk install scala @scalaVersion
77 |

All subsequent steps same as above.

78 |
79 | 80 |

Install Local Version(s)

81 |

82 | Using a snapshot version? Already have a local installation? Setup a local version by specifying 83 | the path to the local installation: 84 |

85 |
$ sdk install groovy 3.0.0-SNAPSHOT /path/to/groovy-3.0.0-SNAPSHOT
86 |
$ sdk install java 17-zulu /Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home
87 |

88 | Note that the local version name (3.0.0-SNAPSHOT and 89 | 17-zulu in the examples above) must be a unique name 90 | which is not already in the list of available version names. 91 |

92 |
93 |
94 | 95 |
96 |

Remove Version

97 |

Remove an installed version.

98 |
$ sdk uninstall scala @scalaVersion
99 |

Note that removing a local version will not remove the local installation.

100 |
101 |
102 | 103 |
104 |

List Candidates

105 |

To get a listing of available Candidates:

106 |
$ sdk list
107 |

108 | This will render a searchable alphabetic list with name, current stable default 109 | version, website URL, description and easy install command for each Candidate. 110 | The output is piped to less so standard keyboard shortcuts may be 111 | used with q to exit. 112 |

113 |
================================================================================
114 | Available Candidates
115 | ================================================================================
116 | q-quit                                  /-search down
117 | j-down                                  ?-search up
118 | k-up                                    h-help
119 | --------------------------------------------------------------------------------
120 | ...
121 | --------------------------------------------------------------------------------
122 | Java (@javaVersion)        https://projects.eclipse.org/projects/adoptium.temurin/
123 | 
124 | Java Platform, Standard Edition (or Java SE) is a widely used platform for
125 | development and deployment of portable code for desktop and server environments.
126 | Java SE uses the object-oriented Java programming language. It is part of the
127 | Java software-platform family. Java SE defines a wide range of general-purpose
128 | APIs – such as Java APIs for the Java Class Library – and also includes the Java
129 | Language Specification and the Java Virtual Machine Specification.
130 | 
131 | $ sdk install java
132 | --------------------------------------------------------------------------------
133 | ...
134 | 
135 |
136 |
137 | 138 |
139 |

List Versions

140 |

To get a listing of Candidate Versions:

141 |
$ sdk list groovy
142 |

143 | This will result in a list view showing the available, local, installed and 144 | current versions of the SDK. 145 |

146 |
================================================================================
147 | Available Groovy Versions
148 | ================================================================================
149 | > * 2.4.4                2.3.1                2.0.8                1.8.3
150 | 2.4.3                2.3.0                2.0.7                1.8.2
151 | 2.4.2                2.2.2                2.0.6                1.8.1
152 | 2.4.1                2.2.1                2.0.5                1.8.0
153 | 2.4.0                2.2.0                2.0.4                1.7.9
154 | 2.3.9                2.1.9                2.0.3                1.7.8
155 | 2.3.8                2.1.8                2.0.2                1.7.7
156 | 2.3.7                2.1.7                2.0.1                1.7.6
157 | 2.3.6                2.1.6                2.0.0                1.7.5
158 | 2.3.5                2.1.5                1.8.9                1.7.4
159 | 2.3.4                2.1.4                1.8.8                1.7.3
160 | 2.3.3                2.1.3                1.8.7                1.7.2
161 | 2.3.2                2.1.2                1.8.6                1.7.11
162 | 2.3.11               2.1.1                1.8.5                1.7.10
163 | 2.3.10               2.1.0                1.8.4                1.7.1
164 | 
165 | ================================================================================
166 | + - local version
167 | * - installed
168 | > - currently in use
169 | ================================================================================
170 | 
171 |
172 |
173 | 174 |
175 |

Use Version

176 |

Choose to use a given version in the current terminal:

177 |
$ sdk use scala @scalaVersion
178 |

179 | It is important to realise that this will switch the candidate version for 180 | the current shell only. To make this change permanent, use the default command instead. 181 |

182 |
183 |
184 | 185 |
186 |

Default Version

187 |

Chose to make a given version the default:

188 |
$ sdk default scala @scalaVersion
189 |

This will ensure that all subsequent shells will start with version @scalaVersion in use.

190 |
191 |
192 | 193 |
194 |

Current Version(s)

195 |

To see what is currently in use for a Candidate:

196 |
$ sdk current java
197 | Using java version @javaVersion
198 | 
199 |

To see what is currently in use for all Candidates:

200 |
$ sdk current
201 | Using:
202 | groovy: @groovyVersion
203 | java: @javaVersion
204 | scala: @scalaVersion
205 | 
206 |
207 |
208 | 209 |
210 |

Env Command

211 |

212 | Want to switch to a specific JDK or SDK every time you visit a project? 213 | This can be achieved through an .sdkmanrc file in the base 214 | directory of your project. This file can be generated automatically by 215 | issuing the following command: 216 |

217 |
$ sdk env init
218 |

A config file with the following content has now been created in the current directory:

219 |
# Enable auto-env through the sdkman_auto_env config
220 | # Add key=value pairs of SDKs to use below
221 | java=@javaVersion
222 | 
223 |

224 | The file is pre-populated with the current JDK version in use, but can 225 | contain as many key-value pairs of supported SDKs as needed. 226 | To switch to the configuration present in your .sdkmanrc file, 227 | simply issue the following command: 228 |

229 |
sdk env
230 |

You should see output that looks something like this:

231 |
Using java version @javaVersion in this shell.
232 |

233 | Your path has now also been updated to use any of these SDKs in your current shell. 234 | When leaving a project, you may want to reset the SDKs to their default version. 235 | This can be achieved by entering: 236 |

237 |
$ sdk env clear
238 | Restored java version to @javaVersion (default)
239 | 
240 |

241 | After checking out a new project, you may be missing some SDKs specified in the project's 242 | .sdkmanrc file. To install these missing SDKs, just type: 243 |

244 |
$ sdk env install
245 | 
246 | Downloading: java @javaVersion
247 | 
248 | In progress...
249 | 
250 | ######################################################################## 100,0%
251 | 
252 | Repackaging Java @javaVersion...
253 | 
254 | Done repackaging...
255 | 
256 | Installing: java @javaVersion
257 | Done installing!
258 | 
259 |

260 | Do you want to switch SDK versions automatically when you cd into a 261 | directory? This can be done by setting the sdkman_auto_env=true in 262 | the SDKMAN configuration. 263 | Note that this will also reset any project-specific SDKs to their default version 264 | when leaving the directory. 265 |

266 |
267 |
268 | 269 |
270 |

Upgrade Version(s)

271 |

To see what is currently out of date for a Candidate on your system:

272 |
$ sdk upgrade springboot
273 | Upgrade:
274 | springboot (1.2.4.RELEASE, 1.2.3.RELEASE < @springbootVersion)
275 | 
276 |

To see what is outdated for all Candidates:

277 |
$ sdk upgrade
278 | Upgrade:
279 | gradle (2.3, 1.11, 2.4, 2.5 < @gradleVersion)
280 | grails (2.5.1 < @grailsVersion)
281 | springboot (1.2.4.RELEASE, 1.2.3.RELEASE < @springbootVersion
282 | 
283 |
284 |
285 | 286 |
287 |

SDKMAN! Version

288 |

Display the current script and native versions of SDKMAN!:

289 |
$ sdk version
290 | 
291 | SDKMAN!
292 | script: 5.7.0
293 | native: 0.1.3
294 | 
295 |
296 |
297 | 298 |
299 |

Offline Mode

300 |

301 | Initially called Aeroplane Mode, this allows SDKMAN! to function 302 | when working offline. It has a parameter that can be passed 303 | toenable or disable the offline mode. 304 |

305 |
$ sdk offline enable
306 | Forced offline mode enabled.
307 | 
308 | $ sdk offline disable
309 | Online mode re-enabled!
310 | 
311 |

312 | When operating in offline mode, most commands will still work 313 | even though they will operate in a scaled down capacity. An example is the list 314 | command, which will only display the currently installed and active version(s): 315 |

316 |
$ sdk list groovy
317 | ------------------------------------------------------------
318 | Offline Mode: only showing installed groovy versions
319 | ------------------------------------------------------------
320 | > 2.4.4
321 | * 2.4.3
322 | ------------------------------------------------------------
323 | * - installed
324 | > - currently in use
325 | ------------------------------------------------------------
326 | 
327 | The offline mode will also be disabled/enabled automatically when the internet 328 | becomes available/unavailable. Naturally, commands that require internet 329 | connectivity will not function but give a warning. 330 |
331 |
332 | 333 |
334 |

Self-Update

335 |

Installs a new version of SDKMAN! if available.

336 |
$ sdk selfupdate
337 |

338 | If no new version is available an appropriate message will be displayed. 339 | Re-installation may be forced by passing the force parameter to the command: 340 |

341 |
$ sdk selfupdate force
342 |

343 | Automatic daily checks for new versions of SDKMAN! will also be performed on the 344 | behalf of the user. 345 |

346 |
347 |
348 | 349 |
350 |

Update

351 |

352 | Periodically SDKMAN! requires a refresh to become aware of new (or removed) 353 | candidates. 354 | When candidate metadata has potentially grown stale, a warning is displayed 355 | with instruction 356 | on how to update. By simply running the following command, the candidate 357 | cache will be refreshed and new candidates will become available for 358 | installation: 359 |

360 |
WARNING: SDKMAN is out-of-date and requires an update.
361 | 
362 | $ sdk update
363 | Adding new candidates(s): kotlin
364 | 
365 |
366 |
367 | 368 |
369 |

Flush

370 |

371 | It should rarely be necessary to flush SDKMAN!'s local state. 372 | The flush command helps with this, so you don't need to delete any directories. 373 |
374 | 375 | Manually deleting directories like the .sdkman/tmp directory will 376 | break SDKMAN! Always usethe flush command instead! 377 | 378 |

379 |
$ sdk flush
380 |
381 |
382 | 383 |
384 |

Home

385 |

386 | When using SDKMAN in scripts, it is often useful to get the absolute 387 | path of where an SDK resides (similar to how the java_home 388 | command works on macOS). For this we have the home command. 389 |

390 |
$ sdk home java @javaVersion
391 | /home/myuser/.sdkman/candidates/java/@javaVersion
392 | 
393 |
394 |
395 | 396 |
397 |

Help

398 |

You can get basic help by running the following command:

399 |
$ sdk help
400 |

401 | This should render a useful top-level help page. You can add qualifier to this command to get help 402 | about a specific sub-command. 403 |

404 |
$ sdk help install
405 |
406 |
407 |
408 | 409 |
410 |

Configuration

411 |

412 | Configuration can be found in the ~/.sdkman/etc/config file. To edit the 413 | configuration, the sdk config command may be issued to edit this file 414 | in the system editor. The following configurations are available: 415 |

416 |
# make sdkman non-interactive, preferred for CI environments
417 | sdkman_auto_answer=true|false
418 | 
419 | # check for newer versions and prompt for update
420 | sdkman_selfupdate_feature=true|false
421 | 
422 | # disables SSL certificate verification
423 | # https://github.com/sdkman/sdkman-cli/issues/327
424 | # HERE BE DRAGONS....
425 | sdkman_insecure_ssl=true|false
426 | 
427 | # configure curl timeouts
428 | sdkman_curl_connect_timeout=5
429 | sdkman_curl_continue=true
430 | sdkman_curl_max_time=10
431 | 
432 | # subscribe to the beta channel
433 | sdkman_beta_channel=true|false
434 | 
435 | # enable verbose debugging
436 | sdkman_debug_mode=true|false
437 | 
438 | # enable colour mode
439 | sdkman_colour_enable=true|false
440 | 
441 | # enable automatic env
442 | sdkman_auto_env=true|false
443 | 
444 | # enable bash or zsh auto-completion
445 | sdkman_auto_complete=true|false
446 | 
447 |
448 |
449 |
450 |
451 | } -------------------------------------------------------------------------------- /app/views/vendors.scala.html: -------------------------------------------------------------------------------- 1 | @()(implicit request: Request[AnyContent]) 2 | @main(title = "Vendors", request) { 3 |
4 |
5 |
6 | 16 |
17 | 18 |
19 |

Vendors

20 | @includes.advertisement() 21 | 22 |
23 |

SDKMAN! is unique in that it empowers SDK Vendors to publish their candidate releases on our 24 | platform. We provide a secure API that can be used to manage all aspects of a release on SDKMAN!. 25 | Such aspects include Releasing a new version, setting an existing version as 26 | Default (Stable) and Announcing the release on the SDKMAN! CLI 27 | broadcast and Twitter feed.

28 |
29 |
30 | 31 |
32 |

Operations

33 | The API is a simple JSON REST API that allows three basic operations: 34 |
    35 |
  • Release a new candidate version
  • 36 |
  • Set the default for a candidate
  • 37 |
  • Broadcast a release message
  • 38 |
39 |
40 |
41 | 42 |
43 |

Access

44 |

This is a secured API, and requires appropriate credentials to perform the 45 | above operations. Access will be granted on a 46 | case-by-case basis to Vendors who are interested in making their SDK 47 | available on SDKMAN!. If you want to publish your releases on SDKMAN!, please follow the Vendor Onboarding 48 | wiki page 49 | and then contact us for help with setting up your credentials.

50 |
51 |
52 | 53 |
54 |

Endpoints

55 | The simplest way to call the API is by using curl. Of course, 56 | any other client can be used to perform the API operations. 57 | 58 |

Release a new Candidate Version

59 | This will perform a minor release on SDKMAN!. It will 60 | simply add the new candidate version, but will not make it the default version 61 | for that candidate. This endpoint supports POST and DELETE HTTP methods. 62 | The POST endpoint is idempotent. 63 |
curl -X POST \
 64 | -H "Consumer-Key: CONSUMER_KEY" \
 65 | -H "Consumer-Token: CONSUMER_TOKEN" \
 66 | -H "Content-Type: application/json" \
 67 | -H "Accept: application/json" \
 68 | -d '{"candidate": "groovy", "version": "2.4.2", "url": "https://groovy.jfrog.io/artifactory/dist-release-local/groovy-zips/apache-groovy-binary-2.4.6.zip"}' \
 69 | https://vendors.sdkman.io/release
70 | 71 |
Multi-platform binary distributions
72 | We support both universal and multi-platform binary distributions. Universal binaries run on all 73 | platforms, so you need to publish only a single SDK archive to our API. Multi-platform APIs are 74 | compiled specifically for the target platform and require an archive per target platform to be 75 | published. We currently support the following platforms: 76 |
    77 |
  • LINUX_64
  • 78 |
  • LINUX_ARM64
  • 79 |
  • LINUX_32
  • 80 |
  • LINUX_ARM32SF
  • 81 |
  • LINUX_ARM32HF
  • 82 |
  • MAC_OSX
  • 83 |
  • MAC_ARM64
  • 84 |
  • WINDOWS_64
  • 85 |
86 | 87 | To indicate the target platform, a platform key with associated platform 88 | should be included in the payload. If no platform is included, we assume the 89 | value to be UNIVERSAL. 90 | 91 |
Multi-vendor candidates
92 | For vendors who wish to publish to a multi-vendor candidate like Java or JMC, 93 | we require the presence of a vendor string in the JSON payload. 94 | This will result in a new version comprised of $version-$vendor, 95 | so in this case it would appear as 11.0.10-zulu on SDKMAN!. 96 | 97 |
Checksums
98 | An optional map of checksums may be provided in the payload for each published binary. 99 | Supported checksum algorithms are: 100 |
    101 |
  • MD5
  • 102 |
  • SHA-1
  • 103 |
  • SHA-224
  • 104 |
  • SHA-256
  • 105 |
  • SHA-384
  • 106 |
  • SHA-512
  • 107 |
108 | 109 |
Sample payload
110 | An example payload demonstrating the release of a multi-platform Java binary 111 | for LINUX_64 published by Azul as zulu with two checksums 112 | will look something like this: 113 |
{
114 |     "candidate": "java",
115 |     "version": "11.0.10",
116 |     "vendor": "zulu",
117 |     "url": "https://cdn.azul.com/zulu/bin/zulu11.45.27-ca-jdk11.0.10-linux_x64.tar.gz",
118 |     "platform": "LINUX_64",
119 |     "checksums": {
120 |         "MD5": "93c9d427af64f2da8c00c9219360815b",
121 |         "SHA-256": "0bd85593bae021314378f3b146cfe36a6c9b0afd964d897c34201034ace3e785"
122 |     }
123 | }
124 | 125 |

Set existing Version as Default for Candidate

126 | When calling this endpoint for an existing candidate version, it will make it the default version 127 | for that candidate. This makes a minor release a major release! 128 |
curl -X PUT \
129 | -H "Consumer-Key: CONSUMER_KEY" \
130 | -H "Consumer-Token: CONSUMER_TOKEN" \
131 | -H "Content-Type: application/json" \
132 | -H "Accept: application/json" \
133 | -d '{"candidate": "groovy", "version": "2.3.8"}' \
134 | https://vendors.sdkman.io/default
135 |
136 |

Broadcast a Structured Message

This will result in a structured 137 | message announcement on social media and SDKMAN! CLI. The result will look 138 | something like: grails 3.0.0 available for download. https://git.io/release. 139 | The url can point to the github release page or the version's changelog. 140 | This message will be announced to the broadcast channel of SDKMAN! CLI, as well 141 | as on the @@sdkman_ Twitter feed. 142 |
curl -X POST \
143 | -H "Consumer-Key: CONSUMER_KEY" \
144 | -H "Consumer-Token: CONSUMER_TOKEN" \
145 | -H "Content-Type: application/json" \
146 | -H "Accept: application/json" \
147 | -d '{"candidate": "grails", "version": "3.0.0", "url": "https://git.io/release"}' \
148 | https://vendors.sdkman.io/announce/struct
149 |
150 |
151 | 152 |
153 |

Gradle SDK Vendor Plugin

154 |

If fiddling with cURL (or HttpClient) isn’t your thing, you could consider 155 | using our Gradle plugin. The plugin allows the release to be done as a side 156 | effect of your CI build! It exposes several useful tasks like: 157 |

    158 |
  • sdkReleaseVersion
  • 159 |
  • sdkDefaultVersion
  • 160 |
  • sdkAnnounceVersion
  • 161 |
162 | It also exposes some convenience tasks that roll the above into single tasks: 163 |
    164 |
  • sdkMajorRelease: performs release, default and structured 165 | announce 166 |
  • 167 |
  • sdkMinorRelease: performs release and structured announce, 168 | no default 169 |
  • 170 |
171 | For more details of about this plugin, as well as how to configure it, please 172 | refer to the Github 173 | Page for the project.

174 |
175 |
176 | 177 |
178 |

Maven SDK Vendor Plugin

179 |

If fiddling with cURL (or HttpClient) or Gradle isn’t your thing, you could consider 180 | using our Maven plugin. The plugin allows the release to be done as a side 181 | effect of your CI build! It exposes several useful goals like: 182 |

    183 |
  • release
  • 184 |
  • default
  • 185 |
  • announce
  • 186 |
187 | It also exposes some convenience goals that roll the above into single goals: 188 |
    189 |
  • major-release: performs release, default and structured 190 | announce 191 |
  • 192 |
  • minor-release: performs release and structured announce, 193 | no default 194 |
  • 195 |
196 | For more details of about this plugin, as well as how to configure it, please 197 | refer to the Github 198 | Page for the project.

199 |
200 |
201 |
202 |
203 | } 204 | -------------------------------------------------------------------------------- /app/wrappers/OpenCollectiveWebApi.scala: -------------------------------------------------------------------------------- 1 | package wrappers 2 | 3 | import javax.inject.Inject 4 | import com.typesafe.config.Config 5 | import play.api.http.Status._ 6 | import play.api.libs.ws.WSClient 7 | import play.api.libs.json.{Json, JsValue} 8 | 9 | import scala.concurrent.{ExecutionContext, Future} 10 | 11 | class OpenCollectiveWebApi @Inject() ( 12 | ws: WSClient, 13 | conf: Config, 14 | implicit val ec: ExecutionContext 15 | ) { 16 | val url = conf.getString("openCollective.url") 17 | 18 | val query = Json.obj( 19 | "query" -> """ 20 | query Collective { 21 | collective(slug: "sdkman") { 22 | contributors(limit: 200, offset: 0) { 23 | totalCount 24 | nodes { 25 | name 26 | since 27 | totalAmountDonated 28 | type 29 | description 30 | collectiveSlug 31 | image 32 | } 33 | } 34 | } 35 | } 36 | """ 37 | ) 38 | 39 | def getContributors(): Future[JsValue] = { 40 | ws 41 | .url(url) 42 | .addHttpHeaders("Accept" -> "application/json") 43 | .post(query) 44 | .map { response => 45 | if (response.status == OK) { 46 | (response.json \ "data" \ "collective" \ "contributors" \ "nodes").as[JsValue] 47 | } else { 48 | throw ApiError(response.status, Some(response.statusText)) 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/wrappers/package.scala: -------------------------------------------------------------------------------- 1 | package object wrappers { 2 | case class ApiError( 3 | status: Int, 4 | statusText: Option[String] = None, 5 | data: Option[Any] = None 6 | ) extends Exception(statusText.orNull) 7 | } 8 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | enablePlugins(JavaServerAppPackaging) 2 | enablePlugins(DockerPlugin) 3 | enablePlugins(GitVersioning) 4 | 5 | name := """sdkman-website""" 6 | 7 | organization := "io.sdkman" 8 | 9 | git.formattedShaVersion := git.gitHeadCommit.value.map(_.take(7)) 10 | 11 | Docker / packageName := "registry.digitalocean.com/sdkman/sdkman-website" 12 | 13 | dockerUpdateLatest := true 14 | 15 | dockerBaseImage := "openjdk:11" 16 | 17 | dockerExposedPorts ++= Seq(9000) 18 | 19 | Universal / javaOptions ++= Seq( 20 | "-Dpidfile.path=/dev/null" 21 | ) 22 | 23 | lazy val root = (project in file(".")).enablePlugins(PlayScala) 24 | 25 | scalaVersion := "2.12.13" 26 | 27 | resolvers ++= Seq( 28 | Resolver.mavenCentral, 29 | "jitpack" at "https://jitpack.io" 30 | ) 31 | 32 | libraryDependencies ++= Seq( 33 | ws, 34 | guice, 35 | caffeine, 36 | "com.github.sdkman" % "sdkman-mongodb-persistence" % "2.4", 37 | "com.typesafe.scala-logging" %% "scala-logging" % "3.9.3", 38 | "com.iheart" %% "ficus" % "1.5.0" 39 | ) 40 | 41 | -------------------------------------------------------------------------------- /conf/application.conf: -------------------------------------------------------------------------------- 1 | play.http.secret.key = "66c19d060036a87266e76678bd798af4896fe53c55baf611afde542f59a658d1" 2 | 3 | mongo { 4 | url { 5 | host = "localhost" 6 | host = ${?MONGO_HOST} 7 | 8 | port = 27017 9 | port = ${?MONGO_PORT} 10 | } 11 | 12 | database = "sdkman" 13 | database = ${?MONGO_DATABASE} 14 | 15 | username = "" 16 | username = ${?MONGO_USERNAME} 17 | 18 | password = "" 19 | password = ${?MONGO_PASSWORD} 20 | } 21 | 22 | openCollective { 23 | url = "https://api.opencollective.com/graphql/v2" 24 | url = ${?OPEN_COLLECTIVE_URL} 25 | } 26 | 27 | play.http.errorHandler = handlers.ErrorHandler 28 | 29 | play.filters.hosts { 30 | allowed = [ 31 | "sdkman.io", 32 | "site.sdkman.io", 33 | "www.sdkman.io", 34 | "sdkman-website-rxljo.ondigitalocean.app", 35 | "localhost" 36 | ] 37 | } 38 | 39 | include "jdks.conf" 40 | -------------------------------------------------------------------------------- /conf/jdks.conf: -------------------------------------------------------------------------------- 1 | jdks { 2 | vendors: [ 3 | { 4 | id = "amzn" 5 | vendor = "Amazon" 6 | distribution = "Corretto" 7 | url = "https://aws.amazon.com/corretto/" 8 | description = """ 9 | Amazon Corretto is a no-cost, multiplatform, production-ready distribution 10 | of the Open Java Development Kit (OpenJDK). Corretto comes with long-term 11 | support that will include performance enhancements and security fixes. 12 | Amazon runs Corretto internally on thousands of production services and 13 | Corretto is certified as compatible with the Java SE standard. With 14 | Corretto, you can develop and run Java applications on popular operating 15 | systems, including Linux, Windows, and macOS. 16 | """ 17 | }, 18 | { 19 | id = "albba", 20 | vendor = "Alibaba", 21 | distribution = "Dragonwell", 22 | url = "http://dragonwell-jdk.io", 23 | description = """ 24 | Dragonwell, as a downstream version of OpenJDK, is the in-house 25 | OpenJDK implementation at Alibaba. It is optimized for online e-commerce, 26 | financial and logistics applications running on 100,000+ servers. Alibaba 27 | Dragonwell is the engine that runs these distributed Java applications in 28 | extreme scaling. 29 | """ 30 | }, 31 | { 32 | id = "bsg" 33 | vendor = "Huawei", 34 | distribution = "Bisheng", 35 | url = "https://bishengjdk.openeuler.org/" 36 | description = """ 37 | BiSheng JDK, an open-source adaptation of Huawei JDK derived from 38 | OpenJDK, is utilized across 500+ Huawei products, benefitting from 39 | the R&D team's extensive experience in addressing service-related 40 | challenges. As a downstream product of OpenJDK, it serves as a 41 | high-performance distribution for production environments, 42 | specifically addressing performance and stability issues in Huawei 43 | applications. BiSheng JDK excels in optimizing ARM architecture 44 | performance and stability, delivering enhanced results in big data 45 | scenarios. Its primary goal is to offer Java developers a stable, 46 | high-performance JDK, particularly excelling on the ARM architecture. 47 | """ 48 | }, 49 | { 50 | id = "graal" 51 | vendor = "Oracle" 52 | distribution = "GraalVM" 53 | url = "https://www.graalvm.org/" 54 | description = """ 55 | Oracle GraalVM is the free GraalVM distribution from Oracle, based on 56 | Oracle JDK, and includes the high-performance Graal JIT compiler. 57 | GraalVM can compile Java applications ahead of time into standalone 58 | binaries that start instantly, scale fast, and use fewer compute 59 | resources. Oracle GraalVM Native Image provides advanced features 60 | including G1 GC, SBOM, as well as performance and size optimizations. 61 | It also makes it possible to embed Python, JavaScript, Ruby, and other 62 | languages into Java applications. 63 | """ 64 | }, 65 | { 66 | id = "graalce" 67 | vendor = "GraalVM Community" 68 | distribution = "GraalVM" 69 | url = "https://www.graalvm.org/" 70 | description = """ 71 | GraalVM CE is the open source distribution of GraalVM, based on OpenJDK, 72 | and includes the high-performance Graal JIT compiler. GraalVM can 73 | compile Java applications ahead of time into standalone binaries that 74 | start instantly, scale fast, and use fewer compute resources. It also 75 | makes it possible to embed Python, JavaScript, Ruby, and other languages 76 | into Java applications. 77 | """ 78 | }, 79 | { 80 | id = "kona" 81 | vendor = "Tencent" 82 | distribution = "Kona" 83 | url = "https://tencent.github.io/konajdk/" 84 | description = """ 85 | Tencent Kona is a free, multi-platform, and production-ready distribution 86 | of OpenJDK, featuring Long-Term Support (LTS) releases. It serves as the 87 | default JDK within Tencent for cloud computing, big data, and numerous 88 | other Java applications. 89 | """ 90 | }, 91 | { 92 | id = "oracle" 93 | vendor = "Oracle" 94 | distribution = "Java SE Development Kit" 95 | url = "https://www.oracle.com/java/" 96 | description = """ 97 | This proprietary Java Development Kit is an implementation of the Java Platform, 98 | Standard Edition released by Oracle Corporation in the form of a binary 99 | product aimed at Java developers on Linux, macOS or Windows. The JDK 100 | includes a private JVM and a few other resources to finish the development 101 | of a Java application. It is distributed under the Oracle No-Fee Terms and 102 | Conditions License 103 | """ 104 | }, 105 | { 106 | id = "librca" 107 | vendor = "Bellsoft" 108 | distribution = "Liberica" 109 | url = "https://bell-sw.com/" 110 | description = """ 111 | Liberica is a 100% open-source Java implementation. It is built from 112 | OpenJDK which BellSoft contributes to, is thoroughly tested and passed the 113 | JCK provided under the license from OpenJDK. All supported versions of 114 | Liberica also contain JavaFX. 115 | """ 116 | }, 117 | { 118 | id = "nik" 119 | vendor = "Bellsoft" 120 | distribution = "Liberica NIK" 121 | url = "https://bell-sw.com/pages/liberica-native-image-kit" 122 | description = """ 123 | Liberica Native Image Kit is a utility that converts your JVM-based application 124 | into a fully compiled native executable ahead-of-time under the closed-world 125 | assumption with an almost instant startup time. Being compatible with various 126 | platforms, including lightweight musl-based Alpine Linux, it optimizes resource 127 | consumption and minimizes the static footprint. 128 | """ 129 | }, 130 | { 131 | id = "mandrel" 132 | vendor = "Red Hat" 133 | distribution = "Mandrel" 134 | url = "https://github.com/graalvm/mandrel" 135 | description = """ 136 | Mandrel focuses on GraalVM's native-image component in order to provide 137 | an easy way for Quarkus users to generate native images for their 138 | applications. Developers using Quarkus should be able to go all the way 139 | from Java source code to lean, native, platform-dependent applications 140 | running on Linux. This capability is vital for deploying to containers 141 | in a cloud-native application development model. 142 | """ 143 | }, 144 | { 145 | id = "open" 146 | vendor = "jdk.java.net" 147 | distribution = "OpenJDK" 148 | url = "https://jdk.java.net/" 149 | description = """ 150 | OpenJDK (Open Java Development Kit) is a free and open-source 151 | implementation of the Java Platform, Standard Edition (Java SE). It is the 152 | result of an effort Sun Microsystems began in 2006. The implementation is 153 | licensed under the GNU General Public License (GNU GPL) version 2 with a 154 | linking exception. Were it not for the GPL linking exception, components 155 | that linked to the Java class library would be subject to the terms of the 156 | GPL license. OpenJDK is the official reference implementation of Java SE 157 | since version 7. 158 | """ 159 | }, 160 | { 161 | id = "ms" 162 | vendor = "Microsoft" 163 | distribution = "OpenJDK" 164 | url = "https://www.microsoft.com/openjdk" 165 | description = """ 166 | The Microsoft Build of OpenJDK is a no-cost distribution of OpenJDK that's 167 | open source and available for free for anyone to deploy anywhere. It 168 | includes Long-Term Support (LTS) binaries for Java 11 on x64 server and 169 | desktop environments on macOS, Linux, and Windows, and AArch64/ARM64 on 170 | Linux and Windows. Microsoft also publishes Java 16 binaries for all three 171 | major Operating Systems and both x64 and AArch64 (M1/ARM64) architectures. 172 | """ 173 | }, 174 | { 175 | id = "sapmchn" 176 | vendor = "SAP" 177 | distribution = "SapMachine" 178 | url = "https://sap.github.io/SapMachine/" 179 | description = """ 180 | SapMachine is a downstream version of the OpenJDK 181 | project. It is used to build and maintain a SAP supported version of 182 | OpenJDK for SAP customers and partners who wish to use OpenJDK to run their 183 | applications. SAP is committed to ensuring the continued success of the 184 | Java platform. 185 | """ 186 | }, 187 | { 188 | id = "sem", 189 | vendor = "IBM", 190 | distribution = "Semeru", 191 | url = "https://developer.ibm.com/languages/java/semeru-runtimes/", 192 | description = """ 193 | Semeru Runtimes use the class libraries from OpenJDK, along with 194 | the Eclipse OpenJ9 Java Virtual Machine to enable developers to build 195 | and deploy Java applications that will start quickly, deliver great 196 | performance, all while using less memory. 197 | """ 198 | }, 199 | { 200 | id = "tem", 201 | vendor = "Eclipse", 202 | distribution = "Temurin", 203 | url = "https://projects.eclipse.org/projects/adoptium.temurin", 204 | description = """ 205 | Formerly AdoptOpenJDK, the Eclipse Adoptium Temurin™ project provides 206 | code and processes that support the building of runtime binaries and 207 | associated technologies that are high performance, enterprise-caliber, 208 | cross-platform, open-source licensed, and Java SE TCK-tested for general 209 | use across the Java ecosystem. 210 | """ 211 | }, 212 | { 213 | id = "trava", 214 | vendor = "Trava", 215 | distribution = "Trava", 216 | url = "https://github.com/TravaOpenJDK/trava-jdk-11-dcevm", 217 | description = """ 218 | TravaOpenJDK is OpenJDK for developers. It is based on dcevm 219 | and uses an integrated HotswapAgent, so allowing advanced hotswapping of 220 | classes by method and field addition or updates at runtime. 221 | """ 222 | }, 223 | { 224 | id = "zulu" 225 | vendor = "Azul Systems" 226 | distribution = "Zulu" 227 | url = "https://www.azul.com/downloads/zulu/" 228 | description = """ 229 | Azul Zulu Builds of OpenJDK are no-cost, production-ready open-source, TCK-tested, 230 | and certified OpenJDK distributions. They are available for a wide range of hardware 231 | platforms and operating systems and are compatible with special requirements, such 232 | as stripped-down JREs and builds, including OpenJFX and Coordinated Restore at 233 | Checkpoint (CRaC). They are supported as part of Azul Platform Core, which provides 234 | stabilized security updates for rapid, assured deployment into production and 235 | solution-oriented engineering assistance. 236 | """ 237 | }, 238 | ] 239 | } 240 | -------------------------------------------------------------------------------- /conf/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /conf/routes: -------------------------------------------------------------------------------- 1 | # Routes 2 | # This file defines all application routes (Higher priority routes first) 3 | # https://www.playframework.com/documentation/latest/ScalaRouting 4 | # ~~~~ 5 | 6 | # An example controller showing a sample home page 7 | GET /alive controllers.HealthController.alive 8 | GET / controllers.ContextualController.index 9 | GET /install controllers.ContextualController.install 10 | GET /usage controllers.ContextualController.usage 11 | GET /vendors controllers.ContextualController.vendors 12 | GET /sdks controllers.ContextualController.sdks 13 | GET /jdks controllers.ContextualController.jdks 14 | GET /contributors controllers.ContextualController.contributors 15 | 16 | # Map static resources from the /public folder to the /assets URL path 17 | GET /assets/*file controllers.Assets.at(path="/public", file: String) 18 | -------------------------------------------------------------------------------- /libexec/sbt-launch.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdkman/sdkman-website-playframework/062523cd309629c59d3826e458ce87d2e7be132b/libexec/sbt-launch.jar -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.4.9 2 | -------------------------------------------------------------------------------- /project/metals.sbt: -------------------------------------------------------------------------------- 1 | // format: off 2 | // DO NOT EDIT! This file is auto-generated. 3 | 4 | // This file enables sbt-bloop to create bloop config files. 5 | 6 | addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.5.17") 7 | 8 | // format: on 9 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.8") 2 | addSbtPlugin("org.foundweekends.giter8" % "sbt-giter8-scaffold" % "0.11.0") 3 | addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.9.1") 4 | addSbtPlugin("com.github.sbt" % "sbt-git" % "2.0.1") 5 | -------------------------------------------------------------------------------- /public/css/carbon.css: -------------------------------------------------------------------------------- 1 | #carbonads { 2 | display: block; 3 | overflow: hidden; 4 | padding: 1em; 5 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; 6 | max-width: 400px; 7 | } 8 | 9 | #carbonads a { 10 | text-decoration: none; 11 | } 12 | 13 | #carbonads span { 14 | position: relative; 15 | display: block; 16 | overflow: hidden; 17 | } 18 | 19 | .carbon-img { 20 | float: right; 21 | margin-left: 1em; 22 | } 23 | 24 | .carbon-img img { 25 | display: block; 26 | } 27 | 28 | .carbon-text { 29 | display: block; 30 | line-height: 1.4; 31 | max-width: calc(100% - 130px - 1em); 32 | text-align: right; 33 | font-size: 14px; 34 | } 35 | 36 | .carbon-poweredby { 37 | position: absolute; 38 | right: calc(130px + 1rem); 39 | bottom: 0; 40 | display: block; 41 | font-size: 10px; 42 | text-transform: uppercase; 43 | line-height: 1; 44 | letter-spacing: 1px; 45 | } 46 | 47 | .carbon-band { 48 | display: flex; 49 | justify-content: flex-end; 50 | } -------------------------------------------------------------------------------- /public/css/prism-dark.min.css: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.29.0 2 | https://prismjs.com/download.html#themes=prism-okaidia&languages=bash+json */ 3 | code[class*=language-],pre[class*=language-]{color:#f8f8f2;background:0 0;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#272822}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8292a2}.token.punctuation{color:#f8f8f2}.token.namespace{opacity:.7}.token.constant,.token.deleted,.token.property,.token.symbol,.token.tag{color:#f92672}.token.boolean,.token.number{color:#ae81ff}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#a6e22e}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url,.token.variable{color:#f8f8f2}.token.atrule,.token.attr-value,.token.class-name,.token.function{color:#e6db74}.token.keyword{color:#66d9ef}.token.important,.token.regex{color:#fd971f}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help} 4 | -------------------------------------------------------------------------------- /public/css/prism.min.css: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.29.0 2 | https://prismjs.com/download.html#themes=prism&languages=bash+json */ 3 | code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help} 4 | -------------------------------------------------------------------------------- /public/img/bubble-logo-sdkman-groovy-color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdkman/sdkman-website-playframework/062523cd309629c59d3826e458ce87d2e7be132b/public/img/bubble-logo-sdkman-groovy-color.png -------------------------------------------------------------------------------- /public/img/bubble-logo-sdkman-groovy-color.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 28 | 31 | 32 | 39 | 43 | 45 | 47 | 49 | 52 | 55 | 56 | 57 | 67 | 69 | 72 | 74 | 77 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /public/img/chain-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdkman/sdkman-website-playframework/062523cd309629c59d3826e458ce87d2e7be132b/public/img/chain-web.png -------------------------------------------------------------------------------- /public/img/city.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdkman/sdkman-website-playframework/062523cd309629c59d3826e458ce87d2e7be132b/public/img/city.png -------------------------------------------------------------------------------- /public/img/crypton-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdkman/sdkman-website-playframework/062523cd309629c59d3826e458ce87d2e7be132b/public/img/crypton-web.png -------------------------------------------------------------------------------- /public/img/duke-thumbsup-comic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdkman/sdkman-website-playframework/062523cd309629c59d3826e458ce87d2e7be132b/public/img/duke-thumbsup-comic.png -------------------------------------------------------------------------------- /public/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdkman/sdkman-website-playframework/062523cd309629c59d3826e458ce87d2e7be132b/public/img/favicon.ico -------------------------------------------------------------------------------- /public/img/icons-comic-colset-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdkman/sdkman-website-playframework/062523cd309629c59d3826e458ce87d2e7be132b/public/img/icons-comic-colset-red.png -------------------------------------------------------------------------------- /public/img/icons-comic-colset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdkman/sdkman-website-playframework/062523cd309629c59d3826e458ce87d2e7be132b/public/img/icons-comic-colset.png -------------------------------------------------------------------------------- /public/img/logo-sdkman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdkman/sdkman-website-playframework/062523cd309629c59d3826e458ce87d2e7be132b/public/img/logo-sdkman.png -------------------------------------------------------------------------------- /public/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdkman/sdkman-website-playframework/062523cd309629c59d3826e458ce87d2e7be132b/public/img/logo.png -------------------------------------------------------------------------------- /public/img/sdk-man-small-pattern.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdkman/sdkman-website-playframework/062523cd309629c59d3826e458ce87d2e7be132b/public/img/sdk-man-small-pattern.jpg -------------------------------------------------------------------------------- /public/img/sdk-man-small-pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdkman/sdkman-website-playframework/062523cd309629c59d3826e458ce87d2e7be132b/public/img/sdk-man-small-pattern.png -------------------------------------------------------------------------------- /public/img/sdk-man-small-pattern.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 32 | 33 | 40 | 44 | 46 | 48 | 50 | 53 | 56 | 57 | 60 | 61 | 71 | 73 | 75 | 77 | 80 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /public/img/sdkman-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdkman/sdkman-website-playframework/062523cd309629c59d3826e458ce87d2e7be132b/public/img/sdkman-web.png -------------------------------------------------------------------------------- /public/js/plugins.js: -------------------------------------------------------------------------------- 1 | (function(){var e;var d=function(){};var b=["assert","clear","count","debug","dir","dirxml","error","exception","group","groupCollapsed","groupEnd","info","log","markTimeline","profile","profileEnd","table","time","timeEnd","timeStamp","trace","warn"];var c=b.length;var a=(window.console=window.console||{});while(c--){e=b[c];if(!a[e]){a[e]=d}}}()); -------------------------------------------------------------------------------- /public/js/vendor/prism.min.js: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.29.0 2 | https://prismjs.com/download.html#themes=prism&languages=bash+json */ 3 | var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(e){var n=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,r={},a={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof i?new i(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/=g.reach);A+=w.value.length,w=w.next){var E=w.value;if(n.length>e.length)return;if(!(E instanceof i)){var P,L=1;if(y){if(!(P=l(b,A,e,m))||P.index>=e.length)break;var S=P.index,O=P.index+P[0].length,j=A;for(j+=w.value.length;S>=j;)j+=(w=w.next).value.length;if(A=j-=w.value.length,w.value instanceof i)continue;for(var C=w;C!==n.tail&&(jg.reach&&(g.reach=W);var z=w.prev;if(_&&(z=u(n,z,_),A+=_.length),c(n,z,L),w=u(n,z,new i(f,p?a.tokenize(N,p):N,k,N)),M&&u(n,w,M),L>1){var I={cause:f+","+d,reach:W};o(e,n,t,w.prev,A,I),g&&I.reach>g.reach&&(g.reach=I.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function u(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function c(e,n,t){for(var r=n.next,a=0;a"+i.content+""},!e.document)return e.addEventListener?(a.disableWorkerMessageHandler||e.addEventListener("message",(function(n){var t=JSON.parse(n.data),r=t.language,i=t.code,l=t.immediateClose;e.postMessage(a.highlight(i,a.languages[r],r)),l&&e.close()}),!1),a):a;var g=a.util.currentScript();function f(){a.manual||a.highlightAll()}if(g&&(a.filename=g.src,g.hasAttribute("data-manual")&&(a.manual=!0)),!a.manual){var h=document.readyState;"loading"===h||"interactive"===h&&g&&g.defer?document.addEventListener("DOMContentLoaded",f):window.requestAnimationFrame?window.requestAnimationFrame(f):window.setTimeout(f,16)}return a}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); 4 | !function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",a={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},n={bash:a,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?:\.\w+)*(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},parameter:{pattern:/(^|\s)-{1,2}(?:\w+:[+-]?)?\w+(?:\.\w+)*(?=[=\s]|$)/,alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:n},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:a}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:n},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:n.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:n.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cargo|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|java|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|sysctl|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},a.inside=e.languages.bash;for(var s=["comment","function-name","for-or-select","assign-left","parameter","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],o=n.variable[1].inside,i=0;i