You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2017/04/25 22:57:59 UTC
[20/20] groovy-user-site git commit: initial version
initial version
Project: http://git-wip-us.apache.org/repos/asf/groovy-user-site/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy-user-site/commit/33e32ad0
Tree: http://git-wip-us.apache.org/repos/asf/groovy-user-site/tree/33e32ad0
Diff: http://git-wip-us.apache.org/repos/asf/groovy-user-site/diff/33e32ad0
Branch: refs/heads/asf-site
Commit: 33e32ad01ee7730325da4c109a82eaab28b74ff7
Parents:
Author: paulk <pa...@asert.com.au>
Authored: Wed Apr 26 08:23:07 2017 +1000
Committer: paulk <pa...@asert.com.au>
Committed: Wed Apr 26 08:23:07 2017 +1000
----------------------------------------------------------------------
.gitignore | 10 +
.travis.yml | 5 +
LICENSE | 201 +
README.adoc | 77 +
build.gradle | 23 +
generator/build.gradle | 17 +
.../groovy/generator/AsciidoctorFactory.groovy | 9 +
.../groovy/generator/ChangelogParser.groovy | 104 +
.../src/main/groovy/generator/DocUtils.groovy | 5 +
.../generator/DocumentationHTMLCleaner.groovy | 101 +
.../main/groovy/generator/PageTemplate.groovy | 61 +
.../main/groovy/generator/SiteGenerator.groovy | 251 +
generator/src/main/groovy/model/Book.groovy | 17 +
.../src/main/groovy/model/Changelog.groovy | 11 +
generator/src/main/groovy/model/Course.groovy | 34 +
.../src/main/groovy/model/Distribution.groovy | 19 +
.../main/groovy/model/DownloadPackage.groovy | 23 +
.../src/main/groovy/model/Ecosystem.groovy | 13 +
.../src/main/groovy/model/EcosystemEntry.groovy | 18 +
generator/src/main/groovy/model/Event.groovy | 19 +
generator/src/main/groovy/model/Events.groovy | 13 +
generator/src/main/groovy/model/Issue.groovy | 14 +
generator/src/main/groovy/model/Library.groovy | 13 +
generator/src/main/groovy/model/Menu.groovy | 21 +
generator/src/main/groovy/model/MenuItem.groovy | 13 +
generator/src/main/groovy/model/Page.groovy | 10 +
generator/src/main/groovy/model/Section.groovy | 21 +
.../src/main/groovy/model/SectionItem.groovy | 14 +
generator/src/main/groovy/model/SiteMap.groovy | 134 +
.../src/main/groovy/model/UserGroup.groovy | 28 +
generator/src/main/groovy/model/Video.groovy | 38 +
gradle.properties | 1 +
gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 52797 bytes
gradle/wrapper/gradle-wrapper.properties | 6 +
gradlew | 169 +
gradlew.bat | 84 +
settings.gradle | 4 +
site/build.gradle | 230 +
site/gradle/templates/deadlinks.groovy | 25 +
site/src/site/assets/css/book.css | 680 ++
site/src/site/assets/css/bootstrap.css | 6203 ++++++++++++++++++
site/src/site/assets/css/docstyle.css | 65 +
site/src/site/assets/css/documentation.css | 1 +
site/src/site/assets/css/font-awesome.min.css | 4 +
site/src/site/assets/css/main.css | 304 +
site/src/site/assets/css/normalize.css | 527 ++
site/src/site/assets/css/style.css | 1098 ++++
site/src/site/assets/fonts/FontAwesome.otf | Bin 0 -> 75188 bytes
.../site/assets/fonts/fontawesome-webfont.eot | Bin 0 -> 72449 bytes
.../site/assets/fonts/fontawesome-webfont.svg | 504 ++
.../site/assets/fonts/fontawesome-webfont.ttf | Bin 0 -> 141564 bytes
.../site/assets/fonts/fontawesome-webfont.woff | Bin 0 -> 83760 bytes
site/src/site/assets/img/asf_logo.png | Bin 0 -> 21243 bytes
site/src/site/assets/img/books/Kousen-MJG.png | Bin 0 -> 113588 bytes
site/src/site/assets/img/books/g2cook.jpg | Bin 0 -> 16565 bytes
site/src/site/assets/img/books/gdsl.jpg | Bin 0 -> 181096 bytes
site/src/site/assets/img/books/ggood.jpg | Bin 0 -> 34046 bytes
.../img/books/pratical-grails-3-book-cover.png | Bin 0 -> 59923 bytes
site/src/site/assets/img/books/regina.png | Bin 0 -> 25121 bytes
site/src/site/assets/img/books/vslg2.jpg | Bin 0 -> 105938 bytes
.../img/books/weissmann_groovy_grails.png | Bin 0 -> 76365 bytes
site/src/site/assets/img/confs/g3summit2016.png | Bin 0 -> 42130 bytes
site/src/site/assets/img/confs/gr8confeu.png | Bin 0 -> 15006 bytes
site/src/site/assets/img/confs/gr8confin.png | Bin 0 -> 15470 bytes
site/src/site/assets/img/confs/gr8confus.png | Bin 0 -> 32301 bytes
site/src/site/assets/img/confs/greach2017.png | Bin 0 -> 91218 bytes
.../assets/img/courses/groovy-course-cover.png | Bin 0 -> 97283 bytes
site/src/site/assets/img/ecosystem/geb.png | Bin 0 -> 9785 bytes
site/src/site/assets/img/ecosystem/gpars.png | Bin 0 -> 17029 bytes
site/src/site/assets/img/ecosystem/gradle.png | Bin 0 -> 18405 bytes
site/src/site/assets/img/ecosystem/grails.png | Bin 0 -> 16001 bytes
site/src/site/assets/img/ecosystem/griffon.png | Bin 0 -> 14209 bytes
site/src/site/assets/img/ecosystem/ratpack.png | Bin 0 -> 5589 bytes
site/src/site/assets/img/ecosystem/sdkman.png | Bin 0 -> 6435 bytes
site/src/site/assets/img/favicon.ico | Bin 0 -> 3813 bytes
site/src/site/assets/img/groovy-logo-black.svg | 36 +
.../src/site/assets/img/groovy-logo-colored.svg | 444 ++
site/src/site/assets/img/groovy-logo-white.png | Bin 0 -> 55066 bytes
site/src/site/assets/img/groovy-logo-white.svg | 36 +
site/src/site/assets/img/groovy-logo.png | Bin 0 -> 12303 bytes
site/src/site/assets/img/icons-colset-2-its.png | Bin 0 -> 5196 bytes
site/src/site/assets/img/logo.png | Bin 0 -> 435 bytes
site/src/site/assets/img/logos/airbusgroup.png | Bin 0 -> 1894 bytes
site/src/site/assets/img/logos/amadeus.png | Bin 0 -> 3009 bytes
site/src/site/assets/img/logos/bestbuy.png | Bin 0 -> 11763 bytes
site/src/site/assets/img/logos/carfax.png | Bin 0 -> 7381 bytes
site/src/site/assets/img/logos/carriots.png | Bin 0 -> 3655 bytes
site/src/site/assets/img/logos/cisco.png | Bin 0 -> 4331 bytes
site/src/site/assets/img/logos/commerzbank.png | Bin 0 -> 3052 bytes
.../src/site/assets/img/logos/credit-suisse.png | Bin 0 -> 2678 bytes
site/src/site/assets/img/logos/eads.png | Bin 0 -> 2768 bytes
.../site/assets/img/logos/energy-transfer.png | Bin 0 -> 2893 bytes
site/src/site/assets/img/logos/epo.png | Bin 0 -> 6403 bytes
site/src/site/assets/img/logos/fanniemae.png | Bin 0 -> 3719 bytes
site/src/site/assets/img/logos/google.png | Bin 0 -> 3708 bytes
site/src/site/assets/img/logos/hypoport.png | Bin 0 -> 6236 bytes
site/src/site/assets/img/logos/ibm.png | Bin 0 -> 2544 bytes
.../src/site/assets/img/logos/jpmorganchase.png | Bin 0 -> 2716 bytes
site/src/site/assets/img/logos/linkedin.png | Bin 0 -> 3015 bytes
site/src/site/assets/img/logos/mastercard.png | Bin 0 -> 6312 bytes
site/src/site/assets/img/logos/mtv.png | Bin 0 -> 9553 bytes
.../site/assets/img/logos/mutual-of-omaha.png | Bin 0 -> 6540 bytes
.../img/logos/national-cancer-institute.png | Bin 0 -> 10116 bytes
site/src/site/assets/img/logos/nestle.png | Bin 0 -> 3523 bytes
site/src/site/assets/img/logos/netflix.png | Bin 0 -> 3352 bytes
site/src/site/assets/img/logos/oracle.png | Bin 0 -> 4455 bytes
.../img/logos/paterson-cancer-institute.png | Bin 0 -> 5518 bytes
site/src/site/assets/img/logos/roche.png | Bin 0 -> 5308 bytes
site/src/site/assets/img/logos/sas.png | Bin 0 -> 4680 bytes
site/src/site/assets/img/logos/sky.png | Bin 0 -> 3137 bytes
site/src/site/assets/img/logos/smartthings.png | Bin 0 -> 7829 bytes
site/src/site/assets/img/logos/sony.png | Bin 0 -> 2762 bytes
site/src/site/assets/img/logos/target.png | Bin 0 -> 7259 bytes
site/src/site/assets/img/logos/thales.png | Bin 0 -> 2551 bytes
site/src/site/assets/img/logos/ubs.png | Bin 0 -> 6852 bytes
site/src/site/assets/img/logos/vodafone.png | Bin 0 -> 4623 bytes
site/src/site/assets/img/logos/voyages-sncf.png | Bin 0 -> 5621 bytes
site/src/site/assets/img/logos/walmart.png | Bin 0 -> 3246 bytes
site/src/site/assets/img/logos/wells-fargo.png | Bin 0 -> 5709 bytes
.../img/videos/groovy-ecosystem-revisited.png | Bin 0 -> 71130 bytes
.../site/assets/img/videos/groovy-puzzlers.png | Bin 0 -> 85894 bytes
.../img/videos/metaprogramming-part-1.png | Bin 0 -> 67863 bytes
site/src/site/assets/js/plugins.js | 24 +
site/src/site/assets/js/vendor/bootstrap.js | 2114 ++++++
site/src/site/assets/js/vendor/bootstrap.min.js | 6 +
site/src/site/assets/js/vendor/classie.js | 80 +
.../site/assets/js/vendor/jquery-1.10.2.min.js | 6 +
.../assets/js/vendor/modernizr-2.6.2.min.js | 4 +
.../src/site/assets/js/vendor/sidebarEffects.js | 65 +
site/src/site/html/index.html | 68 +
site/src/site/html/they-use-groovy.html | 45 +
site/src/site/html/twittersearch.html | 2 +
site/src/site/includes/bottommenu.groovy | 29 +
site/src/site/includes/community-navbar.groovy | 22 +
site/src/site/includes/contribute-button.groovy | 7 +
site/src/site/includes/topmenu.groovy | 31 +
site/src/site/layouts/iframedoc.groovy | 16 +
site/src/site/layouts/main.groovy | 21 +
site/src/site/layouts/page.groovy | 90 +
site/src/site/pages/404.groovy | 27 +
site/src/site/pages/api.groovy | 2 +
site/src/site/pages/buildstatus.groovy | 77 +
site/src/site/pages/changelog.groovy | 39 +
site/src/site/pages/changelogs.groovy | 43 +
site/src/site/pages/community.groovy | 58 +
site/src/site/pages/contribute.groovy | 197 +
site/src/site/pages/docpage.groovy | 37 +
site/src/site/pages/documentation.groovy | 79 +
site/src/site/pages/download.groovy | 323 +
site/src/site/pages/ecosystem.groovy | 59 +
site/src/site/pages/events.groovy | 61 +
site/src/site/pages/faq.groovy | 52 +
site/src/site/pages/gdk.groovy | 2 +
site/src/site/pages/groovy-weekly.groovy | 103 +
site/src/site/pages/index.groovy | 44 +
site/src/site/pages/indy.groovy | 174 +
site/src/site/pages/learn.groovy | 193 +
site/src/site/pages/mailing-lists.groovy | 76 +
site/src/site/pages/release-notes.groovy | 48 +
site/src/site/pages/releases.groovy | 36 +
site/src/site/pages/search.groovy | 113 +
site/src/site/pages/security.groovy | 150 +
.../site/pages/singlepagedocumentation.groovy | 2 +
site/src/site/pages/thanks.groovy | 51 +
site/src/site/pages/usergroups.groovy | 66 +
site/src/site/pages/versioning.groovy | 69 +
site/src/site/pages/wiki.groovy | 68 +
site/src/site/releasenotes/groovy-1.5.adoc | 858 +++
site/src/site/releasenotes/groovy-1.6.adoc | 1436 ++++
site/src/site/releasenotes/groovy-1.7.adoc | 433 ++
site/src/site/releasenotes/groovy-1.8.adoc | 1554 +++++
site/src/site/releasenotes/groovy-2.0.adoc | 886 +++
site/src/site/releasenotes/groovy-2.1.adoc | 963 +++
site/src/site/releasenotes/groovy-2.2.adoc | 256 +
site/src/site/releasenotes/groovy-2.3.adoc | 834 +++
site/src/site/releasenotes/groovy-2.4.adoc | 220 +
site/src/site/releasenotes/groovy-2.5.adoc | 112 +
site/src/site/sitemap.groovy | 473 ++
site/src/site/wiki/groovy-release.adoc | 132 +
.../site/wiki/incubation-release-process.adoc | 263 +
180 files changed, 25057 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6ba533c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+.idea
+*.iml
+*.ipr
+*.iws
+build
+.gradle
+.classpath
+atlassian-ide-plugin.xml
+
+
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/.travis.yml
----------------------------------------------------------------------
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..dc7b712
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,5 @@
+script: ./gradlew -q -s generate
+jdk:
+- openjdk7
+
+
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/LICENSE
----------------------------------------------------------------------
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..ad410e1
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+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.
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/README.adoc
----------------------------------------------------------------------
diff --git a/README.adoc b/README.adoc
new file mode 100644
index 0000000..230d929
--- /dev/null
+++ b/README.adoc
@@ -0,0 +1,77 @@
+= Groovy website
+The Groovy development team
+:revdate: 24-02-2014
+:build-icon: http://ci.groovy-lang.org:8111/app/rest/builds/buildType:(id:Groovy_Website)/statusIcon
+:noheader:
+:groovy-www: http://groovy-lang.org/
+:groovy-ci: http://ci.groovy-lang.org/viewType.html?buildTypeId=Groovy_Website&guest=1
+:gradle: http://www.gradle.org
+:markupte: http://docs.groovy-lang.org/latest/html/documentation/markup-template-engine.html
+
+[.left.text-left]
+image::http://groovy-lang.org/img/groovy-logo.png[]
+{groovy-www}[Groovy] is an agile and dynamic language for the Java Virtual Machine. It builds upon the strengths of Java, but has additional power features inspired by languages like Python, Ruby and Smalltalk.
+
+Groovy makes modern programming features available to Java developers with almost-zero learning curve as well as supports Domain-Specific Languages and other compact syntax so your code becomes easy to read and maintain.
+
+Groovy makes writing shell and build scripts easy with its powerful processing primitives, OO abilities and an Ant DSL.
+
+It also increases developer productivity by reducing scaffolding code when developing web, GUI, database or console applications. Groovy simplifies testing by supporting unit testing and mocking out-of-the-box. Groovy also seamlessly integrates with all existing Java classes and libraries and compiles straight to Java bytecode so you can use it anywhere you can use Java.
+
+== Sources for the Groovy website
+
+This project builds the Groovy website. It is using {gradle}[Gradle] and is fully statically generated.
+
+Build is image:{build-icon}[build status, link={groovy-ci}].
+
+== Generating the site
+
+----
+git clone http://git-wip-us.apache.org/repos/asf/groovy-user-site.git
+cd groovy-user-site
+./gradlew webzip
+----
+
+The output can be found in the `build` directory:
+
+----
+build
+ |---- site : the generated static website
+ |---- reports : deadlinks report
+ |---- distributions : zip of the website
+----
+
+== Contributing
+
+The website is generated thanks to Gradle and makes use of the {markupte}[Markup Template Engine]. The structure of the
+project consists of two modules:
+
+----
+generator : utility classes and model for generating the website
+site : the website itself
+----
+
+The website subproject consists of:
+
+----
+src/main/site : sources for the static website
+ |--- assets : static resources such as images, CSS files, ...
+ |--- html : elements that templates include as raw HTML contents
+ |--- includes : includes used by templates
+ |--- layouts : layouts for the various pages
+ |--- pages : individual pages
+build.gradle : website weaving logic
+----
+
+Additional details can be found in this http://melix.github.io/blog/2014/07/new-groovy-website.html[blog post].
+
+== Continuous Integration
+
+The official CI server runs {groovy-ci}[here] (login as user guest and leave the password blank) and is sponsored by http://www.jetbrains.com[JetBrains].
+
+WARNING: The website is continuously updated from the _master_ branch. This means that *every merge on master is immediately published*. Changes that need to be
+applied on a specific date need to be done on a dedicated branch.
+
+== License
+
+Groovy is licensed under the terms of the http://www.apache.org/licenses/LICENSE-2.0.html[Apache License, Version 2.0]
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/build.gradle
----------------------------------------------------------------------
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..d56e185
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,23 @@
+// Grab the plugin from a Maven Repo automatically
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.yahoo.platform.yui:yuicompressor:2.4.7'
+ }
+}
+
+plugins {
+ id 'com.gradle.build-scan' version '1.0'
+}
+
+buildScan {
+ licenseAgreementUrl = 'https://gradle.com/terms-of-service'
+ licenseAgree = 'yes'
+}
+
+allprojects {
+ apply plugin: 'idea'
+}
+
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/build.gradle
----------------------------------------------------------------------
diff --git a/generator/build.gradle b/generator/build.gradle
new file mode 100644
index 0000000..5f36eb0
--- /dev/null
+++ b/generator/build.gradle
@@ -0,0 +1,17 @@
+apply plugin: 'groovy'
+
+repositories {
+ jcenter()
+}
+
+dependencies {
+ ext.groovyVersion = '2.4.8'
+ ext.asciidocVersion = '1.5.4.1'
+ compile "org.codehaus.groovy:groovy:$groovyVersion"
+ compile "org.codehaus.groovy:groovy-json:$groovyVersion"
+ compile "org.codehaus.groovy:groovy-templates:$groovyVersion"
+ compile "org.asciidoctor:asciidoctorj:$asciidocVersion"
+}
+
+compileGroovy.sourceCompatibility = '1.7'
+compileGroovy.targetCompatibility = '1.7'
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/generator/AsciidoctorFactory.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/generator/AsciidoctorFactory.groovy b/generator/src/main/groovy/generator/AsciidoctorFactory.groovy
new file mode 100644
index 0000000..72d48dd
--- /dev/null
+++ b/generator/src/main/groovy/generator/AsciidoctorFactory.groovy
@@ -0,0 +1,9 @@
+package generator
+
+import groovy.transform.CompileStatic
+import org.asciidoctor.Asciidoctor
+
+@CompileStatic
+class AsciidoctorFactory {
+ @Lazy static Asciidoctor instance = Asciidoctor.Factory.create()
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/generator/ChangelogParser.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/generator/ChangelogParser.groovy b/generator/src/main/groovy/generator/ChangelogParser.groovy
new file mode 100644
index 0000000..ee84faa
--- /dev/null
+++ b/generator/src/main/groovy/generator/ChangelogParser.groovy
@@ -0,0 +1,104 @@
+package generator
+
+import groovy.json.JsonSlurper
+import model.Changelog
+import model.Issue
+
+import java.util.regex.Pattern
+
+class ChangelogParser {
+ private static final String JIRA_SERVER = 'https://issues.apache.org/jira'
+ private static final String PROJECT_NAME = 'GROOVY'
+ private static final String PROJECT_ID = '12318123'
+
+ private static final String LOGNOTES_INTRO = /Release Notes - Groovy/
+ private static final String LOGNOTES_END = /<\/textarea>/
+ private static final String BUGTYPE_MARK = '** '
+ private static final String ITEM_MARK = ' * '
+ private static final Pattern ITEM_PATTERN = ~/\[(GROOVY-[0-9]+)\] - (.+)/
+ private static final String VERSION_PATTERN = /^((1\.)|[23]\.)/
+
+ static List<Changelog> fetchReleaseNotes(File cacheDirectory) {
+ def slurper = new JsonSlurper()
+ def versions = slurper.parse("$JIRA_SERVER/rest/api/2/project/$PROJECT_NAME/versions".toURL())
+ def versionMap = versions.findAll {
+ it.name =~ VERSION_PATTERN &&
+ it.released == true
+ }.collectEntries {
+ [fixName(it.name), it.id]
+ }
+
+ def raw = versionMap.collect { name, id ->
+ println "Fetching changelog for version $name"
+ new Changelog(groovyVersion: name, issues: changelogHTML(id, cacheDirectory))
+ }
+ createAggregates(raw, versionMap.keySet())
+ }
+
+ private static String fixName(String name) {
+ String id = name
+ String classifier = ''
+
+ int idx = name.indexOf('-')
+ if (idx>0) {
+ classifier = name.substring(idx)
+ id = name - classifier
+ }
+ if (id.count('.')<2) {
+ // groovy 2.0 instead of 2.0.0
+ id = "${id}.0"
+ }
+ "$id$classifier"
+ }
+
+ private static List<Changelog> createAggregates(final List<Changelog> changelogs, final Set<String> releasedVersions) {
+ def allMajor = changelogs.groupBy {
+ def v = it.groovyVersion
+ v.contains('-')?v-v.substring(v.indexOf('-')):v
+ }.findAll { ver, logs -> ver in releasedVersions }
+ allMajor.collect { k,v ->
+ def changelog = changelogs.find { it.groovyVersion == k }
+ if (!changelog) {
+ println "Not found: $k"
+ changelog = new Changelog(groovyVersion: k, issues:[])
+ changelogs << changelog
+ }
+ v.each {
+ changelog.issues = [*changelog.issues, *it.issues].unique().sort { it.id }
+ }
+ }
+ changelogs
+ }
+
+ private static List<Issue> changelogHTML(String id, File cacheDir) {
+ def cache = new File(cacheDir, "changelog-${id}.html")
+ def log
+ if (cache.exists()) {
+ log = cache.getText('UTF-8')
+ } else {
+ log = new URL("$JIRA_SERVER/secure/ReleaseNote.jspa?version=$id&styleName=Text&projectId=$PROJECT_ID").getText('UTF-8')
+ cache.write(log, 'UTF-8')
+ }
+ boolean inNotes = false
+ String type = null
+ List<Issue> issues = []
+
+ log.eachLine { line ->
+ if (line.startsWith(LOGNOTES_INTRO)) {
+ inNotes = true
+ } else if (line.startsWith(LOGNOTES_END)) {
+ inNotes = false
+ } else if (inNotes) {
+ if (line.startsWith(BUGTYPE_MARK)) {
+ type = line - BUGTYPE_MARK
+ } else if (line.startsWith(ITEM_MARK)) {
+ def m = ITEM_PATTERN.matcher(line)
+ m.find()
+ issues << new Issue(id: m.group(1), description: m.group(2), type: type)
+ }
+ }
+ }
+
+ issues
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/generator/DocUtils.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/generator/DocUtils.groovy b/generator/src/main/groovy/generator/DocUtils.groovy
new file mode 100644
index 0000000..49d8609
--- /dev/null
+++ b/generator/src/main/groovy/generator/DocUtils.groovy
@@ -0,0 +1,5 @@
+package generator
+
+class DocUtils {
+ @Lazy public static final String DOCS_BASEURL = System.getProperty('docs_baseurl')
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/generator/DocumentationHTMLCleaner.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/generator/DocumentationHTMLCleaner.groovy b/generator/src/main/groovy/generator/DocumentationHTMLCleaner.groovy
new file mode 100644
index 0000000..fafa9db
--- /dev/null
+++ b/generator/src/main/groovy/generator/DocumentationHTMLCleaner.groovy
@@ -0,0 +1,101 @@
+package generator
+
+import groovy.transform.CompileStatic
+
+/**
+ * This class is responsible for downloading a documentation page as generated through the Asciidoctor task
+ * of the Groovy build, then filter its contents in order to return only the body of the documentation, as HTML.
+ *
+ * @author C�dric Champeau
+ */
+@CompileStatic
+class DocumentationHTMLCleaner {
+ private final static String BODY_START = /<body/
+ private final static String BODY_END = /<\/body/
+ private final static String TOC_START = /<div id="toc"/
+ private final static String MAIN_START = /<div id="content"/
+ private final static String MAIN_END = /<div id="footer"/
+
+ /**
+ * A list of links which are badly generated, but we know how to fix them
+ */
+ private final static Map<String,String> KNOWN_REPLACEMENTS = [
+ /docs\.groovy-lang\.org\/(latest|next)\/html\/documentation\/gdk\.html/: 'groovy-lang.org/gdk.html',
+ /\/maven\/groovy-/: '/maven/apache-groovy-'
+ ]
+
+ private static String cleanupPage(String location) {
+ def url = location.toURL()
+ try {
+ def fullHTML = url.getText('utf-8')
+ return extractBetween(fullHTML, BODY_START, BODY_END)
+ } catch (FileNotFoundException e) {
+ // 404 not found
+ }
+
+ null
+ }
+
+ private static String extractBetween(String html, String startString, String endString) {
+ def start = html.indexOf(startString)
+ if (start > 0) {
+ start = html.indexOf('>', start) + 1
+ }
+ if (start > 1) {
+ def end = html.indexOf(endString, start)
+ if (end > start) {
+ return html.substring(start, end)
+ }
+ }
+ null
+ }
+
+ public static DocPage parsePage(String location) {
+ String contents = cleanupPage(location)
+ if (contents==null) {
+ return new DocPage(content: "Contents not found for <a href='$location'>$location</a>, most likely because this section has not yet been written.")
+ }
+ String toc = extractTOC(contents)?:''
+ String main = extractBetween(contents, MAIN_START, MAIN_END)?:"Main body not found for <a href='$location'>$location</a>"
+ main = replaceInternalLinks(main)
+ new DocPage(toc: toc, content: main)
+ }
+
+ private static String replaceInternalLinks(String html) {
+ def replacer = { List<String> it ->
+ def (String tag, String attr, String url) = [it[1], it[2], it[3]]
+ url = url.replaceAll(/x(.+)\.(?:pagespeed.+)/, '$1')
+ if (!url.startsWith('http') && !url.startsWith('#') && 'target.html'!=url) {
+ "$tag $attr'${DocUtils.DOCS_BASEURL}/html/documentation/$url'"
+ } else {
+ it[0]
+ }
+ }
+ html = html.replaceAll(/(a)\s+(href=)["'](.+?)["']/,replacer)
+ html = html.replaceAll(/(img)\s+(src=)["'](.+?)["']/,replacer)
+ KNOWN_REPLACEMENTS.each { link, repl ->
+ html = html.replaceAll(link, repl)
+ }
+ html
+ }
+
+ private static String extractTOC(final String html) {
+ int start = html.indexOf(TOC_START)
+ if (start > 0) {
+ int end = html.indexOf(MAIN_START)
+ if (end>0) {
+ def out = html.substring(start, end).replace("<div id=\"toctitle\">Table of Contents</div>", "")
+ end = out.size()-1
+ while (!out.substring(end, out.size()).startsWith('</div>')) end--
+ return out.substring(0, end)
+ }
+ }
+ null
+ }
+
+ static class DocPage {
+ String toc = ''
+ String content
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/generator/PageTemplate.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/generator/PageTemplate.groovy b/generator/src/main/groovy/generator/PageTemplate.groovy
new file mode 100644
index 0000000..cb753f8
--- /dev/null
+++ b/generator/src/main/groovy/generator/PageTemplate.groovy
@@ -0,0 +1,61 @@
+package generator
+
+import groovy.text.markup.BaseTemplate
+import groovy.text.markup.MarkupTemplateEngine
+import groovy.text.markup.TemplateConfiguration
+import groovy.transform.CompileStatic
+import org.asciidoctor.Asciidoctor
+import org.asciidoctor.AttributesBuilder
+
+@CompileStatic
+abstract class PageTemplate extends BaseTemplate {
+ public static final String BASEDIR = "basePath";
+
+ private final Map model
+
+ PageTemplate(
+ final MarkupTemplateEngine templateEngine,
+ final Map model, final Map<String, String> modelTypes, final TemplateConfiguration configuration) {
+ super(templateEngine, model, modelTypes, configuration)
+ this.model = model
+ }
+
+ String relative(String path) {
+ String base = (String) model.get(BASEDIR)
+ if (base && !path.startsWith('http') && !path.startsWith(File.separator)) {
+ String up = "..${File.separator}"
+ "${up*(1+base.count(File.separator))}$path"
+ } else {
+ path
+ }
+ }
+
+ /**
+ * Converts and outputs asciidoctor markup into HTML
+ * @param body the asciidoctor markup
+ */
+ void asciidoc(String body, Map options=[:]) {
+ yieldUnescaped asciidocText(body, options)
+ }
+
+ /**
+ * Converts and returns asciidoctor markup into HTML. This method
+ * does *not* automatically renders the result so it is possible
+ * to post-process the generated HTML.
+ * @param body the asciidoctor markup
+ */
+ String asciidocText(String body, Map options=[:]) {
+ def asciidoctor = AsciidoctorFactory.instance
+ def attributes = options.attributes
+ if (!attributes) {
+ attributes = [:]
+ options.put('attributes', attributes)
+ }
+ attributes['source-highlighter'] = 'prettify'
+ asciidoctor.convert(body,options)
+ }
+
+ String latestDocURL(String target) {
+ "${DocUtils.DOCS_BASEURL}/html/$target"
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/generator/SiteGenerator.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/generator/SiteGenerator.groovy b/generator/src/main/groovy/generator/SiteGenerator.groovy
new file mode 100644
index 0000000..77c9c48
--- /dev/null
+++ b/generator/src/main/groovy/generator/SiteGenerator.groovy
@@ -0,0 +1,251 @@
+package generator
+
+import groovy.text.markup.MarkupTemplateEngine
+import groovy.text.markup.TemplateConfiguration
+import groovy.transform.CompileStatic
+import model.Changelog
+import model.Page
+import model.Section
+import model.SectionItem
+import model.SiteMap
+
+import java.nio.file.FileSystems
+import java.nio.file.Path
+import java.nio.file.WatchEvent
+
+import static generator.DocumentationHTMLCleaner.cleanupPage
+import static generator.DocumentationHTMLCleaner.parsePage
+import static java.nio.file.StandardWatchEventKinds.*
+
+@CompileStatic
+class SiteGenerator {
+
+ private final static Closure SEMANTIC_SORT = { String v1, String v2 ->
+ List<String> items1 = decomposeVersion(v1)
+ List<String> items2 = decomposeVersion(v2)
+ for (int i=0; i<Math.max(items1.size(),items2.size());i++) {
+ if (i>=items2.size()) {
+ return 1
+ }
+ if (i>=items1.size()) {
+ return -1
+ }
+ def p1 = items1[i]
+ def p2 = items2[i]
+ if (p1.isNumber()) {
+ if (p2.isNumber()) {
+ def pi1 = p1.toInteger()
+ def pi2 = p2.toInteger()
+
+ if (pi1 < pi2) {
+ return 1
+ } else if (pi1 > pi2) {
+ return -1
+ }
+ } else {
+ return -1
+ }
+ } else if (p2.isNumber()) {
+ return 1
+ } else {
+ return p2 <=> p1
+ }
+ }
+ 0
+ }
+
+ File sourcesDir
+ File outputDir
+
+ private MarkupTemplateEngine tplEngine
+ private SiteMap siteMap
+
+ void setup() {
+
+ println "Generating website using Groovy ${GroovySystem.version}"
+
+ def tplConf = new TemplateConfiguration()
+ tplConf.autoIndent = true
+ tplConf.autoNewLine = true
+ tplConf.baseTemplateClass = PageTemplate
+
+ def classLoader = new URLClassLoader([sourcesDir.toURI().toURL()] as URL[], this.class.classLoader)
+ tplEngine = new MarkupTemplateEngine(classLoader, tplConf, new MarkupTemplateEngine.CachingTemplateResolver())
+
+ siteMap = SiteMap.from(new File(sourcesDir, "sitemap.groovy"))
+
+ }
+
+ void render(String page, String target = null, Map model = [:], String baseDir=null) {
+ model.menu = siteMap.menu
+ model.currentPage = target
+ target = target ?: page
+ File root
+ if (baseDir) {
+ root = new File(outputDir, baseDir)
+ model[PageTemplate.BASEDIR] = baseDir
+ root.mkdirs()
+ } else {
+ root = outputDir
+ }
+
+ new File(root,"${target}.html").write(tplEngine.createTemplateByPath("pages/${page}.groovy").make(model).toString(), 'utf-8')
+ }
+
+ void generateSite() {
+ long sd = System.currentTimeMillis()
+ setup()
+
+ def cacheDir = new File(new File('build'), 'cache')
+ cacheDir.mkdirs()
+ println "Cache directory: $cacheDir"
+ def changelogs = ChangelogParser.fetchReleaseNotes(cacheDir);
+
+ renderDocumentation()
+
+ renderPages(changelogs)
+
+ renderChangelogs(changelogs)
+
+ renderReleaseNotes()
+
+ renderWiki()
+
+
+ long dur = System.currentTimeMillis() - sd
+ println "Generated site into $outputDir in ${dur}ms"
+ }
+
+ private List<Section> renderDocumentation() {
+ siteMap.documentationSections.each { Section section ->
+ section.items.each { SectionItem item ->
+ if (item.generate) {
+ println "Generating documentation page [$item.name]"
+ render 'docpage', item.targetFilename, [
+ category: 'Learn',
+ title : item.name,
+ page : parsePage("${DocUtils.DOCS_BASEURL}/html/documentation/${item.sourceFilename}.html")]
+ }
+ }
+ }
+ }
+
+ private List<Page> renderPages(List<Changelog> changelogs) {
+ siteMap.pages.each { Page page ->
+ println "Rendering individual page [$page.source]"
+ if ('changelogs' == page.source) {
+ page.model.versions = changelogs.groovyVersion.sort(SEMANTIC_SORT)
+ }
+ render page.source, page.target, page.model
+ }
+ }
+
+ private List<Changelog> renderChangelogs(List<Changelog> changelogs) {
+ changelogs.each {
+ println "Rendering changelog for Groovy $it.groovyVersion"
+ render 'changelog', "changelog-$it.groovyVersion", [groovyVersion: it.groovyVersion, issues: it.issues], 'changelogs'
+ }
+ }
+
+ private void renderReleaseNotes() {
+ def releaseNotesVersions = new TreeSet<String>(new Comparator<String>() {
+ @Override
+ int compare(final String v1, final String v2) {
+ v2.toDouble() <=> v1.toDouble()
+ }
+ })
+ new File(sourcesDir, 'releasenotes').eachFile { File file ->
+ def name = file.name.substring(0, file.name.lastIndexOf('.adoc'))
+ def version = name - 'groovy-'
+ releaseNotesVersions << version
+ println "Rendering release notes for Groovy $version"
+ render 'release-notes', name, [notes: file.getText('utf-8'), groovyVersion: version], 'releasenotes'
+ }
+ render 'releases', 'releases', [versions: releaseNotesVersions]
+ }
+
+ private void renderWiki() {
+ def asciidoctor = AsciidoctorFactory.instance
+ println "Rendering wiki"
+
+ def wikiDir = new File(sourcesDir, "wiki")
+ wikiDir.eachFileRecurse { f->
+ if (f.name.endsWith('.adoc')) {
+ def header = asciidoctor.readDocumentHeader(f)
+ def bn = f.name.substring(0,f.name.lastIndexOf('.adoc'))
+ println "Rendering $header.documentTitle.main by ${header.author?.fullName}"
+ def relativePath = []
+ def p = f.parentFile
+ while (p!=wikiDir) {
+ relativePath << p.name
+ p = p.parentFile
+ }
+ String baseDir = relativePath?"wiki${File.separator}${relativePath.join(File.separator)}":'wiki'
+ render 'wiki', bn, [notes:f.getText('utf-8'), header: header], baseDir
+ println baseDir
+ }
+ }
+ }
+
+ static void main(String... args) {
+ def sourcesDir = args[0] as File
+ def outputDir = args[1] as File
+ def generator = new SiteGenerator(sourcesDir: sourcesDir, outputDir: outputDir)
+ boolean watchMode = args.length > 2 ? Boolean.valueOf(args[2]) : false
+ generator.generateSite()
+
+ if (watchMode) {
+ println "Started watch mode"
+ def watcher = FileSystems.default.newWatchService()
+
+ sourcesDir.toPath().register(watcher,
+ ENTRY_CREATE,
+ ENTRY_DELETE,
+ ENTRY_MODIFY)
+
+ sourcesDir.eachDirRecurse { File f ->
+ f.toPath().register(watcher,
+ ENTRY_CREATE,
+ ENTRY_DELETE,
+ ENTRY_MODIFY)
+ }
+
+ def existingDirectories = ['pages', 'layouts', 'includes', 'html', 'assets', 'css', 'fonts', 'img', 'js', 'vendor']
+
+ while (true) {
+ def key = watcher.take()
+ def pollEvents = (List<WatchEvent<Path>>) key.pollEvents()
+
+ def changed = pollEvents.collect { "${it.context()}".toString() }.join(', ')
+
+ // only generate when the event refers to the actual file modified / created / added
+ // as otherwise the watcher service generates two events:
+ // 1) one for directory containing the modified file, and
+ // 2) one for the actual file being modified
+ // this checks avoid getting two events for one change
+ if (existingDirectories.every { !changed.contains(it) }) {
+ try {
+ println "Regenerating site due to changes in: ${changed}"
+ // todo: selective regeneration
+ generator.generateSite()
+ } finally {
+ key.reset()
+ }
+ }
+ }
+ }
+ }
+
+ static List<String> decomposeVersion(String version) {
+ String qualifier = ''
+ if (version.indexOf('-')>0) {
+ qualifier = version.substring(version.indexOf('-'))
+ version = version - qualifier
+ }
+ List<String> parts = version.split(/\./).toList()
+ if (qualifier) {
+ parts << qualifier
+ }
+ parts
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/model/Book.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/model/Book.groovy b/generator/src/main/groovy/model/Book.groovy
new file mode 100644
index 0000000..4537ace
--- /dev/null
+++ b/generator/src/main/groovy/model/Book.groovy
@@ -0,0 +1,17 @@
+package model
+
+import groovy.transform.CompileStatic
+
+@CompileStatic
+class Book {
+ String title
+ String authors
+ String cover
+ String url
+ String description
+
+ void authors (String authors) { this.authors = authors }
+ void cover (String cover) { this.cover = cover }
+ void url (String url) { this.url = url }
+ void description(String description) { this.description = description }
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/model/Changelog.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/model/Changelog.groovy b/generator/src/main/groovy/model/Changelog.groovy
new file mode 100644
index 0000000..b7ba910
--- /dev/null
+++ b/generator/src/main/groovy/model/Changelog.groovy
@@ -0,0 +1,11 @@
+package model
+
+import groovy.transform.CompileStatic
+import groovy.transform.ToString
+
+@CompileStatic
+@ToString
+class Changelog {
+ String groovyVersion
+ List<Issue> issues
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/model/Course.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/model/Course.groovy b/generator/src/main/groovy/model/Course.groovy
new file mode 100644
index 0000000..68f8618
--- /dev/null
+++ b/generator/src/main/groovy/model/Course.groovy
@@ -0,0 +1,34 @@
+package model
+
+import groovy.transform.CompileStatic
+
+@CompileStatic
+class Course {
+
+ String title
+ String instructor
+ String url
+ String description
+ String cover
+
+ void title(String title) {
+ this.title = title
+ }
+
+ void instructor(String instructor) {
+ this.instructor = instructor
+ }
+
+ void url(String url){
+ this.url = url
+ }
+
+ void description(String description){
+ this.description = description
+ }
+
+ void cover(String cover){
+ this.cover = cover
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/model/Distribution.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/model/Distribution.groovy b/generator/src/main/groovy/model/Distribution.groovy
new file mode 100644
index 0000000..55ef17c
--- /dev/null
+++ b/generator/src/main/groovy/model/Distribution.groovy
@@ -0,0 +1,19 @@
+package model
+
+import groovy.transform.CompileStatic
+
+@CompileStatic
+class Distribution {
+ String name
+ Closure description
+ List<DownloadPackage> packages = []
+
+ void description(Closure cl) { this.description = cl }
+
+ void version(String name, Closure versionSpec) {
+ DownloadPackage pkg = new DownloadPackage(version:name)
+ def clone = versionSpec.rehydrate(pkg,pkg,pkg)
+ clone()
+ packages.add(pkg)
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/model/DownloadPackage.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/model/DownloadPackage.groovy b/generator/src/main/groovy/model/DownloadPackage.groovy
new file mode 100644
index 0000000..152fa8d
--- /dev/null
+++ b/generator/src/main/groovy/model/DownloadPackage.groovy
@@ -0,0 +1,23 @@
+package model
+
+import groovy.transform.CompileStatic
+
+@CompileStatic
+class DownloadPackage {
+ String version
+ String releaseNotes
+ String windowsInstaller
+ boolean stable = false
+
+ void releaseNotes(String notes) {
+ releaseNotes = notes
+ }
+
+ void windowsInstaller(String installer) {
+ windowsInstaller = installer
+ }
+
+ void stable(boolean b) {
+ stable = b
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/model/Ecosystem.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/model/Ecosystem.groovy b/generator/src/main/groovy/model/Ecosystem.groovy
new file mode 100644
index 0000000..17a102f
--- /dev/null
+++ b/generator/src/main/groovy/model/Ecosystem.groovy
@@ -0,0 +1,13 @@
+package model
+
+import groovy.transform.CompileStatic
+
+@CompileStatic
+class Ecosystem extends LinkedHashMap<String,EcosystemEntry> {
+ void project(String name, Closure entrySpec) {
+ def entry = new EcosystemEntry(name:name)
+ def clone = entrySpec.rehydrate(entry,entry,entry)
+ clone()
+ put(name, entry)
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/model/EcosystemEntry.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/model/EcosystemEntry.groovy b/generator/src/main/groovy/model/EcosystemEntry.groovy
new file mode 100644
index 0000000..55dc9fd
--- /dev/null
+++ b/generator/src/main/groovy/model/EcosystemEntry.groovy
@@ -0,0 +1,18 @@
+package model
+
+import groovy.transform.ToString
+
+import groovy.transform.CompileStatic
+
+@CompileStatic
+@ToString(includeNames=true)
+class EcosystemEntry {
+ String name
+ String url
+ String description
+ String logo
+
+ void url(String url) { this.url = url }
+ void description(String description) { this.description = description }
+ void logo(String logo) { this.logo = logo }
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/model/Event.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/model/Event.groovy b/generator/src/main/groovy/model/Event.groovy
new file mode 100644
index 0000000..6eaf7d7
--- /dev/null
+++ b/generator/src/main/groovy/model/Event.groovy
@@ -0,0 +1,19 @@
+package model
+
+import groovy.transform.CompileStatic
+
+@CompileStatic
+class Event {
+ String name
+ String location
+ String date
+ String description
+ String url
+ String logo
+
+ void location (String location) { this.location = location }
+ void date (String date) { this.date = date }
+ void description(String description) { this.description = description }
+ void url (String url) { this.url = url }
+ void logo (String logo) { this.logo = logo }
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/model/Events.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/model/Events.groovy b/generator/src/main/groovy/model/Events.groovy
new file mode 100644
index 0000000..8767dec
--- /dev/null
+++ b/generator/src/main/groovy/model/Events.groovy
@@ -0,0 +1,13 @@
+package model
+
+import groovy.transform.CompileStatic
+
+@CompileStatic
+class Events extends LinkedHashMap<String, Event> {
+ void event(String name, Closure eventClosure) {
+ def entry = new Event(name: name)
+ def clone = eventClosure.rehydrate(entry, entry, entry)
+ clone()
+ put(name, entry)
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/model/Issue.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/model/Issue.groovy b/generator/src/main/groovy/model/Issue.groovy
new file mode 100644
index 0000000..db4b1ee
--- /dev/null
+++ b/generator/src/main/groovy/model/Issue.groovy
@@ -0,0 +1,14 @@
+package model
+
+import groovy.transform.CompileStatic
+import groovy.transform.EqualsAndHashCode
+import groovy.transform.ToString
+
+@CompileStatic
+@ToString
+@EqualsAndHashCode
+class Issue {
+ String id
+ String type
+ String description
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/model/Library.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/model/Library.groovy b/generator/src/main/groovy/model/Library.groovy
new file mode 100644
index 0000000..879cd98
--- /dev/null
+++ b/generator/src/main/groovy/model/Library.groovy
@@ -0,0 +1,13 @@
+package model
+
+import groovy.transform.CompileStatic
+
+@CompileStatic
+class Library extends LinkedHashMap<String, Book> {
+ void book(String title, Closure bookClosure) {
+ def book = new Book(title: title)
+ def clone = bookClosure.rehydrate(book, book, book)
+ clone()
+ put(title, book)
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/model/Menu.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/model/Menu.groovy b/generator/src/main/groovy/model/Menu.groovy
new file mode 100644
index 0000000..9e495ed
--- /dev/null
+++ b/generator/src/main/groovy/model/Menu.groovy
@@ -0,0 +1,21 @@
+package model
+
+import groovy.transform.CompileStatic
+
+@CompileStatic
+class Menu extends LinkedHashMap<String, List<MenuItem>> {
+
+ void group(String name, Closure groupSpec) {
+ Group g = new Group()
+ def clone = groupSpec.rehydrate(g,g,g)
+ clone()
+ put(name, g.items)
+ }
+
+ private static class Group {
+ List<MenuItem> items = []
+ void item(String name, String link, String style=null) {
+ items << new MenuItem(name:name, link: link, style:style)
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/model/MenuItem.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/model/MenuItem.groovy b/generator/src/main/groovy/model/MenuItem.groovy
new file mode 100644
index 0000000..6e58074
--- /dev/null
+++ b/generator/src/main/groovy/model/MenuItem.groovy
@@ -0,0 +1,13 @@
+package model
+
+import groovy.transform.ToString
+
+import groovy.transform.CompileStatic
+
+@CompileStatic
+@ToString(includeNames=true)
+class MenuItem {
+ String name
+ String link
+ String style
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/model/Page.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/model/Page.groovy b/generator/src/main/groovy/model/Page.groovy
new file mode 100644
index 0000000..5b29679
--- /dev/null
+++ b/generator/src/main/groovy/model/Page.groovy
@@ -0,0 +1,10 @@
+package model
+
+import groovy.transform.CompileStatic
+
+@CompileStatic
+class Page {
+ String source
+ String target
+ Map model = [:]
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/model/Section.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/model/Section.groovy b/generator/src/main/groovy/model/Section.groovy
new file mode 100644
index 0000000..b0b14fd
--- /dev/null
+++ b/generator/src/main/groovy/model/Section.groovy
@@ -0,0 +1,21 @@
+package model
+
+import groovy.transform.ToString
+
+@ToString(includeNames=true)
+import groovy.transform.CompileStatic
+
+@CompileStatic
+class Section {
+ String name
+ String icon
+ List<SectionItem> items = []
+
+ void item(String name, String targetFile, String sourceFile, boolean generate = true) {
+ items.add(new SectionItem(name: name, sourceFilename: sourceFile, targetFilename: targetFile, generate:generate))
+ }
+
+ String getAnchor() {
+ name.replaceAll('[^a-zA-Z0-9]','').toLowerCase()
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/model/SectionItem.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/model/SectionItem.groovy b/generator/src/main/groovy/model/SectionItem.groovy
new file mode 100644
index 0000000..7379b23
--- /dev/null
+++ b/generator/src/main/groovy/model/SectionItem.groovy
@@ -0,0 +1,14 @@
+package model
+
+import groovy.transform.ToString
+
+import groovy.transform.CompileStatic
+
+@CompileStatic
+@ToString(includeNames=true)
+class SectionItem {
+ String name
+ String targetFilename
+ String sourceFilename
+ boolean generate = true
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/model/SiteMap.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/model/SiteMap.groovy b/generator/src/main/groovy/model/SiteMap.groovy
new file mode 100644
index 0000000..8742dbc
--- /dev/null
+++ b/generator/src/main/groovy/model/SiteMap.groovy
@@ -0,0 +1,134 @@
+package model
+
+import groovy.transform.ToString
+import org.codehaus.groovy.control.CompilerConfiguration
+
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.control.customizers.ImportCustomizer
+
+@CompileStatic
+@ToString(includeNames=true)
+class SiteMap {
+ final List<Section> documentationSections = []
+ final List<Distribution> distributions = []
+ final Menu menu = new Menu()
+ final Ecosystem ecosystem = new Ecosystem()
+ final Events allEvents = new Events()
+ final Library library = new Library()
+ final List<String> allDocVersions = []
+ final List<Page> pages = []
+ final List<UserGroup> usergroups = []
+ final List<Video> videos = []
+ final List<Course> courses = []
+
+ private SiteMap() {}
+
+ public static SiteMap from(File source) {
+ CompilerConfiguration config = new CompilerConfiguration()
+ def customizer = new ImportCustomizer()
+ config.addCompilationCustomizers(customizer)
+ customizer.addStaticImport('generator.DocUtils','DOCS_BASEURL')
+ config.scriptBaseClass = 'groovy.util.DelegatingScript'
+ GroovyShell shell = new GroovyShell(config)
+ def script = shell.parse(source)
+
+ def result = new SiteMap()
+ ((DelegatingScript)script).setDelegate(result)
+ script.run()
+
+ result
+ }
+
+ private void documentation(Closure docSpec) {
+ def clone = docSpec.rehydrate(this, this, this)
+ clone()
+ }
+
+ private void section(String name, String icon, Closure sectionSpec) {
+ Section section = new Section(name:name, icon:icon)
+ def spec = sectionSpec.rehydrate(section,section,section)
+ spec()
+ documentationSections.add(section)
+ }
+
+ private void groovyDocumentationVersions(List<String> allDocVersions) {
+ this.allDocVersions.addAll(allDocVersions)
+ }
+
+ private void downloads(Closure dlSpec) {
+ def clone = dlSpec.rehydrate(this, this, this)
+ clone()
+ }
+
+ private void pages(Closure pagesSpec) {
+ def clone = pagesSpec.rehydrate(this, this, this)
+ clone()
+ }
+
+ private void usergroups(Closure groupsSpec) {
+ def clone = groupsSpec.rehydrate(this ,this ,this)
+ clone()
+ }
+
+ private void videos(Closure videosSpec) {
+ def clone = videosSpec.rehydrate(this, this, this)
+ clone()
+ }
+
+ private void courses(Closure coursesSpec) {
+ def clone = coursesSpec.rehydrate(this, this, this)
+ clone()
+ }
+
+ private void distribution(String name, Closure distSpec) {
+ Distribution dist = new Distribution(name: name)
+ def clone = distSpec.rehydrate(dist, dist, dist)
+ clone()
+ distributions.add(dist)
+ }
+
+ private void menu(Closure menuSpec) {
+ def clone = menuSpec.rehydrate(menu, menu, menu)
+ clone()
+ }
+
+ private void ecosystem(Closure ecoSpec) {
+ def clone = ecoSpec.rehydrate(ecosystem, ecosystem, ecosystem)
+ clone()
+ }
+
+ private void allEvents(Closure eventsSpec) {
+ def clone = eventsSpec.rehydrate(allEvents, allEvents, allEvents)
+ clone()
+ }
+
+ private void books(Closure booksSpec) {
+ def clone = booksSpec.rehydrate(library, library, library)
+ clone()
+ }
+
+ private void page(String source, String target, Map model = [:]) {
+ pages.add(new Page(source:source, target: target, model: model))
+ }
+
+ private void userGroup(String name, Closure groupSpec) {
+ def group = new UserGroup(name: name)
+ def clone = groupSpec.rehydrate(group,group,group)
+ clone()
+ usergroups.add(group)
+ }
+
+ private void video(String title, Closure videoSpec) {
+ def video = new Video(title: title)
+ def clone = videoSpec.rehydrate(video, video, video)
+ clone()
+ videos.add(video)
+ }
+
+ private void course(String title, Closure courseSpec) {
+ def course = new Course(title: title)
+ def clone = courseSpec.rehydrate(course,course,course)
+ clone()
+ courses.add(course)
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/model/UserGroup.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/model/UserGroup.groovy b/generator/src/main/groovy/model/UserGroup.groovy
new file mode 100644
index 0000000..84007e3
--- /dev/null
+++ b/generator/src/main/groovy/model/UserGroup.groovy
@@ -0,0 +1,28 @@
+package model
+
+import groovy.transform.CompileStatic
+import groovy.transform.ToString
+
+@CompileStatic
+@ToString(includeNames=true)
+class UserGroup {
+ String location
+ String name
+ String url
+
+ void location(String location) {
+ this.location = location
+ }
+
+ void name(String name) {
+ this.name = name
+ }
+
+ void url(String url) {
+ this.url = url
+ }
+
+ String[] getLocationParts() {
+ location.split('/')
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/generator/src/main/groovy/model/Video.groovy
----------------------------------------------------------------------
diff --git a/generator/src/main/groovy/model/Video.groovy b/generator/src/main/groovy/model/Video.groovy
new file mode 100644
index 0000000..a5a4667
--- /dev/null
+++ b/generator/src/main/groovy/model/Video.groovy
@@ -0,0 +1,38 @@
+package model
+
+import groovy.transform.CompileStatic
+
+@CompileStatic
+class Video {
+ String title
+ String speaker
+ String summary
+ String pictureUrl
+ String videoUrl = ""
+ String slidesUrl = ""
+ String codeUrl = ""
+
+ void speaker(String speaker) {
+ this.speaker = speaker
+ }
+
+ void summary(String summary) {
+ this.summary = summary
+ }
+
+ void pictureUrl(String pictureUrl) {
+ this.pictureUrl = pictureUrl
+ }
+
+ void videoUrl(String videoUrl) {
+ this.videoUrl = videoUrl
+ }
+
+ void slidesUrl(String slidesUrl) {
+ this.slidesUrl = slidesUrl
+ }
+
+ void codeUrl(String codeUrl) {
+ this.codeUrl = codeUrl
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/gradle.properties
----------------------------------------------------------------------
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..c9d5166
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1 @@
+systemProp.docs_baseurl=http://docs.groovy-lang.org/latest
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/gradle/wrapper/gradle-wrapper.jar
----------------------------------------------------------------------
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..1d7437d
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/gradle/wrapper/gradle-wrapper.properties
----------------------------------------------------------------------
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..da60a3a
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Apr 03 10:41:25 AEST 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-bin.zip
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/gradlew
----------------------------------------------------------------------
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..9aa616c
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,169 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/gradlew.bat
----------------------------------------------------------------------
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/settings.gradle
----------------------------------------------------------------------
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..2fd2033
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,4 @@
+rootProject.name = 'groovy-user-site'
+
+include 'generator','site'
+
http://git-wip-us.apache.org/repos/asf/groovy-user-site/blob/33e32ad0/site/build.gradle
----------------------------------------------------------------------
diff --git a/site/build.gradle b/site/build.gradle
new file mode 100644
index 0000000..d63bb9a
--- /dev/null
+++ b/site/build.gradle
@@ -0,0 +1,230 @@
+import org.apache.http.client.config.RequestConfig
+import org.apache.http.client.methods.CloseableHttpResponse
+import org.apache.http.client.methods.HttpGet
+import org.apache.http.impl.client.CloseableHttpClient
+import org.apache.http.impl.client.HttpClients
+import groovy.text.markup.MarkupTemplateEngine
+import groovy.text.markup.TemplateConfiguration
+import org.gradle.internal.logging.ConsoleRenderer
+import com.yahoo.platform.yui.compressor.CssCompressor
+import com.yahoo.platform.yui.compressor.JavaScriptCompressor
+import org.apache.tools.ant.filters.BaseFilterReader
+
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'org.apache.httpcomponents:httpclient:4.5.1'
+ }
+}
+
+ext.watchmode = project.hasProperty('watchmode')?project.getProperty('watchmode'):'false'
+
+apply plugin: 'base'
+
+task copyAssets(type:Copy) {
+ from file('src/site/assets')
+ into file("$buildDir/site")
+ filesMatching('**/*.css') { f->
+ if (!f.name.contains('.min.')) {
+ filter(CssFilter)
+ }
+ }
+ filesMatching('**/*.js') { f->
+ if (!f.name.contains('.min.')) {
+ filter(JsFilter)
+ }
+ }
+}
+
+task generateSite(type:JavaExec) {
+
+ description = 'Generates the Groovy Website'
+ dependsOn copyAssets
+
+ ext.sources = file('src/site')
+ ext.outputDir = file("$buildDir/site")
+
+ inputs.files fileTree(sources)
+ outputs.files fileTree(outputDir)
+
+ classpath = project(':generator').sourceSets.main.runtimeClasspath
+ main = 'generator.SiteGenerator'
+ args = [sources, outputDir, project.watchmode]
+ systemProperties.docs_baseurl = System.getProperty('docs_baseurl')
+}
+
+task checkDeadLinks(dependsOn: generateSite) {
+ description = "Checks for dead links in the generated Groovy website"
+
+ ext.outputDir = file("$buildDir/reports")
+ ext.reportFile = file("$outputDir/deadlinks.html")
+
+ inputs.files fileTree(generateSite.outputDir)
+ outputs.file reportFile
+
+ // a collection of links which have either been validated
+ // or are dummy links
+ def excludeFromChecks = [
+ 'http://issues.apache.org/jira',
+ 'https://issues.apache.org/jira',
+ 'target.html',
+ 'foo.html',
+ 'http://www.acme.com/cars',
+ 'http://localhost:8080/groovy/hello.groovy'
+ ]
+
+ doLast {
+ def deadLinks = [:]
+
+ def currentPath
+ def isDead = [:].withDefault { String link ->
+ if (excludeFromChecks.any { link.startsWith(it) }) {
+ // skip checking those links because they dramatically increase build time
+ // while being most likely ok because generated through changelog parsing
+ return false
+ }
+
+ try {
+ URL url
+ try {
+ url = URI.create(link).toURL()
+ } catch (e) {
+ if (e.message.contains('URI is not absolute')) {
+ url = URI.create("file://${file("${generateSite.outputDir}/$currentPath/$link").absoluteFile}").toURL()
+ }
+ }
+ logger.debug("Checking URL: $url")
+ def cx = url.openConnection()
+ if (cx instanceof HttpURLConnection) {
+ CloseableHttpClient httpclient = HttpClients.createDefault()
+ RequestConfig requestConfig = RequestConfig.custom()
+ .setSocketTimeout(5_000)
+ .setConnectTimeout(5_000)
+ .setConnectionRequestTimeout(5_000)
+ .build()
+ HttpGet httpget = new HttpGet(link)
+ httpget.config = requestConfig
+ CloseableHttpResponse response
+ try {
+ response = httpclient.execute(httpget)
+ if (response.statusLine.statusCode == 404) {
+ return true
+ }
+ } finally {
+ response.close()
+ }
+ }
+ } catch (e) {
+ return true
+ }
+ return false
+ }
+
+ def checkLink = { List dead, int line, String link ->
+ if (isDead[link]) {
+ dead << [line:line, link:link]
+ }
+ }
+
+ def checkPage = { File f ->
+ currentPath = GFileUtils.relativePath(generateSite.outputDir, f.parentFile)
+ f.eachLine('utf-8') { String line, int nb ->
+ def dead = []
+ [/\shref=['"](.+?)['"]/, /src=['"](.+?)['"]/].each { regex ->
+ def matcher = line =~ regex
+ if (matcher) {
+ matcher.each {
+ def path = it[1]
+ checkLink(dead, nb, path)
+ }
+ }
+ }
+ if (dead) {
+ deadLinks[f] = dead
+ }
+ }
+ }
+
+ file(generateSite.outputDir).eachFileRecurse {
+ if (it.name.endsWith('.html')) {
+ checkPage(it)
+ }
+ }
+
+ outputDir.mkdirs()
+ def tplConf = new TemplateConfiguration()
+ tplConf.with {
+ autoIndent = true
+ autoNewLine = true
+ }
+ def tplEngine = new MarkupTemplateEngine(this.class.classLoader, file('gradle/templates'), tplConf)
+
+ def report = tplEngine.createTemplateByPath("deadlinks.groovy").make(deadLinks: deadLinks).toString()
+
+ reportFile.write(report, 'utf-8')
+ def reportURL = new ConsoleRenderer().asClickableFileUrl(reportFile)
+ logger.lifecycle "Dead links report written at $reportURL"
+ }
+}
+
+task webzip(type:Zip, dependsOn: checkDeadLinks) {
+ description = "Creates a zip with the generated website and the deadlink report"
+ destinationDir = file("$buildDir/distributions")
+
+ baseName = 'groovy'
+ appendix = 'website'
+ from(generateSite.outputDir) {
+ into 'site'
+ }
+ from (checkDeadLinks.outputDir) {
+ into 'reports'
+ }
+}
+
+// Resource filtering classes
+
+class JsFilter extends BaseFilterReader {
+ Writer writer
+ Thread worker
+
+ JsFilter(Reader reader) {
+ super(new PipedReader())
+ writer = new PipedWriter(this.@in)
+ def compressor = new JavaScriptCompressor(reader, null)
+ reader.close()
+ worker = Thread.start {
+ compressor.compress(writer, -1, true, false, false, false)
+ writer.close()
+ }
+ }
+
+ void close() {
+ worker.join()
+ super.close()
+ }
+
+}
+
+class CssFilter extends BaseFilterReader {
+ Writer writer
+ Thread worker
+
+ CssFilter(Reader reader) {
+ super(new PipedReader())
+ writer = new PipedWriter(this.@in)
+ def compressor = new CssCompressor(reader)
+ reader.close()
+ worker = Thread.start {
+ compressor.compress(writer, -1)
+ writer.close()
+ }
+ }
+
+ void close() {
+ worker.join()
+ super.close()
+ }
+
+}