Merge branch 'main' of alkmene.hbz-nrw.de:joerg/gradle-plugins
This commit is contained in:
commit
93f49c7bee
252 changed files with 24293 additions and 250 deletions
202
LICENSE.txt
Normal file
202
LICENSE.txt
Normal file
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
0
NOTICE.txt
Normal file
0
NOTICE.txt
Normal file
|
@ -2,7 +2,7 @@
|
|||
group = 'org.xbib.gradle.plugin'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = "${project.property('gradle.wrapper.version')}"
|
||||
gradleVersion = libs.versions.gradle.get()
|
||||
distributionType = Wrapper.DistributionType.ALL
|
||||
}
|
||||
|
||||
|
|
202
gradle-plugin-asciidoctor/LICENSE.txt
Normal file
202
gradle-plugin-asciidoctor/LICENSE.txt
Normal file
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
10
gradle-plugin-asciidoctor/NOTICE.txt
Normal file
10
gradle-plugin-asciidoctor/NOTICE.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
This work is based on an old (before June 2018) 1.5.6 version of
|
||||
|
||||
https://github.com/asciidoctor/asciidoctor-gradle-plugin
|
||||
|
||||
You can find remnants in the official code under org.asciidoctor.gradle.compat, when it was created with
|
||||
|
||||
https://github.com/ysb33r/asciidoctor-gradle-plugin/commit/1ad29b2eba915f7bce3cb004e3e9582578c8ac72
|
||||
|
||||
License: Apache 2.0
|
47
gradle-plugin-asciidoctor/build.gradle
Normal file
47
gradle-plugin-asciidoctor/build.gradle
Normal file
|
@ -0,0 +1,47 @@
|
|||
plugins {
|
||||
id 'java-gradle-plugin'
|
||||
alias(libs.plugins.publish)
|
||||
}
|
||||
|
||||
apply plugin: 'java-gradle-plugin'
|
||||
apply plugin: 'com.gradle.plugin-publish'
|
||||
|
||||
apply from: rootProject.file('gradle/compile/groovy.gradle')
|
||||
|
||||
dependencies {
|
||||
api gradleApi()
|
||||
implementation libs.asciidoctorj
|
||||
implementation libs.jruby
|
||||
testImplementation libs.spock.core
|
||||
testImplementation libs.jsoup
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
asciidoctorPlugin {
|
||||
id = 'org.xbib.gradle.plugin.asciidoctor'
|
||||
implementationClass = 'org.xbib.gradle.plugin.asciidoctor.AsciidoctorPlugin'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (project.hasProperty('gradle.publish.key')) {
|
||||
pluginBundle {
|
||||
mavenCoordinates {
|
||||
groupId = "org.xbib.gradle.plugin"
|
||||
artifactId = "gradle-plugin-asciidoctor"
|
||||
version = project.version
|
||||
}
|
||||
website = 'https://github.com/jprante/gradle-plugins'
|
||||
vcsUrl = 'https://github.com/jprante/gradle-plugins'
|
||||
plugins {
|
||||
asciidoctorPlugin {
|
||||
id = 'org.xbib.gradle.plugin.asciidoctor'
|
||||
version = project.version
|
||||
description = 'Asciidoctor plugin for building documentations'
|
||||
displayName = 'Asciidoctor plugin for building documentations'
|
||||
tags = ['asciidoctor']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
gradle-plugin-asciidoctor/gradle.properties
Normal file
1
gradle-plugin-asciidoctor/gradle.properties
Normal file
|
@ -0,0 +1 @@
|
|||
version = 2.5.2.1
|
|
@ -0,0 +1,32 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor
|
||||
|
||||
enum AsciidoctorBackend {
|
||||
HTML('html'),
|
||||
DOCBOOK('docbook'),
|
||||
HTML5('html5'),
|
||||
DOCBOOK45('docbook45'),
|
||||
DOCBOOK5('docbook5'),
|
||||
EPUB3('epub3'),
|
||||
PDF('pdf'),
|
||||
XHTML('xhtml'),
|
||||
XHTML5('xhtml5'),
|
||||
|
||||
private final static Map<String, AsciidoctorBackend> ALL_BACKENDS
|
||||
private final String id
|
||||
|
||||
static {
|
||||
ALL_BACKENDS = values().collectEntries{ [it.id, it] }.asImmutable()
|
||||
}
|
||||
|
||||
private AsciidoctorBackend(String id) {
|
||||
this.id = id
|
||||
}
|
||||
|
||||
String getId() {
|
||||
id
|
||||
}
|
||||
|
||||
static boolean isBuiltIn(String name) {
|
||||
ALL_BACKENDS.containsKey(name)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor
|
||||
|
||||
import org.gradle.api.Project
|
||||
|
||||
class AsciidoctorExtension {
|
||||
|
||||
String version = '2.5.2'
|
||||
|
||||
boolean addDefaultRepositories = true
|
||||
|
||||
final Project project
|
||||
|
||||
AsciidoctorExtension(Project project) {
|
||||
this.project = project
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor
|
||||
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.ResolvableDependencies
|
||||
import org.gradle.api.artifacts.dsl.DependencyHandler
|
||||
|
||||
class AsciidoctorPlugin implements Plugin<Project> {
|
||||
|
||||
static final String ASCIIDOCTOR = 'asciidoctor'
|
||||
|
||||
static final String ASCIIDOCTORJ = 'asciidoctorj'
|
||||
|
||||
static final String ASCIIDOCTORJ_CORE_DEPENDENCY = 'org.asciidoctor:asciidoctorj:'
|
||||
|
||||
void apply(Project project) {
|
||||
project.apply(plugin: 'base')
|
||||
|
||||
AsciidoctorExtension extension = project.extensions.create(ASCIIDOCTORJ, AsciidoctorExtension, project)
|
||||
|
||||
project.afterEvaluate {
|
||||
if(project.extensions.asciidoctorj.addDefaultRepositories) {
|
||||
project.repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Configuration configuration = project.configurations.maybeCreate(ASCIIDOCTOR)
|
||||
project.logger.info("[Asciidoctor] asciidoctorj: ${extension.version}")
|
||||
|
||||
configuration.incoming.beforeResolve(new Action<ResolvableDependencies>() {
|
||||
@SuppressWarnings('UnusedMethodParameter')
|
||||
void execute(ResolvableDependencies resolvableDependencies) {
|
||||
DependencyHandler dependencyHandler = project.dependencies
|
||||
def dependencies = configuration.dependencies
|
||||
dependencies.add(dependencyHandler.create(ASCIIDOCTORJ_CORE_DEPENDENCY + extension.version))
|
||||
}
|
||||
})
|
||||
|
||||
project.task(ASCIIDOCTOR,
|
||||
type: AsciidoctorTask,
|
||||
group: 'Documentation',
|
||||
description: 'Converts AsciiDoc files and copies the output files and related resources to the build directory.') {
|
||||
classpath = configuration
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor
|
||||
|
||||
interface AsciidoctorProxy {
|
||||
|
||||
String convertFile(File filename, Map<String, Object> options)
|
||||
|
||||
void requireLibrary(String... requiredLibraries)
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor
|
||||
|
||||
class AsciidoctorProxyImpl implements AsciidoctorProxy {
|
||||
|
||||
def delegate
|
||||
|
||||
@Override
|
||||
String convertFile(File filename, Map<String, Object> options) {
|
||||
delegate.convertFile(filename, options)
|
||||
}
|
||||
|
||||
@Override
|
||||
void requireLibrary(String... requiredLibraries) {
|
||||
delegate.requireLibrary(requiredLibraries)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,863 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.InvalidUserDataException
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.file.CopySpec
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.file.FileTree
|
||||
import org.gradle.api.internal.file.copy.CopySpecInternal
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputDirectory
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.Optional
|
||||
import org.gradle.api.tasks.OutputDirectories
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.SkipWhenEmpty
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.util.PatternSet
|
||||
import org.gradle.internal.FileUtils
|
||||
import org.gradle.util.CollectionUtils
|
||||
import org.xbib.gradle.plugin.asciidoctor.groovydsl.AsciidoctorExtensions
|
||||
|
||||
import java.nio.file.Path
|
||||
|
||||
@SuppressWarnings(['MethodCount', 'Instanceof'])
|
||||
class AsciidoctorTask extends DefaultTask {
|
||||
|
||||
public static final String ASCIIDOCTOR_FACTORY_CLASSNAME = 'org.asciidoctor.Asciidoctor$Factory'
|
||||
|
||||
private static final boolean IS_WINDOWS = System.getProperty('os.name').contains('Windows')
|
||||
|
||||
private static final String PATH_SEPARATOR = System.getProperty('path.separator')
|
||||
|
||||
private static final String DOUBLE_BACKLASH = '\\\\'
|
||||
|
||||
private static final String BACKLASH = '\\'
|
||||
|
||||
private static final String SAFE_MODE_CLASSNAME = 'org.asciidoctor.SafeMode'
|
||||
|
||||
private static final String DEFAULT_BACKEND = AsciidoctorBackend.HTML5.id
|
||||
|
||||
private boolean baseDirSetToNull
|
||||
|
||||
private Object outDir
|
||||
|
||||
private Object srcDir
|
||||
|
||||
private final List<Object> gemPaths = []
|
||||
|
||||
private Set<String> backends
|
||||
|
||||
private Set<String> requires
|
||||
|
||||
private Map opts = [:]
|
||||
|
||||
private Map attrs = [:]
|
||||
|
||||
private PatternSet sourceDocumentPattern
|
||||
|
||||
private CopySpec resourceCopy
|
||||
|
||||
private static ClassLoader cl
|
||||
|
||||
/**
|
||||
* If set to true each backend will be output to a separate subfolder below {@code outputDir}
|
||||
*/
|
||||
@Input
|
||||
boolean separateOutputDirs = true
|
||||
|
||||
@Optional
|
||||
@InputDirectory
|
||||
File baseDir
|
||||
|
||||
/**
|
||||
* Logs documents as they are converted
|
||||
*/
|
||||
@Input
|
||||
boolean logDocuments = false
|
||||
|
||||
/**
|
||||
* Old way to set only one source document
|
||||
*/
|
||||
@Optional
|
||||
@InputFile
|
||||
File sourceDocumentName
|
||||
|
||||
/**
|
||||
* Old way to define the backend to use
|
||||
*/
|
||||
@Optional
|
||||
@Input
|
||||
String backend
|
||||
|
||||
@Internal
|
||||
AsciidoctorProxy asciidoctor
|
||||
|
||||
/**
|
||||
* Stores the extensions defined in the configuration phase
|
||||
* to register them in the execution phase.
|
||||
*/
|
||||
@Internal
|
||||
List<Object> asciidoctorExtensions = []
|
||||
|
||||
@Internal
|
||||
ResourceCopyProxy resourceCopyProxy
|
||||
|
||||
@Internal
|
||||
Configuration classpath
|
||||
|
||||
AsciidoctorTask() {
|
||||
srcDir = project.file('src/docs/asciidoc')
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all of the Asciidoctor options
|
||||
*/
|
||||
@Optional
|
||||
@Input
|
||||
Map getOptions() { this.opts }
|
||||
|
||||
/** Apply a new set of Asciidoctor options, clearing any options previously set.
|
||||
*
|
||||
* For backwards compatibility it is still possible to replace attributes via this call. However the
|
||||
* use of {@link #setAttributes(java.util.Map)} and {@link #attributes(java.util.Map)} are the now
|
||||
* correct way of working with attributes
|
||||
*
|
||||
* @param m Map with new options
|
||||
*/
|
||||
@SuppressWarnings('DuplicateStringLiteral')
|
||||
void setOptions(Map m) {
|
||||
if (!m) return // null check
|
||||
if (m.containsKey('attributes')) {
|
||||
logger.warn 'Attributes found in options. Existing attributes will be replaced due to assignment. ' +
|
||||
'Please use \'attributes\' method instead as current behaviour will be removed in future'
|
||||
attrs = coerceLegacyAttributeFormats(m.attributes)
|
||||
m.remove('attributes')
|
||||
}
|
||||
this.opts = m
|
||||
}
|
||||
|
||||
/** Appends a new set of Asciidoctor options.
|
||||
*
|
||||
* For backwards compatibility it is still possible to append attributes via this call. However the
|
||||
* use of {@link #setAttributes(java.util.Map)} and {@link #attributes(java.util.Map)} are the now
|
||||
* correct way of working with attributes
|
||||
*
|
||||
* @param m Map with new options
|
||||
*/
|
||||
@SuppressWarnings('DuplicateStringLiteral')
|
||||
void options(Map m) {
|
||||
if (!m) return // null check
|
||||
if (m.containsKey('attributes')) {
|
||||
logger.warn 'Attributes found in options. These will be added to existing attributes. ' +
|
||||
'Please use \'attributes\' method instead as current behaviour will be removed in future'
|
||||
attributes coerceLegacyAttributeFormats(m.attributes)
|
||||
m.remove('attributes')
|
||||
}
|
||||
this.opts += m
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current set of Asciidoctor attributes
|
||||
*/
|
||||
@Optional
|
||||
@Input
|
||||
Map getAttributes() { this.attrs }
|
||||
|
||||
/**
|
||||
* Applies a new set of Asciidoctor attributes, clearing any previously set
|
||||
*
|
||||
* @param m New map of attributes
|
||||
*/
|
||||
void setAttributes(Map m) {
|
||||
if (m) {
|
||||
this.attrs = m
|
||||
} else {
|
||||
this.attrs.clear()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a set of Asciidoctor attributes.
|
||||
*
|
||||
* @param o a Map, List or a literal (String) definition
|
||||
*/
|
||||
void attributes(Object... o) {
|
||||
if (!o) {
|
||||
this.attrs.clear()
|
||||
return
|
||||
}
|
||||
for (input in o) {
|
||||
this.attrs += coerceLegacyAttributeFormats(input)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of Ruby modules to be included.
|
||||
*/
|
||||
@Optional
|
||||
@Input
|
||||
Set<String> getRequires() { this.requires }
|
||||
|
||||
/**
|
||||
* Applies a new set of Ruby modules to be included, clearing any previous set.
|
||||
*
|
||||
* @param b One or more ruby modules to be included
|
||||
*/
|
||||
void setRequires(Object... b) {
|
||||
this.requires?.clear()
|
||||
requires(b)
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends new set of Ruby modules to be included.
|
||||
*
|
||||
* @param b One or more ruby modules to be included
|
||||
*/
|
||||
@SuppressWarnings('ConfusingMethodName')
|
||||
void requires(Object... b) {
|
||||
if (this.requires == null) {
|
||||
this.requires = []
|
||||
}
|
||||
if (!b) {
|
||||
return
|
||||
}
|
||||
this.requires.addAll(CollectionUtils.stringize(b as List))
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current set of Asciidoctor backends that will be used for document generation
|
||||
*/
|
||||
@Optional
|
||||
@Input
|
||||
Set<String> getBackends() { this.backends }
|
||||
|
||||
void setBackend(String b) {
|
||||
if (!b) {
|
||||
return
|
||||
}
|
||||
deprecated 'setBackend', 'backends', 'Using `backend` and `backends` together will result in `backend` being ignored.'
|
||||
backend = b
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a new set of Asciidoctor backends that will be used for document generation clearing any
|
||||
* previous backends
|
||||
*
|
||||
* @param b List of backends. Each item must be convertible to string.
|
||||
*/
|
||||
void setBackends(Object... b) {
|
||||
this.backends?.clear()
|
||||
backends(b)
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends additional Asciidoctor backends that will be used for document generation.
|
||||
*
|
||||
* @param b List of backends. Each item must be convertible to string.
|
||||
*/
|
||||
@SuppressWarnings('ConfusingMethodName')
|
||||
void backends(Object... b) {
|
||||
if (this.backends == null) {
|
||||
this.backends = []
|
||||
}
|
||||
if (!b) {
|
||||
return
|
||||
}
|
||||
this.backends.addAll(CollectionUtils.stringize(b as List))
|
||||
}
|
||||
|
||||
/** Defines extensions. The given parameters should
|
||||
* either contain Asciidoctor Groovy DSL closures or files
|
||||
* with content conforming to the Asciidoctor Groovy DSL.
|
||||
*/
|
||||
void extensions(Object... exts) {
|
||||
if (!exts) return // null check
|
||||
asciidoctorExtensions.addAll(exts as List)
|
||||
}
|
||||
|
||||
/** Sets a new gemPath to be used
|
||||
*
|
||||
* @param f A path object can be be converted with {@code project.file}.
|
||||
*/
|
||||
@SuppressWarnings('ConfusingMethodName')
|
||||
void gemPath(Object... f) {
|
||||
if (!f) {
|
||||
return
|
||||
}
|
||||
this.gemPaths.addAll(f as List)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new list of GEM paths to be used.
|
||||
*
|
||||
* @param f A {@code File} object pointing to list of installed GEMs
|
||||
*/
|
||||
void setGemPath(Object... f) {
|
||||
this.gemPaths.clear()
|
||||
if (!f) {
|
||||
return
|
||||
}
|
||||
this.gemPaths.addAll(f as List)
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a single string to a GEM path, scanning it for concatenated GEM Paths, separated by the platform
|
||||
* separator. This utility is only for backwards compatibility
|
||||
*
|
||||
* @param s
|
||||
*/
|
||||
void setGemPath(Object path) {
|
||||
this.gemPaths.clear()
|
||||
if (path instanceof CharSequence) {
|
||||
setGemPath(path.tokenize(PATH_SEPARATOR))
|
||||
} else if (path instanceof List) {
|
||||
this.gemPaths.addAll(path)
|
||||
} else if (path instanceof File || path instanceof Path) {
|
||||
this.gemPaths.add(path)
|
||||
} else {
|
||||
throw new IllegalArgumentException("unknown path class: " + path.getClass().getName())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of paths to be used for {@code GEM_HOME}
|
||||
*/
|
||||
@Optional
|
||||
@InputFiles
|
||||
FileCollection getGemPath() {
|
||||
project.files(this.gemPaths)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of paths to be used for GEM installations in a format that is suitable for assignment to {@code GEM_HOME}
|
||||
*
|
||||
* Calling this will cause gemPath to be resolved immediately.
|
||||
*/
|
||||
String asGemPath() {
|
||||
gemPath.files*.toString().join(PATH_SEPARATOR)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the new Asciidoctor parent source directory.
|
||||
*
|
||||
* @param f An object convertible via {@code project.file}
|
||||
*/
|
||||
void sourceDir(Object f) {
|
||||
this.srcDir = f
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the new Asciidoctor parent source directory.
|
||||
*
|
||||
* @param f A {@code File} object pointing to the parent source directory
|
||||
*/
|
||||
void setSourceDir(File f) {
|
||||
this.srcDir = f
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent directory for Asciidoctor source. Default is {@code src/asciidoc}.
|
||||
*/
|
||||
@Optional
|
||||
@InputDirectory
|
||||
File getSourceDir() {
|
||||
project.file(srcDir)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the new Asciidoctor parent output directory.
|
||||
*
|
||||
* @param f An object convertible via {@code project.file}
|
||||
*/
|
||||
void outputDir(Object f) {
|
||||
this.outDir = f
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the new Asciidoctor parent output directory.
|
||||
*
|
||||
* @param f A {@code File} object pointing to the parent output directory
|
||||
*/
|
||||
void setOutputDir(File f) {
|
||||
this.outDir = f
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current toplevel output directory
|
||||
*/
|
||||
@OutputDirectory
|
||||
File getOutputDir() {
|
||||
if (this.outDir == null) {
|
||||
this.outDir = new File(project.buildDir, 'asciidoc')
|
||||
}
|
||||
project.file(this.outDir)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the collection of source documents
|
||||
*
|
||||
* If sourceDocumentNames was not set or is empty, it will return all asciidoc files
|
||||
* in {@code sourceDir}. Otherwise only the files provided earlier to sourceDocumentNames
|
||||
* are returned if they are found below {@code sourceDir}
|
||||
*/
|
||||
@OutputDirectories
|
||||
FileCollection getSourceDocumentNames() {
|
||||
deprecated 'getSourceDocumentNames', 'getSourceFileTree'
|
||||
sourceFileTree
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a single file to the main source file
|
||||
*
|
||||
* @param f A file that is relative to {@code sourceDir}
|
||||
*/
|
||||
void setSourceDocumentName(File f) {
|
||||
deprecated 'setSourceDocumentName',
|
||||
'setIncludes', 'File will be converted to a pattern.'
|
||||
sources {
|
||||
setIncludes([AsciidoctorUtils.getRelativePath(f.absoluteFile, sourceDir.absoluteFile)])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the current set of source documents with a new set
|
||||
*
|
||||
* @parm src List of source documents, which must be convertible using {@code project.files}
|
||||
*/
|
||||
@SuppressWarnings('DuplicateStringLiteral')
|
||||
void setSourceDocumentNames(Object... src) {
|
||||
deprecated 'setSourceDocumentNames',
|
||||
'setIncludes',
|
||||
'Files are converted to patterns. Some might not convert correctly. ' +
|
||||
'FileCollections will not convert'
|
||||
File base = sourceDir.absoluteFile
|
||||
def patterns = CollectionUtils.stringize(src as List).collect { String it ->
|
||||
def tmpFile = new File(it)
|
||||
String relPath
|
||||
if (tmpFile.isAbsolute()) {
|
||||
relPath = AsciidoctorUtils.getRelativePath(tmpFile.absoluteFile, base)
|
||||
} else {
|
||||
relPath = it
|
||||
}
|
||||
logger.debug "setSourceDocumentNames - Found ${it}, converted to ${relPath}"
|
||||
relPath
|
||||
}
|
||||
sources {
|
||||
setIncludes(patterns)
|
||||
}
|
||||
}
|
||||
|
||||
void setBaseDir(File baseDir) {
|
||||
this.baseDir = baseDir
|
||||
baseDirSetToNull = baseDir == null
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all output directories.
|
||||
*/
|
||||
@OutputDirectories
|
||||
Set<File> getOutputDirectories() {
|
||||
if (separateOutputDirs) {
|
||||
backends.collect { new File(outputDir, it) } as Set
|
||||
} else {
|
||||
[outputDir] as Set
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a FileTree containing all of the source documents
|
||||
*
|
||||
* @return If {@code sources} was never called then all asciidoc source files below {@code sourceDir} will
|
||||
* be included
|
||||
*/
|
||||
@InputFiles
|
||||
@SkipWhenEmpty
|
||||
FileTree getSourceFileTree() {
|
||||
project.fileTree(sourceDir).
|
||||
matching(this.sourceDocumentPattern ?: defaultSourceDocumentPattern)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add patterns for source files or source files via a closure
|
||||
*
|
||||
* @param cfg PatternSet configuration closure
|
||||
*/
|
||||
void sources(Closure cfg) {
|
||||
if (sourceDocumentPattern == null) {
|
||||
sourceDocumentPattern = new PatternSet()
|
||||
}
|
||||
def configuration = cfg.clone()
|
||||
configuration.delegate = sourceDocumentPattern
|
||||
configuration()
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to the CopySpec for extra files. The destination of these files will always have a parent directory
|
||||
* of {@code outputDir} or {@code outputDir + backend}
|
||||
*
|
||||
* @param cfg CopySpec configuration closure
|
||||
*/
|
||||
void resources(Closure cfg) {
|
||||
if (this.resourceCopy == null) {
|
||||
this.resourceCopy = project.copySpec(cfg)
|
||||
} else {
|
||||
def configuration = cfg.clone()
|
||||
configuration.delegate = this.resourceCopy
|
||||
configuration()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The default PatternSet that will be used if {@code sources} was never called
|
||||
*
|
||||
* By default all *.adoc,*.ad,*.asc,*.asciidoc is included. Files beginning with underscore are excluded
|
||||
*
|
||||
*/
|
||||
@Internal
|
||||
PatternSet getDefaultSourceDocumentPattern() {
|
||||
PatternSet ps = new PatternSet()
|
||||
ps.include '**/*.adoc'
|
||||
ps.include '**/*.ad'
|
||||
ps.include '**/*.asc'
|
||||
ps.include '**/*.asciidoc'
|
||||
ps.exclude '**/_*'
|
||||
}
|
||||
|
||||
/**
|
||||
* The default CopySpec that will be used if {@code resources} was never called
|
||||
*
|
||||
* By default anything below {@code $sourceDir/images} will be included.
|
||||
*
|
||||
* @return A {@code CopySpec}, never null
|
||||
*/
|
||||
@Internal
|
||||
CopySpec getDefaultResourceCopySpec() {
|
||||
project.copySpec {
|
||||
from(sourceDir) {
|
||||
include 'images/**'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CopySpec for additional resources
|
||||
* If {@code resources} was never called, it will return a default CopySpec otherwise it will return the
|
||||
* one built up via successive calls to {@code resources}
|
||||
*
|
||||
* @return A {@code CopySpec}, never null
|
||||
*/
|
||||
@Internal
|
||||
CopySpec getResourceCopySpec() {
|
||||
this.resourceCopy ?: defaultResourceCopySpec
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the additional resources as a FileCollection.
|
||||
* If {@code resources} was never called, it will return the file collections as per default CopySpec otherwise it
|
||||
* will return the collections as built up via successive calls to {@code resources}
|
||||
*
|
||||
* @return A {@code FileCollection}, never null
|
||||
*/
|
||||
@InputFiles
|
||||
@SkipWhenEmpty
|
||||
@Optional
|
||||
FileCollection getResourceFileCollection() {
|
||||
(resourceCopySpec as CopySpecInternal).buildRootResolver().allSource
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void processAsciidocSources() {
|
||||
if (sourceFileTree.files.size() == 0) {
|
||||
logger.lifecycle 'Asciidoc source file tree is empty. Nothing will be processed.'
|
||||
return
|
||||
}
|
||||
if (classpath == null) {
|
||||
classpath = project.configurations.getByName(AsciidoctorPlugin.ASCIIDOCTOR)
|
||||
}
|
||||
setupClassLoader()
|
||||
if (!asciidoctorExtensions?.empty) {
|
||||
Class asciidoctorExtensionsDslRegistry = loadClass(AsciidoctorExtensions.class.getName())
|
||||
asciidoctorExtensions.each { asciidoctorExtensionsDslRegistry.extensions(it) }
|
||||
}
|
||||
if (!asciidoctor) {
|
||||
instantiateAsciidoctor()
|
||||
}
|
||||
if (resourceCopyProxy == null) {
|
||||
resourceCopyProxy = new ResourceCopyProxyImpl(project)
|
||||
}
|
||||
if (requires) {
|
||||
for (require in requires) {
|
||||
asciidoctor.requireLibrary(require)
|
||||
}
|
||||
}
|
||||
for (activeBackend in activeBackends()) {
|
||||
if (!AsciidoctorBackend.isBuiltIn(activeBackend)) {
|
||||
logger.lifecycle("Passing through unknown backend: $activeBackend")
|
||||
}
|
||||
processDocumentsAndResources(activeBackend)
|
||||
}
|
||||
}
|
||||
|
||||
@groovy.transform.PackageScope
|
||||
File outputDirFor(final File source, final String basePath, final File outputDir, final String backend) {
|
||||
String filePath = source.directory ? source.absolutePath : source.parentFile.absolutePath
|
||||
String relativeFilePath = normalizePath(filePath) - normalizePath(basePath)
|
||||
File baseOutputDir = outputBackendDir(outputDir, backend)
|
||||
File destinationParentDir = new File(baseOutputDir, relativeFilePath)
|
||||
if (!destinationParentDir.exists()) {
|
||||
destinationParentDir.mkdirs()
|
||||
}
|
||||
destinationParentDir
|
||||
}
|
||||
|
||||
private File outputBackendDir(final File outputDir, final String backend) {
|
||||
separateOutputDirs ? new File(outputDir, FileUtils.toSafeFileName(backend)) : outputDir
|
||||
}
|
||||
|
||||
private static String normalizePath(String path) {
|
||||
if (IS_WINDOWS) {
|
||||
path = path.replace(DOUBLE_BACKLASH, BACKLASH)
|
||||
path = path.replace(BACKLASH, DOUBLE_BACKLASH)
|
||||
}
|
||||
path
|
||||
}
|
||||
|
||||
@SuppressWarnings('CatchException')
|
||||
private void instantiateAsciidoctor() {
|
||||
if (gemPaths.size()) {
|
||||
asciidoctor = new AsciidoctorProxyImpl(delegate: loadClass(ASCIIDOCTOR_FACTORY_CLASSNAME).create(asGemPath()))
|
||||
} else {
|
||||
try {
|
||||
asciidoctor = new AsciidoctorProxyImpl(delegate: loadClass(ASCIIDOCTOR_FACTORY_CLASSNAME).create(null as String))
|
||||
} catch (Exception e) {
|
||||
asciidoctor = new AsciidoctorProxyImpl(delegate: loadClass(ASCIIDOCTOR_FACTORY_CLASSNAME).create())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> activeBackends() {
|
||||
if (this.backends) {
|
||||
return this.backends
|
||||
} else if (backend) {
|
||||
return [backend]
|
||||
}
|
||||
[DEFAULT_BACKEND]
|
||||
}
|
||||
|
||||
@SuppressWarnings('CatchException')
|
||||
@SuppressWarnings('DuplicateStringLiteral')
|
||||
private void processDocumentsAndResources(final String backend) {
|
||||
try {
|
||||
sourceFileTree.files.each { File file ->
|
||||
if (file.name.startsWith('_')) {
|
||||
throw new InvalidUserDataException('Source documents may not start with an underscore')
|
||||
}
|
||||
File destinationParentDir = owner.outputDirFor(file, sourceDir.absolutePath, outputDir, backend)
|
||||
processSingleFile(backend, destinationParentDir, file)
|
||||
}
|
||||
|
||||
resourceCopyProxy.copy(outputBackendDir(outputDir, backend), resourceCopySpec)
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new GradleException('Error running Asciidoctor', e)
|
||||
}
|
||||
}
|
||||
|
||||
protected void processSingleFile(String backend, File destinationParentDir, File file) {
|
||||
if (logDocuments) {
|
||||
logger.lifecycle("Converting $file")
|
||||
}
|
||||
asciidoctor.convertFile(file, mergedOptions(file,
|
||||
[
|
||||
project : project,
|
||||
options : options,
|
||||
attributes: attrs,
|
||||
baseDir : !baseDir && !baseDirSetToNull ? file.parentFile : baseDir,
|
||||
projectDir: project.projectDir,
|
||||
rootDir : project.rootDir,
|
||||
outputDir : destinationParentDir,
|
||||
backend : backend]))
|
||||
}
|
||||
|
||||
@SuppressWarnings('AbcMetric')
|
||||
private static Map<String, Object> mergedOptions(File file, Map params) {
|
||||
Map<String, Object> mergedOptions = [:]
|
||||
mergedOptions.putAll(params.options)
|
||||
mergedOptions.backend = params.backend
|
||||
mergedOptions.in_place = false
|
||||
mergedOptions.safe = resolveSafeModeLevel(mergedOptions.safe, 0i)
|
||||
mergedOptions.to_dir = params.outputDir
|
||||
if (params.baseDir) {
|
||||
mergedOptions.base_dir = params.baseDir
|
||||
}
|
||||
|
||||
if (mergedOptions.to_file) {
|
||||
File toFile = new File(mergedOptions.to_file)
|
||||
mergedOptions.to_file = new File(mergedOptions.remove('to_dir'), toFile.name)
|
||||
}
|
||||
|
||||
Map attributes = [:]
|
||||
processMapAttributes(attributes, params.attributes)
|
||||
|
||||
// Note: Directories passed as relative to work around issue #83
|
||||
// Asciidoctor cannot handle absolute paths in Windows properly
|
||||
attributes.projectdir = AsciidoctorUtils.getRelativePath(params.projectDir, file.parentFile)
|
||||
attributes.rootdir = AsciidoctorUtils.getRelativePath(params.rootDir, file.parentFile)
|
||||
|
||||
// resolve these properties here as we want to catch both Map and String definitions parsed above
|
||||
attributes.'project-name' = attributes.'project-name' ?: params.project.name
|
||||
attributes.'project-group' = attributes.'project-group' ?: (params.project.group ?: '')
|
||||
attributes.'project-version' = attributes.'project-version' ?: (params.project.version ?: '')
|
||||
mergedOptions.attributes = attributes
|
||||
|
||||
// Issue #14 force GString -> String as jruby will fail
|
||||
// to find an exact match when invoking Asciidoctor
|
||||
for (entry in mergedOptions) {
|
||||
if (entry.value instanceof CharSequence) {
|
||||
mergedOptions[entry.key] = entry.value.toString()
|
||||
} else if (entry.value instanceof List) {
|
||||
mergedOptions[entry.key] = stringifyList(entry.value)
|
||||
} else if (entry.value instanceof Map) {
|
||||
mergedOptions[entry.key] = stringifyMap(entry.value)
|
||||
} else if (entry.value instanceof File) {
|
||||
mergedOptions[entry.key] = entry.value.absolutePath
|
||||
}
|
||||
}
|
||||
|
||||
mergedOptions
|
||||
}
|
||||
|
||||
private static List stringifyList(List input) {
|
||||
input.collect { element ->
|
||||
if (element instanceof CharSequence) {
|
||||
element.toString()
|
||||
} else if (element instanceof List) {
|
||||
stringifyList(element)
|
||||
} else if (element instanceof Map) {
|
||||
stringifyMap(element)
|
||||
} else if(element instanceof File) {
|
||||
element.absolutePath
|
||||
} else {
|
||||
element
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Map stringifyMap(Map input) {
|
||||
Map output = [:]
|
||||
input.each { key, value ->
|
||||
if (value instanceof CharSequence) {
|
||||
output[key] = value.toString()
|
||||
} else if (value instanceof List) {
|
||||
output[key] = stringifyList(value)
|
||||
} else if (value instanceof Map) {
|
||||
output[key] = stringifyMap(value)
|
||||
} else if(value instanceof File) {
|
||||
output[key] = value.absolutePath
|
||||
} else {
|
||||
output[key] = value
|
||||
}
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
protected static void processMapAttributes(Map attributes, Map rawAttributes) {
|
||||
// copy all attributes in order to prevent changes down
|
||||
// the Asciidoctor chain that could cause serialization
|
||||
// problems with Gradle -> all inputs/outputs get serialized
|
||||
// for caching purposes; Ruby objects are non-serializable
|
||||
// Issue #14 force GString -> String as jruby will fail
|
||||
// to find an exact match when invoking Asciidoctor
|
||||
for (entry in rawAttributes) {
|
||||
if (entry.value == null || entry.value instanceof Boolean) {
|
||||
attributes[entry.key] = entry.value
|
||||
} else {
|
||||
attributes[entry.key] = entry.value.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static void processCollectionAttributes(Map attributes, rawAttributes) {
|
||||
for (attr in rawAttributes) {
|
||||
if (attr instanceof CharSequence) {
|
||||
def (k, v) = attr.toString().split('=', 2) as List
|
||||
attributes.put(k, v != null ? v : '')
|
||||
} else {
|
||||
// QUESTION should we just coerce it to a String?
|
||||
throw new InvalidUserDataException("Unsupported type for attribute ${attr}: ${attr.getClass()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings('DuplicateStringLiteral')
|
||||
@SuppressWarnings('DuplicateNumberLiteral')
|
||||
private static Map coerceLegacyAttributeFormats(Object attributes) {
|
||||
Map transformedMap = [:]
|
||||
switch (attributes) {
|
||||
case Map:
|
||||
transformedMap = attributes
|
||||
break
|
||||
case CharSequence:
|
||||
attributes.replaceAll('([^\\\\]) ', '$1\0').replaceAll('\\\\ ', ' ').split('\0').collect {
|
||||
def split = it.split('=')
|
||||
if (split.size() < 2) {
|
||||
throw new InvalidUserDataException("Unsupported format for attributes: ${attributes}")
|
||||
}
|
||||
transformedMap[split[0]] = split.drop(1).join('=')
|
||||
}
|
||||
break
|
||||
case Collection:
|
||||
processCollectionAttributes(transformedMap, attributes)
|
||||
break
|
||||
default:
|
||||
if (attributes.class.isArray()) {
|
||||
processCollectionAttributes(transformedMap, attributes)
|
||||
} else {
|
||||
throw new InvalidUserDataException("Unsupported type for attributes: ${attributes.class}")
|
||||
}
|
||||
}
|
||||
|
||||
transformedMap
|
||||
}
|
||||
|
||||
private static int resolveSafeModeLevel(Object safe, int defaultLevel) {
|
||||
if (safe == null) {
|
||||
defaultLevel
|
||||
} else if (safe.class.name == SAFE_MODE_CLASSNAME) {
|
||||
safe.level
|
||||
} else if (safe instanceof CharSequence) {
|
||||
try {
|
||||
Enum.valueOf(loadClass(SAFE_MODE_CLASSNAME), safe.toString().toUpperCase()).level
|
||||
} catch (IllegalArgumentException e) {
|
||||
defaultLevel
|
||||
}
|
||||
} else {
|
||||
safe.intValue()
|
||||
}
|
||||
}
|
||||
|
||||
private static Class loadClass(String className) {
|
||||
cl.loadClass(className)
|
||||
}
|
||||
|
||||
@SuppressWarnings('AssignmentToStaticFieldFromInstanceMethod')
|
||||
private void setupClassLoader() {
|
||||
if (classpath?.files) {
|
||||
def urls = classpath.files.collect { it.toURI().toURL() }
|
||||
cl = new URLClassLoader(urls as URL[], Thread.currentThread().contextClassLoader)
|
||||
Thread.currentThread().contextClassLoader = cl
|
||||
} else {
|
||||
cl = Thread.currentThread().contextClassLoader
|
||||
}
|
||||
}
|
||||
|
||||
private void deprecated(final String method, final String alternative, final String msg = '') {
|
||||
logger.lifecycle "Asciidoctor: ${method} is deprecated and will be removed in a future version. " +
|
||||
"Use ${alternative} instead. ${msg}"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor
|
||||
|
||||
import java.util.regex.Pattern
|
||||
|
||||
class AsciidoctorUtils {
|
||||
|
||||
static String getRelativePath(File target, File base) throws IOException {
|
||||
String[] baseComponents = base.canonicalPath.split(Pattern.quote(File.separator))
|
||||
String[] targetComponents = target.canonicalPath.split(Pattern.quote(File.separator))
|
||||
int index = 0
|
||||
for (; index < targetComponents.length && index < baseComponents.length; ++index) {
|
||||
if (!targetComponents[index].equals(baseComponents[index])) {
|
||||
break
|
||||
}
|
||||
}
|
||||
StringBuilder result = new StringBuilder()
|
||||
if (index != baseComponents.length) {
|
||||
for (int i = index; i < baseComponents.length; ++i) {
|
||||
if (i != index) {
|
||||
result.append(File.separator)
|
||||
}
|
||||
result.append('..')
|
||||
}
|
||||
}
|
||||
for (int i = index; i < targetComponents.length; ++i) {
|
||||
if (i != index) {
|
||||
result.append(File.separator)
|
||||
}
|
||||
result.append(targetComponents[i])
|
||||
}
|
||||
result.toString()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor
|
||||
|
||||
import org.gradle.api.file.CopySpec
|
||||
import org.gradle.api.tasks.WorkResult
|
||||
|
||||
interface ResourceCopyProxy {
|
||||
|
||||
WorkResult copy(File outputDir, CopySpec spec)
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.CopySpec
|
||||
import org.gradle.api.tasks.WorkResult
|
||||
|
||||
class ResourceCopyProxyImpl implements ResourceCopyProxy {
|
||||
|
||||
Project project
|
||||
|
||||
ResourceCopyProxyImpl(Project p) { project = p }
|
||||
|
||||
@Override
|
||||
WorkResult copy(File outputDir, CopySpec spec) {
|
||||
project.copy {
|
||||
into outputDir
|
||||
with spec
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor.groovydsl
|
||||
|
||||
class AsciidoctorExtensionException extends Exception {
|
||||
|
||||
AsciidoctorExtensionException() {
|
||||
}
|
||||
|
||||
AsciidoctorExtensionException(String message) {
|
||||
super(message)
|
||||
}
|
||||
|
||||
AsciidoctorExtensionException(String message, Throwable cause) {
|
||||
super(message, cause)
|
||||
}
|
||||
|
||||
AsciidoctorExtensionException(Throwable cause) {
|
||||
super(cause)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor.groovydsl
|
||||
|
||||
import org.asciidoctor.Asciidoctor
|
||||
import org.asciidoctor.extension.BlockMacroProcessor
|
||||
import org.asciidoctor.extension.BlockProcessor
|
||||
import org.asciidoctor.extension.DocinfoProcessor
|
||||
import org.asciidoctor.extension.IncludeProcessor
|
||||
import org.asciidoctor.extension.InlineMacroProcessor
|
||||
import org.asciidoctor.extension.Postprocessor
|
||||
import org.asciidoctor.extension.Preprocessor
|
||||
import org.asciidoctor.extension.Treeprocessor
|
||||
import org.xbib.gradle.plugin.asciidoctor.groovydsl.extensions.DelegatingBlockMacroProcessor
|
||||
import org.xbib.gradle.plugin.asciidoctor.groovydsl.extensions.DelegatingBlockProcessor
|
||||
import org.xbib.gradle.plugin.asciidoctor.groovydsl.extensions.DelegatingDocinfoProcessor
|
||||
import org.xbib.gradle.plugin.asciidoctor.groovydsl.extensions.DelegatingIncludeProcessor
|
||||
import org.xbib.gradle.plugin.asciidoctor.groovydsl.extensions.DelegatingPostprocessor
|
||||
import org.xbib.gradle.plugin.asciidoctor.groovydsl.extensions.DelegatingPreprocessor
|
||||
import org.xbib.gradle.plugin.asciidoctor.groovydsl.extensions.DelegatingInlineMacroProcessor
|
||||
import org.xbib.gradle.plugin.asciidoctor.groovydsl.extensions.DelegatingTreeprocessor
|
||||
|
||||
class AsciidoctorExtensionHandler {
|
||||
|
||||
static final String OPTION_NAME = 'name'
|
||||
|
||||
static final String OPTION_FILTER = 'filter'
|
||||
|
||||
static final String OPTION_CONTEXTS = 'contexts'
|
||||
|
||||
private final Asciidoctor asciidoctor
|
||||
|
||||
AsciidoctorExtensionHandler(Asciidoctor asciidoctor) {
|
||||
this.asciidoctor = asciidoctor
|
||||
}
|
||||
|
||||
void block(String blockName, @DelegatesTo(BlockProcessor) Closure cl) {
|
||||
block([(OPTION_NAME): blockName], cl)
|
||||
}
|
||||
|
||||
void block(Map options=[:], @DelegatesTo(BlockProcessor) Closure cl) {
|
||||
if (!options.containsKey(OPTION_NAME)) {
|
||||
throw new IllegalArgumentException('Block must define a name!')
|
||||
}
|
||||
if (!options.containsKey(OPTION_CONTEXTS)) {
|
||||
//TODO: What are sensible defaults?
|
||||
options[OPTION_CONTEXTS] = [':open', ':paragraph']
|
||||
}
|
||||
asciidoctor.javaExtensionRegistry().block(new DelegatingBlockProcessor(options, cl))
|
||||
}
|
||||
|
||||
void block_macro(Map options, @DelegatesTo(BlockMacroProcessor) Closure cl) {
|
||||
asciidoctor.javaExtensionRegistry().blockMacro(new DelegatingBlockMacroProcessor(options[OPTION_NAME] as String, options, cl))
|
||||
}
|
||||
|
||||
void block_macro(String name, @DelegatesTo(BlockMacroProcessor) Closure cl) {
|
||||
block_macro([(OPTION_NAME): name], cl)
|
||||
}
|
||||
|
||||
void postprocessor(Map options=[:], @DelegatesTo(Postprocessor) Closure cl) {
|
||||
asciidoctor.javaExtensionRegistry().postprocessor(new DelegatingPostprocessor(options, cl))
|
||||
}
|
||||
|
||||
void preprocessor(Map options=[:], @DelegatesTo(Preprocessor) Closure cl) {
|
||||
asciidoctor.javaExtensionRegistry().preprocessor(new DelegatingPreprocessor(options, cl))
|
||||
}
|
||||
|
||||
void include_processor(Map options=[:], @DelegatesTo(IncludeProcessor) Closure cl) {
|
||||
Closure filter = options[OPTION_FILTER] as Closure
|
||||
Map optionsWithoutFilter = options - options.subMap([OPTION_FILTER])
|
||||
asciidoctor.javaExtensionRegistry().includeProcessor(new DelegatingIncludeProcessor(optionsWithoutFilter, filter, cl))
|
||||
}
|
||||
|
||||
void inline_macro(Map options, @DelegatesTo(InlineMacroProcessor) Closure cl) {
|
||||
asciidoctor.javaExtensionRegistry().inlineMacro(new DelegatingInlineMacroProcessor(options[OPTION_NAME] as String, options, cl))
|
||||
}
|
||||
|
||||
void inline_macro(String macroName, @DelegatesTo(InlineMacroProcessor) Closure cl) {
|
||||
inline_macro([(OPTION_NAME): macroName], cl)
|
||||
}
|
||||
|
||||
void treeprocessor(Map options=[:], @DelegatesTo(Treeprocessor) Closure cl) {
|
||||
asciidoctor.javaExtensionRegistry().treeprocessor(new DelegatingTreeprocessor(options, cl))
|
||||
}
|
||||
|
||||
void docinfo_processor(Map options=[:], @DelegatesTo(DocinfoProcessor) Closure cl) {
|
||||
asciidoctor.javaExtensionRegistry().docinfoProcessor(new DelegatingDocinfoProcessor(options, cl))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,178 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor.groovydsl
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import org.asciidoctor.Asciidoctor
|
||||
import org.codehaus.groovy.control.CompilerConfiguration
|
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer
|
||||
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
|
||||
/**
|
||||
* An instance of this class holds all extension closure and scripts.
|
||||
* It evaluates the blocks and scripts and forwards the extracted extensions
|
||||
* to the GroovyExtensionRegistry which is service implementation
|
||||
* of org.asciidoctor.extension.spi.wExtensionRegistry
|
||||
*/
|
||||
@CompileStatic
|
||||
class AsciidoctorExtensions {
|
||||
|
||||
private final List<Object> registeredExtensions = []
|
||||
|
||||
private static final AsciidoctorExtensions INSTANCE = new AsciidoctorExtensions()
|
||||
|
||||
/** Add an extension from a closure
|
||||
*
|
||||
* @param cl Closure containing an extension
|
||||
*/
|
||||
void addExtension(@DelegatesTo(AsciidoctorExtensionHandler) Closure cl) {
|
||||
registeredExtensions.add(cl)
|
||||
}
|
||||
|
||||
/** Add an extension via a string.
|
||||
*
|
||||
* @param groovyScript String containing extension.
|
||||
*/
|
||||
void addExtension(final String groovyScript) {
|
||||
registeredExtensions.add(groovyScript)
|
||||
}
|
||||
|
||||
/** Add an extension via a file.
|
||||
*
|
||||
* @param groovyScript File containing extension
|
||||
*/
|
||||
void addExtension(final File groovyScript) {
|
||||
registeredExtensions.add(groovyScript)
|
||||
}
|
||||
|
||||
/** Add an extension via a path instance
|
||||
*
|
||||
* @param groovyScript Path pointing to an extension
|
||||
*/
|
||||
void addExtension(final Path groovyScript) {
|
||||
registeredExtensions.add(groovyScript)
|
||||
}
|
||||
|
||||
/** Remove all extensions.
|
||||
*
|
||||
*/
|
||||
void clearExtensions() {
|
||||
registeredExtensions.clear()
|
||||
}
|
||||
|
||||
/** Register all extension with an instance of Asciidoctor.
|
||||
*
|
||||
* @param asciidoctor Asciidoctor instance awaiting extensions.
|
||||
* @throw AsciidoctorExtensionException
|
||||
*/
|
||||
@SuppressWarnings('UnnecessarySetter')
|
||||
void registerExtensionsWith(Asciidoctor asciidoctor) {
|
||||
AsciidoctorExtensionHandler extensionHandler = new AsciidoctorExtensionHandler(asciidoctor)
|
||||
for (def it : registeredExtensions) {
|
||||
switch (it) {
|
||||
case Closure:
|
||||
try {
|
||||
((Closure) it).delegate = extensionHandler
|
||||
((Closure) it).call()
|
||||
} catch (e) {
|
||||
throw new AsciidoctorExtensionException("Error registering extension from class in ${it.class.name}", e)
|
||||
}
|
||||
break
|
||||
case String:
|
||||
GroovyShell shell = makeGroovyShell()
|
||||
DelegatingScript script = (DelegatingScript) shell.parse((String) it)
|
||||
script.setDelegate(extensionHandler)
|
||||
try {
|
||||
script.run()
|
||||
} catch (e) {
|
||||
registeredExtensions.clear()
|
||||
throw new AsciidoctorExtensionException('Error registering extension from string', e)
|
||||
}
|
||||
break
|
||||
case File:
|
||||
File file = (File) it
|
||||
GroovyShell shell = makeGroovyShell()
|
||||
file.withReader { reader ->
|
||||
DelegatingScript script = (DelegatingScript) shell.parse(reader, file.name)
|
||||
script.setDelegate(extensionHandler)
|
||||
try {
|
||||
script.run()
|
||||
} catch (e) {
|
||||
throw new AsciidoctorExtensionException("Error registering extension from file ${file.name}", e)
|
||||
}
|
||||
}
|
||||
break
|
||||
case Path:
|
||||
Path path = (Path) it
|
||||
GroovyShell shell = makeGroovyShell()
|
||||
Files.newBufferedReader(path).withReader { reader ->
|
||||
DelegatingScript script = (DelegatingScript) shell.parse(reader, path.toString())
|
||||
script.setDelegate(extensionHandler)
|
||||
try {
|
||||
script.run()
|
||||
} catch (e) {
|
||||
throw new AsciidoctorExtensionException("Error registering extension from file ${path}", e)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds an extension to the AsciidoctorExtension singleton instance.
|
||||
*
|
||||
* @param cl Closure containing an instance
|
||||
*/
|
||||
static void extensions(@DelegatesTo(AsciidoctorExtensionHandler) Closure cl) {
|
||||
INSTANCE.addExtension(cl)
|
||||
}
|
||||
|
||||
/** Adds an extension to the AsciidoctorExtension singleton instance.
|
||||
*
|
||||
* @param s String containing an instance
|
||||
*/
|
||||
static void extensions(String s) {
|
||||
INSTANCE.addExtension(s)
|
||||
}
|
||||
|
||||
/** Adds an extension to the AsciidoctorExtension singleton instance.
|
||||
*
|
||||
* @param f File containing an instance
|
||||
*/
|
||||
static void extensions(File f) {
|
||||
INSTANCE.addExtension(f)
|
||||
}
|
||||
|
||||
/** Attempt to register all exteniosn with ASciidoctor instance.
|
||||
*
|
||||
* This method has the side-effect of removing all extensions as well.
|
||||
*
|
||||
* @param asciidoctor
|
||||
*/
|
||||
static void registerTo(Asciidoctor asciidoctor) {
|
||||
try {
|
||||
INSTANCE.registerExtensionsWith(asciidoctor)
|
||||
} finally {
|
||||
INSTANCE.clearExtensions()
|
||||
}
|
||||
}
|
||||
|
||||
private static GroovyShell makeGroovyShell() {
|
||||
def config = new CompilerConfiguration()
|
||||
|
||||
config.scriptBaseClass = DelegatingScript.name
|
||||
|
||||
ImportCustomizer importCustomizer = new ImportCustomizer()
|
||||
importCustomizer.addStarImports(
|
||||
'org.asciidoctor',
|
||||
'org.asciidoctor.ast',
|
||||
'org.asciidoctor.extension'
|
||||
)
|
||||
|
||||
config.addCompilationCustomizers(
|
||||
importCustomizer
|
||||
)
|
||||
|
||||
new GroovyShell(new Binding(), config)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor.groovydsl
|
||||
|
||||
import org.asciidoctor.Asciidoctor
|
||||
import org.asciidoctor.jruby.extension.spi.ExtensionRegistry
|
||||
|
||||
/**
|
||||
* The service implementation for org.asciidoctor.extension.spi.ExtensionRegistry.
|
||||
* It simply delegates the register() call to {@link AsciidoctorExtensions}
|
||||
* that owns all configured extensions and registers it on the Asciidoctor instance.
|
||||
*/
|
||||
class GroovyExtensionRegistry implements ExtensionRegistry {
|
||||
|
||||
@Override
|
||||
void register(Asciidoctor asciidoctor) {
|
||||
AsciidoctorExtensions.registerTo(asciidoctor)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor.groovydsl.extensions
|
||||
|
||||
import org.asciidoctor.ast.StructuralNode
|
||||
import org.asciidoctor.extension.BlockMacroProcessor
|
||||
|
||||
class DelegatingBlockMacroProcessor extends BlockMacroProcessor {
|
||||
|
||||
private final Closure cl
|
||||
|
||||
DelegatingBlockMacroProcessor(String name, Map options, @DelegatesTo(BlockMacroProcessor) Closure cl) {
|
||||
super(name, options)
|
||||
this.cl = cl
|
||||
cl.delegate = this
|
||||
}
|
||||
|
||||
@Override
|
||||
Object process(StructuralNode parent, String target, Map<String, Object> attributes) {
|
||||
cl.call(parent, target, attributes)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor.groovydsl.extensions
|
||||
|
||||
import org.asciidoctor.ast.StructuralNode
|
||||
import org.asciidoctor.extension.BlockProcessor
|
||||
import org.asciidoctor.extension.Reader
|
||||
import org.xbib.gradle.plugin.asciidoctor.groovydsl.AsciidoctorExtensionHandler
|
||||
|
||||
class DelegatingBlockProcessor extends BlockProcessor {
|
||||
|
||||
private final Closure cl
|
||||
|
||||
DelegatingBlockProcessor(Map<String, Object> attributes, @DelegatesTo(BlockProcessor) Closure cl) {
|
||||
super(attributes[AsciidoctorExtensionHandler.OPTION_NAME] as String, attributes)
|
||||
this.cl = cl
|
||||
cl.delegate = this
|
||||
}
|
||||
|
||||
@Override
|
||||
Object process(StructuralNode parent, Reader reader, Map<String, Object> attributes) {
|
||||
cl.call(parent, reader, attributes)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor.groovydsl.extensions
|
||||
|
||||
import org.asciidoctor.ast.Document
|
||||
import org.asciidoctor.extension.DocinfoProcessor
|
||||
|
||||
class DelegatingDocinfoProcessor extends DocinfoProcessor {
|
||||
|
||||
private final Closure cl
|
||||
|
||||
DelegatingDocinfoProcessor(Map options, @DelegatesTo(DocinfoProcessor) Closure cl) {
|
||||
super(options)
|
||||
this.cl = cl
|
||||
cl.delegate = this
|
||||
}
|
||||
|
||||
@Override
|
||||
String process(Document document) {
|
||||
cl.call(document)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor.groovydsl.extensions
|
||||
|
||||
import org.asciidoctor.ast.Document
|
||||
|
||||
import org.asciidoctor.extension.IncludeProcessor
|
||||
import org.asciidoctor.extension.PreprocessorReader
|
||||
|
||||
class DelegatingIncludeProcessor extends IncludeProcessor {
|
||||
|
||||
private final Closure filter
|
||||
|
||||
private final Closure cl
|
||||
|
||||
DelegatingIncludeProcessor(Map options, Closure filter, @DelegatesTo(IncludeProcessor) Closure cl) {
|
||||
super(options)
|
||||
this.filter = filter
|
||||
this.cl = cl
|
||||
filter.delegate = this
|
||||
cl.delegate = this
|
||||
|
||||
}
|
||||
@Override
|
||||
boolean handles(String target) {
|
||||
filter.call(target)
|
||||
}
|
||||
|
||||
@Override
|
||||
void process(Document document, PreprocessorReader reader, String target, Map<String, Object> attributes) {
|
||||
cl.call(document, reader, target, attributes)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor.groovydsl.extensions
|
||||
|
||||
import org.asciidoctor.ast.ContentNode
|
||||
import org.asciidoctor.extension.InlineMacroProcessor
|
||||
|
||||
class DelegatingInlineMacroProcessor extends InlineMacroProcessor {
|
||||
|
||||
private final Closure cl
|
||||
|
||||
DelegatingInlineMacroProcessor(String name, Map options, @DelegatesTo(InlineMacroProcessor) Closure cl) {
|
||||
super(name, options)
|
||||
this.cl = cl
|
||||
cl.delegate = this
|
||||
}
|
||||
|
||||
@Override
|
||||
Object process(ContentNode parent, String target, Map<String, Object> attributes) {
|
||||
cl.call(parent, target, attributes)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor.groovydsl.extensions
|
||||
|
||||
import org.asciidoctor.ast.Document
|
||||
import org.asciidoctor.extension.Postprocessor
|
||||
|
||||
class DelegatingPostprocessor extends Postprocessor {
|
||||
|
||||
private final Closure cl
|
||||
|
||||
DelegatingPostprocessor(Map options, @DelegatesTo(Postprocessor) Closure cl) {
|
||||
super(options)
|
||||
this.cl = cl
|
||||
cl.delegate = this
|
||||
}
|
||||
|
||||
@Override
|
||||
String process(Document document, String output) {
|
||||
cl.call(document, output)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor.groovydsl.extensions
|
||||
|
||||
import org.asciidoctor.ast.Document
|
||||
import org.asciidoctor.extension.Preprocessor
|
||||
import org.asciidoctor.extension.PreprocessorReader
|
||||
|
||||
class DelegatingPreprocessor extends Preprocessor {
|
||||
|
||||
private final Closure cl
|
||||
|
||||
DelegatingPreprocessor(Map options, @DelegatesTo(Preprocessor) Closure cl) {
|
||||
super(options)
|
||||
this.cl = cl
|
||||
cl.delegate = this
|
||||
}
|
||||
|
||||
@Override
|
||||
void process(Document document, PreprocessorReader reader) {
|
||||
cl.call(document, reader)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor.groovydsl.extensions
|
||||
|
||||
import org.asciidoctor.ast.Document
|
||||
import org.asciidoctor.extension.Treeprocessor
|
||||
|
||||
class DelegatingTreeprocessor extends Treeprocessor {
|
||||
|
||||
private final Closure cl
|
||||
|
||||
DelegatingTreeprocessor(Map options, @DelegatesTo(Treeprocessor) Closure cl) {
|
||||
super(options)
|
||||
this.cl = cl
|
||||
cl.delegate = this
|
||||
}
|
||||
|
||||
@Override
|
||||
Document process(Document document) {
|
||||
def ret = cl.call(document)
|
||||
if (!(ret in Document)) {
|
||||
// Assume that the closure does something as last
|
||||
// statement that was not intended to be the return value
|
||||
// -> Return null
|
||||
null
|
||||
} else {
|
||||
ret
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.xbib.gradle.plugin.asciidoctor.groovydsl.GroovyExtensionRegistry
|
|
@ -0,0 +1,64 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.artifacts.DependencyResolutionListener
|
||||
import org.gradle.api.artifacts.ResolvableDependencies
|
||||
import org.gradle.testfixtures.ProjectBuilder
|
||||
import spock.lang.Ignore
|
||||
import spock.lang.Specification
|
||||
|
||||
class AsciidoctorPluginSpec extends Specification {
|
||||
|
||||
private static final String ASCIIDOCTOR = 'asciidoctor'
|
||||
|
||||
Project project
|
||||
|
||||
def setup() {
|
||||
project = ProjectBuilder.builder().build()
|
||||
}
|
||||
|
||||
@SuppressWarnings('MethodName')
|
||||
def "Applies plugin and checks default setup"() {
|
||||
expect:
|
||||
project.tasks.findByName(ASCIIDOCTOR) == null
|
||||
when:
|
||||
project.apply plugin: AsciidoctorPlugin
|
||||
then:
|
||||
Task asciidoctorTask = project.tasks.findByName(ASCIIDOCTOR)
|
||||
asciidoctorTask != null
|
||||
asciidoctorTask.group == 'Documentation'
|
||||
asciidoctorTask.sourceDir == project.file('src/docs/asciidoc')
|
||||
asciidoctorTask.outputDir == new File(project.buildDir, 'asciidoc')
|
||||
|
||||
project.tasks.findByName('clean') != null
|
||||
}
|
||||
|
||||
@Ignore("Method 'getDependencyResolutionBroadcast' is unknown")
|
||||
def "testPluginWithAlternativeAsciidoctorVersion"() {
|
||||
expect:
|
||||
project.tasks.findByName(ASCIIDOCTOR) == null
|
||||
|
||||
when:
|
||||
project.apply plugin: AsciidoctorPlugin
|
||||
|
||||
def expectedVersion = 'my.expected.version-SNAPSHOT'
|
||||
project.asciidoctorj.version = expectedVersion
|
||||
|
||||
def expectedDslVersion = 'dsl.' + expectedVersion
|
||||
project.asciidoctorj.groovyDslVersion = expectedDslVersion
|
||||
|
||||
def config = project.project.configurations.getByName('asciidoctor')
|
||||
def dependencies = config.dependencies
|
||||
assert dependencies.isEmpty();
|
||||
|
||||
// mock-trigger beforeResolve() to avoid 'real' resolution of dependencies
|
||||
DependencyResolutionListener broadcast = config.getDependencyResolutionBroadcast()
|
||||
ResolvableDependencies incoming = config.getIncoming()
|
||||
broadcast.beforeResolve(incoming)
|
||||
def dependencyHandler = project.getDependencies();
|
||||
|
||||
then:
|
||||
assert dependencies.contains(dependencyHandler.create(AsciidoctorPlugin.ASCIIDOCTORJ_CORE_DEPENDENCY + expectedVersion))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor
|
||||
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.testfixtures.ProjectBuilder
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import spock.lang.Specification
|
||||
|
||||
class AsciidoctorTaskInlineExtensionsSpec extends Specification {
|
||||
|
||||
private static final String ASCIIDOCTOR = 'asciidoctor'
|
||||
|
||||
private static final String ASCIIDOC_RESOURCES_DIR = 'build/resources/test/src/asciidocextensions'
|
||||
|
||||
private static final String ASCIIDOC_BUILD_DIR = 'build/asciidocextensions'
|
||||
|
||||
private static final String ASCIIDOC_MACRO_EXTENSION_SCRIPT = 'blockMacro.groovy'
|
||||
|
||||
private static final String ASCIIDOC_INLINE_EXTENSIONS_FILE = 'inlineextensions.asciidoc'
|
||||
|
||||
private static final String ASCIIDOC_INLINE_EXTENSIONS_RESULT_FILE = 'inlineextensions.html'
|
||||
|
||||
Project project
|
||||
File testRootDir
|
||||
File srcDir
|
||||
File outDir
|
||||
|
||||
def setup() {
|
||||
project = ProjectBuilder.builder().withName('test').build()
|
||||
project.configurations.create(ASCIIDOCTOR)
|
||||
testRootDir = new File('.')
|
||||
srcDir = new File(testRootDir, ASCIIDOC_RESOURCES_DIR).absoluteFile
|
||||
outDir = new File(project.projectDir, ASCIIDOC_BUILD_DIR)
|
||||
}
|
||||
|
||||
|
||||
def "Should apply inline BlockProcessor"() {
|
||||
given:
|
||||
Task task = project.tasks.create(name: ASCIIDOCTOR, type: AsciidoctorTask) {
|
||||
sourceDir = srcDir
|
||||
sourceDocumentNames = [ASCIIDOC_INLINE_EXTENSIONS_FILE]
|
||||
outputDir = outDir
|
||||
extensions {
|
||||
block(name: "BIG", contexts: [":paragraph"]) {
|
||||
parent, reader, attributes ->
|
||||
def upperLines = reader.readLines()
|
||||
.collect {it.toUpperCase()}
|
||||
.inject("") {a, b -> a + '\n' + b}
|
||||
|
||||
createBlock(parent, "paragraph", [upperLines], attributes, [:])
|
||||
}
|
||||
block("small") {
|
||||
parent, reader, attributes ->
|
||||
def lowerLines = reader.readLines()
|
||||
.collect {it.toLowerCase()}
|
||||
.inject("") {a, b -> a + '\n' + b}
|
||||
|
||||
createBlock(parent, "paragraph", [lowerLines], attributes, [:])
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
File resultFile = new File(outDir, 'html5' + File.separator + ASCIIDOC_INLINE_EXTENSIONS_RESULT_FILE)
|
||||
when:
|
||||
task.processAsciidocSources()
|
||||
then:
|
||||
resultFile.exists()
|
||||
resultFile.getText().contains("WRITE THIS IN UPPERCASE")
|
||||
resultFile.getText().contains("and write this in lowercase")
|
||||
}
|
||||
|
||||
def "Should apply BlockProcessor from file"() {
|
||||
given:
|
||||
print project.files('src/test/resources/src/asciidocextensions/blockMacro.groovy').each {println ">>> $it"}
|
||||
Task task = project.tasks.create(name: ASCIIDOCTOR, type: AsciidoctorTask) {
|
||||
sourceDir = srcDir
|
||||
sourceDocumentNames = [ASCIIDOC_INLINE_EXTENSIONS_FILE]
|
||||
outputDir = outDir
|
||||
extensions new File(sourceDir, ASCIIDOC_MACRO_EXTENSION_SCRIPT)
|
||||
}
|
||||
File resultFile = new File(outDir, 'html5' + File.separator + ASCIIDOC_INLINE_EXTENSIONS_RESULT_FILE)
|
||||
when:
|
||||
task.processAsciidocSources()
|
||||
then:
|
||||
resultFile.exists()
|
||||
resultFile.getText().contains("WRITE THIS IN UPPERCASE")
|
||||
resultFile.getText().contains("and write this in lowercase")
|
||||
}
|
||||
|
||||
|
||||
def "Should apply inline Postprocessor"() {
|
||||
given:
|
||||
String copyright = "Copyright Acme, Inc." + System.currentTimeMillis()
|
||||
Task task = project.tasks.create(name: ASCIIDOCTOR, type: AsciidoctorTask) {
|
||||
sourceDir = srcDir
|
||||
sourceDocumentNames = [ASCIIDOC_INLINE_EXTENSIONS_FILE]
|
||||
outputDir = outDir
|
||||
extensions {
|
||||
postprocessor {
|
||||
document, String output ->
|
||||
if(document.basebackend("html")) {
|
||||
Document doc = Jsoup.parse(output, "UTF-8")
|
||||
|
||||
Element contentElement = doc.getElementById("footer-text")
|
||||
contentElement.append(copyright)
|
||||
|
||||
doc.html()
|
||||
} else {
|
||||
throw new IllegalArgumentException("Expected html!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File resultFile = new File(outDir, 'html5' + File.separator + ASCIIDOC_INLINE_EXTENSIONS_RESULT_FILE)
|
||||
when:
|
||||
task.processAsciidocSources()
|
||||
then:
|
||||
resultFile.exists()
|
||||
resultFile.getText().contains(copyright)
|
||||
resultFile.getText().contains("Inline Extension Test document")
|
||||
}
|
||||
|
||||
def "Should fail if inline Postprocessor fails"() {
|
||||
given:
|
||||
Task task = project.tasks.create(name: ASCIIDOCTOR, type: AsciidoctorTask) {
|
||||
sourceDir = srcDir
|
||||
sourceDocumentNames = [ASCIIDOC_INLINE_EXTENSIONS_FILE]
|
||||
outputDir = outDir
|
||||
extensions {
|
||||
postprocessor {
|
||||
document, output ->
|
||||
if (output.contains("blacklisted")) {
|
||||
throw new IllegalArgumentException("Document contains a blacklisted word")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
when:
|
||||
task.processAsciidocSources()
|
||||
then:
|
||||
thrown(GradleException)
|
||||
}
|
||||
|
||||
def "Should apply inline Preprocessor"() {
|
||||
given:
|
||||
Task task = project.tasks.create(name: ASCIIDOCTOR, type: AsciidoctorTask) {
|
||||
sourceDir = srcDir
|
||||
sourceDocumentNames = [ASCIIDOC_INLINE_EXTENSIONS_FILE]
|
||||
outputDir = outDir
|
||||
extensions {
|
||||
preprocessor {
|
||||
document, reader ->
|
||||
reader.advance()
|
||||
reader
|
||||
}
|
||||
}
|
||||
}
|
||||
File resultFile = new File(outDir, 'html5' + File.separator + ASCIIDOC_INLINE_EXTENSIONS_RESULT_FILE)
|
||||
when:
|
||||
task.processAsciidocSources()
|
||||
then:
|
||||
resultFile.exists()
|
||||
!resultFile.getText().contains("Inline Extension Test document")
|
||||
}
|
||||
|
||||
def "Should apply inline Includeprocessor"() {
|
||||
given:
|
||||
String content = "The content of the URL " + System.currentTimeMillis()
|
||||
Task task = project.tasks.create(name: ASCIIDOCTOR, type: AsciidoctorTask) {
|
||||
sourceDir = srcDir
|
||||
sourceDocumentNames = [ASCIIDOC_INLINE_EXTENSIONS_FILE]
|
||||
outputDir = outDir
|
||||
extensions {
|
||||
include_processor (filter: {it.startsWith('http')}) {
|
||||
document, reader, target, attributes ->
|
||||
reader.push_include(content, target, target, 1, attributes);
|
||||
}
|
||||
}
|
||||
}
|
||||
File resultFile = new File(outDir, 'html5' + File.separator + ASCIIDOC_INLINE_EXTENSIONS_RESULT_FILE)
|
||||
when:
|
||||
task.processAsciidocSources()
|
||||
then:
|
||||
resultFile.exists()
|
||||
resultFile.getText().contains(content)
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,27 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor
|
||||
|
||||
import spock.lang.Specification
|
||||
|
||||
class AsciidoctorUtilsSpec extends Specification {
|
||||
|
||||
static s = File.separator
|
||||
|
||||
def 'finds relative paths'(String target, String base, String relative) {
|
||||
expect:
|
||||
AsciidoctorUtils.getRelativePath(new File(target), new File(base)) == relative
|
||||
where:
|
||||
target | base | relative
|
||||
'src/test/groovy' | 'src' | "test${s}groovy"
|
||||
'src/test/groovy/' | 'src/' | "test${s}groovy"
|
||||
'src/test/groovy' | 'src/' | "test${s}groovy"
|
||||
'src/test/groovy/' | 'src' | "test${s}groovy"
|
||||
'src' | 'src/test/groovy' | "..${s}.."
|
||||
'src/' | 'src/test/groovy/' | "..${s}.."
|
||||
'src' | 'src/test/groovy/' | "..${s}.."
|
||||
'src/' | 'src/test/groovy' | "..${s}.."
|
||||
'src/test' | 'src/test' | ''
|
||||
'src/test/' | 'src/test/' | ''
|
||||
'src/test' | 'src/test/' | ''
|
||||
'src/test/' | 'src/test' | ''
|
||||
}
|
||||
}
|
|
@ -0,0 +1,288 @@
|
|||
package org.xbib.gradle.plugin.asciidoctor.groovydsl
|
||||
|
||||
import org.asciidoctor.Asciidoctor
|
||||
import org.asciidoctor.SafeMode
|
||||
import spock.lang.Specification
|
||||
|
||||
import static org.asciidoctor.OptionsBuilder.options
|
||||
|
||||
/**
|
||||
* Asciidoctor task inline extensions specification
|
||||
*
|
||||
*/
|
||||
class AsciidoctorGroovyDSLSpec extends Specification {
|
||||
|
||||
private static final String TEST_DOC_BLOCK = '''Ignore this.
|
||||
|
||||
[BIG]
|
||||
But this should be uppercase
|
||||
|
||||
[small]
|
||||
And THIS should be lowercase\n\
|
||||
|
||||
capitalize::tHIS_sets_the_fIRST_letter_in_cApItAlS_and_REMOVES_underscores[]
|
||||
|
||||
.Gemfile
|
||||
[source,ruby]
|
||||
----
|
||||
include::https://raw.github.com/asciidoctor/asciidoctor/master/Gemfile[]
|
||||
----
|
||||
|
||||
.My Gist
|
||||
gist::123456[]
|
||||
|
||||
See man:gittutorial[7] to get started.
|
||||
|
||||
blacklisted is a blacklisted word.
|
||||
|
||||
'''
|
||||
|
||||
File testRootDir
|
||||
|
||||
def setup() {
|
||||
testRootDir = new File('.')
|
||||
}
|
||||
|
||||
|
||||
def 'Should clear registry on exception when registering from a Closure'() {
|
||||
given:
|
||||
AsciidoctorExtensions.extensions {
|
||||
throw new Exception('This error is on purpose')
|
||||
}
|
||||
|
||||
when:
|
||||
Asciidoctor.Factory.create().convert(TEST_DOC_BLOCK, [:])
|
||||
|
||||
then:
|
||||
def e = thrown(ServiceConfigurationError)
|
||||
}
|
||||
|
||||
def 'Should clear registry on exception when registering from a String'() {
|
||||
|
||||
given:
|
||||
AsciidoctorExtensions.extensions 'throw new Exception(\'This error is on purpose\')'
|
||||
|
||||
when:
|
||||
Asciidoctor.Factory.create().convert(TEST_DOC_BLOCK, [:])
|
||||
|
||||
then:
|
||||
def e = thrown(ServiceConfigurationError)
|
||||
}
|
||||
|
||||
def 'Should clear registry on exception when registering from a File'() {
|
||||
given:
|
||||
AsciidoctorExtensions.extensions(new File('src/test/resources/error.groovy'))
|
||||
|
||||
when:
|
||||
Asciidoctor.Factory.create().convert(TEST_DOC_BLOCK, [:])
|
||||
|
||||
then:
|
||||
def e = thrown(ServiceConfigurationError)
|
||||
}
|
||||
|
||||
|
||||
def 'Should apply BlockProcessor from Script as String'() {
|
||||
given:
|
||||
|
||||
AsciidoctorExtensions.extensions '''
|
||||
block(name: 'BIG', contexts: [':paragraph']) {
|
||||
parent, reader, attributes ->
|
||||
def upperLines = reader.readLines()
|
||||
.collect {it.toUpperCase()}
|
||||
.inject('') {a, b -> a + '\\n' + b}
|
||||
|
||||
createBlock(parent, 'paragraph', [upperLines], attributes, [:])
|
||||
}
|
||||
block('small') {
|
||||
parent, reader, attributes ->
|
||||
def lowerLines = reader.readLines()
|
||||
.collect {it.toLowerCase()}
|
||||
.inject('') {a, b -> a + '\\n' + b}
|
||||
|
||||
createBlock(parent, 'paragraph', [lowerLines], attributes, [:])
|
||||
}
|
||||
|
||||
'''
|
||||
when:
|
||||
String rendered = Asciidoctor.Factory.create().convert(TEST_DOC_BLOCK, [:])
|
||||
|
||||
then:
|
||||
rendered.contains('BUT THIS SHOULD BE UPPERCASE')
|
||||
rendered.contains('and this should be lowercase')
|
||||
rendered.contains('Ignore this.')
|
||||
}
|
||||
|
||||
|
||||
def 'Should apply BlockProcessor from Closure'() {
|
||||
given:
|
||||
|
||||
AsciidoctorExtensions.extensions {
|
||||
block(name: 'BIG', contexts: [':paragraph']) {
|
||||
parent, reader, attributes ->
|
||||
def upperLines = reader.readLines()
|
||||
.collect { it.toUpperCase() }
|
||||
.inject('') { a, b -> a + '\n' + b }
|
||||
|
||||
createBlock(parent, 'paragraph', [upperLines], attributes, [:])
|
||||
}
|
||||
block('small') {
|
||||
parent, reader, attributes ->
|
||||
def lowerLines = reader.readLines()
|
||||
.collect { it.toLowerCase() }
|
||||
.inject('') { a, b -> a + '\n' + b }
|
||||
|
||||
createBlock(parent, 'paragraph', [lowerLines], attributes, [:])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
when:
|
||||
String rendered = Asciidoctor.Factory.create().convert(TEST_DOC_BLOCK, [:])
|
||||
|
||||
then:
|
||||
rendered.contains('BUT THIS SHOULD BE UPPERCASE')
|
||||
rendered.contains('and this should be lowercase')
|
||||
rendered.contains('Ignore this.')
|
||||
}
|
||||
|
||||
def 'Should apply BlockProcessor from Extension file'() {
|
||||
given:
|
||||
|
||||
AsciidoctorExtensions.extensions(new File('src/test/resources/testblockextensions.groovy'))
|
||||
when:
|
||||
String rendered = Asciidoctor.Factory.create().convert(TEST_DOC_BLOCK, [:])
|
||||
|
||||
then:
|
||||
rendered.contains('BUT THIS SHOULD BE UPPERCASE')
|
||||
rendered.contains('and this should be lowercase')
|
||||
rendered.contains('Ignore this.')
|
||||
}
|
||||
|
||||
def 'Should apply Postprocessor from Extension file'() {
|
||||
given:
|
||||
AsciidoctorExtensions.extensions(new File('src/test/resources/testpostprocessorextension.groovy'))
|
||||
|
||||
when:
|
||||
String rendered = Asciidoctor.Factory.create().convert(TEST_DOC_BLOCK, [:])
|
||||
|
||||
then:
|
||||
rendered.contains('Copyright Acme, Inc.')
|
||||
}
|
||||
|
||||
def 'Should apply Preprocessor from Extension file'() {
|
||||
given:
|
||||
AsciidoctorExtensions.extensions(new File('src/test/resources/testpreprocessorextension.groovy'))
|
||||
|
||||
when:
|
||||
String rendered = Asciidoctor.Factory.create().convert(TEST_DOC_BLOCK, [:])
|
||||
|
||||
then:
|
||||
!rendered.contains('Ignore this.')
|
||||
}
|
||||
|
||||
def 'Should apply Includeprocessor from Extension file'() {
|
||||
given:
|
||||
AsciidoctorExtensions.extensions(new File('src/test/resources/testincludeprocessorextension.groovy'))
|
||||
|
||||
when:
|
||||
String rendered = Asciidoctor.Factory.create().convert(TEST_DOC_BLOCK, [:])
|
||||
|
||||
then:
|
||||
rendered.contains('The content of the URL')
|
||||
}
|
||||
|
||||
def 'Should apply BlockMacroProcessor from Closure'() {
|
||||
given:
|
||||
AsciidoctorExtensions.extensions {
|
||||
block_macro ("gist") { parent, target, attributes ->
|
||||
String content = """<div class="content">
|
||||
<script src="https://gist.github.com/${target}.js"></script>
|
||||
</div>"""
|
||||
createBlock(parent, "pass", [content], attributes);
|
||||
}
|
||||
}
|
||||
|
||||
when:
|
||||
String rendered = Asciidoctor.Factory.create().convert(TEST_DOC_BLOCK, [:])
|
||||
|
||||
then:
|
||||
rendered.contains("https://gist.github.com/123456.js")
|
||||
}
|
||||
|
||||
def 'Should apply BlockMacroProcessor from Extension file'() {
|
||||
given:
|
||||
AsciidoctorExtensions.extensions(new File('src/test/resources/testblockmacroextension.groovy'))
|
||||
|
||||
when:
|
||||
String rendered = Asciidoctor.Factory.create().convert(TEST_DOC_BLOCK, [:])
|
||||
|
||||
then:
|
||||
rendered.contains("https://gist.github.com/123456.js")
|
||||
}
|
||||
|
||||
def 'Should apply InlineMacroProcessor from Closure'() {
|
||||
given:
|
||||
|
||||
AsciidoctorExtensions.extensions {
|
||||
inline_macro('man') {
|
||||
parent, target, attributes ->
|
||||
def options = ["type": ":link", "target": target + ".html"]
|
||||
createPhraseNode(parent, "anchor", target, attributes, options).convert()
|
||||
}
|
||||
}
|
||||
|
||||
when:
|
||||
String rendered = Asciidoctor.Factory.create().convert(TEST_DOC_BLOCK, [:])
|
||||
|
||||
then:
|
||||
rendered.contains('<a href="gittutorial.html">gittutorial</a>')
|
||||
}
|
||||
|
||||
def 'Should apply InlineMacroProcessor from Extension file'() {
|
||||
given:
|
||||
AsciidoctorExtensions.extensions(new File('src/test/resources/testinlinemacroprocessorextension.groovy'))
|
||||
|
||||
when:
|
||||
String rendered = Asciidoctor.Factory.create().convert(TEST_DOC_BLOCK, [:])
|
||||
|
||||
then:
|
||||
rendered.contains('<a href="gittutorial.html">gittutorial</a>')
|
||||
}
|
||||
|
||||
def 'Should apply Treeprocessor from Extension file'() {
|
||||
given:
|
||||
AsciidoctorExtensions.extensions(new File('src/test/resources/testtreeprocessorextension.groovy'))
|
||||
|
||||
when:
|
||||
String rendered = Asciidoctor.Factory.create().convert('''
|
||||
$ echo "Hello, World!"
|
||||
|
||||
$ gem install asciidoctor
|
||||
''', [:])
|
||||
|
||||
then:
|
||||
rendered.contains('<span class="command">gem install asciidoctor</span>')
|
||||
}
|
||||
|
||||
def 'Should apply DocinfoProcessor from Closure'() {
|
||||
given:
|
||||
String metatag = '<meta name="hello" content="world">'
|
||||
AsciidoctorExtensions.extensions {
|
||||
docinfo_processor {
|
||||
document -> metatag
|
||||
}
|
||||
}
|
||||
|
||||
when:
|
||||
String rendered = Asciidoctor.Factory.create().convert(
|
||||
'''
|
||||
= Hello
|
||||
|
||||
World''',
|
||||
options().headerFooter(true).safe(SafeMode.SERVER).toFile(false).get());
|
||||
|
||||
then:
|
||||
// (?ms) Multiline regexp with dotall (= '.' matches newline as well)
|
||||
rendered ==~ /(?ms).*<head>.*<meta name="hello" content="world">.*<\/head>.*/
|
||||
}
|
||||
}
|
10
gradle-plugin-asciidoctor/src/test/resources/error.groovy
Executable file
10
gradle-plugin-asciidoctor/src/test/resources/error.groovy
Executable file
|
@ -0,0 +1,10 @@
|
|||
throw new Exception('This error is on purpose')
|
||||
|
||||
block (name: "BIG", contexts: [":paragraph"]) {
|
||||
parent, reader, attributes ->
|
||||
def upperLines = reader.readLines()
|
||||
.collect {it.toUpperCase()}
|
||||
.inject("") {a, b -> a + '\\n' + b}
|
||||
|
||||
createBlock(parent, "paragraph", [upperLines], attributes, [:])
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<!--
|
||||
|
||||
Copyright 2013-2014 the original author or authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
-->
|
|
@ -0,0 +1,17 @@
|
|||
<!--
|
||||
|
||||
Copyright 2013-2014 the original author or authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
-->
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
=====================
|
||||
Not a real image file
|
||||
=====================
|
|
@ -0,0 +1,17 @@
|
|||
<!--
|
||||
|
||||
Copyright 2013-2014 the original author or authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
-->
|
|
@ -0,0 +1,17 @@
|
|||
<!--
|
||||
|
||||
Copyright 2013-2014 the original author or authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
-->
|
|
@ -0,0 +1,26 @@
|
|||
Document Title
|
||||
==============
|
||||
Doc Writer <thedoc@asciidoctor.org>
|
||||
:idprefix: id_
|
||||
|
||||
Preamble paragraph.
|
||||
|
||||
NOTE: This is test, only a test.
|
||||
|
||||
== Section A
|
||||
|
||||
*Section A* paragraph.
|
||||
|
||||
=== Section A Subsection
|
||||
|
||||
*Section A* 'subsection' paragraph.
|
||||
|
||||
== Section B
|
||||
|
||||
*Section B* paragraph.
|
||||
|
||||
.Section B list
|
||||
* Item 1
|
||||
* Item 2
|
||||
* Item 3
|
||||
|
|
@ -0,0 +1 @@
|
|||
an include file
|
|
@ -0,0 +1,26 @@
|
|||
Document Title
|
||||
==============
|
||||
Doc Writer <thedoc@asciidoctor.org>
|
||||
:idprefix: id_
|
||||
|
||||
Preamble paragraph.
|
||||
|
||||
NOTE: This is test, only a test.
|
||||
|
||||
== Section A
|
||||
|
||||
*Section A* paragraph.
|
||||
|
||||
=== Section A Subsection
|
||||
|
||||
*Section A* 'subsection' paragraph.
|
||||
|
||||
== Section B
|
||||
|
||||
*Section B* paragraph.
|
||||
|
||||
.Section B list
|
||||
* Item 1
|
||||
* Item 2
|
||||
* Item 3
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
block(name: "BIG", contexts: [":paragraph"]) {
|
||||
parent, reader, attributes ->
|
||||
def upperLines = reader.readLines()
|
||||
.collect {it.toUpperCase()}
|
||||
.inject("") {a, b -> a + '\n' + b}
|
||||
|
||||
createBlock(parent, "paragraph", [upperLines], attributes, [:])
|
||||
}
|
||||
block("small") {
|
||||
parent, reader, attributes ->
|
||||
def lowerLines = reader.readLines()
|
||||
.collect {it.toLowerCase()}
|
||||
.inject("") {a, b -> a + '\n' + b}
|
||||
|
||||
createBlock(parent, "paragraph", [lowerLines], attributes, [:])
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
= Inline Extension Test document
|
||||
|
||||
[BIG]
|
||||
Write this in uppercase
|
||||
|
||||
[small]
|
||||
AND WRITE THIS IN LOWERCASE
|
||||
|
||||
|
||||
.Gemfile
|
||||
[source,ruby]
|
||||
----
|
||||
include::https://raw.github.com/asciidoctor/asciidoctor/master/Gemfile[]
|
||||
----
|
||||
|
||||
|
||||
.My Gist
|
||||
gist::123456[]
|
||||
|
||||
See man:gittutorial[7] to get started.
|
||||
|
||||
blacklisted is a blacklisted word.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
$ echo "Hello, World!"
|
||||
|
||||
$ gem install asciidoctor
|
||||
|
16
gradle-plugin-asciidoctor/src/test/resources/testblockextensions.groovy
Executable file
16
gradle-plugin-asciidoctor/src/test/resources/testblockextensions.groovy
Executable file
|
@ -0,0 +1,16 @@
|
|||
block (name: "BIG", contexts: [":paragraph"]) {
|
||||
parent, reader, attributes ->
|
||||
def upperLines = reader.readLines()
|
||||
.collect {it.toUpperCase()}
|
||||
.inject("") {a, b -> a + '\\n' + b}
|
||||
|
||||
createBlock(parent, "paragraph", [upperLines], attributes, [:])
|
||||
}
|
||||
block("small") {
|
||||
parent, reader, attributes ->
|
||||
def lowerLines = reader.readLines()
|
||||
.collect {it.toLowerCase()}
|
||||
.inject("") {a, b -> a + '\\n' + b}
|
||||
|
||||
createBlock(parent, "paragraph", [lowerLines], attributes, [:])
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
block_macro (name: "gist") { parent, target, attributes ->
|
||||
String content = """<div class="content">
|
||||
<script src="https://gist.github.com/${target}.js"></script>
|
||||
</div>"""
|
||||
createBlock(parent, "pass", [content], attributes)
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
String content = "The content of the URL"
|
||||
|
||||
include_processor (filter: {it.startsWith("http")}) {
|
||||
document, reader, target, attributes ->
|
||||
reader.push_include(content, target, target, 1, attributes);
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
inline_macro (name: "man") { parent, target, attributes ->
|
||||
options=["type": ":link", "target": target + ".html"]
|
||||
createPhraseNode(parent, "anchor", target, attributes, options).render()
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
import org.jsoup.*
|
||||
|
||||
String copyright = "Copyright Acme, Inc."
|
||||
|
||||
postprocessor {
|
||||
document, output ->
|
||||
if(document.basebackend("html")) {
|
||||
org.jsoup.nodes.Document doc = Jsoup.parse(output, "UTF-8")
|
||||
|
||||
def contentElement = doc.getElementsByTag("body")
|
||||
contentElement.append(copyright)
|
||||
doc.html()
|
||||
} else {
|
||||
throw new IllegalArgumentException("Expected html!")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
preprocessor {
|
||||
document, reader ->
|
||||
reader.advance()
|
||||
reader
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
treeprocessor { document ->
|
||||
def blocks = document.blocks()
|
||||
(0..<blocks.size()).each {
|
||||
def block = blocks[it]
|
||||
def lines = block.lines()
|
||||
if (lines.size() > 0 && lines[0].startsWith('$')) {
|
||||
Map attributes = block.attributes
|
||||
attributes['role'] = 'terminal';
|
||||
def resultLines = lines.collect {
|
||||
it.startsWith('$') ? "<span class=\"command\">${it.substring(2)}</span>".toString() : it
|
||||
}
|
||||
blocks[it] = createBlock(document, 'listing', resultLines, attributes, [:])
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,44 +1,18 @@
|
|||
plugins {
|
||||
id 'java-gradle-plugin'
|
||||
id 'groovy'
|
||||
id 'com.gradle.plugin-publish' version '0.17.0'
|
||||
alias(libs.plugins.publish)
|
||||
}
|
||||
|
||||
ext {
|
||||
user = 'jprante'
|
||||
name = 'gradle-plugin-docker'
|
||||
description = 'Docker support in a Gradle plugin'
|
||||
inceptionYear = '2016'
|
||||
url = 'https://github.com/' + user + '/' + name
|
||||
scmUrl = 'https://github.com/' + user + '/' + name
|
||||
scmConnection = 'scm:git:git://github.com/' + user + '/' + name + '.git'
|
||||
scmDeveloperConnection = 'scm:git:ssh://git@github.com:' + user + '/' + name + '.git'
|
||||
issueManagementSystem = 'Github'
|
||||
issueManagementUrl = ext.scmUrl + '/issues'
|
||||
licenseName = 'The Apache License, Version 2.0'
|
||||
licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
|
||||
}
|
||||
apply plugin: 'java-gradle-plugin'
|
||||
apply plugin: 'com.gradle.plugin-publish'
|
||||
|
||||
apply from: rootProject.file('gradle/compile/groovy.gradle')
|
||||
|
||||
dependencies {
|
||||
api gradleApi()
|
||||
implementation "org.codehaus.groovy:groovy-all:${project.property('groovy.version')}"
|
||||
testImplementation gradleTestKit()
|
||||
}
|
||||
|
||||
compileGroovy {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
compileTestGroovy {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
validatePlugins {
|
||||
failOnWarning = false
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
dockerPlugin {
|
||||
|
@ -50,14 +24,19 @@ gradlePlugin {
|
|||
|
||||
if (project.hasProperty('gradle.publish.key')) {
|
||||
pluginBundle {
|
||||
website = 'https://github.com/jprante/gradle-plugin-docker'
|
||||
vcsUrl = 'https://github.com/jprante/gradle-plugin-docker'
|
||||
mavenCoordinates {
|
||||
groupId = "org.xbib.gradle.plugin"
|
||||
artifactId = "gradle-plugin-docker"
|
||||
version = project.version
|
||||
}
|
||||
website = 'https://github.com/jprante/gradle-plugins'
|
||||
vcsUrl = 'https://github.com/jprante/gradle-plugins'
|
||||
plugins {
|
||||
dockerPlugin {
|
||||
id = 'org.xbib.gradle.plugin.docker'
|
||||
version = project.version
|
||||
description = rootProject.ext.description
|
||||
displayName = 'Gradle Docker Plugin'
|
||||
description = 'Docker plugin for build and push by Dockerfile'
|
||||
displayName = 'Docker Plugin for build and push by Dockerfile'
|
||||
tags = ['docker']
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
version = 2.2.0
|
||||
version = 2.4.0
|
||||
|
|
202
gradle-plugin-git/LICENSE.txt
Normal file
202
gradle-plugin-git/LICENSE.txt
Normal file
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -1,33 +1,19 @@
|
|||
plugins {
|
||||
id 'java-gradle-plugin'
|
||||
id 'groovy'
|
||||
id 'com.gradle.plugin-publish' version '0.17.0'
|
||||
alias(libs.plugins.publish)
|
||||
}
|
||||
|
||||
apply plugin: 'groovy'
|
||||
apply plugin: 'java-gradle-plugin'
|
||||
apply plugin: 'com.gradle.plugin-publish'
|
||||
|
||||
apply from: rootProject.file('gradle/compile/groovy.gradle')
|
||||
|
||||
dependencies {
|
||||
api gradleApi()
|
||||
api "org.xbib:groovy-git:${project.property('groovy-git.version')}"
|
||||
api libs.groovy.git
|
||||
testImplementation gradleTestKit()
|
||||
testImplementation "org.spockframework:spock-core:${project.property('spock.version')}"
|
||||
testImplementation "junit:junit:${project.property('junit4.version')}"
|
||||
}
|
||||
|
||||
compileGroovy {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
compileTestGroovy {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
validatePlugins {
|
||||
failOnWarning = false
|
||||
testImplementation libs.spock.core
|
||||
testImplementation libs.junit4
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
|
@ -41,14 +27,19 @@ gradlePlugin {
|
|||
|
||||
if (project.hasProperty('gradle.publish.key')) {
|
||||
pluginBundle {
|
||||
website = 'https://github.com/jprante/groovy-git'
|
||||
vcsUrl = 'https://github.com/jprante/groovy-git.git'
|
||||
mavenCoordinates {
|
||||
groupId = "org.xbib.gradle.plugin"
|
||||
artifactId = "gradle-plugin-git"
|
||||
version = project.version
|
||||
}
|
||||
website = 'https://github.com/jprante/gradle-plugins'
|
||||
vcsUrl = 'https://github.com/jprante/gradle-plugins'
|
||||
plugins {
|
||||
gitPlugin {
|
||||
id = 'org.xbib.gradle.plugin.git'
|
||||
version = project.version
|
||||
description = rootProject.ext.description
|
||||
displayName = rootProject.ext.description
|
||||
description = 'Git client plugin based on JGit'
|
||||
displayName = 'Git client plugin based on JGit'
|
||||
tags = ['git']
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
version = 2.0.1
|
||||
version = 2.2.0
|
202
gradle-plugin-jacc/LICENSE.txt
Normal file
202
gradle-plugin-jacc/LICENSE.txt
Normal file
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
52
gradle-plugin-jacc/README.md
Executable file
52
gradle-plugin-jacc/README.md
Executable file
|
@ -0,0 +1,52 @@
|
|||
# gradle-plugin-jacc
|
||||
|
||||
A Gradle plugin for [Jacc](http://web.cecs.pdx.edu/~mpj/jacc/)
|
||||
|
||||
## Usage
|
||||
|
||||
plugins {
|
||||
id 'org.xbib.gradle.plugin.jacc'
|
||||
}
|
||||
|
||||
apply plugin: 'org.xbib.gradle.plugin.jacc'
|
||||
|
||||
Gradle will look for your jacc files in the source sets you specified.
|
||||
By default, it looks with the pattern `**/*.jacc` under `src/main/jacc`
|
||||
and `src/test/jacc`.
|
||||
|
||||
You can set up the source sets like this:
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
jacc {
|
||||
srcDir "src/main/jacc"
|
||||
}
|
||||
java {
|
||||
srcDir "build/my-generated-sources/jacc"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
The lastJava `srcDir` definition will be used as the base for the Jacc target path.
|
||||
If not given, the Jacc target path for generated Java source follows the pattern:
|
||||
|
||||
`${project.buildDir}/generated/sources/jacc`
|
||||
|
||||
The Jacc target path will be added automaticlly to the java compile task source directory
|
||||
of the source set.
|
||||
|
||||
# License
|
||||
|
||||
Copyright (C) 2015-2020 Jörg Prante
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
41
gradle-plugin-jacc/build.gradle
Executable file
41
gradle-plugin-jacc/build.gradle
Executable file
|
@ -0,0 +1,41 @@
|
|||
plugins {
|
||||
id 'java-gradle-plugin'
|
||||
alias(libs.plugins.publish)
|
||||
}
|
||||
|
||||
apply plugin: 'java-gradle-plugin'
|
||||
apply plugin: 'com.gradle.plugin-publish'
|
||||
|
||||
apply from: rootProject.file('gradle/compile/groovy.gradle')
|
||||
apply from: rootProject.file('gradle/test/junit5.gradle')
|
||||
|
||||
dependencies {
|
||||
api gradleApi()
|
||||
implementation libs.jacc
|
||||
testImplementation gradleTestKit()
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
jaccPlugin {
|
||||
id = 'org.xbib.gradle.plugin.jacc'
|
||||
implementationClass = 'org.xbib.gradle.plugin.jacc.JaccPlugin'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (project.hasProperty('gradle.publish.key')) {
|
||||
pluginBundle {
|
||||
website = scmUrl
|
||||
vcsUrl = scmUrl
|
||||
plugins {
|
||||
jaccPlugin {
|
||||
id = 'org.xbib.gradle.plugin.jacc'
|
||||
version = project.version
|
||||
description = 'Gradle Jacc plugin'
|
||||
displayName = 'Gradle Jacc plugin'
|
||||
tags = ['jacc']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
gradle-plugin-jacc/gradle.properties
Normal file
1
gradle-plugin-jacc/gradle.properties
Normal file
|
@ -0,0 +1 @@
|
|||
version = 1.4.0
|
|
@ -0,0 +1,80 @@
|
|||
package org.xbib.gradle.plugin.jacc
|
||||
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.SourceDirectorySet
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
|
||||
class JaccPlugin implements Plugin<Project> {
|
||||
|
||||
private static final Logger logger = Logging.getLogger(JaccPlugin)
|
||||
|
||||
@Override
|
||||
void apply(Project project) {
|
||||
project.with {
|
||||
apply plugin: 'java-library'
|
||||
addSourceSetExtensions(project)
|
||||
}
|
||||
project.afterEvaluate {
|
||||
addTasks(project)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void addSourceSetExtensions(Project project) {
|
||||
project.sourceSets.all { SourceSet sourceSet ->
|
||||
createSourceSetExtension(project, sourceSet)
|
||||
createConfiguration(project, sourceSet)
|
||||
}
|
||||
}
|
||||
|
||||
private static void createSourceSetExtension(Project project, SourceSet sourceSet) {
|
||||
String name = sourceSet.name
|
||||
SourceDirectorySet sourceDirectorySet = project.objects.sourceDirectorySet(name, "${name} Jacc source")
|
||||
sourceSet.extensions.add('jacc', sourceDirectorySet)
|
||||
sourceDirectorySet.srcDir("src/${name}/jacc")
|
||||
sourceDirectorySet.include("**/*.jacc")
|
||||
}
|
||||
|
||||
|
||||
private static void createConfiguration(Project project, SourceSet sourceSet) {
|
||||
String configName = sourceSet.name + 'Jacc'
|
||||
if (project.configurations.findByName(configName) == null) {
|
||||
logger.info "create configuration ${configName}"
|
||||
project.configurations.create(configName) {
|
||||
visible = false
|
||||
transitive = true
|
||||
extendsFrom = []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addTasks(Project project) {
|
||||
project.sourceSets.all { SourceSet sourceSet ->
|
||||
addTaskForSourceSet(project, sourceSet)
|
||||
}
|
||||
}
|
||||
|
||||
private static void addTaskForSourceSet(Project project, SourceSet sourceSet) {
|
||||
String taskName = sourceSet.getTaskName('generate', 'jacc')
|
||||
SourceDirectorySet sourceDirectorySet = sourceSet.extensions.getByName('jacc') as SourceDirectorySet
|
||||
File targetFile = sourceSet.java && sourceSet.java.srcDirs ? sourceSet.java.srcDirs.last() :
|
||||
project.file("${project.buildDir}/generated/sources/${sourceSet.name}")
|
||||
if (sourceDirectorySet.asList()) {
|
||||
TaskProvider<JaccTask> taskProvider = project.tasks.register(taskName, JaccTask) {
|
||||
group = 'jacc'
|
||||
description = 'Generates code from Jacc files in ' + sourceSet.name
|
||||
source = sourceDirectorySet.asList()
|
||||
target = targetFile
|
||||
}
|
||||
logger.info "created ${taskName} for sources ${sourceDirectorySet.asList()} and target ${targetFile}"
|
||||
project.tasks.findByName(sourceSet.compileJavaTaskName).dependsOn taskProvider
|
||||
if (sourceSet.java && sourceSet.java.srcDirs) {
|
||||
sourceSet.java.srcDirs += targetFile
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package org.xbib.gradle.plugin.jacc
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.xbib.jacc.Jacc
|
||||
|
||||
class JaccTask extends DefaultTask {
|
||||
|
||||
@InputFiles
|
||||
Iterable<File> source
|
||||
|
||||
@OutputDirectory
|
||||
File target
|
||||
|
||||
@TaskAction
|
||||
void generateAndTransformJacc() throws Exception {
|
||||
source.each { file ->
|
||||
String pkg = getPackageName(file)
|
||||
File fullTarget = new File(target, pkg.replace('.','/'))
|
||||
project.mkdir(fullTarget)
|
||||
Jacc.main([file.absolutePath, '-d', fullTarget] as String[])
|
||||
}
|
||||
}
|
||||
|
||||
static String getPackageName(File file) {
|
||||
String string = file.readLines().find { line ->
|
||||
line.startsWith('package')
|
||||
}
|
||||
return string == null ? '' : string.substring(8, string.length() - 1)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package org.xbib.gradle.plugin.jacc
|
||||
|
||||
import org.gradle.testkit.runner.BuildResult
|
||||
import org.gradle.testkit.runner.GradleRunner
|
||||
import org.gradle.testkit.runner.TaskOutcome
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
|
||||
class JaccPluginTest {
|
||||
|
||||
private File projectDir
|
||||
|
||||
private File settingsFile
|
||||
|
||||
private File buildFile
|
||||
|
||||
@BeforeEach
|
||||
void setup(@TempDir File testProjectDir) throws IOException {
|
||||
this.projectDir = testProjectDir
|
||||
this.settingsFile = new File(testProjectDir, "settings.gradle")
|
||||
this.buildFile = new File(testProjectDir, "build.gradle")
|
||||
}
|
||||
|
||||
@Test
|
||||
void testJacc() {
|
||||
String settingsFileContent = '''
|
||||
rootProject.name = 'jacc-test'
|
||||
'''
|
||||
settingsFile.write(settingsFileContent)
|
||||
String buildFileContent = '''
|
||||
plugins {
|
||||
id 'org.xbib.gradle.plugin.jacc'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
test {
|
||||
jacc {
|
||||
srcDir "${System.getProperty('user.dir')}/src/test/jacc"
|
||||
}
|
||||
java {
|
||||
srcDir "${System.getProperty('user.dir')}/build/my-generated-sources/jacc"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
'''
|
||||
buildFile.write(buildFileContent)
|
||||
BuildResult result = GradleRunner.create()
|
||||
.withProjectDir(projectDir)
|
||||
.withArguments(":build", "--info")
|
||||
.withPluginClasspath()
|
||||
.forwardOutput()
|
||||
.build()
|
||||
assertEquals(TaskOutcome.SUCCESS, result.task(":build").getOutcome())
|
||||
|
||||
File file = new File("${System.getProperty('user.dir')}/build/my-generated-sources/jacc")
|
||||
if (file.exists()) {
|
||||
List<File> list = Arrays.asList(file.listFiles())
|
||||
assertEquals(2, list.size())
|
||||
}
|
||||
}
|
||||
}
|
104
gradle-plugin-jacc/src/test/jacc/simpleCalc.jacc
Normal file
104
gradle-plugin-jacc/src/test/jacc/simpleCalc.jacc
Normal file
|
@ -0,0 +1,104 @@
|
|||
// To compile and run this program using jacc and Sun's JDK:
|
||||
//
|
||||
// jacc simpleCalc.jacc
|
||||
// javac Calc.java CalcTokens.java
|
||||
// java Calc
|
||||
// ... enter arithmetic expressions ... hit EOF to terminate
|
||||
//
|
||||
|
||||
%class Calc
|
||||
%interface CalcTokens
|
||||
%semantic int : yylval
|
||||
%get token
|
||||
%next yylex()
|
||||
|
||||
%token '+' '-' '*' '/' '(' ')' ';' INTEGER
|
||||
%left '+' '-'
|
||||
%left '*' '/'
|
||||
|
||||
%%
|
||||
|
||||
prog : prog ';' expr { System.out.println($3); }
|
||||
| expr { System.out.println($1); }
|
||||
;
|
||||
expr : expr '+' expr { $$ = $1 + $3; }
|
||||
| expr '-' expr { $$ = $1 - $3; }
|
||||
| expr '*' expr { $$ = $1 * $3; }
|
||||
| expr '/' expr { $$ = $1 / $3; }
|
||||
| '(' expr ')' { $$ = $2; }
|
||||
| INTEGER { $$ = $1; }
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
private void yyerror(String msg) {
|
||||
System.out.println("ERROR: " + msg);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
private int c;
|
||||
|
||||
/** Read a single input character from standard input.
|
||||
*/
|
||||
private void nextChar() {
|
||||
if (c>=0) {
|
||||
try {
|
||||
c = System.in.read();
|
||||
} catch (Exception e) {
|
||||
c = (-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int token;
|
||||
int yylval;
|
||||
|
||||
/** Read the next token and return the
|
||||
* corresponding integer code.
|
||||
*/
|
||||
int yylex() {
|
||||
for (;;) {
|
||||
// Skip whitespace
|
||||
while (c==' ' || c=='\n' || c=='\t' || c=='\r') {
|
||||
nextChar();
|
||||
}
|
||||
if (c<0) {
|
||||
return (token=ENDINPUT);
|
||||
}
|
||||
switch (c) {
|
||||
case '+' : nextChar();
|
||||
return token='+';
|
||||
case '-' : nextChar();
|
||||
return token='-';
|
||||
case '*' : nextChar();
|
||||
return token='*';
|
||||
case '/' : nextChar();
|
||||
return token='/';
|
||||
case '(' : nextChar();
|
||||
return token='(';
|
||||
case ')' : nextChar();
|
||||
return token=')';
|
||||
case ';' : nextChar();
|
||||
return token=';';
|
||||
default : if (Character.isDigit((char)c)) {
|
||||
int n = 0;
|
||||
do {
|
||||
n = 10*n + (c - '0');
|
||||
nextChar();
|
||||
} while (Character.isDigit((char)c));
|
||||
yylval = n;
|
||||
return token=INTEGER;
|
||||
} else {
|
||||
yyerror("Illegal character "+c);
|
||||
nextChar();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Calc calc = new Calc();
|
||||
calc.nextChar(); // prime the character input stream
|
||||
calc.yylex(); // prime the token input stream
|
||||
calc.parse(); // parse the input
|
||||
}
|
202
gradle-plugin-jflex/LICENSE.txt
Normal file
202
gradle-plugin-jflex/LICENSE.txt
Normal file
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
79
gradle-plugin-jflex/README.md
Executable file
79
gradle-plugin-jflex/README.md
Executable file
|
@ -0,0 +1,79 @@
|
|||
# gradle-plugin-jflex
|
||||
|
||||
A Gradle plugin for [JFlex](http://jflex.de)
|
||||
|
||||
## Usage
|
||||
|
||||
plugins {
|
||||
id "org.xbib.gradle.plugin.jflex" version "1.4.0"
|
||||
}
|
||||
|
||||
Gradle will look for your JFlex files in the source sets you specified.
|
||||
By default, it looks with the pattern `**/*.jflex` under `src/main/jflex`
|
||||
and `src/test/jflex`.
|
||||
|
||||
You can set up the source sets like this:
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
jflex {
|
||||
srcDir "src/main/jflex"
|
||||
}
|
||||
java {
|
||||
srcDir "$buildDir/my-generated-sources/jflex"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
The lastJava `srcDir` definition will be used as the base for the JFLex target path.
|
||||
If not given, the JFlex target path for generated Java source follows the pattern:
|
||||
|
||||
`${project.buildDir}/generated/sources/jflex`
|
||||
|
||||
The JFlex target path will be added automatically to the java compile task source directory
|
||||
of the source set.
|
||||
|
||||
## Parameter support
|
||||
|
||||
The following parameters can be set in a global `jflex` extension
|
||||
in the gradle script. See also https://jflex.de/manual.html
|
||||
|
||||
| Name | Description |
|
||||
| ------- | ---------- |
|
||||
| encoding | the file encoding |
|
||||
| rootDirectory | the root directory used by JFlex (modification discouraged since the directories are derived from gradle source set)
|
||||
| skel | uses external skeleton <file> in UTF-8 encoding. This is mainly for JFlex maintenance and special low level customisations. Use only when you know what you are doing! JFlex comes with a skeleton file in the src directory that reflects exactly the internal, pre-compiled skeleton and can be used with the skel option. |
|
||||
| verbose | display generation progress messages (disabled by default) |
|
||||
| jlex | tries even harder to comply to JLex interpretation of specs |
|
||||
| no_minimize | skip the DFA minimisation step during scanner generation |
|
||||
| no_backup | don't write backup files if this is true |
|
||||
| unused_warning | warn about unused macros (by default false) |
|
||||
| progress | progress dots will be printed (by default false) |
|
||||
| dot | If true, jflex will write graphviz .dot files for generated automata (by default, false) |
|
||||
| time | If true, jflex will print time statistics about the generation process (by default false) |
|
||||
| dump | If true, you will be flooded with information, e.g. dfa tables (by default, false) |
|
||||
| legacy_dot | dot (.) meta character matches [^\n] instead of [^\n\r\u000B\u000C\u0085\u2028\u2029] |
|
||||
| statistics | print output statistics (by default, false) |
|
||||
|
||||
## Credits
|
||||
|
||||
gradle-plugin-jflex is a plugin based on
|
||||
[gradle-jflex-plugin](https://github.com/thomaslee/gradle-jflex-plugin)
|
||||
which was written by [Tom Lee](http://tomlee.co).
|
||||
|
||||
# License
|
||||
|
||||
Copyright (C) 2015-2020 Jörg Prante
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
41
gradle-plugin-jflex/build.gradle
Executable file
41
gradle-plugin-jflex/build.gradle
Executable file
|
@ -0,0 +1,41 @@
|
|||
plugins {
|
||||
id 'java-gradle-plugin'
|
||||
alias(libs.plugins.publish)
|
||||
}
|
||||
|
||||
apply plugin: 'java-gradle-plugin'
|
||||
apply plugin: 'com.gradle.plugin-publish'
|
||||
|
||||
apply from: rootProject.file('gradle/compile/groovy.gradle')
|
||||
apply from: rootProject.file('gradle/test/junit5.gradle')
|
||||
|
||||
dependencies {
|
||||
api gradleApi()
|
||||
implementation libs.jflex
|
||||
testImplementation gradleTestKit()
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
jflexPlugin {
|
||||
id = 'org.xbib.gradle.plugin.jflex'
|
||||
implementationClass = 'org.xbib.gradle.plugin.jflex.JFlexPlugin'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (project.hasProperty('gradle.publish.key')) {
|
||||
pluginBundle {
|
||||
website = scmUrl
|
||||
vcsUrl = scmUrl
|
||||
plugins {
|
||||
jflexPlugin {
|
||||
id = 'org.xbib.gradle.plugin.jflex'
|
||||
version = project.version
|
||||
description = 'Gradle JFlex plugin'
|
||||
displayName = 'Gradle JFlex plugin'
|
||||
tags = ['jflex']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
gradle-plugin-jflex/gradle.properties
Normal file
1
gradle-plugin-jflex/gradle.properties
Normal file
|
@ -0,0 +1 @@
|
|||
version = 1.6.0
|
|
@ -0,0 +1,67 @@
|
|||
package org.xbib.gradle.plugin.jflex
|
||||
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.Optional
|
||||
|
||||
class JFlexExtension {
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
String encoding
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
File rootDirectory
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
File skel
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Boolean verbose = false
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Boolean jlex = false
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Boolean no_minimize = false
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Boolean no_backup = false
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Boolean unused_warning = false
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Boolean progress = false
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Boolean time = false
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Boolean dot = false
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Boolean dump = false
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Boolean legacy_dot = false
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Boolean statistics = false
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Boolean writeIntoJavaSrc = false
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package org.xbib.gradle.plugin.jflex
|
||||
|
||||
import org.gradle.api.file.SourceDirectorySet
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
|
||||
class JFlexPlugin implements Plugin<Project> {
|
||||
|
||||
private static final Logger logger = Logging.getLogger(JFlexPlugin)
|
||||
|
||||
@Override
|
||||
void apply(Project project) {
|
||||
logger.info "JFlex plugin says hello"
|
||||
project.with {
|
||||
apply plugin: 'java-library'
|
||||
createJflexExtension(project)
|
||||
addSourceSetExtensions(project)
|
||||
}
|
||||
project.afterEvaluate {
|
||||
addJFlexTasks(project)
|
||||
}
|
||||
}
|
||||
|
||||
private static void addSourceSetExtensions(Project project) {
|
||||
project.sourceSets.all { SourceSet sourceSet ->
|
||||
createSourceSetExtension(project, sourceSet)
|
||||
createConfiguration(project, sourceSet)
|
||||
}
|
||||
}
|
||||
|
||||
private static void createSourceSetExtension(Project project, SourceSet sourceSet) {
|
||||
String name = sourceSet.name
|
||||
SourceDirectorySet sourceDirectorySet = project.objects.sourceDirectorySet(name, "${name} JFlex source")
|
||||
sourceSet.extensions.add('jflex', sourceDirectorySet)
|
||||
sourceDirectorySet.srcDir("src/${name}/jflex")
|
||||
sourceDirectorySet.include("**/*.jflex")
|
||||
}
|
||||
|
||||
private static void createConfiguration(Project project, SourceSet sourceSet) {
|
||||
String configName = sourceSet.name + capitalize('jflex' as CharSequence)
|
||||
if (project.configurations.findByName(configName) == null) {
|
||||
logger.info "create configuration ${configName}"
|
||||
project.configurations.create(configName) {
|
||||
visible = false
|
||||
transitive = true
|
||||
extendsFrom = []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void createJflexExtension(Project project) {
|
||||
project.extensions.create ('jflex', JFlexExtension)
|
||||
}
|
||||
|
||||
private static void addJFlexTasks(Project project) {
|
||||
project.sourceSets.all { SourceSet sourceSet ->
|
||||
addJFlexTaskForSourceSet(project, sourceSet)
|
||||
}
|
||||
}
|
||||
|
||||
private static void addJFlexTaskForSourceSet(Project project, SourceSet sourceSet) {
|
||||
String taskName = sourceSet.getTaskName('generate', 'jflex')
|
||||
SourceDirectorySet sourceDirectorySet = sourceSet.extensions.getByName('jflex') as SourceDirectorySet
|
||||
File targetFile = project.file("${project.buildDir}/generated/sources/${sourceSet.name}")
|
||||
if (sourceDirectorySet.asList()) {
|
||||
TaskProvider<JFlexTask> taskProvider = project.tasks.register(taskName, JFlexTask) {
|
||||
group = 'jflex'
|
||||
description = 'Generates code from JFlex files in ' + sourceSet.name
|
||||
source = sourceDirectorySet.asList()
|
||||
target = targetFile
|
||||
theSourceSet = sourceSet
|
||||
}
|
||||
logger.info "created ${taskName} for sources ${sourceDirectorySet.asList()} and target ${targetFile}"
|
||||
project.tasks.named(sourceSet.compileJavaTaskName).configure({
|
||||
dependsOn taskProvider
|
||||
})
|
||||
if (sourceSet.java && sourceSet.java.srcDirs) {
|
||||
sourceSet.java.srcDirs += targetFile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String capitalize(CharSequence charSequence) {
|
||||
return charSequence.length() == 0 ? "" : "" + Character.toUpperCase(charSequence.charAt(0)) + charSequence.subSequence(1, charSequence.length())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package org.xbib.gradle.plugin.jflex
|
||||
|
||||
import jflex.exceptions.GeneratorException
|
||||
import jflex.generator.LexGenerator
|
||||
import jflex.logging.Out
|
||||
import jflex.option.Options
|
||||
import jflex.skeleton.Skeleton
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.gradle.api.tasks.CacheableTask
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.PathSensitive
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.api.tasks.StopActionException
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
|
||||
import java.nio.charset.Charset
|
||||
|
||||
@CacheableTask
|
||||
class JFlexTask extends DefaultTask {
|
||||
|
||||
private final Logger logger = Logging.getLogger(JFlexTask)
|
||||
|
||||
@InputFiles
|
||||
@PathSensitive(PathSensitivity.RELATIVE)
|
||||
Iterable<File> source
|
||||
|
||||
@OutputDirectory
|
||||
File target
|
||||
|
||||
@Internal
|
||||
SourceSet theSourceSet
|
||||
|
||||
@TaskAction
|
||||
void generateAndTransformJflex() throws Exception {
|
||||
JFlexExtension ext = project.extensions.findByType(JFlexExtension)
|
||||
Options.setRootDirectory(ext.rootDirectory ? ext.rootDirectory : new File(""))
|
||||
Skeleton.readDefault()
|
||||
if (ext.skel) {
|
||||
Skeleton.readSkelFile(ext.skel)
|
||||
}
|
||||
Options.encoding = ext.encoding ? Charset.forName(ext.encoding) : Charset.defaultCharset()
|
||||
Options.verbose = ext.verbose
|
||||
Options.progress = ext.progress
|
||||
Options.unused_warning = ext.unused_warning
|
||||
Options.jlex = ext.jlex
|
||||
Options.no_minimize = ext.no_minimize
|
||||
Options.no_backup = ext.no_backup
|
||||
Options.time = ext.time
|
||||
Options.dot = ext.dot
|
||||
Options.dump = ext.dump
|
||||
Options.legacy_dot = ext.legacy_dot
|
||||
// hack for writing directly into java source. Not recommended.
|
||||
if (ext.writeIntoJavaSrc) {
|
||||
if (theSourceSet.java && theSourceSet.java.srcDirs) {
|
||||
logger.info "java sources: ${theSourceSet.java.srcDirs}"
|
||||
target = theSourceSet.java.srcDirs.first()
|
||||
logger.info "switching to first java source directory ${target}"
|
||||
} else {
|
||||
logger.warn "writing into java source not possible, is empty"
|
||||
}
|
||||
}
|
||||
source.each { file ->
|
||||
String pkg = getPackageName(file)
|
||||
File fullTarget = new File(target, pkg.replace('.','/'))
|
||||
project.mkdir(fullTarget)
|
||||
Options.directory = fullTarget
|
||||
logger.info "jflex task: source=${file} pkg=${pkg} dir=${target}"
|
||||
try {
|
||||
new LexGenerator(file).generate()
|
||||
} catch (GeneratorException e) {
|
||||
Logging.getLogger(JFlexTask).error("JFlex error: ${e.message}", e)
|
||||
throw new StopActionException('an error occurred during JFlex code generation')
|
||||
}
|
||||
}
|
||||
if (ext.statistics) {
|
||||
Out.statistics()
|
||||
}
|
||||
}
|
||||
|
||||
static String getPackageName(File file) {
|
||||
String string = file.readLines().find { line ->
|
||||
line.startsWith('package')
|
||||
}
|
||||
return string == null ? '' : string.substring(8, string.length() - 1)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
package org.xbib.gradle.plugin.test
|
||||
|
||||
import org.gradle.testkit.runner.BuildResult
|
||||
import org.gradle.testkit.runner.GradleRunner
|
||||
import org.gradle.testkit.runner.TaskOutcome
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
|
||||
import java.nio.file.Files
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
|
||||
class JFlexPluginTest {
|
||||
|
||||
private File projectDir
|
||||
|
||||
private File settingsFile
|
||||
|
||||
private File buildFile
|
||||
|
||||
@BeforeEach
|
||||
void setup(@TempDir File testProjectDir) throws IOException {
|
||||
this.projectDir = testProjectDir
|
||||
this.settingsFile = new File(testProjectDir, "settings.gradle")
|
||||
this.buildFile = new File(testProjectDir, "build.gradle")
|
||||
}
|
||||
|
||||
@Test
|
||||
void testJFlex() {
|
||||
String settingsFileContent = '''
|
||||
rootProject.name = 'jflex-test'
|
||||
'''
|
||||
settingsFile.write(settingsFileContent)
|
||||
String buildFileContent = '''
|
||||
plugins {
|
||||
id 'org.xbib.gradle.plugin.jflex'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
test {
|
||||
jflex {
|
||||
// point to our test directory where the jflex file lives
|
||||
srcDir "${System.getProperty('user.dir')}/src/test/jflex"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jflex {
|
||||
verbose = true
|
||||
dump = false
|
||||
progress = false
|
||||
}
|
||||
|
||||
'''
|
||||
buildFile.write(buildFileContent)
|
||||
BuildResult result = GradleRunner.create()
|
||||
.withProjectDir(projectDir)
|
||||
.withArguments(":build", "--info")
|
||||
.withPluginClasspath()
|
||||
.forwardOutput()
|
||||
.build()
|
||||
assertEquals(TaskOutcome.SUCCESS, result.task(":build").getOutcome())
|
||||
// default output dir
|
||||
File target = new File(projectDir, "build/generated/sources/test")
|
||||
boolean found = false
|
||||
if (target.exists()) {
|
||||
// check for generated output
|
||||
assertEquals(1, target.listFiles().length)
|
||||
target.eachFileRecurse {
|
||||
if (it.isFile()) {
|
||||
println "found: ${it}"
|
||||
found = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fail("directory not found: ${target}")
|
||||
}
|
||||
if (!found) {
|
||||
fail("jflex output not found")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testJFlexWriteIntoJavaSrc() {
|
||||
Files.createDirectories(projectDir.toPath().resolve('src/main/java'))
|
||||
Files.createDirectories(projectDir.toPath().resolve('src/test/java'))
|
||||
String settingsFileContent = '''
|
||||
rootProject.name = 'jflex-test'
|
||||
'''
|
||||
settingsFile.write(settingsFileContent)
|
||||
String buildFileContent = '''
|
||||
plugins {
|
||||
id 'org.xbib.gradle.plugin.jflex'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDir "src/main/java"
|
||||
}
|
||||
jflex {
|
||||
// point to our test directory where the jflex file lives
|
||||
srcDir "${System.getProperty('user.dir')}/src/test/jflex"
|
||||
}
|
||||
}
|
||||
test {
|
||||
java {
|
||||
srcDir "src/test/java"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jflex {
|
||||
verbose = true
|
||||
dump = false
|
||||
progress = false
|
||||
// enable legacy behavior of writing directly into Java source directory. Not recommended.
|
||||
writeIntoJavaSrc = true
|
||||
}
|
||||
|
||||
'''
|
||||
buildFile.write(buildFileContent)
|
||||
BuildResult result = GradleRunner.create()
|
||||
.withProjectDir(projectDir)
|
||||
.withArguments(":build", "--info")
|
||||
.withPluginClasspath()
|
||||
.forwardOutput()
|
||||
.build()
|
||||
assertEquals(TaskOutcome.SUCCESS, result.task(":build").getOutcome())
|
||||
// search the Java source directory
|
||||
File target = new File(projectDir, "src/main/java")
|
||||
boolean found = false
|
||||
if (target.exists()) {
|
||||
// check for generated file
|
||||
assertEquals(1, target.listFiles().length)
|
||||
target.eachFileRecurse {
|
||||
if (it.isFile()) {
|
||||
println "found: ${it}"
|
||||
found = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fail("directory not found: ${target}")
|
||||
}
|
||||
if (!found) {
|
||||
fail("jflex output not found")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTaskIsNotStarted() {
|
||||
String buildFileContent = '''
|
||||
plugins {
|
||||
id 'org.xbib.gradle.plugin.jflex'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
test {
|
||||
jflex {
|
||||
srcDir "${System.getProperty('user.dir')}/src/test/jflex"
|
||||
}
|
||||
java {
|
||||
srcDir "${System.getProperty('user.dir')}/build/my-generated-sources/jflex"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jflex {
|
||||
verbose = false
|
||||
dump = false
|
||||
progress = false
|
||||
}
|
||||
|
||||
def configuredTasks = []
|
||||
tasks.configureEach {
|
||||
configuredTasks << it
|
||||
}
|
||||
|
||||
gradle.buildFinished {
|
||||
def configuredTaskPaths = configuredTasks*.path
|
||||
assert configuredTaskPaths == [':help',':clean']
|
||||
}
|
||||
'''
|
||||
buildFile.write(buildFileContent)
|
||||
GradleRunner.create()
|
||||
.withProjectDir(projectDir)
|
||||
.withArguments(":help")
|
||||
.withPluginClasspath()
|
||||
.forwardOutput()
|
||||
.build()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package org.xbib.gradle.plugin.test;
|
||||
import java.io.IOException;
|
||||
|
||||
%%
|
||||
|
||||
%class Test
|
||||
%int
|
||||
%unicode
|
||||
%line
|
||||
%column
|
||||
|
||||
%{
|
||||
int token;
|
||||
double yylval;
|
||||
|
||||
int nextToken() {
|
||||
try {
|
||||
return token = yylex();
|
||||
} catch (IOException e) {
|
||||
return token = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
double getSemantic() {
|
||||
return yylval;
|
||||
}
|
||||
%}
|
||||
|
||||
ws = [ \t\f]
|
||||
digit = [0-9]
|
||||
number = {digit}+(\.{digit}+)?(E[+\-]?{digit}+)?
|
||||
|
||||
%%
|
||||
\r|\n|\r\n { return 0; }
|
||||
{ws}+ { }
|
||||
{number} { yylval = Double.parseDouble(yytext()); return 1; }
|
||||
[+\-*/()=] { return (int)(yytext().charAt(0)); }
|
||||
"*+" { return 2; }
|
||||
. { throw new Error(yytext()); }
|
8
gradle-plugin-rpm/NOTICE.txt
Normal file
8
gradle-plugin-rpm/NOTICE.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
Very loosely based on a 2018 version of nebula.rpm
|
||||
|
||||
https://github.com/nebula-plugins/gradle-ospackage-plugin
|
||||
|
||||
but completely revised, using the xbib rpm library, not redline rpm.
|
||||
|
||||
Lincense: Apache 2.0
|
|
@ -1,48 +1,44 @@
|
|||
plugins {
|
||||
id 'java-gradle-plugin'
|
||||
id 'groovy'
|
||||
id 'com.gradle.plugin-publish' version '1.0.0-rc-2'
|
||||
alias(libs.plugins.publish)
|
||||
}
|
||||
|
||||
apply plugin: 'groovy'
|
||||
apply plugin: 'java-gradle-plugin'
|
||||
apply plugin: 'com.gradle.plugin-publish'
|
||||
|
||||
apply from: rootProject.file('gradle/compile/groovy.gradle')
|
||||
|
||||
dependencies {
|
||||
api gradleApi()
|
||||
api "org.xbib:rpm-core:${project.property('rpm.version')}"
|
||||
api libs.rpm
|
||||
testImplementation gradleTestKit()
|
||||
}
|
||||
|
||||
compileGroovy {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
compileTestGroovy {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
validatePlugins {
|
||||
// disable warning as failures because gradle plugin does not recognize @Delegate tag
|
||||
failOnWarning = false
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
rpmPlugin {
|
||||
id = 'org.xbib.gradle.plugin.rpm'
|
||||
implementationClass = 'org.xbib.gradle.plugin.RpmPlugin'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (project.hasProperty('gradle.publish.key')) {
|
||||
pluginBundle {
|
||||
website = 'https://github.com/jprante/gradle-plugins/gradle-plugin-rpm'
|
||||
vcsUrl = 'https://github.com/jprante/gradle-plugins/'
|
||||
tags = ['rpm']
|
||||
}
|
||||
gradlePlugin {
|
||||
mavenCoordinates {
|
||||
groupId = "org.xbib.gradle.plugin"
|
||||
artifactId = "gradle-plugin-rpm"
|
||||
version = project.version
|
||||
}
|
||||
website = 'https://github.com/jprante/gradle-plugins'
|
||||
vcsUrl = 'https://github.com/jprante/gradle-plugins'
|
||||
plugins {
|
||||
rpmPlugin {
|
||||
id = 'org.xbib.gradle.plugin.rpm'
|
||||
version = project.version
|
||||
description = rootProject.ext.description
|
||||
displayName = rootProject.ext.description
|
||||
implementationClass = 'org.xbib.gradle.plugin.RpmPlugin'
|
||||
description = 'Java implementation for RPM packaging'
|
||||
displayName = 'Java implementation for RPM packaging'
|
||||
tags = [ 'rpm' ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
version = 2.4.0
|
||||
version = 2.3.0
|
||||
|
|
|
@ -1,19 +1,13 @@
|
|||
package org.xbib.gradle.plugin
|
||||
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.BasePlugin
|
||||
import org.gradle.util.GradleVersion
|
||||
|
||||
class RpmPlugin implements Plugin<Project> {
|
||||
|
||||
@Override
|
||||
void apply(Project project) {
|
||||
String version = '6.4'
|
||||
if (GradleVersion.current() < GradleVersion.version(version)) {
|
||||
throw new GradleException("need Gradle ${version} or higher")
|
||||
}
|
||||
project.plugins.apply(BasePlugin)
|
||||
project.ext.Rpm = Rpm.class
|
||||
}
|
||||
|
|
45
gradle-plugin-shadow/build.gradle
Normal file
45
gradle-plugin-shadow/build.gradle
Normal file
|
@ -0,0 +1,45 @@
|
|||
plugins {
|
||||
id 'java-gradle-plugin'
|
||||
alias(libs.plugins.publish)
|
||||
}
|
||||
|
||||
apply plugin: 'java-gradle-plugin'
|
||||
apply plugin: 'com.gradle.plugin-publish'
|
||||
|
||||
apply from: rootProject.file('gradle/compile/groovy.gradle')
|
||||
apply from: rootProject.file('gradle/test/junit5.gradle')
|
||||
|
||||
dependencies {
|
||||
api gradleApi()
|
||||
implementation libs.asm
|
||||
implementation libs.asm.commons
|
||||
implementation libs.asm.util
|
||||
testImplementation gradleTestKit()
|
||||
testImplementation libs.spock.core
|
||||
testImplementation libs.spock.junit4
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
shadowPlugin {
|
||||
id = 'org.xbib.gradle.plugin.shadow'
|
||||
implementationClass = 'org.xbib.gradle.plugin.shadow.ShadowPlugin'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (project.hasProperty('gradle.publish.key')) {
|
||||
pluginBundle {
|
||||
website = scmUrl
|
||||
vcsUrl = scmUrl
|
||||
plugins {
|
||||
shadowPlugin {
|
||||
id = 'org.xbib.gradle.plugin.shadow'
|
||||
version = project.version
|
||||
description = 'Shadow plugin for Gradle'
|
||||
displayName = 'Shadow plugin for Gradle'
|
||||
tags = [ 'shadow' ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
gradle-plugin-shadow/gradle.properties
Normal file
1
gradle-plugin-shadow/gradle.properties
Normal file
|
@ -0,0 +1 @@
|
|||
version = 2.0.0
|
28
gradle-plugin-shadow/src/docs/asciidoc/00-intro.adoc
Normal file
28
gradle-plugin-shadow/src/docs/asciidoc/00-intro.adoc
Normal file
|
@ -0,0 +1,28 @@
|
|||
:tests: ../../test/groovy/org/xbib/gradle/plugin/shadow
|
||||
== Introduction
|
||||
|
||||
Shadow is a Gradle plugin for combining dependency classes and resources with a project's into a single
|
||||
output Jar.
|
||||
The combined Jar is often referred to a __fat-jar__ or __uber-jar__.
|
||||
Shadow utilizes `JarInputStream` and `JarOutputStream` to efficiently process dependent libraries
|
||||
into the output jar without incurring the I/O overhead of expanding the jars to disk.
|
||||
|
||||
=== Benefits of Shadow
|
||||
|
||||
Shadowing a project output has a major use case:
|
||||
|
||||
. Bundling and relocating common dependencies in libraries to avoid classpath conflicts
|
||||
|
||||
==== Bundling
|
||||
|
||||
Dependency bundling and relocation is the main use case for __library__ authors.
|
||||
The goal of a bundled library is to create a pre-packaged dependency for other libraries or applications to utilize.
|
||||
Often in these scenarios, a library may contain a dependency that a downstream library or application also uses.
|
||||
In __some__ cases, different versions of this common dependency can cause an issue in either the upstream library or
|
||||
the downstream application.
|
||||
These issues often manifest themselves as binary incompatibilities in either the library or application code.
|
||||
|
||||
By utilizing Shadow's ability to __relocate__ the package names for dependencies, a library author can ensure that the
|
||||
library's dependencies will not conflict with the same dependency being declared by the downstream application.
|
||||
|
||||
include::01-getting-started.adoc[]
|
|
@ -0,0 +1,96 @@
|
|||
=== Getting Started
|
||||
|
||||
[source,groovy,subs="+attributes"]
|
||||
----
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'org.xbib.gradle.plugin:gradle-plugin-shadow:{project-version}'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'org.xbib.gradle.plugin.shadow'
|
||||
----
|
||||
|
||||
Alternatively, the Gradle Plugin syntax can be used:
|
||||
|
||||
[source,groovy,subs="+attributes"]
|
||||
----
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'org.xbib.gradle.plugin.shadow' version '{project-version}'
|
||||
}
|
||||
----
|
||||
|
||||
Shadow is a reactive plugin.
|
||||
This means that applying Shadow by itself will perform no configuration on your project.
|
||||
Instead, Shadow __reacts__ to the application of other plugins to decorate the project.
|
||||
|
||||
This means, that for most users, the `java` or `groovy` plugins must be __explicitly__ applied
|
||||
to have the desired effect.
|
||||
|
||||
=== Default Java/Groovy Tasks
|
||||
|
||||
In the presence of the `java` or `groovy` plugins, Shadow will automatically configure the
|
||||
following behavior:
|
||||
|
||||
* Adds a `shadowJar` task to the project.
|
||||
* Adds a `shadow` configuration to the project.
|
||||
* Configures the `shadowJar` task to include all sources from the project's `main` sourceSet.
|
||||
* Configures the `shadowJar` task to bundle all dependencies from the `runtime` configuration.
|
||||
* Configures the __classifier__ attribute of the `shadowJar` task to be `'all'` .
|
||||
* Configures the `shadowJar` task to generate a `Manifest` with:
|
||||
** Inheriting all configuration from the standard `jar` task.
|
||||
** Adds a `Class-Path` attribute to the `Manifest` that appends all dependencies from the `shadow` configuration
|
||||
* Configures the `shadowJar` task to __exclude__ any JAR index or cryptographic signature files matching the following patterns:
|
||||
** `META-INF/INDEX.LIST`
|
||||
** `META-INF/*.SF`
|
||||
** `META-INF/*.DSA`
|
||||
** `META-INF/*.RSA`
|
||||
* Creates and registers the `shadow` component in the project (used for integrating with `maven-publish`).
|
||||
* Configures the `uploadShadow` task (as part of the `maven` plugin) with the following behavior:
|
||||
** Removes the `compile` and `runtime` configurations from the `pom.xml` file mapping.
|
||||
** Adds the `shadow` configuration to the `pom.xml` file as `RUNTIME` scope.
|
||||
|
||||
=== Shadowing Gradle Plugins
|
||||
|
||||
Shadow is capable of automatically configuring package relocation for your dependencies.
|
||||
This is useful especially when building Gradle plugins where you want your dependencies to not conflict with versions
|
||||
provided by the Gradle runtime.
|
||||
|
||||
[source,groovy,subs="+attributes"]
|
||||
----
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'org.xbib.gradle.plugin:shadow:{project-version}'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'org.xbib.gradle.plugin.shadow'
|
||||
apply plugin: 'java'
|
||||
----
|
||||
|
||||
Alternatively, the Gradle Plugin syntax can be used:
|
||||
|
||||
[source,groovy,subs="+attributes"]
|
||||
----
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'org.xbib.gradle.plugin.plugin-shadow' version '{project-version}'
|
||||
}
|
||||
----
|
||||
|
||||
Applying the `plugin-shadow` plugin is the same as applying the standard `shadow` plugin with the additional creation
|
||||
of the `configureRelocationShadowJar` task.
|
||||
This task runs before the `shadowJar` task and scans the packages present in the dependencies that will be merged into
|
||||
the final jar and automatically configures relocation for them.
|
||||
By default the tasks relocates all packages to the `shadow.` prefix.
|
||||
For example `org.jdom2.JDOMException` becomes `shadow.org.jdom2.JDOMException`
|
||||
|
||||
For more details see the sectinon <<Using Shadow to Package Gradle Plugins>>
|
106
gradle-plugin-shadow/src/docs/asciidoc/10-configuring.adoc
Normal file
106
gradle-plugin-shadow/src/docs/asciidoc/10-configuring.adoc
Normal file
|
@ -0,0 +1,106 @@
|
|||
== Configuring Shadow
|
||||
|
||||
The link:{api}/tasks/ShadowJar.html[`ShadowJar`] task type extends from Gradle's
|
||||
https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html[`Jar`] type.
|
||||
This means that all attributes and methods available on `Jar` are also available on
|
||||
link:{api}/tasks/ShadowJar.html[`ShadowJar`].
|
||||
Refer the __Gradle User Guide__ for https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html[Jar] for
|
||||
details.
|
||||
|
||||
=== Configuring Output Name
|
||||
|
||||
Shadow configures the default `shadowJar` task to set the output JAR's `destinationDir`, `baseName`, `appendix`,
|
||||
`version`, and `extension` to the same default values as Gradle does for all `Jar` tasks.
|
||||
Additionally, it configures the `classifier` to be `all`.
|
||||
|
||||
If working with a Gradle project with the name `myApp` and version `1.0`, the default `shadowJar` task will output a
|
||||
file at: `build/libs/myApp-1.0-all.jar`
|
||||
|
||||
As with all `Jar` tasks in Gradle, these values can be overridden:
|
||||
|
||||
.Output to `build/libs/shadow.jar`
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{tests}/ShadowPluginSpec.groovy[tags=rename]
|
||||
----
|
||||
|
||||
=== Configuring the Runtime Classpath
|
||||
|
||||
Each Java JAR file contains a manifest file that provides meta data about the contents of the JAR file itself.
|
||||
When using a shadowed JAR file as an executable JAR, it is assumed that all necessary runtime classes are contained
|
||||
within the JAR itself.
|
||||
There may be situations where the desire is to **not** bundle select dependencies into the shadowed JAR file but
|
||||
they are still required for runtime execution.
|
||||
|
||||
In these scenarios, Shadow creates a `shadow` configuration to declare these dependencies.
|
||||
Dependencies added to the `shadow` configuration are *not* bundled into the output JAR.
|
||||
Think of `configurations.shadow` as unmerged, runtime dependencies.
|
||||
The integration with the `maven` and `maven-publish` plugins will automatically configure dependencies added
|
||||
to `configurations.shadow` as `RUNTIME` scope dependencies in the resulting POM file.
|
||||
|
||||
Additionally, Shadow automatically configures the manifest of the `shadowJar` task to contain a `Class-Path` entry
|
||||
in the JAR manifest.
|
||||
The value of the `Class-Path` entry is the name of all dependencies resolved in the `shadow` configuration
|
||||
for the project.
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{tests}/ShadowPluginSpec.groovy[tags=shadowConfig]
|
||||
----
|
||||
|
||||
Inspecting the `META-INF/MANIFEST.MF` entry in the JAR file will reveal the following attribute:
|
||||
[source,property,indent=0]
|
||||
----
|
||||
Class-Path: junit-3.8.2.jar
|
||||
----
|
||||
|
||||
When deploying a shadowed JAR as an execution JAR, it is important to note that any non-bundled runtime dependencies
|
||||
**must** be deployed in the location specified in the `Class-Path` entry in the manifest.
|
||||
|
||||
=== Configuring the JAR Manifest
|
||||
|
||||
Beyond the automatic configuration of the `Class-Path` entry, the `shadowJar` manifest is configured in a number of ways.
|
||||
First, the manifest for the `shadowJar` task is configured to __inherit__ from the manifest of the standard `jar` task.
|
||||
This means that any configuration performed on the `jar` task will propagate to the `shadowJar` tasks.
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{tests}/ShadowPluginSpec.groovy[tags=jarManifest]
|
||||
----
|
||||
|
||||
Inspecting the `META-INF/MANIFEST.MF` entry in the JAR file will revel the following attribute:
|
||||
[source,property,indent=0]
|
||||
----
|
||||
Class-Path: /libs/a.jar
|
||||
----
|
||||
|
||||
If it is desired to inherit a manifest from a JAR task other than the standard `jar` task, the `inheritFrom` methods
|
||||
on the `shadowJar.manifest` object can be used to configure the upstream.
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
|
||||
task testJar(type: Jar) {
|
||||
manifest {
|
||||
attributes 'Description': 'This is an application JAR'
|
||||
}
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
manifest {
|
||||
inheritFrom project.tasks.testJar.manifest
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
include::11-filtering-contents.adoc[]
|
||||
|
||||
include::12-controlling-dependencies.adoc[]
|
||||
|
||||
include::13-controlling-merging.adoc[]
|
||||
|
||||
include::14-package-relocation.adoc[]
|
||||
|
||||
include::15-minimizing.adoc[]
|
||||
|
||||
include::16-reproducible-builds.adoc[]
|
|
@ -0,0 +1,27 @@
|
|||
=== Filtering Shadow Jar Contents
|
||||
|
||||
The final contents of a shadow JAR can be filtered using the `exclude` and `include` methods inherited from Gradle's
|
||||
`Jar` task type.
|
||||
|
||||
Refer to the https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html[Jar] documentation for details
|
||||
on the various versions of the methods and their behavior.
|
||||
|
||||
When using `exclude`/`include` with a `ShadowJar` task, the resulting copy specs are applied to the __final__ JAR
|
||||
contents.
|
||||
This means that, the configuration is applied to the individual files from both the project source set or __any__
|
||||
of the dependencies to be merged.
|
||||
|
||||
.Exclude a file from Shadow Jar
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{tests}/FilteringSpec.groovy[tags=excludeFile]
|
||||
----
|
||||
|
||||
Excludes and includes can be combined just like a normal `Jar` task, with `excludes` taking precendence over `includes`.
|
||||
Additionally, ANT style patterns can be used to match multiple files.
|
||||
|
||||
.Configuring output using ANT patterns
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{tests}/FilteringSpec.groovy[tags=excludeOverInclude]
|
||||
----
|
|
@ -0,0 +1,118 @@
|
|||
=== Configuring Shadowed Dependencies
|
||||
|
||||
Shadow configures the default `shadowJar` task to merge all dependencies from the project's `runtime` configuration
|
||||
into the final JAR.
|
||||
The configurations to from which to source dependencies for the merging can be configured using the `configurations` property
|
||||
of the link:{api}/tasks/ShadowJar.html[`ShadowJar`] task type.
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
shadowJar {
|
||||
configurations = [project.configurations.compile]
|
||||
}
|
||||
----
|
||||
|
||||
The above code sample would configure the `shadowJar` task to merge depdencies from only the `compile` configuration.
|
||||
This means any dependency declared in the `runtime` configuration would be **not** be included in the final JAR.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Note the literal use of `project.configurations` when setting the `configurations` attribute of a
|
||||
link:{api}/tasks/ShadowJar.html[`ShadowJar`] task.
|
||||
This is **required**. It maybe be tempting to specify `configurations = [configurations.compile]` but this will not
|
||||
have the intended effect, as `configurations.compile` will try to delegate to the `configurations` property of the
|
||||
the link:{api}/tasks/ShadowJar.html[`ShadowJar`] task instead of the `project`
|
||||
====
|
||||
|
||||
=== Embedding Jar Files Inside Your Shadow Jar
|
||||
|
||||
Because of the way that Gradle handles dependency configuration, from a plugin perspective, shadow is unable to distinguish between a jar file configured as a dependency and a jar file included in the resource folder. This means that any jar found in a resource directory will be merged into the shadow jar the same as any other dependency. If your intention is to embed the jar inside, you must rename the jar as to not end with `.jar` before the shadow task begins.
|
||||
|
||||
=== Filtering Dependencies
|
||||
|
||||
Individual dependencies can be filtered from the final JAR by using the `dependencies` block of a
|
||||
link:{api}/tasks/ShadowJar.html[`ShadowJar`] task.
|
||||
Dependency filtering does **not** apply to transitive dependencies.
|
||||
That is, excluding a dependency does not exclude any of its dependencies from the final JAR.
|
||||
|
||||
The `dependency` blocks provides a number of methods for resolving dependencies using the notations familiar from
|
||||
Gradle's `configurations` block.
|
||||
|
||||
.Exclude an Module Dependency
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{tests}/FilteringSpec.groovy[tags=excludeDep]
|
||||
----
|
||||
|
||||
.Exclude a Project Dependency
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{tests}/FilteringSpec.groovy[tags=excludeProject]
|
||||
----
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
While not being able to filter entire transitive dependency graphs might seem like an oversight, it is necessary
|
||||
because it would not be possible to intelligently determine the build author's intended results when there is a
|
||||
common dependency between two 1st level dependencies when one is excluded and the other is not.
|
||||
====
|
||||
|
||||
==== Using Regex Patterns to Filter Dependencies
|
||||
|
||||
Dependencies can be filtered using regex patterns.
|
||||
Coupled with the `<group>:<artifact>:<version>` notation for dependencies, this allows for excluding/including
|
||||
using any of these individual fields.
|
||||
|
||||
.Exclude Any Version of a Dependency
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{tests}/FilteringSpec.groovy[tags=excludeDepWildcard]
|
||||
----
|
||||
|
||||
Any of the individual fields can be safely absent and will function as though a wildcard was specified.
|
||||
|
||||
.Ignore Dependency Version
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
shadowJar {
|
||||
dependencies {
|
||||
exclude(dependency('shadow:d'))
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
The above code snippet is functionally equivalent to the previous example.
|
||||
|
||||
This same patten can be used for any of the dependency notation fields.
|
||||
|
||||
.Ignoring An Artifact Regardless of Group
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
shadowJar {
|
||||
dependencies {
|
||||
exclude(dependency(':d:1.0'))
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
.Excluding All Artifacts From Group
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
shadowJar {
|
||||
dependencies {
|
||||
exclude(dependency('shadow::1.0'))
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
==== Programmatically Selecting Dependencies to Filter
|
||||
|
||||
If more complex decisions are needed to select the dependencies to be included, the
|
||||
link:{api}/tasks/ShadowJar.html#dependencies(Action<DependencyFilter>)[`dependencies`] block provides a
|
||||
method that accepts a `Closure` for selecting dependencies.
|
||||
|
||||
.Selecting Dependencies to Filter With a Spec
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{tests}/FilteringSpec.groovy[tags=excludeSpec]
|
||||
----
|
|
@ -0,0 +1,151 @@
|
|||
=== Controlling JAR Content Merging
|
||||
|
||||
Shadow allows for customizing the process by which the output JAR is generated through the
|
||||
link:{api}/transformers/Transformer.html[`Transformer`] interface.
|
||||
This is a concept that has been carried over from the original Maven Shade implementation.
|
||||
A link:{api}/transformers/Transformer.html[`Transformer`] is invoked for each entry in the JAR before being written to
|
||||
the final output JAR.
|
||||
This allows a link:{api}/transformers/Transformer.html[`Transformer`] to determine if it should process a particular
|
||||
entry and apply any modifications beforewriting the stream to the output.
|
||||
|
||||
.Adding a Transformer
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
shadowJar {
|
||||
transform(MyTransformer.class)
|
||||
}
|
||||
----
|
||||
|
||||
Additionally, a `Transformer` can accept a `Closure` to configure the provided `Transformer`.
|
||||
|
||||
.Configuring a Transformer
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
shadowJar {
|
||||
transform(MyTransformer.class) {
|
||||
enable = true
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
An instantiated instance of a `Transformer` can also be provided.
|
||||
|
||||
.Adding a Transformer Instance
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
shadowJar {
|
||||
transform(new MyTransformer(enabled: true))
|
||||
}
|
||||
----
|
||||
|
||||
==== Merging Service Descriptor Files
|
||||
|
||||
Java libraries often contain service descriptors files in the `META-INF/services` directory of the JAR.
|
||||
A service descriptor typically contains a line delimited list of classes that are supported for a particular __service__.
|
||||
At runtime, this file is read and used to configure library or application behavior.
|
||||
|
||||
Multiple dependencies may use the same service descriptor file name.
|
||||
In this case, it is generally desired to merge the content of each instance of the file into a single output file.
|
||||
The link:{api}/transformers/ServiceFileTransformer.html[`ServiceFileTransformer`] class is used to perform this merging.
|
||||
By default, it will merge each copy of a file under `META-INF/services` into a single file in the output JAR.
|
||||
|
||||
.Merging Service Files
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
shadowJar {
|
||||
mergeServiceFiles()
|
||||
}
|
||||
----
|
||||
|
||||
The above code snippet is a convenience syntax for calling
|
||||
link:{api}/tasks/ShadowJar.html#transform(Class++<? extends Transformer>++)[`transform(ServiceFileTransformer.class)`].
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Groovy Extension Module descriptor files (located at `META-INF/services/org.codehaus.groovy.runtime.ExtensionModule`)
|
||||
are ignored by the link:{api}/transformers/ServiceFileTransformer.html[`ServiceFileTransformer`].
|
||||
This is due to these files having a different syntax than standard service descriptor files.
|
||||
Use the link:{api}/tasks/ShadowJar.html#mergeGroovyExtensionModules()[`mergeGroovyExtensionModules()`] method to merge
|
||||
these files if your dependencies contain them.
|
||||
====
|
||||
|
||||
===== Configuring the Location of Service Descriptor Files
|
||||
|
||||
By default the link:{api}/transformers/ServiceFileTransformer.html[`ServiceFileTransformer`] is configured to merge
|
||||
files in `META-INF/services`.
|
||||
This directory can be overridden to merge descriptor files in a different location.
|
||||
|
||||
.Merging Service Files in a Specific Directory
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
shadowJar {
|
||||
mergeServiceFiles {
|
||||
path = 'META-INF/custom'
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
===== Excluding/Including Specific Service Descriptor Files From Merging
|
||||
|
||||
The link:{api}/transformers/ServiceFileTransformer.html[`ServiceFileTransformer`] class supports specifying specific
|
||||
files to include or exclude from merging.
|
||||
|
||||
.Excluding a Service Descriptor From Merging
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
shadowJar {
|
||||
mergeServiceFiles {
|
||||
exclude 'META-INF/services/com.acme.*'
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
==== Merging Groovy Extension Modules
|
||||
|
||||
Shadow provides a specific transformer for dealing with Groovy extension module files.
|
||||
This is due to their special syntax and how they need to be merged together.
|
||||
The link:{api}/transformers/GroovyExtensionModuleTransformer.html[`GroovyExtensionModuleTransformer`] will handle these
|
||||
files.
|
||||
The link:{api}/tasks/ShadowJar.html[`ShadowJar`] task also provides a short syntax method to add this transformer.
|
||||
|
||||
.Merging Groovy Extension Modules
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
shadowJar {
|
||||
mergeGroovyExtensionModules()
|
||||
}
|
||||
----
|
||||
|
||||
==== Appending Text Files
|
||||
|
||||
Generic text files can be appended together using the
|
||||
link:{api}/transformers/AppendingTransformer.html[`AppendingTransformer`].
|
||||
Each file is appended using new lines to separate content.
|
||||
The link:{api}/tasks/ShadowJar.html[`ShadowJar`] task provides a short syntax method of
|
||||
link:{api}/tasks/ShadowJar.html#append(java.lang.String)[`append(String)`] to configure this transformer.
|
||||
|
||||
.Appending a Property File
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
shadowJar {
|
||||
append 'test.properties'
|
||||
}
|
||||
----
|
||||
|
||||
==== Appending XML Files
|
||||
|
||||
XML files require a special transformer for merging.
|
||||
The link:{api}/transformers/XmlAppendingTransformer.html[`XmlAppendingTransformer`] reads each XML document and merges
|
||||
each root element into a single document.
|
||||
There is no short syntax method for the link:{api}/transformers/XmlAppendingTransformer.html[`XmlAppendingTransformer`].
|
||||
It must be added using the link:{api}/tasks/ShadowJar.html#transform(++Class<? extends Transformer>++)[`transform`] methods.
|
||||
|
||||
.Appending a XML File
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
shadowJar {
|
||||
tranform(XmlAppendingTransformer.class) {
|
||||
resource = 'properties.xml'
|
||||
}
|
||||
}
|
||||
----
|
|
@ -0,0 +1,72 @@
|
|||
=== Relocating Packages
|
||||
|
||||
Shade is capable of scanning a project's classes and relocating specific dependencies to a new location.
|
||||
This is often required when one of the dependencies is susceptible to breaking changes in versions or
|
||||
to classpath pollution in a downstream project.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Google's Guava and the ASM library are typical cases where package relocation can come in handy.
|
||||
====
|
||||
|
||||
Shadow uses the ASM library to modify class byte code to replace the package name and any import
|
||||
statements for a class.
|
||||
Any non-class files that are stored within a package structure are also relocated to the new location.
|
||||
|
||||
.Relocating a Package
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{tests}/RelocationSpec.groovy[tags=relocate]
|
||||
----
|
||||
|
||||
The code snippet will rewrite the location for any class in the `junit.framework` to be `shadow.junit`.
|
||||
For example, the class `junit.textui.TestRunner` becomes `shadow.junit.TestRunner`.
|
||||
In the resulting JAR, the class file is relocated from `junit/textui/TestRunner.class` to
|
||||
`shadow/junit/TestRunner.class`.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Relocation operates at a package level.
|
||||
It is not necessary to specify any patterns for matching, it will operate simply on the prefix
|
||||
provided.
|
||||
====
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Relocation will be applied globally to all instance of the matched prefix.
|
||||
That is, it does **not** scope to __only__ the dependencies being shadowed.
|
||||
Be specific as possible when configuring relocation as to avoid unintended relocations.
|
||||
====
|
||||
|
||||
==== Filtering Relocation
|
||||
|
||||
Specific classes or files can be `included`/`excluded` from the relocation operation if necessary.
|
||||
|
||||
.Configuring Filtering for Relocation
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{tests}/RelocationSpec.groovy[tags=relocateFilter]
|
||||
----
|
||||
|
||||
==== Automatically Relocating Dependencies
|
||||
Shadow ships with a task that can be used to automatically configure all packages from all dependencies to be relocated.
|
||||
To configure automatic dependency relocation, declare a task of type `ConfigureShadowRelocation` and configure the
|
||||
`target` parameter to be the `ShadowJar` task you wish to auto configure. You will also need to declared a task
|
||||
dependency so the tasks execute in the correct order.
|
||||
.Configure Auto Relocation
|
||||
[source,groovy]
|
||||
----
|
||||
task relocateShadowJar(type: ConfigureShadowRelocation) {
|
||||
target = tasks.shadowJar
|
||||
prefix = "myapp" // Default value is "shadow"
|
||||
}
|
||||
tasks.shadowJar.dependsOn tasks.relocateShadowJar
|
||||
----
|
||||
[NOTE]
|
||||
====
|
||||
Configuring package auto relocation can add significant time to the shadow process as it will process all dependencies
|
||||
in the configurations declared to be shadowed. By default, this is the `runtime` or `runtimeClasspath` configurations.
|
||||
Be mindful that some Gradle plugins (such as `java-gradle-plugin` will automatically add dependencies to your class path
|
||||
(e.g. `java-gradle-plugin` automatically adds the full Gradle API to your `compile` configuratinon. You may need to
|
||||
remove these dependencies if you do not intend to shadow them into your library.
|
||||
====
|
25
gradle-plugin-shadow/src/docs/asciidoc/15-minimizing.adoc
Normal file
25
gradle-plugin-shadow/src/docs/asciidoc/15-minimizing.adoc
Normal file
|
@ -0,0 +1,25 @@
|
|||
=== Minimizing
|
||||
|
||||
Shadow can automatically remove all classes of dependencies that are not used by the project, thereby minimizing the resulting shadowed JAR.
|
||||
|
||||
.Minimizing an shadow JAR
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
shadowJar {
|
||||
minimize()
|
||||
}
|
||||
----
|
||||
|
||||
A dependency can be excluded from the minimization process thereby forcing it's inclusion the shadow JAR.
|
||||
This is useful when the dependency analyzer cannot find the usage of a class programmatically, for example if the class
|
||||
is loaded dynamically via `Class.forName(String)`.
|
||||
|
||||
.Force a class to be retained during minimization
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
shadowJar {
|
||||
minimize {
|
||||
exclude(dependency('org.scala-lang:.*:.*'))
|
||||
}
|
||||
}
|
||||
----
|
|
@ -0,0 +1,16 @@
|
|||
=== Reproducible Builds
|
||||
|
||||
Because JAR files contain the timestamp of the included files, it is often difficult to create reproducible builds
|
||||
from a source commit that results in a hash identical file.
|
||||
Gradle supports reproducible JAR creation by setting the timestamps of included files to a consistent value.
|
||||
Shadow includes support for overriding file timestamps. By default, Shadow will preserve
|
||||
the file timestamps when creating the Shadow JAR. To set timestamps to a consistent value (1980/1/1 00:00:00),
|
||||
set the `preserveFileTimestamps` property to `false` on the `ShadowJar` task.
|
||||
|
||||
.Reset file timestamps
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
shadowJar {
|
||||
preserveFileTimestamps = false
|
||||
}
|
||||
----
|
20
gradle-plugin-shadow/src/docs/asciidoc/20-custom-tasks.adoc
Normal file
20
gradle-plugin-shadow/src/docs/asciidoc/20-custom-tasks.adoc
Normal file
|
@ -0,0 +1,20 @@
|
|||
== Creating a Custom ShadowJar Task
|
||||
|
||||
The built in `shadowJar` task only provides an output for the `main` source set of the project.
|
||||
It is possible to add arbitrary link:{api}/tasks/ShadowJar.html[`ShadowJar`] tasks to a project.
|
||||
When doing so, ensure that the `configurations` property is specified to inform Shadow which dependencies to merge
|
||||
into the output.
|
||||
|
||||
.Shadowing Test Sources and Dependencies
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
task testJar(type: ShadowJar) {
|
||||
classifier = 'tests'
|
||||
from sourceSets.test.output
|
||||
configurations = [project.configurations.testRuntime]
|
||||
}
|
||||
----
|
||||
|
||||
The code snippet above will geneated a shadowed JAR contain both the `main` and `test` sources as well as all `runtime`
|
||||
and `testRuntime` dependencies.
|
||||
The file is output to `build/libs/<project>-<version>-tests.jar`.
|
69
gradle-plugin-shadow/src/docs/asciidoc/40-publishing.adoc
Normal file
69
gradle-plugin-shadow/src/docs/asciidoc/40-publishing.adoc
Normal file
|
@ -0,0 +1,69 @@
|
|||
== Publishing Shadow JARs
|
||||
|
||||
=== Publishing with Maven-Publish Plugin
|
||||
|
||||
The Shadow plugin will automatically configure the necessary tasks in the presence of Gradle's
|
||||
`maven-publish` plugin.
|
||||
The plugin provides the `component` method from the `shadow` extension to configure the
|
||||
publication with the necessary artifact and dependencies in the POM file.
|
||||
|
||||
.Publishing a Shadow JAR with the Maven-Publish Plugin
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'maven-publish'
|
||||
apply plugin: 'org.xbib.plugin.gradle.shadow'
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
shadow(MavenPublication) { publication ->
|
||||
project.shadow.component(publication)
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
maven {
|
||||
url "http://repo.myorg.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
=== Publishing with Maven Plugin
|
||||
|
||||
The Shadow plugin will automatically configure the necessary tasks in the presence of Gradle's
|
||||
`maven` plugin.
|
||||
To publish the JAR, simply configure the publish location for the `uploadShadow` task and execute it.
|
||||
|
||||
.Publishing a Shadow JAR with the Maven Plugin
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'maven'
|
||||
apply plugin: 'org.xbib.gradle.plugin.shadow'
|
||||
|
||||
uploadShadow {
|
||||
repositories {
|
||||
mavenDeployer {
|
||||
repository(url: "http://repo.myorg.com")
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
=== Shadow Configuration and Publishing
|
||||
|
||||
The Shadow plugin provides a custom configuration (`configurations.shadow`) to specify
|
||||
runtime dependencies that are *not* merged into the final JAR file.
|
||||
When configuring publishing with the Shadow plugin, the dependencies in the `shadow`
|
||||
configuration, are translated to become `RUNTIME` scoped dependencies of the
|
||||
published artifact.
|
||||
|
||||
No other dependencies are automatically configured for inclusion in the POM file.
|
||||
For example, excluded dependencies are *not* automatically added to the POM file or
|
||||
if the configuration for merging are modified by specifying
|
||||
`shadowJar.configurations = [configurations.myconfiguration]`, there is no automatic
|
||||
configuration of the POM file.
|
||||
|
||||
This automatic configuration occurs _only_ when using the above methods for
|
||||
configuring publishing. If this behavior is not desirable, then publishing *must*
|
||||
be manually configured.
|
|
@ -0,0 +1,21 @@
|
|||
== Using Shadow in Multi-Project Builds
|
||||
|
||||
When using Shadow in a multi-project build, project dependencies will be treated the same as
|
||||
external dependencies.
|
||||
That is a project dependency will be merged into the `shadowJar` output of the project that
|
||||
is applying the Shadow plugin.
|
||||
|
||||
=== Depending on the Shadow Jar from Another Project
|
||||
|
||||
In a multi-project build there may be one project that applies Shadow and another that
|
||||
requires the shadowed JAR as a dependency.
|
||||
In this case, use Gradle's normal dependency declaration mechanism to depend on the `shadow`
|
||||
configuration of the shadowed project.
|
||||
|
||||
.Depending On Shadow Output of Project
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
dependencies {
|
||||
compile project(path: 'api', configuration: 'shadow')
|
||||
}
|
||||
----
|
|
@ -0,0 +1,49 @@
|
|||
== Using Shadow to Package Gradle Plugins
|
||||
|
||||
In some scenarios, writing a Gradle plugin can be problematic because your plugin may depend on a version that
|
||||
conflicts with the same dependency provided by the Gradle runtime. If this is the case, then you can utilize Shadow
|
||||
to relocate your dependencies to a different package name to avoid the collision.
|
||||
|
||||
Configuring the relocation has always been possible, but the build author is required to know all the package names
|
||||
before hand. Shadow introduces a new task type `ConfigureShadowRelocation`.
|
||||
Tasks of this type are configured to target an instance of a `ShadowJar` task and run immediately before it.
|
||||
|
||||
The `ConfigureShadowRelocation` task, scans the dependencies from the configurations specified on the associated
|
||||
`ShadowJar` task and collects the package names contained within them. It then configures relocation for these
|
||||
packages using the specified `prefix` on the associated `ShadowJar` task.
|
||||
|
||||
While this is useful for developing Gradle plugins, nothing about the `ConfigureShadowRelocation` task is tied to
|
||||
Gradle projects. It can be used for standard Java or Groovy projects.
|
||||
|
||||
A simple Gradle plugin can use this feature by applying the `shadow` plugin and configuring the dependencies
|
||||
like so:
|
||||
|
||||
[source,groovy,subs="+attributes"]
|
||||
----
|
||||
import org.xbib.gradle.plugin.shadow.tasks.ConfigureShadowRelocation
|
||||
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'org.xbib.gradle.plugin.shadow' version '{project-version}'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
shadow localGroovy()
|
||||
shadow gradleApi()
|
||||
|
||||
compile 'org.ow2.asm:asm:7.0-beta'
|
||||
compile 'org.ow2.asm:asm-commons:7.0-beta'
|
||||
compile 'org.ow2.asm:asm-util:7.0-beta'
|
||||
}
|
||||
|
||||
task relocateShadowJar(type: ConfigureShadowRelocation) {
|
||||
target = tasks.shadowJar
|
||||
}
|
||||
tasks.shadowJar.dependsOn tasks.relocateShadowJar
|
||||
|
||||
----
|
||||
|
||||
Note that the `localGroovy()` and `gradleApi()` dependencies are added to the `shadow` configuration instead of the
|
||||
normal `compile` configuration. These dependencies are provided by Gradle to compile your project but are ultimately
|
||||
provided by the Gradle runtime when executing the plugin. Thus, it is __not__ advisable to bundle these dependencies
|
||||
with your plugin.
|
0
gradle-plugin-shadow/src/docs/asciidoc/80-examples.adoc
Normal file
0
gradle-plugin-shadow/src/docs/asciidoc/80-examples.adoc
Normal file
23
gradle-plugin-shadow/src/docs/asciidoc/99-about.adoc
Normal file
23
gradle-plugin-shadow/src/docs/asciidoc/99-about.adoc
Normal file
|
@ -0,0 +1,23 @@
|
|||
== About This Project
|
||||
|
||||
John Engelman about the original Shadow plugin:
|
||||
|
||||
____
|
||||
I started this project in December of 2012. We were working on converting from a monolithic application into a the
|
||||
new hot jazz of "microservices" using Dropwizard.
|
||||
I had also just started learning about Gradle and I knew that the incremental build system it provided would benefit
|
||||
our development team greatly.
|
||||
Unfortunately, the closest thing that Gradle had to Maven's Shade plugin was its ability to create application TARs and
|
||||
ZIPs.
|
||||
|
||||
So, Charlie Knudsen and myself set out to port the existing Shade code into a Gradle plugin.
|
||||
This port is what existing up until the `0.9` milestone releases for Shadow.
|
||||
It functioned, but it wasn't idiomatic Gradle by any means.
|
||||
|
||||
Starting with 0.9, Shadow was rewritten from the ground up as standard Gradle plugin and leveraged as much of Gradle's
|
||||
classes and concepts as possible.
|
||||
At the same time as the 0.9 release, Gradle was announcing the https://plugins.gradle.org[Gradle Plugin Portal] and
|
||||
so Shadow was published there.
|
||||
|
||||
Shadow has had nearly ~900,000 downloads from Bintray and countless more from the Gradle Plugin Portal.
|
||||
____
|
32
gradle-plugin-shadow/src/docs/asciidoc/index.adoc
Normal file
32
gradle-plugin-shadow/src/docs/asciidoc/index.adoc
Normal file
|
@ -0,0 +1,32 @@
|
|||
:src: ../
|
||||
:tests: {src}/test/groovy/org/xbib/gradle/plugin/shadow
|
||||
:api: api/org/xbib/gradle/plugin/shadow
|
||||
:docinfo1:
|
||||
ifdef::env-github[]
|
||||
:note-caption: :information-source:
|
||||
endif::[]
|
||||
|
||||
= Gradle Shadow Plugin User Guide & Examples
|
||||
|
||||
:revnumber: {project-version}
|
||||
|
||||
NOTE: This documentation was taken from the original Shadow Plugin and is copyrighted by John R. Engelman.
|
||||
References to older original Shadow Plugin versions have been removed for consistency.
|
||||
The references to the application mode (runShadow) are no longer supported and have been removed.
|
||||
To create application images, use Java Platform Module System, especially the `jlink` tool.
|
||||
|
||||
link:api/index.html[API Docs]
|
||||
|
||||
include::00-intro.adoc[]
|
||||
|
||||
include::10-configuring.adoc[]
|
||||
|
||||
include::20-custom-tasks.adoc[]
|
||||
|
||||
include::40-publishing.adoc[]
|
||||
|
||||
include::50-multi-project-builds.adoc[]
|
||||
|
||||
include::60-shadowing-plugins.adoc[]
|
||||
|
||||
include::99-about.adoc[]
|
|
@ -0,0 +1,21 @@
|
|||
package org.xbib.gradle.plugin.shadow
|
||||
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.util.GradleVersion
|
||||
|
||||
class ShadowBasePlugin implements Plugin<Project> {
|
||||
|
||||
static final String EXTENSION_NAME = 'shadow'
|
||||
|
||||
static final String CONFIGURATION_NAME = 'shadow'
|
||||
|
||||
@Override
|
||||
void apply(Project project) {
|
||||
if (GradleVersion.current() < GradleVersion.version('4.10')) {
|
||||
throw new IllegalArgumentException('shadow requires at least Gradle 4.10')
|
||||
}
|
||||
project.extensions.create(EXTENSION_NAME, ShadowExtension, project)
|
||||
project.configurations.create(CONFIGURATION_NAME)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package org.xbib.gradle.plugin.shadow
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.SelfResolvingDependency
|
||||
import org.gradle.api.file.CopySpec
|
||||
import org.gradle.api.publish.maven.MavenPom
|
||||
import org.gradle.api.publish.maven.MavenPublication
|
||||
|
||||
class ShadowExtension {
|
||||
|
||||
CopySpec applicationDistribution
|
||||
Project project
|
||||
|
||||
ShadowExtension(Project project) {
|
||||
this.project = project
|
||||
applicationDistribution = project.copySpec {}
|
||||
}
|
||||
|
||||
void component(MavenPublication publication) {
|
||||
|
||||
publication.artifact(project.tasks.shadowJar)
|
||||
publication.pom { MavenPom pom ->
|
||||
pom.withXml { xml ->
|
||||
def dependenciesNode = xml.asNode().appendNode('dependencies')
|
||||
|
||||
project.configurations.shadow.allDependencies.each {
|
||||
if (! (it instanceof SelfResolvingDependency)) {
|
||||
def dependencyNode = dependenciesNode.appendNode('dependency')
|
||||
dependencyNode.appendNode('groupId', it.group)
|
||||
dependencyNode.appendNode('artifactId', it.name)
|
||||
dependencyNode.appendNode('version', it.version)
|
||||
dependencyNode.appendNode('scope', 'runtime')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package org.xbib.gradle.plugin.shadow
|
||||
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.JavaPluginConvention
|
||||
import org.gradle.configuration.project.ProjectConfigurationActionContainer
|
||||
import org.xbib.gradle.plugin.shadow.tasks.ShadowJar
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
class ShadowJavaPlugin implements Plugin<Project> {
|
||||
|
||||
static final String SHADOW_JAR_TASK_NAME = 'shadowJar'
|
||||
|
||||
static final String SHADOW_GROUP = 'Shadow'
|
||||
|
||||
private final ProjectConfigurationActionContainer configurationActionContainer;
|
||||
|
||||
@Inject
|
||||
ShadowJavaPlugin(ProjectConfigurationActionContainer configurationActionContainer) {
|
||||
this.configurationActionContainer = configurationActionContainer
|
||||
}
|
||||
|
||||
@Override
|
||||
void apply(Project project) {
|
||||
configureShadowTask(project)
|
||||
project.configurations.compileClasspath.extendsFrom project.configurations.shadow
|
||||
}
|
||||
|
||||
protected void configureShadowTask(Project project) {
|
||||
JavaPluginConvention convention = project.convention.getPlugin(JavaPluginConvention)
|
||||
project.tasks.register(SHADOW_JAR_TASK_NAME, ShadowJar) { shadow ->
|
||||
shadow.group = SHADOW_GROUP
|
||||
shadow.description = 'Create a combined JAR of project and runtime dependencies'
|
||||
shadow.archiveClassifier.set("all")
|
||||
shadow.manifest.inheritFrom project.tasks.jar.manifest
|
||||
def libsProvider = project.provider { -> [project.tasks.jar.manifest.attributes.get('Class-Path')] }
|
||||
def files = project.objects.fileCollection().from { ->
|
||||
project.configurations.findByName(ShadowBasePlugin.CONFIGURATION_NAME)
|
||||
}
|
||||
shadow.doFirst {
|
||||
if (!files.empty) {
|
||||
def libs = libsProvider.get()
|
||||
libs.addAll files.collect { "${it.name}" }
|
||||
manifest.attributes 'Class-Path': libs.findAll { it }.join(' ')
|
||||
}
|
||||
}
|
||||
shadow.from(convention.sourceSets.main.output)
|
||||
shadow.configurations = [project.configurations.findByName('runtimeClasspath') ?
|
||||
project.configurations.runtimeClasspath : project.configurations.runtime]
|
||||
shadow.exclude('META-INF/INDEX.LIST', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'module-info.class')
|
||||
shadow.dependencies {
|
||||
exclude(dependency(project.dependencies.gradleApi()))
|
||||
}
|
||||
project.artifacts.add(ShadowBasePlugin.CONFIGURATION_NAME, shadow)
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue