Introduce contracted compiled patch tries for faster lookup, make compiled patch commands the primary runtime path, refresh stemmer benchmarks and documentation, and restructure the documentation for 3.0.0 onboarding. BREAKING CHANGE: Radixor 3.0.0 promotes compiled patch-command APIs and new compiled trie artifacts as the primary runtime integration model.
224 lines
8.1 KiB
Groovy
224 lines
8.1 KiB
Groovy
import org.gradle.plugins.ide.eclipse.model.SourceFolder
|
|
|
|
|
|
def luceneVersion = '10.5.0'
|
|
def luceneRootRelativePath = 'third-party/lucene'
|
|
def luceneSourceArtifacts = ['lucene-analysis-common', 'lucene-analyzers-common']
|
|
def luceneSourceDirectory = layout.buildDirectory.dir("${luceneRootRelativePath}/source/analyzers-common")
|
|
|
|
def luceneGeneratedSourceDirectory = layout.buildDirectory.dir('generated/sources/lucene')
|
|
def luceneGeneratedPorterFile = luceneGeneratedSourceDirectory.map { it.file('org/egothor/stemmer/benchmark/LucenePorterStemmerCopied.java') }
|
|
|
|
def luceneSourceDownloadFile = layout.buildDirectory.file("${luceneRootRelativePath}/lucene-${luceneVersion}-sources.jar")
|
|
|
|
dependencies {
|
|
jmhImplementation "org.apache.lucene:lucene-analysis-common:${luceneVersion}"
|
|
jmhImplementation "org.apache.lucene:lucene-analysis-stempel:${luceneVersion}"
|
|
jmhImplementation "org.apache.lucene:lucene-analysis-morfologik:${luceneVersion}"
|
|
}
|
|
|
|
def buildLuceneSourcesName = { final String artifact ->
|
|
"${artifact}-${luceneVersion}-sources.jar"
|
|
}
|
|
def buildLuceneSourcesUrl = { final String artifact ->
|
|
"https://repo1.maven.org/maven2/org/apache/lucene/${artifact}/${luceneVersion}/${buildLuceneSourcesName(artifact)}"
|
|
}
|
|
|
|
def isLuceneSourcesDownloadable = { final String artifact ->
|
|
try {
|
|
final URL sourceUrl = new URL(buildLuceneSourcesUrl(artifact))
|
|
final java.net.HttpURLConnection connection = (java.net.HttpURLConnection) sourceUrl.openConnection()
|
|
connection.requestMethod = 'HEAD'
|
|
connection.instanceFollowRedirects = true
|
|
connection.connectTimeout = 10000
|
|
connection.readTimeout = 10000
|
|
final int responseCode = connection.responseCode
|
|
connection.disconnect()
|
|
return responseCode == 200
|
|
} catch (Exception ignored) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
def downloadLuceneSourcesJar = { ->
|
|
final File targetFile = luceneSourceDownloadFile.get().asFile
|
|
|
|
for (String artifact : luceneSourceArtifacts) {
|
|
if (!isLuceneSourcesDownloadable(artifact)) {
|
|
continue
|
|
}
|
|
|
|
final String sourceUrl = buildLuceneSourcesUrl(artifact)
|
|
final File tempFile = new File(targetFile.parentFile, "${artifact}.${luceneVersion}.tmp")
|
|
try {
|
|
new URL(sourceUrl).withInputStream { inputStream ->
|
|
tempFile.parentFile.mkdirs()
|
|
tempFile.withOutputStream { outputStream ->
|
|
outputStream << inputStream
|
|
}
|
|
}
|
|
if (!tempFile.exists() || tempFile.length() <= 0L) {
|
|
throw new GradleException("Downloaded Lucene source artifact for ${artifact} was empty.")
|
|
}
|
|
targetFile.delete()
|
|
if (!tempFile.renameTo(targetFile)) {
|
|
throw new GradleException("Failed to persist downloaded Lucene source artifact for ${artifact}.")
|
|
}
|
|
return
|
|
} catch (Exception ignored) {
|
|
tempFile.delete()
|
|
}
|
|
}
|
|
|
|
throw new GradleException(
|
|
"Failed to download Apache Lucene source artifacts ${luceneSourceArtifacts} for version ${luceneVersion}.")
|
|
}
|
|
|
|
def luceneSourceClasspathPath = provider {
|
|
project.relativePath(luceneGeneratedSourceDirectory.get().asFile)
|
|
}
|
|
def luceneEclipseClasspathAttributes = [
|
|
gradle_scope : 'jmh',
|
|
gradle_used_by_scope: 'jmh',
|
|
test : 'true'
|
|
]
|
|
|
|
def isAbsoluteClasspathPath = { String path ->
|
|
path.startsWith('/') || path ==~ /^[A-Za-z]:[\\\/].*/
|
|
}
|
|
|
|
def luceneGeneratedPorterNotice = '''
|
|
/**
|
|
* Generated at benchmark execution time from Apache Lucene source.
|
|
*
|
|
* This source copy is compiled only for the JMH benchmark source set and is
|
|
* not committed as production code.
|
|
*/
|
|
'''
|
|
|
|
def transformPorterStemmerSource = { final File sourceFile, final File targetFile ->
|
|
if (!sourceFile.exists()) {
|
|
throw new GradleException("Apache Lucene PorterStemmer source was not available at ${sourceFile}.")
|
|
}
|
|
|
|
final String sourceText = sourceFile.getText('UTF-8')
|
|
String transformedText = sourceText
|
|
|
|
if (transformedText.contains('package org.apache.lucene.analysis.en;')) {
|
|
transformedText = transformedText.replaceFirst(/(?m)^\s*package\s+org\.apache\.lucene\.analysis\.en\s*;/,
|
|
'package org.egothor.stemmer.benchmark;')
|
|
} else {
|
|
throw new GradleException(
|
|
'Expected Lucene package-private PorterStemmer in org.apache.lucene.analysis.en package was not found in downloaded source.')
|
|
}
|
|
|
|
transformedText = transformedText.replaceFirst(/(?m)^\s*class\s+PorterStemmer\s*\{/, 'public final class LucenePorterStemmerCopied {')
|
|
transformedText = transformedText.replaceFirst(/(?m)^\s*public\s+PorterStemmer\(\)/, 'public LucenePorterStemmerCopied()')
|
|
|
|
if (!transformedText.contains('class LucenePorterStemmerCopied')) {
|
|
throw new GradleException("Failed to rename PorterStemmer class when generating ${targetFile}.")
|
|
}
|
|
|
|
targetFile.parentFile.mkdirs()
|
|
targetFile.text = transformedText
|
|
}
|
|
|
|
def resolveLucenePorterStemmerSource = { ->
|
|
final File sourceRoot = luceneSourceDirectory.get().asFile
|
|
final List<String> candidates = [
|
|
'org/apache/lucene/analysis/en/org/apache/lucene/analysis/en/PorterStemmer.java',
|
|
'org/apache/lucene/analysis/en/PorterStemmer.java',
|
|
'org/apache/lucene/analysis/en/org/tartarus/snowball/ext/PorterStemmer.java'
|
|
]
|
|
|
|
for (String candidate : candidates) {
|
|
final File file = new File(sourceRoot, candidate)
|
|
if (file.exists()) {
|
|
return file
|
|
}
|
|
}
|
|
|
|
final FileTree porterCandidates = fileTree(sourceRoot).matching { include '**/PorterStemmer.java' }
|
|
for (File file : porterCandidates.files) {
|
|
if (file.text.contains('class PorterStemmer') && file.text.contains('package org.apache.lucene.analysis.en;')) {
|
|
return file
|
|
}
|
|
}
|
|
|
|
throw new GradleException('Unable to resolve Lucene PorterStemmer source file from extracted artifact.')
|
|
}
|
|
|
|
tasks.register('downloadLuceneAnalyzersSources') {
|
|
group = 'build setup'
|
|
description = 'Downloads Apache Lucene analysis sources for benchmark-only code generation.'
|
|
|
|
outputs.file(luceneSourceDownloadFile)
|
|
|
|
doLast {
|
|
if (!luceneSourceDownloadFile.get().asFile.exists()) {
|
|
downloadLuceneSourcesJar()
|
|
}
|
|
}
|
|
}
|
|
|
|
tasks.register('extractLuceneAnalyzersSources', Copy) {
|
|
group = 'build setup'
|
|
description = 'Extracts Apache Lucene analysis source JAR for benchmark-only extraction.'
|
|
|
|
dependsOn(tasks.named('downloadLuceneAnalyzersSources'))
|
|
|
|
from(zipTree(luceneSourceDownloadFile))
|
|
into(luceneSourceDirectory)
|
|
}
|
|
|
|
tasks.register('generateLucenePorterStemmerCopied') {
|
|
group = 'build setup'
|
|
description = 'Generates LucenePorterStemmerCopied into the build-only benchmark source directory.'
|
|
|
|
dependsOn(tasks.named('extractLuceneAnalyzersSources'))
|
|
|
|
inputs.dir(luceneSourceDirectory)
|
|
outputs.file(luceneGeneratedPorterFile)
|
|
|
|
doLast {
|
|
final File sourceFile = resolveLucenePorterStemmerSource()
|
|
transformPorterStemmerSource(sourceFile, luceneGeneratedPorterFile.get().asFile)
|
|
}
|
|
}
|
|
|
|
sourceSets {
|
|
jmh {
|
|
java {
|
|
srcDir(luceneGeneratedSourceDirectory)
|
|
}
|
|
}
|
|
}
|
|
|
|
tasks.named('compileJmhJava') {
|
|
dependsOn(tasks.named('generateLucenePorterStemmerCopied'))
|
|
}
|
|
|
|
eclipse {
|
|
classpath {
|
|
file {
|
|
whenMerged { classpath ->
|
|
String generatedPath = luceneSourceClasspathPath.get()
|
|
|
|
classpath.entries.removeAll { entry ->
|
|
entry.hasProperty('path') && (
|
|
entry.path == generatedPath ||
|
|
isAbsoluteClasspathPath(entry.path)
|
|
)
|
|
}
|
|
|
|
SourceFolder luceneEntry = new SourceFolder(generatedPath, null)
|
|
luceneEntry.output = 'bin/jmh'
|
|
luceneEclipseClasspathAttributes.each { String name, String value ->
|
|
luceneEntry.entryAttributes[name] = value
|
|
}
|
|
classpath.entries.add(luceneEntry)
|
|
}
|
|
}
|
|
}
|
|
}
|