/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ buildscript { repositories { mavenCentral() jcenter() } dependencies { classpath "org.asciidoctor:asciidoctorj:1.6.2" } } plugins { id 'java' id 'com.github.jruby-gradle.base' version '2.0.0' } // This project does not contribute anything to main dependencies. versionsLock { testProject() } description = 'Solr reference guide' // Use an internal proxy to ruby gems. repositories { ruby.gems() } configurations { depVer refGuide } dependencies { // Dependencies to compile internal tools. implementation('org.asciidoctor:asciidoctorj') implementation('com.vaadin.external.google:android-json') implementation('org.jsoup:jsoup') implementation('org.slf4j:jcl-over-slf4j') implementation('org.slf4j:slf4j-simple') implementation('org.apache.logging.log4j:log4j-core') implementation('com.google.guava:guava') implementation('commons-codec:commons-codec') // Dependencies referenced in the guide. depVer('commons-codec:commons-codec') depVer('io.dropwizard.metrics:metrics-core') depVer('org.apache.logging.log4j:log4j-core') depVer('org.apache.opennlp:opennlp-tools') depVer('org.apache.tika:tika-core') depVer('org.apache.zookeeper:zookeeper') // jekyll dependencies gems 'rubygems:jekyll:3.5.2' gems 'rubygems:jekyll-asciidoc:3.0.0' // don't know why we have to explicitly add these deps but it doesn't resolve them // automatically. gems 'rubygems:tilt:2.0.10' gems 'rubygems:slim:4.0.1' gems 'rubygems:concurrent-ruby:1.0.5' } sourceSets { refGuide { java { srcDirs = [] } resources { srcDirs = ['src'] } } main { java { srcDirs = ['tools'] } } test { java { srcDirs = [] } } } ext { mainPage = "index" // the "MAJOR.MINOR" version of solr this guide is about (guides aren't specific to BUGFIX releases) // So on 'branch_9_9' where 'version' may be 9.9.0, 9.9.1, 9.9.9, etc..; solrDocsVersion = 9.9 solrDocsVersion = "${version}".replaceAll(/^(\d+\.\d+)(|\..*)$/, "\$1") // the "MAJOR_MINOR" version as a path for publishing the guide // So on 'branch_9_9' where solrDocsVersion = 9.9; solrGuideVersionPath => 9_9 solrGuideVersionPath = "${solrDocsVersion}".replaceAll(/^(\d+)\.(\d+)$/, "\$1_\$2") // these will be used to dynamically build up (nearly) identical tasks with consistent names // for building & link checking the ref guide. One using absolute URLs to javadocs, the // other using local paths that can be validated by the link checker. htmlSiteDetails = [name: 'Site', path: 'html-site', desc: 'HTML Site for publishing to the Solr website', props: [ htmlSolrJavadocs: "https://lucene.apache.org/solr/${solrGuideVersionPath}_0/", htmlLuceneJavadocs: "https://lucene.apache.org/core/${solrGuideVersionPath}_0/" ] ] linkCheckSiteDetails = [name: 'LocalJavadocLinksSite', path: 'local-jdoc-links-site', desc: 'Local Site for checking javadoc links', // NOTE: extra '../' because we'll in a sub-dir of buildDir that will be built later... props: [ htmlSolrJavadocs : 'link:../' + buildDir.toPath().relativize(project(':solr:documentation').docroot.toPath()).toString().replace(File.separator, '/'), htmlLuceneJavadocs : 'link:../' + buildDir.toPath().relativize(project(':lucene:documentation').docroot.toPath()).toString().replace(File.separator, '/') ] ] } // dynamically define the 2 variations of each target that we need... [ htmlSiteDetails, linkCheckSiteDetails ].each{ details -> final def contentDir = file("${buildDir}/${details.path}-content") final def htmlDir = file("${buildDir}/${details.path}") final def extraProps = details.props.clone() extraProps.htmlOutDir = "../${details.path}" task "prepare${details.name}Sources"(type: PrepareSources) { outDir contentDir props extraProps } task "build${details.name}"(type: com.github.jrubygradle.JRubyExec) { dependsOn "prepare${details.name}Sources" group "Documentation" description "Builds the ${details.desc}" inputs.dir contentDir outputs.dir htmlDir script 'jekyll' scriptArgs 'build' //, '--verbose' workingDir contentDir } task "check${details.name}"(type: JavaExec) { dependsOn "build${details.name}" classpath = sourceSets.main.runtimeClasspath main = 'CheckLinksAndAnchors' workingDir = contentDir // NOTE: even for the 'real' site, we check all relative links // (there will just be less of them, and this way any stray hardcoded // '../../' paths can be caught more easily) args([ htmlDir, "-check-all-relative-links" ]) } } // Hook in our dependency on all top level documentation in order to check local javadoc links checkLocalJavadocLinksSite.dependsOn ':documentation' // Hook up custom tasks with standard tasks. check.dependsOn checkLocalJavadocLinksSite, checkSite // Hook site building to assemble. assemble.dependsOn buildSite abstract class PrepareSources extends DefaultTask { /** Original Source files we'll be syncing FROM */ @InputDirectory public File getSrcDir() { return getProject().file("src") } /** * Where we sync the source files TO */ public void setOutDir(File outDir) { this.outDir = outDir; getOutputs().dir(outDir); } public File outDir; /** * Task specific props */ @Input public Map getProps() { return props; } public void setProps(Map props) { this.props = props; } private Map props; /** * Basic properties that should be the same for all tasks of this type */ @Input public Map getStandardProps() { final Project p = getProject(); return [ javadocLink : "https://docs.oracle.com/en/java/javase/11/docs/api/", solrGuideDraftStatus : p.propertyOrDefault('solrGuideDraft', "true").toBoolean() ? "DRAFT" : "", solrRootPath : p.project(':solr').projectDir.toString() + File.separator, solrDocsVersion : p.property('solrDocsVersion'), solrGuideVersionPath : p.property('solrGuideVersionPath'), buildDate : p.property('buildDate'), buildYear : p.property('buildYear'), ]; } public PrepareSources() { // setup 'dependsOn classes, configurations.depVer' here // so that it's not neccessary for every task impl to declare redundently final Project p = getProject(); dependsOn(p.getConfigurations().getByName('depVer')) dependsOn(p.getTasksByName('classes', false)) } @TaskAction public void doCopy() { final Project p = getProject(); final Configuration depVer = p.getConfigurations().getByName('depVer'); // start with any task (instance) specific props. final def props = getProps().clone(); // then add/override with anystandard props that should alwasy be used getStandardProps().each { k, v -> props[k] = v }; // These properties have to be resolved after the configuration phase is complete // (palantir's constraint) so we can't use them as input for caches. But as this task // depends on the configuration, it's used correctly [ ["ivyCommonsCodec", "commons-codec", "commons-codec"], ["ivyDropwizardMetrics", "io.dropwizard.metrics", "metrics-core"], ["ivyLog4j", "org.apache.logging.log4j", "log4j-core"], ["ivyOpennlpTools", "org.apache.opennlp", "opennlp-tools"], ["ivyTika", "org.apache.tika", "tika-core"], ["ivyZookeeper", "org.apache.zookeeper", "zookeeper"], ].each { prop, depGroup, depId -> props[prop] = p.getVersion(depGroup, depId, depVer) } final File intoDir = this.outDir; // Emit info about properties for clarity. logger.lifecycle('Syncing source files to {} using props:\n{}', intoDir, props.collect({ k, v -> " ${k} -> ${v}" }).join('\n')) // Escape all the properties, so they can be inserted into YAML templates. final def escapedProps = props.collectEntries{k, v -> [k, v.replace("'","''")]} final WorkResult syncResult = p.sync({ copySpec -> copySpec.setFilteringCharset('UTF-8'); copySpec.from(getSrcDir(), { raw -> raw.exclude('**/*.template') }) copySpec.from(getSrcDir(), { templated -> templated.include('**/*.template') templated.rename('(.+)\\.template', '$1') templated.expand(escapedProps) }) copySpec.into(intoDir); }); setDidWork(syncResult.getDidWork()); if (syncResult.getDidWork()) { // if sync did work, that means we need to rebuild the nav data files... p.javaexec({ execSpec -> execSpec.setClasspath( getProject().getConvention() .getPlugin(JavaPluginConvention.class) .getSourceSets().getByName("main").getRuntimeClasspath() ) execSpec.setWorkingDir( intoDir ) execSpec.setMain( 'BuildNavDataFiles' ) execSpec.args([ intoDir, p.property('mainPage') ]) }) } } }