├── .gitattributes
├── .github
├── dependabot.yml
└── workflows
│ ├── codeql.yml
│ ├── dependency-review-action.yml
│ ├── dependency-submission.yml
│ ├── gradle.yml
│ └── submit-dependency-graph.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── docs
└── plugin-release-process.md
├── foojay-resolver
├── build.gradle.kts
├── gradle.properties
├── release-notes-1.0.0.txt
└── src
│ ├── functionalTest
│ └── kotlin
│ │ └── org
│ │ └── gradle
│ │ └── toolchains
│ │ └── foojay
│ │ ├── AbstractFoojayToolchainsPluginFunctionalTest.kt
│ │ ├── FoojayToolchainsConventionPluginFunctionalTest.kt
│ │ ├── FoojayToolchainsPluginFunctionalTest.kt
│ │ └── gradleVersions.kt
│ ├── main
│ └── kotlin
│ │ └── org
│ │ └── gradle
│ │ └── toolchains
│ │ └── foojay
│ │ ├── AbstractFoojayToolchainPlugin.kt
│ │ ├── FoojayApi.kt
│ │ ├── FoojayToolchainResolver.kt
│ │ ├── FoojayToolchainsConventionPlugin.kt
│ │ ├── FoojayToolchainsPlugin.kt
│ │ ├── distributions.kt
│ │ └── packages.kt
│ └── test
│ └── kotlin
│ └── org
│ └── gradle
│ └── toolchains
│ └── foojay
│ └── FoojayApiTest.kt
├── gradle.properties
├── gradle
├── detekt.yml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle.kts
/.gitattributes:
--------------------------------------------------------------------------------
1 | #
2 | # https://help.github.com/articles/dealing-with-line-endings/
3 | #
4 | # Linux start script should use lf
5 | /gradlew text eol=lf
6 |
7 | # These are Windows script files and should use crlf
8 | *.bat text eol=crlf
9 |
10 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "gradle"
9 | directory: "/"
10 | schedule:
11 | interval: "daily"
12 | - package-ecosystem: "github-actions"
13 | directory: "/"
14 | schedule:
15 | interval: "daily"
16 | labels:
17 | - "@dev-productivity"
18 |
--------------------------------------------------------------------------------
/.github/workflows/codeql.yml:
--------------------------------------------------------------------------------
1 | name: "CodeQL Advanced"
2 |
3 | on:
4 | push:
5 | branches: [ "main" ]
6 | pull_request:
7 | branches: [ "main" ]
8 | schedule:
9 | - cron: '17 18 * * 2'
10 |
11 | jobs:
12 | analyze:
13 | name: Analyze (${{ matrix.language }})
14 | # Runner size impacts CodeQL analysis time. To learn more, please see:
15 | # - https://gh.io/recommended-hardware-resources-for-running-codeql
16 | # - https://gh.io/supported-runners-and-hardware-resources
17 | # - https://gh.io/using-larger-runners (GitHub.com only)
18 | # Consider using larger runners or machines with greater resources for possible analysis time improvements.
19 | runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
20 | permissions:
21 | # required for all workflows
22 | security-events: write
23 | # required to fetch internal or private CodeQL packs
24 | packages: read
25 | strategy:
26 | fail-fast: false
27 | matrix:
28 | include:
29 | - language: actions
30 | build-mode: none
31 | - language: java-kotlin
32 | build-mode: autobuild
33 | # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
34 | # Use `c-cpp` to analyze code written in C, C++ or both
35 | # Use 'java-kotlin' to analyze code written in Java, Kotlin or both
36 | # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
37 | # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
38 | # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
39 | # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
40 | # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
41 | steps:
42 | - name: Checkout repository
43 | uses: actions/checkout@v4
44 | - name: Setup Java
45 | uses: actions/setup-java@v4
46 | with:
47 | java-version: '17'
48 | distribution: 'temurin'
49 | - name: Setup Gradle
50 | uses: gradle/actions/setup-gradle@v4
51 | # Initializes the CodeQL tools for scanning.
52 | - name: Initialize CodeQL
53 | uses: github/codeql-action/init@v3
54 | with:
55 | languages: ${{ matrix.language }}
56 | build-mode: ${{ matrix.build-mode }}
57 | # If you wish to specify custom queries, you can do so here or in a config file.
58 | # By default, queries listed here will override any specified in a config file.
59 | # Prefix the list here with "+" to use these queries and those in the config file.
60 |
61 | # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
62 | # queries: security-extended,security-and-quality
63 |
64 | - name: Perform CodeQL Analysis
65 | uses: github/codeql-action/analyze@v3
66 | with:
67 | category: "/language:${{matrix.language}}"
68 |
--------------------------------------------------------------------------------
/.github/workflows/dependency-review-action.yml:
--------------------------------------------------------------------------------
1 | name: Dependency review for pull requests
2 |
3 | on:
4 | workflow_dispatch:
5 | pull_request:
6 |
7 | permissions:
8 | contents: write
9 | id-token: write
10 |
11 | jobs:
12 | dependency-submission:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - name: Configure AWS credentials
16 | uses: aws-actions/configure-aws-credentials@v4
17 | with:
18 | role-to-assume: arn:aws:iam::992382829881:role/GHASecrets_foojay-toolchains_all
19 | aws-region: "eu-central-1"
20 | - name: Get secrets
21 | uses: aws-actions/aws-secretsmanager-get-secrets@v2
22 | with:
23 | secret-ids: |
24 | DEVELOCITY_ACCESS_KEY, gha/foojay-toolchains/_all/DEVELOCITY_ACCESS_KEY
25 | - uses: actions/checkout@v4
26 | - uses: actions/setup-java@v4
27 | with:
28 | distribution: temurin
29 | java-version: 21
30 |
31 | - name: Generate and submit dependency graph
32 | uses: gradle/actions/dependency-submission@v4
33 |
34 | - name: Perform dependency review
35 | uses: actions/dependency-review-action@v4
36 |
--------------------------------------------------------------------------------
/.github/workflows/dependency-submission.yml:
--------------------------------------------------------------------------------
1 | name: Generate and save dependency graph
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | branches:
7 | - main
8 | pull_request:
9 |
10 | permissions:
11 | contents: read
12 | id-token: write
13 |
14 | jobs:
15 | dependency-submission:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - name: Configure AWS credentials
19 | uses: aws-actions/configure-aws-credentials@v4
20 | with:
21 | role-to-assume: arn:aws:iam::992382829881:role/GHASecrets_foojay-toolchains_all
22 | aws-region: "eu-central-1"
23 | - name: Get secrets
24 | uses: aws-actions/aws-secretsmanager-get-secrets@v2
25 | with:
26 | secret-ids: |
27 | DEVELOCITY_ACCESS_KEY, gha/foojay-toolchains/_all/DEVELOCITY_ACCESS_KEY
28 | - name: Checkout sources
29 | uses: actions/checkout@v4
30 | - name: Setup Java
31 | uses: actions/setup-java@v4
32 | with:
33 | distribution: 'temurin'
34 | java-version: 21
35 | - name: Generate and save dependency graph
36 | uses: gradle/actions/dependency-submission@v4
37 | with:
38 | dependency-graph: generate-and-upload
39 |
--------------------------------------------------------------------------------
/.github/workflows/gradle.yml:
--------------------------------------------------------------------------------
1 | # This workflow uses actions that are not certified by GitHub.
2 | # They are provided by a third-party and are governed by
3 | # separate terms of service, privacy policy, and support
4 | # documentation.
5 | # This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
6 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle
7 |
8 | name: Build with Gradle
9 |
10 | on:
11 | push:
12 | branches:
13 | - "main"
14 | pull_request:
15 | branches:
16 | - "main"
17 | workflow_dispatch:
18 |
19 | permissions:
20 | contents: read
21 | id-token: write
22 |
23 | jobs:
24 | build:
25 | runs-on: ubuntu-latest
26 | steps:
27 | - name: Configure AWS credentials
28 | uses: aws-actions/configure-aws-credentials@v4
29 | with:
30 | role-to-assume: arn:aws:iam::992382829881:role/GHASecrets_foojay-toolchains_all
31 | aws-region: "eu-central-1"
32 | - name: Get secrets
33 | uses: aws-actions/aws-secretsmanager-get-secrets@v2
34 | with:
35 | secret-ids: |
36 | DEVELOCITY_ACCESS_KEY, gha/foojay-toolchains/_all/DEVELOCITY_ACCESS_KEY
37 | - id: determine-sys-prop-args
38 | uses: actions/github-script@v7
39 | with:
40 | script: |
41 | if (context.payload.pull_request && context.payload.pull_request.head.repo.fork) {
42 | core.setOutput('sys-prop-args', '-DagreePublicBuildScanTermOfService=yes -DcacheNode=us --scan')
43 | } else {
44 | core.setOutput('sys-prop-args', '-DcacheNode=us')
45 | }
46 | - uses: actions/checkout@v4
47 | - name: Setup Java
48 | uses: actions/setup-java@v4
49 | with:
50 | java-version: '17'
51 | distribution: 'temurin'
52 | - name: Setup Gradle
53 | uses: gradle/actions/setup-gradle@v4
54 | - run: ./gradlew build ${{ steps.determine-sys-prop-args.outputs.sys-prop-args }}
55 |
--------------------------------------------------------------------------------
/.github/workflows/submit-dependency-graph.yml:
--------------------------------------------------------------------------------
1 | name: Download and submit dependency graph
2 |
3 | on:
4 | workflow_run:
5 | workflows: ['Generate and save dependency graph']
6 | types: [completed]
7 |
8 | permissions:
9 | actions: read
10 | contents: write
11 |
12 | jobs:
13 | submit-dependency-graph:
14 | runs-on: ubuntu-latest
15 | steps:
16 | - name: Download and submit dependency graph
17 | uses: gradle/actions/dependency-submission@v4
18 | with:
19 | dependency-graph: download-and-submit
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | *.jar
15 | *.war
16 | *.nar
17 | *.ear
18 | *.zip
19 | *.tar.gz
20 | *.rar
21 |
22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
23 | hs_err_pid*
24 |
25 | # Ignore Gradle project-specific cache directory
26 | .gradle
27 |
28 | # Ignore Gradle build output directory
29 | build
30 |
31 | # Ignore IntelliJ IDEA folder
32 | .idea
33 |
34 | # Ignore local publishing repo for testing plugin
35 | foojay-resolver/repo/
36 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## [Unreleased]
4 |
5 | ### Added
6 |
7 | ### Changed
8 |
9 | ### Deprecated
10 |
11 | ### Removed
12 |
13 | ### Fixed
14 |
15 | ### Security
16 |
17 | ## [1.0.0] - 2025-05-19
18 |
19 | ### Changed
20 |
21 | - Plugin now compiled with Java 17, meaning it requires that version or higher to run
22 | - Removed direct references to deprecated JvmVendorSpec.IBM_SEMERU, to prepare for Gradle 9 compatibility.
23 | - Implementation dependencies are now shaded to reduce potential conflicts with other plugins
24 |
25 | ## [0.10.0] - 2025-04-08
26 |
27 | ### Added
28 |
29 | - Support the nativeImageCapable criteria from JavaToolchainSpec in Gradle 8.14+
30 |
31 | ## [0.9.0] - 2024-11-26
32 |
33 | ### Added
34 |
35 | - Provide an x86-64 based Java version when ARM64 is requested from macOS and none is available
36 |
37 | ## [0.8.0] - 2024-01-12
38 |
39 | ### Changed
40 |
41 | - Bump Gson dependency version
42 |
43 | ### Fixed
44 |
45 | - Fix issues related to Java version parameter
46 |
47 | ## [0.7.0] - 2023-08-17
48 |
49 | ### Added
50 |
51 | - Provide meaningful error message when plugin is applied in a build script (instead of the settings script)
52 |
53 | ## [0.6.0] - 2023-07-10
54 |
55 | ### Added
56 |
57 | - Add support for new GraalVM Community distributions
58 |
59 | ## [0.5.0] - 2023-04-24
60 |
61 | ### Added
62 |
63 | - Generate useful error message if used with unsupported Gradle versions
64 |
65 | ## [0.4.0] - 2022-12-22
66 |
67 | ### Added
68 |
69 | - Try distributions one-by-one if no vendor is specified
70 |
71 | ## [0.3.0] - 2022-12-22
72 |
73 | ### Fixed
74 |
75 | - Make sure vendors IBM and IBM_SEMERU are handled identically
76 |
77 | ## [0.2] - 2022-11-29
78 |
79 | ### Added
80 |
81 | - Make the plugin compatible with Java 8
82 |
83 | ## [0.1] - 2022-11-28
84 |
85 | Toolchains resolver using the Foojay Disco API for resolving Java runtimes. Automatically configures toolchain management.
86 |
87 |
88 |
89 | [Unreleased]: https://github.com/gradle/foojay-toolchains/compare/foojay-toolchains-plugin-1.0.0...HEAD
90 | [1.0.0]: https://github.com/gradle/foojay-toolchains/releases/tag/foojay-toolchains-plugin-1.0.0
91 | [0.10.0]: https://github.com/gradle/foojay-toolchains/releases/tag/foojay-toolchains-plugin-0.10.0
92 | [0.9.0]: https://github.com/gradle/foojay-toolchains/releases/tag/foojay-toolchains-plugin-0.9.0
93 | [0.8.0]: https://github.com/gradle/foojay-toolchains/releases/tag/foojay-toolchains-plugin-0.8.0
94 | [0.7.0]: https://github.com/gradle/foojay-toolchains/releases/tag/foojay-toolchains-plugin-0.7.0
95 | [0.6.0]: https://github.com/gradle/foojay-toolchains/releases/tag/foojay-toolchains-plugin-0.6.0
96 | [0.5.0]: https://github.com/gradle/foojay-toolchains/releases/tag/foojay-toolchains-plugin-0.5.0
97 | [0.4.0]: https://github.com/gradle/foojay-toolchains/releases/tag/foojay-toolchains-plugin-0.4.0
98 | [0.3.0]: https://github.com/gradle/foojay-toolchains/releases/tag/foojay-toolchains-plugin-0.3.0
99 | [0.2]: https://github.com/gradle/foojay-toolchains/releases/tag/foojay-toolchain-plugin-0.2
100 | [0.1]: https://github.com/gradle/foojay-toolchains/releases/tag/foojay-toolchain-plugin-0.1
101 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Foojay Toolchains Plugin
2 |
3 | The `org.gradle.toolchains.foojay-resolver` plugin provides a [repository for downloading JVMs](https://docs.gradle.org/current/userguide/toolchains.html#sub:download_repositories).
4 |
5 | It is based on the [foojay DiscoAPI](https://github.com/foojayio/discoapi), therefore, the [foojay API's Swagger UI](https://api.foojay.io/swagger-ui) can be used to explore what distributions are available.
6 | See the [Matching Toolchain Specifications](#matching-toolchain-specifications) section below for how to select specific distributions.
7 |
8 | > **TAKE HEED!**
9 | >
10 | > Requires Gradle **7.6 or later** to work.
11 | >
12 | > As opposed to most of the Gradle plugins, which are Project plugins
13 | > and must be applied in `build.gradle[.kts]` files, this is a **SETTINGS PLUGIN** and
14 | > must be applied in `settings.gradle[.kts]` files.
15 |
16 | > [!NOTE]
17 | > Versions prior to 1.0.0 require Java 8 or later and Gradle 7.6 or later.
18 | > Versions 1.0.0 and after require Java 17 or later and Gradle 7.6 or later.
19 |
20 | # Usage
21 |
22 | To make use of the plugin add following to your `settings.gradle[.kts]` file.
23 |
24 |
25 |
26 | Kotlin DSL
27 |
28 | ```kotlin
29 | // settings.gradle.kts
30 | plugins {
31 | id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
32 | }
33 | ```
34 |
35 |
36 |
37 |
38 |
39 | Groovy DSL
40 |
41 | ```groovy
42 | // settings.gradle
43 | plugins {
44 | id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
45 | }
46 | ```
47 |
48 |
49 |
50 | This is a convention plugin meant to simplify configuration.
51 | What it does is equivalent to applying the base plugin and some extra configuration:
52 |
53 |
54 |
55 | Kotlin DSL
56 |
57 | ```kotlin
58 | // settings.gradle.kts
59 | plugins {
60 | id("org.gradle.toolchains.foojay-resolver") version "1.0.0"
61 | }
62 |
63 | toolchainManagement {
64 | jvm {
65 | javaRepositories {
66 | repository("foojay") {
67 | resolverClass.set(org.gradle.toolchains.foojay.FoojayToolchainResolver::class.java)
68 | }
69 | }
70 | }
71 | }
72 | ```
73 |
74 |
75 |
76 |
77 |
78 | Groovy DSL
79 |
80 | ```groovy
81 | // settings.gradle
82 | plugins {
83 | id("org.gradle.toolchains.foojay-resolver") version "1.0.0"
84 | }
85 |
86 | toolchainManagement {
87 | jvm {
88 | javaRepositories {
89 | repository("foojay") {
90 | resolverClass = org.gradle.toolchains.foojay.FoojayToolchainResolver
91 | }
92 | }
93 | }
94 | }
95 | ```
96 |
97 |
98 |
99 | Feel free to use either approach.
100 |
101 | For further information about using Toolchain Download Repositories consult the [Gradle Manual](https://docs.gradle.org/current/userguide/toolchains.html#sub:download_repositories).
102 |
103 | # Matching Toolchain Specifications
104 |
105 | The main thing the plugin does is to match [Gradle's toolchain specifications](https://docs.gradle.org/current/javadoc/org/gradle/jvm/toolchain/JavaToolchainSpec.html) to foojay DiscoAPI distributions and packages.
106 |
107 | ## `nativeImageCapable` criteria
108 |
109 | When set, it is used to filter out distributions that are not capable of creating native images with GraalVM.
110 |
111 | ## Vendors
112 |
113 | There is mostly a 1-to-1 relationship between the DiscoAPI's distributions and [Gradle vendors](https://docs.gradle.org/current/userguide/toolchains.html#sec:vendors).
114 | The plugin works with the following mapping:
115 |
116 | | Gradle JVM Vendor | Foojay Distribution |
117 | |-------------------|---------------------------|
118 | | ADOPTIUM | Temurin |
119 | | ADOPTOPENJDK | AOJ |
120 | | AMAZON | Corretto |
121 | | APPLE | - |
122 | | AZUL | Zulu |
123 | | BELLSOFT | Liberica |
124 | | GRAAL_VM | Graal VM CE 8/11/16/17/19 |
125 | | HEWLETT_PACKARD | - |
126 | | IBM | Semeru |
127 | | IBM_SEMERU* | Semeru |
128 | | JETBRAINS | JetBrains |
129 | | MICROSOFT | Microsoft |
130 | | ORACLE | Oracle OpenJDK |
131 | | SAP | SAP Machine |
132 |
133 | **To note:**
134 | Not all Gradle vendors have an equivalent DiscoAPI distribution, empty cells indicate that no toolchain will be provisioned.
135 | If no vendor is specified, distributions are iterated in the order they are provided by the DiscoAPI, and the first one that has a compatible installation package available is selected.
136 | The exception to the Foojay ordering of distributions is that "Temurin" (ADOPTIUM) and then "AOJ" (ADOPTOPENJDK) come first, due to the history of the auto-provisioning feature in Gradle, specifically that AdoptOpenJDK/Adoptium have been the default sources for downloading JVMs.
137 |
138 | > [!WARNING]
139 | > `IBM_SEMERU` is deprecated in Gradle for a while and removed in Gradle 9+.
140 |
141 | ## Implementations
142 |
143 | When specifying toolchains Gradle distinguishes between `J9` JVMs and `VENDOR_SPECIFIC` ones (ie. any other).
144 | What this criteria does in the plugin is to influence the Vendor-to-Distribution matching table.
145 | `VENDOR_SPECIFICATION` doesn't change it at all, while `J9` alter it like this:
146 |
147 | | Gradle JVM Vendor | Foojay Distribution |
148 | |-------------------------|---------------------|
149 | | \ | Semeru |
150 | | ADOPTIUM | - |
151 | | ADOPTOPENJDK | AOJ OpenJ9 |
152 | | AMAZON | - |
153 | | APPLE | - |
154 | | AZUL | - |
155 | | BELLSOFT | - |
156 | | GRAAL_VM | - |
157 | | HEWLETT_PACKARD | - |
158 | | IBM | Semeru |
159 | | IBM_SEMERU* | Semeru |
160 | | JETBRAINS | - |
161 | | MICROSOFT | - |
162 | | ORACLE | - |
163 | | SAP | - |
164 |
165 | Empty cells indicate that no toolchain will be provisioned
166 |
167 | > [!WARNING]
168 | > `IBM_SEMERU` is deprecated in Gradle for a while and removed in Gradle 9+.
169 |
170 | ## Versions
171 |
172 | Once the vendor and the implementation values of the toolchain spec have been used to select a DiscoAPI distribution, a specific package of that distribution needs to be picked by the plugin, in order for it to obtain a download link.
173 | The inputs it uses to do this are:
174 | * the major **Java version** number for the spec
175 | * the **operating system** running the build that made the request
176 | * the **CPU architecture** of the system running the build that made the request
177 |
178 | Additional criteria used for selection:
179 | * for each major version number only packages having the latest minor version will be considered
180 | * only packages containing an archive of a format known to Gradle will be considered (zip, tar, tgz)
181 | * JDKs have priority over JREs
182 |
--------------------------------------------------------------------------------
/docs/plugin-release-process.md:
--------------------------------------------------------------------------------
1 | # Foojay Toolchains Plugin (FTP) Release Process
2 |
3 | ## 1. Bump the plugin version number
4 |
5 | This should be the next version.
6 | Verify that it's higher than the version reported [in the portal](https://plugins.gradle.org/plugin/org.gradle.toolchains.foojay-resolver).
7 |
8 | This lives in [`foojay-resolver/gradle.properties`](https://github.com/gradle/foojay-toolchains/blob/main/foojay-resolver/gradle.properties).
9 |
10 |
11 | ## 2. Add some release notes
12 |
13 | You'll need to add a plain text file with name [`foojay-resolver/release-notes-${plugin-version}.txt`](https://github.com/gradle/foojay-toolchains/tree/main/foojay-resolver).
14 | Whatever you put here is what will appear in the portal for that version.
15 | E.g. for [0.2](https://plugins.gradle.org/plugin/org.gradle.toolchains.foojay-resolver/0.2) it was "- Make the plugin compatible with Java 8".
16 |
17 | *NOTE:* Only include new changes relative to the previously published version.
18 |
19 | Remove any old release notes files.
20 |
21 |
22 | ## 3. Update the CHANGELOG.md file
23 |
24 | On one hand it needs some content describing what is in the new release, can be the same as the release notes above.
25 | On the other hand it needs an entry towards the end of the file to specify which tag belongs to this new release.
26 | See previous content for reference.
27 |
28 |
29 | ## 4. Deploy to Dev Portal
30 |
31 | Use [this job](https://builds.gradle.org/buildConfiguration/Dotcom_PluginsPortal_DeployFoojayToolchainsPluginDevelopment?branch=%3Cdefault%3E&buildTypeTab=overview&mode=builds#all-projects) to deploy the plugin to the dev portal.
32 |
33 | Make sure it [looks ok](https://plugins.grdev.net/plugin/org.gradle.toolchains.foojay-resolver) in the portal and the release notes are formatted as you want them to be.
34 | Do the same check for the [convention version](https://plugins.grdev.net/plugin/org.gradle.toolchains.foojay-resolver-convention) too.
35 |
36 | If you need to make changes, you'll need to delete the published version from the portal before you try again.
37 | Just use the big red "Delete version X" button of the [portal page](https://plugins.grdev.net/plugin/org.gradle.toolchains.foojay-resolver).
38 | Don't forget about the [convention version](https://plugins.grdev.net/plugin/org.gradle.toolchains.foojay-resolver-convention) either.
39 |
40 |
41 | ## 5. Deploy to Prod Portal
42 |
43 | Use [this job](https://builds.gradle.org/buildConfiguration/Dotcom_PluginsPortal_DeployFoojayToolchainsPluginProduction?branch=%3Cdefault%3E&buildTypeTab=overview&mode=builds#all-projects) to deploy the plugin to the production portal.
44 |
45 | Make sure it [looks ok](https://plugins.gradle.org/plugin/org.gradle.toolchains.foojay-resolver) in the portal and the release notes are formatted as you want them to be.
46 | Check the [convention version](https://plugins.gradle.org/plugin/org.gradle.toolchains.foojay-resolver-convention) too.
47 |
48 |
49 | ## 6. Tag the release
50 |
51 | We don't have any automated tagging, but please manually tag the current master and push it in, e.g.:
52 |
53 | git tag foojay-toolchains-plugin-1.0
54 | git push origin main --tags
55 |
56 |
57 | ## 7. Notify anyone waiting for a fix
58 |
59 |
60 | ## 8. Bump the development version of the plugin
61 |
62 | - Increment the version in [`foojay-resolver/gradle.properties`](https://github.com/gradle/foojay-toolchains/blob/main/foojay-resolver/gradle.properties).
63 | - Update all usages of the previous version in [`the project`](https://github.com/gradle/foojay-toolchains/)
64 |
--------------------------------------------------------------------------------
/foojay-resolver/build.gradle.kts:
--------------------------------------------------------------------------------
1 | @file:Suppress("UnusedPrivateProperty", "UnstableApiUsage")
2 |
3 | import java.io.FileNotFoundException
4 |
5 | plugins {
6 | `kotlin-dsl`
7 | signing
8 | id("com.gradle.plugin-publish") version "1.3.1"
9 | id("io.gitlab.arturbosch.detekt") version "1.23.8"
10 | id("com.gradleup.shadow") version "8.3.6"
11 | }
12 |
13 | group = "org.gradle.toolchains"
14 | val pluginVersion = property("pluginVersion") ?: throw GradleException("`pluginVersion` missing in gradle.properties!")
15 | version = pluginVersion
16 |
17 | // This value is used both for toolchain and for configuration attributes
18 | val jvmVersion = 17
19 |
20 | java {
21 | toolchain {
22 | languageVersion = JavaLanguageVersion.of(jvmVersion)
23 | }
24 | }
25 |
26 | tasks.shadowJar {
27 | isEnableRelocation = true
28 | archiveClassifier = ""
29 | minimize()
30 |
31 | // Clean up some of the unwanted files from gson shading
32 | includeEmptyDirs = false
33 | exclude("**/module-info.class")
34 | exclude("META-INF/maven/**")
35 | }
36 |
37 | detekt {
38 | buildUponDefaultConfig = true // preconfigure defaults
39 | config.setFrom(project.rootProject.file("gradle/detekt.yml"))
40 |
41 | // also check the project build file
42 | source.from(project.buildFile)
43 | }
44 |
45 | dependencies {
46 | implementation("com.google.code.gson:gson:2.13.1")
47 | }
48 |
49 | gradlePlugin {
50 | vcsUrl = "https://github.com/gradle/foojay-toolchains"
51 | website = "https://github.com/gradle/foojay-toolchains"
52 |
53 | val discoToolchains by plugins.creating {
54 | id = "org.gradle.toolchains.foojay-resolver"
55 | implementationClass = "org.gradle.toolchains.foojay.FoojayToolchainsPlugin"
56 | displayName = "Foojay Disco API Toolchains Resolver"
57 | description = "Toolchains resolver using the Foojay Disco API for resolving Java runtimes."
58 | tags = listOf("gradle", "toolchains")
59 | }
60 |
61 | val discoToolchainsConvenience by plugins.creating {
62 | id = "org.gradle.toolchains.foojay-resolver-convention"
63 | implementationClass = "org.gradle.toolchains.foojay.FoojayToolchainsConventionPlugin"
64 | displayName = "Foojay Disco API Toolchains Resolver Convention"
65 | description = "Toolchains resolver using the Foojay Disco API for resolving Java runtimes. Automatically configures toolchain management."
66 | tags = listOf("gradle", "toolchains")
67 | }
68 |
69 | }
70 |
71 | publishing {
72 | repositories {
73 | maven {
74 | url = uri(layout.projectDirectory.dir("repo"))
75 | }
76 | }
77 | }
78 |
79 | signing {
80 | useInMemoryPgpKeys(
81 | project.providers.environmentVariable("PGP_SIGNING_KEY").orNull,
82 | project.providers.environmentVariable("PGP_SIGNING_KEY_PASSPHRASE").orNull
83 | )
84 |
85 | setRequired({
86 | providers.environmentVariable("CI").isPresent
87 | })
88 | }
89 |
90 | testing {
91 | suites {
92 | val functionalTest by registering(JvmTestSuite::class) {
93 | dependencies {
94 | implementation("org.jetbrains.kotlin:kotlin-test-junit5")
95 | }
96 | }
97 | val test by getting(JvmTestSuite::class) {
98 | useJUnitJupiter()
99 | dependencies {
100 | implementation("org.jetbrains.kotlin:kotlin-test-junit5")
101 | }
102 | }
103 | }
104 | }
105 |
106 | gradlePlugin.testSourceSets(sourceSets.getAt("functionalTest"))
107 |
108 | tasks.check {
109 | // Run the functional tests as part of `check`
110 | dependsOn(testing.suites.named("functionalTest"))
111 | }
112 |
113 | val readReleaseNotes by tasks.registering {
114 | notCompatibleWithConfigurationCache("This task modifies other tasks")
115 | description = "Ensure we've got some release notes handy"
116 | doLast {
117 | val releaseNotesFile = file("release-notes-$version.txt")
118 | if (!releaseNotesFile.exists()) {
119 | throw FileNotFoundException("Couldn't find release notes file ${releaseNotesFile.absolutePath}")
120 | }
121 | val releaseNotes = releaseNotesFile.readText().trim()
122 | require(!releaseNotes.isBlank()) { "Release notes file ${releaseNotesFile.absolutePath} is empty" }
123 | gradlePlugin.plugins["discoToolchains"].description = releaseNotes
124 | gradlePlugin.plugins["discoToolchainsConvenience"].description = releaseNotes
125 | }
126 | }
127 |
128 | tasks.publishPlugins {
129 | notCompatibleWithConfigurationCache("This task still has a project reference")
130 | dependsOn(readReleaseNotes)
131 | }
132 |
133 | tasks.check {
134 | dependsOn(tasks.named("detektMain"), tasks.named("detektTest"), tasks.named("detektFunctionalTest"))
135 | }
136 |
137 | configurations.named("shadowRuntimeElements") {
138 | attributes {
139 | attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, jvmVersion)
140 | attribute(TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE, objects.named(TargetJvmEnvironment.STANDARD_JVM))
141 | attribute(GradlePluginApiVersion.GRADLE_PLUGIN_API_VERSION_ATTRIBUTE, objects.named("7.6"))
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/foojay-resolver/gradle.properties:
--------------------------------------------------------------------------------
1 | pluginVersion=1.1.0
--------------------------------------------------------------------------------
/foojay-resolver/release-notes-1.0.0.txt:
--------------------------------------------------------------------------------
1 | - Plugin now compiled with Java 17, meaning it requires that version or higher to run
2 | - Removed direct references to deprecated JvmVendorSpec.IBM_SEMERU, to prepare for Gradle 9 compatibility.
3 | - Implementation dependencies are now shaded to reduce potential conflicts with other plugins
--------------------------------------------------------------------------------
/foojay-resolver/src/functionalTest/kotlin/org/gradle/toolchains/foojay/AbstractFoojayToolchainsPluginFunctionalTest.kt:
--------------------------------------------------------------------------------
1 | package org.gradle.toolchains.foojay
2 |
3 | import org.gradle.testkit.runner.BuildResult
4 | import org.gradle.testkit.runner.GradleRunner
5 | import org.gradle.testkit.runner.TaskOutcome
6 | import org.junit.jupiter.api.BeforeEach
7 | import org.junit.jupiter.api.io.TempDir
8 | import java.io.File
9 | import kotlin.test.assertTrue
10 |
11 | abstract class AbstractFoojayToolchainsPluginFunctionalTest {
12 |
13 | @field:TempDir
14 | protected lateinit var projectDir: File
15 |
16 | @field:TempDir
17 | protected lateinit var homeDir: File
18 |
19 | private val settingsFile by lazy { projectDir.resolve("settings.gradle.kts") }
20 | private val propertiesFile by lazy { projectDir.resolve("gradle.properties") }
21 | private val buildFile by lazy { projectDir.resolve("build.gradle.kts") }
22 | private val sourceFolder by lazy { projectDir.resolve("src/main/java/") }
23 |
24 | @BeforeEach
25 | internal fun setUp() {
26 | propertiesFile.writeText("""
27 | org.gradle.java.installations.auto-detect=false
28 | org.gradle.java.installations.auto-download=true
29 | """.trimIndent())
30 | }
31 |
32 | protected fun runner(settings: String, buildScript: String): GradleRunner {
33 | settingsFile.writeText(settings)
34 | buildFile.writeText(buildScript.trimIndent())
35 |
36 | sourceFolder.mkdirs()
37 | val sourceFile = File(sourceFolder, "Java.java")
38 | sourceFile.writeText("""
39 | public class Java {
40 | public static void main(String[] args) {
41 | System.out.println();
42 | }
43 | }
44 | """.trimIndent())
45 |
46 | return GradleRunner.create()
47 | .forwardOutput()
48 | .withPluginClasspath()
49 | .withArguments(listOf("--info", "-g", homeDir.absolutePath, "compileJava"))
50 | .withProjectDir(projectDir)
51 | }
52 |
53 | protected fun getDifferentJavaVersion() = when {
54 | System.getProperty("java.version").startsWith("11.") -> "16"
55 | else -> "11"
56 | }
57 |
58 | protected fun assertProvisioningSuccessful(buildResult: BuildResult) {
59 | val successfulTasks = buildResult.tasks(TaskOutcome.SUCCESS)
60 | assertTrue(":compileJava" in successfulTasks.map { it.path })
61 | }
62 |
63 | protected companion object {
64 | @JvmStatic
65 | @Suppress("MagicNumber")
66 | fun getGradleTestVersions(): List {
67 | val versions = GradleTestVersions.getVersions()
68 | val latestVersions = versions.take(3)
69 | val oldestVersion = versions.takeLast(1)
70 | return latestVersions + oldestVersion // compromise, testing takes too long with all versions
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/foojay-resolver/src/functionalTest/kotlin/org/gradle/toolchains/foojay/FoojayToolchainsConventionPluginFunctionalTest.kt:
--------------------------------------------------------------------------------
1 | package org.gradle.toolchains.foojay
2 |
3 | import org.junit.jupiter.params.ParameterizedTest
4 | import org.junit.jupiter.params.provider.MethodSource
5 | import kotlin.test.Test
6 | import kotlin.test.assertTrue
7 |
8 | class FoojayToolchainsConventionPluginFunctionalTest: AbstractFoojayToolchainsPluginFunctionalTest() {
9 |
10 | @ParameterizedTest(name = "gradle version: {0}")
11 | @MethodSource("getGradleTestVersions")
12 | fun `can use convention plugin`(gradleVersion: String) {
13 | val settings = """
14 | plugins {
15 | id("org.gradle.toolchains.foojay-resolver-convention")
16 | }
17 | """.trimIndent()
18 |
19 | val buildScript = """
20 | plugins {
21 | java
22 | }
23 |
24 | java {
25 | toolchain {
26 | languageVersion.set(JavaLanguageVersion.of(${getDifferentJavaVersion()}))
27 | }
28 | }
29 | """
30 | val result = runner(settings, buildScript)
31 | .withGradleVersion(gradleVersion)
32 | .build()
33 | assertProvisioningSuccessful(result)
34 | }
35 |
36 | @Test
37 | fun `generates useful error for unsupported Gradle versions`() {
38 | val settings = """
39 | plugins {
40 | id("org.gradle.toolchains.foojay-resolver-convention")
41 | }
42 | """.trimIndent()
43 |
44 | val buildScript = """
45 | plugins {
46 | java
47 | }
48 |
49 | java {
50 | toolchain {
51 | languageVersion.set(JavaLanguageVersion.of(${getDifferentJavaVersion()}))
52 | }
53 | }
54 | """
55 | val result = runner(settings, buildScript)
56 | .withGradleVersion("7.5")
57 | .buildAndFail()
58 |
59 | assertTrue("FoojayToolchainsPlugin needs Gradle version 7.6 or higher" in result.output)
60 | }
61 |
62 | @ParameterizedTest(name = "gradle version: {0}")
63 | @MethodSource("getGradleTestVersions")
64 | fun `provides meaningful error when applied as a project plugin`(gradleVersion: String) {
65 | val settings = ""
66 |
67 | val buildScript = """
68 | plugins {
69 | id("org.gradle.toolchains.foojay-resolver-convention")
70 | java
71 | }
72 |
73 | java {
74 | toolchain {
75 | languageVersion.set(JavaLanguageVersion.of(${getDifferentJavaVersion()}))
76 | }
77 | }
78 | """
79 | val result = runner(settings, buildScript)
80 | .withGradleVersion(gradleVersion)
81 | .buildAndFail()
82 |
83 | assertTrue(
84 | "> Failed to apply plugin 'org.gradle.toolchains.foojay-resolver-convention'.\n" +
85 | " > Settings plugins must be applied in the settings script." in result.output
86 | )
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/foojay-resolver/src/functionalTest/kotlin/org/gradle/toolchains/foojay/FoojayToolchainsPluginFunctionalTest.kt:
--------------------------------------------------------------------------------
1 | package org.gradle.toolchains.foojay
2 |
3 | import org.junit.jupiter.params.ParameterizedTest
4 | import org.junit.jupiter.params.provider.MethodSource
5 | import kotlin.test.Test
6 | import kotlin.test.assertTrue
7 |
8 | class FoojayToolchainsPluginFunctionalTest: AbstractFoojayToolchainsPluginFunctionalTest() {
9 |
10 | @ParameterizedTest(name = "gradle version: {0}")
11 | @MethodSource("getGradleTestVersions")
12 | fun `can use base plugin`(gradleVersion: String) {
13 | val settings = """
14 | plugins {
15 | id("org.gradle.toolchains.foojay-resolver")
16 | }
17 |
18 | toolchainManagement {
19 | jvm {
20 | javaRepositories {
21 | repository("foojay") {
22 | resolverClass.set(org.gradle.toolchains.foojay.FoojayToolchainResolver::class.java)
23 | }
24 | }
25 | }
26 | }
27 | """.trimIndent()
28 |
29 | val buildScript = """
30 | plugins {
31 | java
32 | }
33 |
34 | java {
35 | toolchain {
36 | languageVersion.set(JavaLanguageVersion.of(${getDifferentJavaVersion()}))
37 | }
38 | }
39 | """
40 | val result = runner(settings, buildScript)
41 | .withGradleVersion(gradleVersion)
42 | .build()
43 | assertProvisioningSuccessful(result)
44 | }
45 |
46 | @Test
47 | fun `generates useful error for unsupported Gradle versions`() {
48 | val settings = """
49 | plugins {
50 | id("org.gradle.toolchains.foojay-resolver")
51 | }
52 |
53 | toolchainManagement {
54 | jvm {
55 | javaRepositories {
56 | repository("foojay") {
57 | resolverClass.set(org.gradle.toolchains.foojay.FoojayToolchainResolver::class.java)
58 | }
59 | }
60 | }
61 | }
62 | """.trimIndent()
63 |
64 | val buildScript = """
65 | plugins {
66 | java
67 | }
68 |
69 | java {
70 | toolchain {
71 | languageVersion.set(JavaLanguageVersion.of(${getDifferentJavaVersion()}))
72 | }
73 | }
74 | """
75 | val result = runner(settings, buildScript)
76 | .withGradleVersion("7.5")
77 | .buildAndFail()
78 |
79 | assertTrue("FoojayToolchainsPlugin needs Gradle version 7.6 or higher" in result.output)
80 | }
81 |
82 | @ParameterizedTest(name = "gradle version: {0}")
83 | @MethodSource("getGradleTestVersions")
84 | fun `provides meaningful error when applied as a project plugin`(gradleVersion: String) {
85 | val settings = ""
86 |
87 | val buildScript = """
88 | plugins {
89 | java
90 | id("org.gradle.toolchains.foojay-resolver")
91 | }
92 |
93 | toolchainManagement {
94 | jvm {
95 | javaRepositories {
96 | repository("foojay") {
97 | resolverClass.set(org.gradle.toolchains.foojay.FoojayToolchainResolver::class.java)
98 | }
99 | }
100 | }
101 | }
102 |
103 | java {
104 | toolchain {
105 | languageVersion.set(JavaLanguageVersion.of(${getDifferentJavaVersion()}))
106 | }
107 | }
108 | """
109 | val result = runner(settings, buildScript)
110 | .withGradleVersion(gradleVersion)
111 | .buildAndFail()
112 |
113 | assertTrue("> Failed to apply plugin 'org.gradle.toolchains.foojay-resolver'.\n" +
114 | " > Settings plugins must be applied in the settings script." in result.output)
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/foojay-resolver/src/functionalTest/kotlin/org/gradle/toolchains/foojay/gradleVersions.kt:
--------------------------------------------------------------------------------
1 | package org.gradle.toolchains.foojay
2 |
3 | import org.gradle.internal.impldep.com.google.gson.Gson
4 | import org.gradle.util.GradleVersion
5 | import java.net.URL
6 |
7 |
8 | internal
9 | object GradleTestVersions {
10 |
11 | private val smallestVersionOfInterest = GradleVersion.version("7.6")
12 |
13 | internal
14 | fun getVersions(): List {
15 | val releasedVersions = getReleasedVersions()
16 |
17 | val testVersions = keepOnlyLatestMinor(releasedVersions)
18 | .toMutableList()
19 | testVersions.add(getLatestNightlyVersion())
20 |
21 | return testVersions
22 | .sortedByDescending { it.majorVersion }
23 | .map { it.gradleVersion.version }
24 | .toList()
25 | }
26 |
27 | private fun getLatestNightlyVersion(): VersionInfo {
28 | val jsonText = URL("https://services.gradle.org/versions/nightly").readText()
29 | return VersionInfo(Gson().fromJson(jsonText, VersionJsonBlock::class.java).version)
30 | }
31 |
32 | private fun getReleasedVersions(): List {
33 | val jsonText = URL("https://services.gradle.org/versions/all").readText()
34 | val allVersions = Gson().fromJson(jsonText, Array::class.java)
35 | .asSequence()
36 | .filter { !it.snapshot }
37 | .filter { !it.nightly }
38 | .filter { it.rcFor.isBlank() }
39 | .filter { it.milestoneFor.isBlank() }
40 | .map { VersionInfo(it.version) }
41 | .filter { it.gradleVersion >= smallestVersionOfInterest }
42 | .toList()
43 | return allVersions
44 | }
45 |
46 | private fun keepOnlyLatestMinor(versions: List): MutableList {
47 | val filteredVersions = versions
48 | .sortedWith(compareBy { it.majorVersion }.thenBy { it.gradleVersion })
49 | .toMutableList()
50 | var i = 0
51 | while (i < filteredVersions.size - 1) {
52 | if (filteredVersions[i].majorVersion == filteredVersions[i + 1].majorVersion) {
53 | filteredVersions.removeAt(i)
54 | } else {
55 | i++
56 | }
57 | }
58 | return filteredVersions
59 | }
60 | }
61 |
62 | fun main() {
63 | val versions = GradleTestVersions.getVersions()
64 | println("versions = $versions")
65 | }
66 |
67 | @Suppress("MagicNumber")
68 | private class VersionInfo(val version: String) {
69 | val gradleVersion: GradleVersion = GradleVersion.version(version)
70 | val majorVersion: GradleVersion = GradleVersion.version(getMajorVersion(version))
71 | private fun getMajorVersion(version: String): String {
72 | val majorVersionParts = version.split("\\.".toRegex())
73 | return when (majorVersionParts.size) {
74 | 2 -> version
75 | 3 -> "${majorVersionParts[0]}.${majorVersionParts[1]}"
76 | else -> error("Unexpected version number: $version")
77 | }
78 | }
79 |
80 | override fun toString(): String = version
81 |
82 | }
83 |
84 | data class VersionJsonBlock(
85 | val version: String,
86 | val snapshot: Boolean,
87 | val nightly: Boolean,
88 | val rcFor: String,
89 | val milestoneFor: String,
90 | )
91 |
--------------------------------------------------------------------------------
/foojay-resolver/src/main/kotlin/org/gradle/toolchains/foojay/AbstractFoojayToolchainPlugin.kt:
--------------------------------------------------------------------------------
1 | package org.gradle.toolchains.foojay
2 |
3 | import org.gradle.api.GradleException
4 | import org.gradle.api.Plugin
5 | import org.gradle.api.initialization.Settings
6 |
7 | abstract class AbstractFoojayToolchainPlugin: Plugin {
8 |
9 | override fun apply(target: Any) {
10 | if (target is Settings) {
11 | apply(target)
12 | } else {
13 | throw GradleException("Settings plugins must be applied in the settings script.")
14 | }
15 | }
16 |
17 | abstract fun apply(settings: Settings)
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/foojay-resolver/src/main/kotlin/org/gradle/toolchains/foojay/FoojayApi.kt:
--------------------------------------------------------------------------------
1 | package org.gradle.toolchains.foojay
2 |
3 | import org.gradle.api.GradleException
4 | import org.gradle.jvm.toolchain.JavaLanguageVersion
5 | import org.gradle.jvm.toolchain.JvmImplementation
6 | import org.gradle.jvm.toolchain.JvmVendorSpec
7 | import org.gradle.platform.Architecture
8 | import org.gradle.platform.OperatingSystem
9 | import java.io.BufferedReader
10 | import java.io.InputStream
11 | import java.net.HttpURLConnection
12 | import java.net.URI
13 | import java.net.URL
14 | import java.net.URLEncoder
15 | import java.nio.charset.StandardCharsets.UTF_8
16 | import java.util.concurrent.TimeUnit.SECONDS
17 |
18 |
19 | @Suppress("UnstableApiUsage")
20 | class FoojayApi {
21 |
22 | companion object {
23 | val CONNECT_TIMEOUT = SECONDS.toMillis(10).toInt()
24 | val READ_TIMEOUT = SECONDS.toMillis(20).toInt()
25 |
26 | const val SCHEMA = "https"
27 |
28 | private const val ENDPOINT_ROOT = "api.foojay.io/disco/v3.0"
29 | const val DISTRIBUTIONS_ENDPOINT = "$ENDPOINT_ROOT/distributions"
30 | const val PACKAGES_ENDPOINT = "$ENDPOINT_ROOT/packages"
31 | }
32 |
33 | private val distributions = mutableListOf()
34 |
35 | fun toUri(links: Links?): URI? = links?.pkg_download_redirect
36 |
37 | @Suppress("LongParameterList")
38 | fun toPackage(
39 | version: JavaLanguageVersion,
40 | vendor: JvmVendorSpec,
41 | implementation: JvmImplementation,
42 | nativeImageCapable: Boolean,
43 | operatingSystem: OperatingSystem,
44 | architecture: Architecture
45 | ): Package? {
46 | val distributions = match(vendor, implementation, version, nativeImageCapable)
47 | return distributions.asSequence().mapNotNull { distribution ->
48 | match(distribution.api_parameter, version, operatingSystem, architecture)
49 | }.firstOrNull()
50 | }
51 |
52 | internal fun match(vendor: JvmVendorSpec, implementation: JvmImplementation, version: JavaLanguageVersion, nativeImageCapable: Boolean): List {
53 | fetchDistributionsIfMissing()
54 | return match(distributions, vendor, implementation, version, nativeImageCapable)
55 | }
56 |
57 | private fun fetchDistributionsIfMissing() {
58 | if (distributions.isEmpty()) {
59 | val con = createConnection(
60 | DISTRIBUTIONS_ENDPOINT,
61 | mapOf("include_versions" to "true", "include_synonyms" to "true")
62 | )
63 | val json = readResponse(con)
64 | con.disconnect()
65 |
66 | distributions.addAll(parseDistributions(json))
67 | }
68 | }
69 |
70 | internal fun match(distributionName: String, version: JavaLanguageVersion, operatingSystem: OperatingSystem, architecture: Architecture): Package? {
71 | val versionApiKey = when {
72 | distributionName.startsWith("graalvm_community") -> "version"
73 | distributionName == "graalvm" -> "version"
74 | else -> "jdk_version"
75 | }
76 |
77 | val con = createConnection(
78 | PACKAGES_ENDPOINT,
79 | mapOf(
80 | versionApiKey to "$version",
81 | "distro" to distributionName,
82 | "operating_system" to operatingSystem.toApiValue(),
83 | "latest" to "available",
84 | "directly_downloadable" to "true"
85 | )
86 | )
87 | val json = readResponse(con)
88 | con.disconnect()
89 |
90 | val packages = parsePackages(json)
91 | return match(packages, architecture)
92 | }
93 |
94 | private fun createConnection(endpoint: String, parameters: Map): HttpURLConnection {
95 | val url = URL("$SCHEMA://$endpoint?${toParameterString(parameters)}")
96 | val con = url.openConnection() as HttpURLConnection
97 | con.setRequestProperty("Content-Type", "application/json")
98 | con.requestMethod = "GET"
99 | con.connectTimeout = CONNECT_TIMEOUT
100 | con.readTimeout = READ_TIMEOUT
101 | return con
102 | }
103 |
104 | private fun toParameterString(params: Map): String {
105 | return params.entries.joinToString("&") {
106 | "${URLEncoder.encode(it.key, UTF_8.name())}=${URLEncoder.encode(it.value, UTF_8.name())}"
107 | }
108 | }
109 |
110 | private fun readResponse(con: HttpURLConnection): String {
111 | val status = con.responseCode
112 | if (status != HttpURLConnection.HTTP_OK) {
113 | throw GradleException("Requesting vendor list failed: ${readContent(con.errorStream)}")
114 | }
115 | return readContent(con.inputStream)
116 | }
117 |
118 | private fun readContent(stream: InputStream) = stream.bufferedReader().use(BufferedReader::readText)
119 | }
120 |
--------------------------------------------------------------------------------
/foojay-resolver/src/main/kotlin/org/gradle/toolchains/foojay/FoojayToolchainResolver.kt:
--------------------------------------------------------------------------------
1 | package org.gradle.toolchains.foojay
2 |
3 | import org.gradle.api.provider.Property
4 | import org.gradle.jvm.toolchain.JavaToolchainDownload
5 | import org.gradle.jvm.toolchain.JavaToolchainRequest
6 | import org.gradle.jvm.toolchain.JavaToolchainResolver
7 | import org.gradle.jvm.toolchain.JavaToolchainSpec
8 | import org.gradle.util.GradleVersion
9 | import java.util.*
10 |
11 | abstract class FoojayToolchainResolver : JavaToolchainResolver {
12 |
13 | private val api: FoojayApi = FoojayApi()
14 |
15 | override fun resolve(request: JavaToolchainRequest): Optional {
16 | val spec = request.javaToolchainSpec
17 | val nativeImageCapable = if (GradleVersion.current().baseVersion >= GradleVersion.version("8.14")) {
18 | extractNativeImageCapability(spec)
19 | } else {
20 | false
21 | }
22 | val platform = request.buildPlatform
23 | val links = api.toPackage(
24 | spec.languageVersion.get(),
25 | spec.vendor.get(),
26 | spec.implementation.get(),
27 | nativeImageCapable,
28 | platform.operatingSystem,
29 | platform.architecture
30 | )?.links
31 | val uri = api.toUri(links)
32 | return Optional.ofNullable(uri).map(JavaToolchainDownload::fromUri)
33 | }
34 |
35 | @Suppress("UNCHECKED_CAST")
36 | private fun extractNativeImageCapability(spec: JavaToolchainSpec): Boolean {
37 | val result = spec.javaClass.getMethod("getNativeImageCapable").invoke(spec) as Property
38 | return result.getOrElse(false)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/foojay-resolver/src/main/kotlin/org/gradle/toolchains/foojay/FoojayToolchainsConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | package org.gradle.toolchains.foojay
2 |
3 | import org.gradle.api.initialization.Settings
4 | import org.gradle.kotlin.dsl.jvm
5 |
6 | @Suppress("unused")
7 | abstract class FoojayToolchainsConventionPlugin: AbstractFoojayToolchainPlugin() {
8 |
9 | override fun apply(settings: Settings) {
10 | settings.plugins.apply(FoojayToolchainsPlugin::class.java)
11 |
12 | settings.toolchainManagement {
13 | jvm {
14 | javaRepositories {
15 | repository("foojay") {
16 | resolverClass.set(FoojayToolchainResolver::class.java)
17 | }
18 | }
19 | }
20 | }
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/foojay-resolver/src/main/kotlin/org/gradle/toolchains/foojay/FoojayToolchainsPlugin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * This Kotlin source file was generated by the Gradle 'init' task.
3 | */
4 | package org.gradle.toolchains.foojay
5 |
6 | import org.gradle.api.initialization.Settings
7 | import org.gradle.api.internal.SettingsInternal
8 | import org.gradle.jvm.toolchain.JavaToolchainResolverRegistry
9 | import org.gradle.util.GradleVersion
10 |
11 | @Suppress("unused")
12 | abstract class FoojayToolchainsPlugin: AbstractFoojayToolchainPlugin() {
13 |
14 | @Suppress("TooGenericExceptionThrown")
15 | override fun apply(settings: Settings) {
16 | if (GradleVersion.current().baseVersion < GradleVersion.version("7.6")) {
17 | throw RuntimeException("${FoojayToolchainsPlugin::class.simpleName} needs Gradle version 7.6 or higher")
18 | }
19 |
20 | settings.plugins.apply("jvm-toolchain-management")
21 |
22 | val registry = (settings as SettingsInternal).services.get(JavaToolchainResolverRegistry::class.java)
23 | registry.register(FoojayToolchainResolver::class.java)
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/foojay-resolver/src/main/kotlin/org/gradle/toolchains/foojay/distributions.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("UnstableApiUsage")
2 |
3 | package org.gradle.toolchains.foojay
4 |
5 | import com.google.gson.Gson
6 | import org.gradle.jvm.toolchain.JavaLanguageVersion
7 | import org.gradle.jvm.toolchain.JvmImplementation
8 | import org.gradle.jvm.toolchain.JvmVendorSpec
9 | import org.gradle.jvm.toolchain.JvmVendorSpec.ADOPTIUM
10 | import org.gradle.jvm.toolchain.JvmVendorSpec.ADOPTOPENJDK
11 | import org.gradle.jvm.toolchain.JvmVendorSpec.AMAZON
12 | import org.gradle.jvm.toolchain.JvmVendorSpec.AZUL
13 | import org.gradle.jvm.toolchain.JvmVendorSpec.BELLSOFT
14 | import org.gradle.jvm.toolchain.JvmVendorSpec.IBM
15 | import org.gradle.jvm.toolchain.JvmVendorSpec.ORACLE
16 | import org.gradle.jvm.toolchain.JvmVendorSpec.SAP
17 | import org.gradle.jvm.toolchain.internal.DefaultJvmVendorSpec.any
18 | import java.net.URI
19 |
20 | val vendorAliases: Map
21 | get() {
22 | val tmpMap = mutableMapOf(
23 | ADOPTIUM to "Temurin",
24 | ADOPTOPENJDK to "AOJ",
25 | AMAZON to "Corretto",
26 | AZUL to "Zulu",
27 | BELLSOFT to "Liberica",
28 | IBM to "Semeru",
29 | ORACLE to "Oracle OpenJDK",
30 | SAP to "SAP Machine"
31 | )
32 | addPossiblyUndefinedVendor("IBM_SEMERU", "Semeru", tmpMap)
33 | return tmpMap.toMap()
34 | }
35 |
36 | val distributionOrderOfPreference = listOf("Temurin", "AOJ")
37 |
38 | val j9Aliases: Map
39 | get() {
40 | val tmpMap = mutableMapOf(
41 | IBM to "Semeru",
42 | ADOPTOPENJDK to "AOJ OpenJ9"
43 | )
44 | addPossiblyUndefinedVendor("IBM_SEMERU", "Semeru", tmpMap)
45 | return tmpMap.toMap()
46 | }
47 |
48 | /**
49 | * Given a list of [distributions], return those that match the provided [vendor] and JVM [implementation]. The Java
50 | * language [version] is only used to remove wrong GraalVM distributions; no general version filtering is done here.
51 | */
52 | @Suppress("ReturnCount")
53 | fun match(
54 | distributions: List,
55 | vendor: JvmVendorSpec,
56 | implementation: JvmImplementation,
57 | version: JavaLanguageVersion,
58 | nativeImageCapable: Boolean
59 | ): List {
60 | // Start by filtering based on the native image criteria.
61 | // If it is defined, we only keep the distributions that have `build_of_graalvm` set to true.
62 | val filteredDistributions = distributions.filter { !nativeImageCapable || it.build_of_graalvm }
63 |
64 | // Specific filter when J9 is requested
65 | if (implementation == JvmImplementation.J9) return matchForJ9(filteredDistributions, vendor)
66 |
67 | // Return early if an explicit non-GraalVM distribution is requested.
68 | if (vendor != JvmVendorSpec.GRAAL_VM && vendor != any()) return match(filteredDistributions, vendor)
69 |
70 | // Remove GraalVM distributions that target the wrong Java language version.
71 | val graalVmCeVendor = JvmVendorSpec.matching("GraalVM CE $version")
72 | val distributionsWithoutWrongGraalVm = filteredDistributions.filter { (name) ->
73 | when {
74 | // Naming scheme for old GraalVM community releases: The Java language version is part of the name.
75 | name.startsWith("GraalVM CE") -> graalVmCeVendor.matches(name)
76 |
77 | else -> true
78 | }
79 | }
80 |
81 | if (vendor == any()) return allDistributionsPrecededByWellKnownOnes(distributionsWithoutWrongGraalVm)
82 |
83 | // As Gradle has no means to distinguish between Community and Oracle distributions of GraalVM (see
84 | // https://github.com/gradle/gradle/issues/25521), disregard Oracle GraalVM distributions for now by only matching
85 | // "GraalVM Community" and "GraalVM CE".
86 | val graalVmVendor = JvmVendorSpec.matching("GraalVM C")
87 |
88 | return match(distributionsWithoutWrongGraalVm, graalVmVendor)
89 | }
90 |
91 | private fun matchForJ9(distributions: List, vendor: JvmVendorSpec) =
92 | if (vendor == any()) {
93 | distributions
94 | .filter { it.name in j9Aliases.values }
95 | .sortedBy { j9Aliases.values.indexOf(it.name) }
96 | } else {
97 | distributions.filter { it.name == j9Aliases[vendor] }
98 | }
99 |
100 | private fun match(distributions: List, vendor: JvmVendorSpec): List =
101 | findByMatchingAliases(distributions, vendor) ?: findByMatchingNamesAndSynonyms(distributions, vendor)
102 |
103 | private fun allDistributionsPrecededByWellKnownOnes(distributions: List): List =
104 | distributions.sortedBy {
105 | // Put our preferences first, preserve Foojay order otherwise.
106 | val indexOf = distributionOrderOfPreference.indexOf(it.name)
107 | when {
108 | indexOf < 0 -> distributionOrderOfPreference.size
109 | else -> indexOf
110 | }
111 | }
112 |
113 | private fun findByMatchingAliases(distributions: List, vendor: JvmVendorSpec): List? =
114 | distributions.find { it.name == vendorAliases[vendor] }?.let {
115 | listOf(it)
116 | }
117 |
118 | private fun findByMatchingNamesAndSynonyms(distributions: List, vendor: JvmVendorSpec) =
119 | distributions.filter { distribution ->
120 | vendor.matches(distribution.name) || distribution.synonyms.any { vendor.matches(it) }
121 | }
122 |
123 | fun parseDistributions(json: String): List {
124 | return Gson().fromJson(json, DistributionsResult::class.java).result
125 | }
126 |
127 |
128 | private fun addPossiblyUndefinedVendor(
129 | vendorFieldName: String,
130 | vendorAlias: String,
131 | map: MutableMap
132 | ) {
133 | try {
134 | val vendorField = JvmVendorSpec::class.java.getDeclaredField(vendorFieldName)
135 | map.put(vendorField.get(null) as JvmVendorSpec, vendorAlias)
136 | } catch (_: Exception) {
137 | // Ignore - removed in the Gradle version currently running the build where the plugin is applied.
138 | }
139 | }
140 |
141 | /**
142 | * The data class for the result objects as returned by [FoojayApi.DISTRIBUTIONS_ENDPOINT].
143 | */
144 | @Suppress("ConstructorParameterNaming")
145 | data class Distribution(
146 | /**
147 | * The distribution (vendor) name, e.g. "Temurin", "Oracle OpenJDK", "JetBrains", "GraalVM", ...
148 | */
149 | val name: String,
150 |
151 | /**
152 | * The name to use as part of the path when requesting distribution-specific details, see
153 | * https://github.com/foojayio/discoapi#endpoint-distributions
154 | */
155 | val api_parameter: String,
156 |
157 | /**
158 | * A flag to indicate whether the distribution is still maintained or not.
159 | */
160 | val maintained: Boolean,
161 |
162 | /**
163 | * A flag to indicate whether this is an OpenJDK (re-)distribution.
164 | */
165 | val build_of_openjdk: Boolean,
166 |
167 | /**
168 | * A flag to indicate whether this is a GraalVM (re-)distribution.
169 | */
170 | val build_of_graalvm: Boolean,
171 |
172 | /**
173 | * The URI of the offical homepage of the ditribution.
174 | */
175 | val official_uri: URI,
176 |
177 | /**
178 | * A list of alterative names / spellings for the distribution.
179 | */
180 | val synonyms: List,
181 |
182 | /**
183 | * The version strings available for this distribution.
184 | */
185 | val versions: List
186 | )
187 |
188 | private data class DistributionsResult(
189 | val result: List
190 | )
191 |
--------------------------------------------------------------------------------
/foojay-resolver/src/main/kotlin/org/gradle/toolchains/foojay/packages.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("ConstructorParameterNaming", "UnstableApiUsage")
2 |
3 | package org.gradle.toolchains.foojay
4 |
5 | import com.google.gson.Gson
6 | import org.gradle.platform.Architecture
7 | import org.gradle.platform.OperatingSystem
8 | import java.net.URI
9 |
10 | val architectures32Bit = setOf("x32", "i386", "x86")
11 | val architectures64Bit = setOf("x64", "x86_64", "amd64", "ia64")
12 | val architecturesArm64Bit = setOf("aarch64", "arm64")
13 |
14 | val handledArchiveTypes = setOf("tar", "tar.gz", "tgz", "zip")
15 |
16 | fun parsePackages(json: String): List {
17 | return Gson().fromJson(json, PackagesResult::class.java).result
18 | }
19 |
20 | fun match(packages: List, architecture: Architecture): Package? {
21 | val candidates = packages
22 | .filter { p -> matches(p, architecture) } // we filter out packages not matching the architecture the build is running on
23 | .filter { p -> hasHandledArchiveType(p) } // Gradle can handle only certain archive types
24 | .sortedWith(compareBy(Package::package_type, Package::lib_c_type, Package::architecture)) // prefer JDKs over JREs & prefer "glibc" over "musl"
25 | return candidates.firstOrNull()
26 | }
27 |
28 | fun OperatingSystem.toApiValue(): String =
29 | when (this) {
30 | OperatingSystem.LINUX -> "linux"
31 | OperatingSystem.UNIX -> "linux"
32 | OperatingSystem.WINDOWS -> "windows"
33 | OperatingSystem.MAC_OS -> "macos"
34 | OperatingSystem.SOLARIS -> "solaris"
35 | OperatingSystem.FREE_BSD -> "linux"
36 | }
37 |
38 | private fun matches(p: Package, architecture: Architecture): Boolean =
39 | when (architecture) {
40 | Architecture.X86 -> p.architecture in architectures32Bit
41 | Architecture.X86_64 -> p.architecture in architectures64Bit
42 | Architecture.AARCH64 -> p.architecture in architecturesArm64Bit
43 | || (p.operating_system == OperatingSystem.MAC_OS.toApiValue() && p.architecture in architectures64Bit)
44 | }
45 |
46 | private fun hasHandledArchiveType(p: Package): Boolean {
47 | return p.archive_type in handledArchiveTypes
48 | }
49 |
50 | data class Package(
51 | val archive_type: String,
52 | val distribution: String,
53 | val jdk_version: Int,
54 | val distribution_version: String,
55 | val operating_system: String,
56 | val architecture: String,
57 | val package_type: String,
58 | val lib_c_type: String,
59 | val links: Links
60 | )
61 |
62 | data class Links(
63 | val pkg_download_redirect: URI,
64 | val pkg_info_uri: URI?
65 | )
66 |
67 | private data class PackagesResult(
68 | val result: List
69 | )
70 |
--------------------------------------------------------------------------------
/foojay-resolver/src/test/kotlin/org/gradle/toolchains/foojay/FoojayApiTest.kt:
--------------------------------------------------------------------------------
1 | package org.gradle.toolchains.foojay
2 |
3 | import org.gradle.jvm.toolchain.JavaLanguageVersion.of
4 | import org.gradle.jvm.toolchain.JvmImplementation
5 | import org.gradle.jvm.toolchain.JvmImplementation.J9
6 | import org.gradle.jvm.toolchain.JvmImplementation.VENDOR_SPECIFIC
7 | import org.gradle.jvm.toolchain.JvmVendorSpec
8 | import org.gradle.jvm.toolchain.JvmVendorSpec.*
9 | import org.gradle.jvm.toolchain.internal.DefaultJvmVendorSpec.any
10 | import org.gradle.platform.Architecture
11 | import org.gradle.platform.OperatingSystem
12 | import org.junit.jupiter.params.ParameterizedTest
13 | import org.junit.jupiter.params.provider.Arguments
14 | import org.junit.jupiter.params.provider.MethodSource
15 | import org.junit.jupiter.params.provider.ValueSource
16 | import kotlin.test.Test
17 | import kotlin.test.assertEquals
18 | import kotlin.test.assertNotNull
19 | import kotlin.test.assertTrue
20 |
21 | @Suppress("UnstableApiUsage")
22 | class FoojayApiTest {
23 |
24 | private val api = FoojayApi()
25 |
26 | @ParameterizedTest(name = "javaVersion: {0}, vendor: {1}, isJ9: {2}, os: {3}, arch: {4}")
27 | @MethodSource("getData")
28 | fun `download URI provided correctly`(
29 | javaVersion: Int,
30 | vendor: JvmVendorSpec,
31 | isJ9: Boolean,
32 | os: OperatingSystem,
33 | arch: Architecture
34 | ) = assertDownloadUri(javaVersion, vendor, isJ9, false, os, arch)
35 |
36 | companion object {
37 |
38 | private
39 | val IBM_SEMERU_VENDOR = try {
40 | JvmVendorSpec::class.java.getDeclaredField("IBM_SEMERU").get(null) as JvmVendorSpec
41 | } catch (_: Exception) {
42 | null
43 | }
44 |
45 | @Suppress("DEPRECATION")
46 | @JvmStatic
47 | fun getData(): List {
48 | val tmpList = mutableListOf(
49 | Arguments.of(8, any(), false, OperatingSystem.MAC_OS, Architecture.X86_64),
50 | Arguments.of(8, any(), false, OperatingSystem.MAC_OS, Architecture.AARCH64),
51 | Arguments.of(17, any(), false, OperatingSystem.MAC_OS, Architecture.X86_64),
52 | Arguments.of(17, any(), false, OperatingSystem.MAC_OS, Architecture.AARCH64),
53 | Arguments.of(17, ADOPTIUM, false, OperatingSystem.MAC_OS, Architecture.AARCH64),
54 | Arguments.of(17, GRAAL_VM, false, OperatingSystem.MAC_OS, Architecture.AARCH64),
55 | Arguments.of(21, any(), true, OperatingSystem.MAC_OS, Architecture.X86_64),
56 | Arguments.of(21, IBM, true, OperatingSystem.MAC_OS, Architecture.X86_64),
57 |
58 | Arguments.of(17, GRAAL_VM, false, OperatingSystem.LINUX, Architecture.X86_64),
59 | Arguments.of(17, any(), false, OperatingSystem.LINUX, Architecture.X86_64),
60 | Arguments.of(17, any(), true, OperatingSystem.LINUX, Architecture.X86_64),
61 | Arguments.of(21, GRAAL_VM, false, OperatingSystem.LINUX, Architecture.X86_64),
62 |
63 | Arguments.of(8, any(), false, OperatingSystem.WINDOWS, Architecture.X86_64),
64 | Arguments.of(8, GRAAL_VM, false, OperatingSystem.WINDOWS, Architecture.X86_64),
65 | Arguments.of(17, any(), false, OperatingSystem.WINDOWS, Architecture.X86_64),
66 | Arguments.of(17, GRAAL_VM, false, OperatingSystem.WINDOWS, Architecture.X86_64),
67 | )
68 | IBM_SEMERU_VENDOR?.let { tmpList.add(Arguments.of(21, it, true, OperatingSystem.MAC_OS, Architecture.X86_64)) }
69 | return tmpList.toList()
70 | }
71 | }
72 |
73 | @ParameterizedTest(name = "J9 implementation influences vendor resolution (Java {0})")
74 | @ValueSource(ints = [8, 11, 16])
75 | fun `J9 implementation influences vendor resolution`(version: Int) {
76 | assertMatchedDistributions(any(), J9, version, "Semeru", "AOJ OpenJ9")
77 |
78 | assertMatchedDistributions(ADOPTOPENJDK, J9, version, "AOJ OpenJ9")
79 | assertMatchedDistributions(IBM, J9, version, "Semeru")
80 | IBM_SEMERU_VENDOR?.let { assertMatchedDistributions(it, J9, version, "Semeru") }
81 |
82 | assertMatchedDistributions(ADOPTIUM, J9, version)
83 | assertMatchedDistributions(AZUL, J9, version)
84 | assertMatchedDistributions(AMAZON, J9, version)
85 | assertMatchedDistributions(BELLSOFT, J9, version)
86 | assertMatchedDistributions(MICROSOFT, J9, version)
87 | assertMatchedDistributions(ORACLE, J9, version)
88 | assertMatchedDistributions(SAP, J9, version)
89 | assertMatchedDistributions(APPLE, J9, version)
90 | assertMatchedDistributions(GRAAL_VM, J9, version)
91 | assertMatchedDistributions(HEWLETT_PACKARD, J9, version)
92 | }
93 |
94 | @ParameterizedTest(name = "vendor specific implementation does not influence vendor resolution (Java {0})")
95 | @ValueSource(ints = [8, 11, 16])
96 | fun `vendor specific implementation does not influence vendor resolution`(version: Int) {
97 | assertMatchedDistributions(any(), VENDOR_SPECIFIC, version,
98 | "Temurin", "AOJ",
99 | "ZuluPrime", "Zulu", "Trava", "Semeru certified", "Semeru", "SAP Machine", "Red Hat", "Oracle OpenJDK",
100 | "Oracle", "OpenLogic", "OJDKBuild", "Microsoft", "Mandrel", "Liberica Native", "Liberica", "Kona",
101 | "JetBrains", "GraalVM Community", "GraalVM CE $version", "GraalVM", "Gluon GraalVM", "Dragonwell",
102 | "Debian", "Corretto", "Bi Sheng", "AOJ OpenJ9"
103 | )
104 |
105 | assertMatchedDistributions(ADOPTOPENJDK, VENDOR_SPECIFIC, version, "AOJ")
106 | assertMatchedDistributions(IBM, VENDOR_SPECIFIC, version, "Semeru")
107 | IBM_SEMERU_VENDOR?.let { assertMatchedDistributions(it, VENDOR_SPECIFIC, version, "Semeru") }
108 |
109 | assertMatchedDistributions(ADOPTIUM, VENDOR_SPECIFIC, version, "Temurin")
110 | assertMatchedDistributions(AZUL, VENDOR_SPECIFIC, version, "Zulu")
111 | assertMatchedDistributions(AMAZON, VENDOR_SPECIFIC, version, "Corretto")
112 | assertMatchedDistributions(BELLSOFT, VENDOR_SPECIFIC, version, "Liberica")
113 | assertMatchedDistributions(MICROSOFT, VENDOR_SPECIFIC, version, "Microsoft")
114 | assertMatchedDistributions(ORACLE, VENDOR_SPECIFIC, version, "Oracle OpenJDK")
115 | assertMatchedDistributions(SAP, VENDOR_SPECIFIC, version, "SAP Machine")
116 |
117 | assertMatchedDistributions(GRAAL_VM, VENDOR_SPECIFIC, version, "GraalVM Community", "GraalVM CE $version")
118 |
119 | assertMatchedDistributions(APPLE, VENDOR_SPECIFIC, version)
120 | assertMatchedDistributions(HEWLETT_PACKARD, VENDOR_SPECIFIC, version)
121 | }
122 |
123 | private fun assertMatchedDistributions(
124 | vendor: JvmVendorSpec,
125 | implementation: JvmImplementation,
126 | version: Int,
127 | vararg expectedDistributions: String
128 | ) {
129 | assertEquals(
130 | listOf(*expectedDistributions),
131 | api.match(vendor, implementation, of(version), false).map { it.name },
132 | "Mismatch in matching distributions for vendor: $vendor, implementation: $implementation, version: $version"
133 | )
134 | }
135 |
136 | @ParameterizedTest(name = "can resolve arbitrary vendors (Java {0})")
137 | @ValueSource(ints = [8, 11, 16])
138 | fun `can resolve arbitrary vendors`(version: Int) {
139 | assertEquals("ZuluPrime", api.match(vendorSpec("zuluprime"), VENDOR_SPECIFIC, of(version), false).firstOrNull()?.name)
140 | assertEquals("ZuluPrime", api.match(vendorSpec("zUluprIme"), VENDOR_SPECIFIC, of(version), false).firstOrNull()?.name)
141 | assertEquals("JetBrains", api.match(vendorSpec("JetBrains"), VENDOR_SPECIFIC, of(version), false).firstOrNull()?.name)
142 | }
143 |
144 | @Test
145 | fun `can pick the right package`() {
146 | val p = api.match("temurin", of(11), OperatingSystem.LINUX, Architecture.X86_64)
147 | assertNotNull(p)
148 | assertEquals("tar.gz", p.archive_type)
149 | assertEquals("temurin", p.distribution)
150 | assertEquals(11, p.jdk_version)
151 | assertTrue(Regex("11.\\d+.\\d+").matches(p.distribution_version))
152 | assertEquals("linux", p.operating_system)
153 | assertEquals("x64", p.architecture)
154 | assertEquals("jdk", p.package_type)
155 | }
156 |
157 | @Test
158 | fun `macos arm is mapped to x64 when arm isn't available`() {
159 | // RISC architecture is preferred when available
160 | val p1 = assertDownloadUri(17, AZUL, false, false,OperatingSystem.MAC_OS, Architecture.AARCH64)
161 | assertEquals("aarch64", p1.architecture)
162 |
163 | // X86 architecture is provided when RISC is not available
164 | val p2 = assertDownloadUri(7, AZUL, false, false, OperatingSystem.MAC_OS, Architecture.AARCH64)
165 | assertEquals("x64", p2.architecture)
166 | }
167 |
168 | @Test
169 | fun `can pick a native image capable package`() {
170 | assertDownloadUri(21, any(), false, true, OperatingSystem.MAC_OS, Architecture.AARCH64)
171 | }
172 |
173 | @Test
174 | fun `can pick graalvm package`() {
175 | assertDownloadUri(21, matching("GraalVM"), false, true, OperatingSystem.MAC_OS, Architecture.AARCH64)
176 | }
177 |
178 | @Suppress("LongParameterList")
179 | private fun assertDownloadUri(
180 | javaVersion: Int,
181 | vendor: JvmVendorSpec,
182 | isJ9: Boolean,
183 | nativeImageCapable: Boolean,
184 | os: OperatingSystem,
185 | arch: Architecture
186 | ): Package {
187 | val actual = api.toPackage(
188 | of(javaVersion),
189 | vendor,
190 | if (isJ9) J9 else VENDOR_SPECIFIC,
191 | nativeImageCapable,
192 | os,
193 | arch
194 | )
195 | assertNotNull(actual)
196 | assertNotNull(actual.links.pkg_download_redirect)
197 | assertJavaVersion(javaVersion, actual)
198 | assertDistribution(vendor, actual)
199 | assertNativeImageCapable(nativeImageCapable, vendor, actual)
200 | assertOperatingSystem(os, actual)
201 | assertArchitecture(os, arch, actual)
202 | return actual
203 | }
204 |
205 | private fun assertJavaVersion(javaVersion: Int, actual: Package) {
206 | val actualValue = actual.jdk_version
207 | assertEquals(javaVersion, actualValue,
208 | "Expected Java version ($javaVersion) doesn't match actual one ($actualValue), ${moreDetailsAt(actual)}"
209 | )
210 | }
211 |
212 | private fun assertDistribution(vendor: JvmVendorSpec, actual: Package) {
213 | var expectedValue = vendor.toString().replace("_", "").lowercase()
214 | expectedValue = when (expectedValue) {
215 | "ibm" -> "semeru"
216 | "azul zulu" -> "zulu"
217 | else -> expectedValue
218 | }
219 |
220 | val actualValue = actual.distribution
221 |
222 | assertTrue(vendor.matches(actualValue) || actualValue.startsWith(expectedValue),
223 | "Expected vendor spec ($expectedValue) doesn't match actual distribution (${actualValue}), ${moreDetailsAt(actual)}"
224 | )
225 | }
226 |
227 | private fun assertNativeImageCapable(nativeImageCapable: Boolean, vendor: JvmVendorSpec, actual: Package) {
228 | if (nativeImageCapable) {
229 | // TODO this is not a great test, but the package does not carry the native-image / Graal capability information anymore
230 | if (vendor == any()) {
231 | assertTrue(actual.distribution.contains("mandrel"),
232 | "Expected vendor to contain 'mandrel' when native image capable, got ${actual.distribution}")
233 | } else {
234 | assertDistribution(vendor, actual)
235 | }
236 | }
237 | }
238 |
239 | private fun assertOperatingSystem(os: OperatingSystem, actual: Package) {
240 | val expectedValue = os.toString().replace("_", "").lowercase()
241 | val actualValue = actual.operating_system
242 | assertEquals(expectedValue, actualValue,
243 | "Expected operating system ($expectedValue) doesn't match actual one ($actualValue), ${moreDetailsAt(actual)}"
244 | )
245 | }
246 |
247 | private fun assertArchitecture(os: OperatingSystem, arch: Architecture, actual: Package) {
248 | val expectedValues = when (arch) {
249 | Architecture.X86 -> architectures32Bit
250 | Architecture.X86_64 -> architectures64Bit
251 | Architecture.AARCH64 ->
252 | if (os == OperatingSystem.MAC_OS) architecturesArm64Bit + architectures64Bit
253 | else architecturesArm64Bit
254 | }
255 | val actualValue = actual.architecture
256 | assertTrue(expectedValues.contains(actualValue),
257 | "Expected architecture (${arch}) doesn't match actual one ($actualValue), ${moreDetailsAt(actual)}"
258 | )
259 | }
260 |
261 | private fun moreDetailsAt(actual: Package?) = "for more details see ${actual?.links?.pkg_info_uri}"
262 |
263 | private fun vendorSpec(vendorName: String): JvmVendorSpec = matching(vendorName)
264 |
265 | }
266 |
267 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.parallel=true
2 | org.gradle.caching=true
3 | org.gradle.configuration-cache=true
4 | org.gradle.configuration-cache.parallel=true
--------------------------------------------------------------------------------
/gradle/detekt.yml:
--------------------------------------------------------------------------------
1 | style:
2 | MaxLineLength:
3 | maxLineLength: 180 # default is 120
4 | WildcardImport:
5 | active: false
6 | UnnecessaryAbstractClass:
7 | active: false
8 |
9 | naming:
10 | FunctionNaming:
11 | functionPattern: '[a-z][a-zA-Z0-9]*|`.*`'
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gradle/foojay-toolchains/4b5f91e9acfe51b2c7fe8f56da5932d660d69506/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionSha256Sum=61ad310d3c7d3e5da131b76bbf22b5a4c0786e9d892dae8c1658d4b484de3caa
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
5 | networkTimeout=10000
6 | validateDistributionUrl=true
7 | zipStoreBase=GRADLE_USER_HOME
8 | zipStorePath=wrapper/dists
9 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 | # SPDX-License-Identifier: Apache-2.0
19 | #
20 |
21 | ##############################################################################
22 | #
23 | # Gradle start up script for POSIX generated by Gradle.
24 | #
25 | # Important for running:
26 | #
27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
28 | # noncompliant, but you have some other compliant shell such as ksh or
29 | # bash, then to run this script, type that shell name before the whole
30 | # command line, like:
31 | #
32 | # ksh Gradle
33 | #
34 | # Busybox and similar reduced shells will NOT work, because this script
35 | # requires all of these POSIX shell features:
36 | # * functions;
37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
39 | # * compound commands having a testable exit status, especially «case»;
40 | # * various built-in commands including «command», «set», and «ulimit».
41 | #
42 | # Important for patching:
43 | #
44 | # (2) This script targets any POSIX shell, so it avoids extensions provided
45 | # by Bash, Ksh, etc; in particular arrays are avoided.
46 | #
47 | # The "traditional" practice of packing multiple parameters into a
48 | # space-separated string is a well documented source of bugs and security
49 | # problems, so this is (mostly) avoided, by progressively accumulating
50 | # options in "$@", and eventually passing that to Java.
51 | #
52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
54 | # see the in-line comments for details.
55 | #
56 | # There are tweaks for specific operating systems such as AIX, CygWin,
57 | # Darwin, MinGW, and NonStop.
58 | #
59 | # (3) This script is generated from the Groovy template
60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
61 | # within the Gradle project.
62 | #
63 | # You can find Gradle at https://github.com/gradle/gradle/.
64 | #
65 | ##############################################################################
66 |
67 | # Attempt to set APP_HOME
68 |
69 | # Resolve links: $0 may be a link
70 | app_path=$0
71 |
72 | # Need this for daisy-chained symlinks.
73 | while
74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
75 | [ -h "$app_path" ]
76 | do
77 | ls=$( ls -ld "$app_path" )
78 | link=${ls#*' -> '}
79 | case $link in #(
80 | /*) app_path=$link ;; #(
81 | *) app_path=$APP_HOME$link ;;
82 | esac
83 | done
84 |
85 | # This is normally unused
86 | # shellcheck disable=SC2034
87 | APP_BASE_NAME=${0##*/}
88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 | CLASSPATH="\\\"\\\""
118 |
119 |
120 | # Determine the Java command to use to start the JVM.
121 | if [ -n "$JAVA_HOME" ] ; then
122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 | # IBM's JDK on AIX uses strange locations for the executables
124 | JAVACMD=$JAVA_HOME/jre/sh/java
125 | else
126 | JAVACMD=$JAVA_HOME/bin/java
127 | fi
128 | if [ ! -x "$JAVACMD" ] ; then
129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 |
131 | Please set the JAVA_HOME variable in your environment to match the
132 | location of your Java installation."
133 | fi
134 | else
135 | JAVACMD=java
136 | if ! command -v java >/dev/null 2>&1
137 | then
138 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
139 |
140 | Please set the JAVA_HOME variable in your environment to match the
141 | location of your Java installation."
142 | fi
143 | fi
144 |
145 | # Increase the maximum file descriptors if we can.
146 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
147 | case $MAX_FD in #(
148 | max*)
149 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
150 | # shellcheck disable=SC2039,SC3045
151 | MAX_FD=$( ulimit -H -n ) ||
152 | warn "Could not query maximum file descriptor limit"
153 | esac
154 | case $MAX_FD in #(
155 | '' | soft) :;; #(
156 | *)
157 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
158 | # shellcheck disable=SC2039,SC3045
159 | ulimit -n "$MAX_FD" ||
160 | warn "Could not set maximum file descriptor limit to $MAX_FD"
161 | esac
162 | fi
163 |
164 | # Collect all arguments for the java command, stacking in reverse order:
165 | # * args from the command line
166 | # * the main class name
167 | # * -classpath
168 | # * -D...appname settings
169 | # * --module-path (only if needed)
170 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
171 |
172 | # For Cygwin or MSYS, switch paths to Windows format before running java
173 | if "$cygwin" || "$msys" ; then
174 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
175 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
176 |
177 | JAVACMD=$( cygpath --unix "$JAVACMD" )
178 |
179 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
180 | for arg do
181 | if
182 | case $arg in #(
183 | -*) false ;; # don't mess with options #(
184 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
185 | [ -e "$t" ] ;; #(
186 | *) false ;;
187 | esac
188 | then
189 | arg=$( cygpath --path --ignore --mixed "$arg" )
190 | fi
191 | # Roll the args list around exactly as many times as the number of
192 | # args, so each arg winds up back in the position where it started, but
193 | # possibly modified.
194 | #
195 | # NB: a `for` loop captures its iteration list before it begins, so
196 | # changing the positional parameters here affects neither the number of
197 | # iterations, nor the values presented in `arg`.
198 | shift # remove old arg
199 | set -- "$@" "$arg" # push replacement arg
200 | done
201 | fi
202 |
203 |
204 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
205 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
206 |
207 | # Collect all arguments for the java command:
208 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
209 | # and any embedded shellness will be escaped.
210 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
211 | # treated as '${Hostname}' itself on the command line.
212 |
213 | set -- \
214 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
215 | -classpath "$CLASSPATH" \
216 | -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
217 | "$@"
218 |
219 | # Stop when "xargs" is not available.
220 | if ! command -v xargs >/dev/null 2>&1
221 | then
222 | die "xargs is not available"
223 | fi
224 |
225 | # Use "xargs" to parse quoted args.
226 | #
227 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
228 | #
229 | # In Bash we could simply go:
230 | #
231 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
232 | # set -- "${ARGS[@]}" "$@"
233 | #
234 | # but POSIX shell has neither arrays nor command substitution, so instead we
235 | # post-process each arg (as a line of input to sed) to backslash-escape any
236 | # character that might be a shell metacharacter, then use eval to reverse
237 | # that process (while maintaining the separation between arguments), and wrap
238 | # the whole thing up as a single "set" statement.
239 | #
240 | # This will of course break if any of these variables contains a newline or
241 | # an unmatched quote.
242 | #
243 |
244 | eval "set -- $(
245 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
246 | xargs -n1 |
247 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
248 | tr '\n' ' '
249 | )" '"$@"'
250 |
251 | exec "$JAVACMD" "$@"
252 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 | @rem SPDX-License-Identifier: Apache-2.0
17 | @rem
18 |
19 | @if "%DEBUG%"=="" @echo off
20 | @rem ##########################################################################
21 | @rem
22 | @rem Gradle startup script for Windows
23 | @rem
24 | @rem ##########################################################################
25 |
26 | @rem Set local scope for the variables with windows NT shell
27 | if "%OS%"=="Windows_NT" setlocal
28 |
29 | set DIRNAME=%~dp0
30 | if "%DIRNAME%"=="" set DIRNAME=.
31 | @rem This is normally unused
32 | set APP_BASE_NAME=%~n0
33 | set APP_HOME=%DIRNAME%
34 |
35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
37 |
38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
40 |
41 | @rem Find java.exe
42 | if defined JAVA_HOME goto findJavaFromJavaHome
43 |
44 | set JAVA_EXE=java.exe
45 | %JAVA_EXE% -version >NUL 2>&1
46 | if %ERRORLEVEL% equ 0 goto execute
47 |
48 | echo. 1>&2
49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
50 | echo. 1>&2
51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
52 | echo location of your Java installation. 1>&2
53 |
54 | goto fail
55 |
56 | :findJavaFromJavaHome
57 | set JAVA_HOME=%JAVA_HOME:"=%
58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
59 |
60 | if exist "%JAVA_EXE%" goto execute
61 |
62 | echo. 1>&2
63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
64 | echo. 1>&2
65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
66 | echo location of your Java installation. 1>&2
67 |
68 | goto fail
69 |
70 | :execute
71 | @rem Setup the command line
72 |
73 | set CLASSPATH=
74 |
75 |
76 | @rem Execute Gradle
77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
78 |
79 | :end
80 | @rem End local scope for the variables with windows NT shell
81 | if %ERRORLEVEL% equ 0 goto mainEnd
82 |
83 | :fail
84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
85 | rem the _cmd.exe /c_ return code!
86 | set EXIT_CODE=%ERRORLEVEL%
87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
89 | exit /b %EXIT_CODE%
90 |
91 | :mainEnd
92 | if "%OS%"=="Windows_NT" endlocal
93 |
94 | :omega
95 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("com.gradle.develocity") version "4.0.1"
3 | id("io.github.gradle.gradle-enterprise-conventions-plugin").version("0.10.3")
4 | id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
5 | }
6 |
7 | dependencyResolutionManagement {
8 | repositories {
9 | mavenCentral()
10 | }
11 | }
12 |
13 | rootProject.name = "foojay-toolchains"
14 | include("foojay-resolver")
15 |
--------------------------------------------------------------------------------