Move bundled stemmer dictionaries from the core artifact into independently versioned model modules. Add model discovery and explicit model-loading APIs, a standard model aggregate, a model BOM, and dedicated model and catalog release workflows. Add full PoliMorf integration, model provenance and licensing validation, streaming model-input verification, strict dependency verification, consumer resolution tests, Configuration Cache compatibility, and expanded JMH, quality, documentation, and release checks. Upgrade the CycloneDX and JMH Gradle plugins and remove Gradle 10 and Java compiler deprecations. BREAKING CHANGE: The core Radixor artifact no longer contains bundled stemmer dictionaries. Applications must add the required model artifacts, the standard model aggregate, or model dependencies managed through the Radixor model BOM.
225 lines
7.9 KiB
Groovy
225 lines
7.9 KiB
Groovy
import org.gradle.plugins.ide.eclipse.model.SourceFolder
|
|
|
|
|
|
def paicehuskVersion = 'master'
|
|
def paicehuskArchiveName = "paice-husk-stemmer-${paicehuskVersion}.zip"
|
|
def paicehuskDownloadUrl = "https://github.com/Hopper262/paice-husk-stemmer/archive/refs/heads/${paicehuskVersion}.zip"
|
|
def paicehuskDownloadFile = layout.buildDirectory.file("third-party/paicehusk/${paicehuskArchiveName}")
|
|
def paicehuskExtractDirectory = layout.buildDirectory.dir('third-party/paicehusk/source')
|
|
def paicehuskArchiveDirectory = paicehuskExtractDirectory.map { it.dir('paice-husk-stemmer-master') }
|
|
def paicehuskJavaFile = paicehuskArchiveDirectory.map { it.file('paicehusk_java.java') }
|
|
def paicehuskRulesFile = paicehuskArchiveDirectory.map { it.file('paicehusk_rules.txt') }
|
|
|
|
def paicehuskGeneratedSourceDirectory = layout.buildDirectory.dir('generated/sources/paicehusk')
|
|
def paicehuskGeneratedStemmerFile = paicehuskGeneratedSourceDirectory.map { it.file('org/egothor/stemmer/benchmark/PaiceHuskLancasterStemmer.java') }
|
|
|
|
def paicehuskGeneratedSourcePath = provider {
|
|
project.relativePath(paicehuskGeneratedSourceDirectory.get().asFile)
|
|
}
|
|
def paicehuskSourceEclipseClasspathAttributes = [
|
|
gradle_scope : 'jmh',
|
|
gradle_used_by_scope: 'jmh',
|
|
test : 'true'
|
|
]
|
|
|
|
def paicehuskIsAbsolutePath = { String path ->
|
|
path.startsWith('/') || path ==~ /^[A-Za-z]:[\\\/].*/
|
|
}
|
|
|
|
def paicehuskGeneratedNotice = '''
|
|
/**
|
|
* Generated at benchmark execution time from upstream
|
|
* https://github.com/Hopper262/paice-husk-stemmer .
|
|
*
|
|
* This source copy is compiled only for the JMH benchmark source set and is
|
|
* not committed as production code.
|
|
*/
|
|
'''
|
|
|
|
def escapeForJava = { final String text ->
|
|
return text.replace('\\\\', '\\\\\\\\')
|
|
.replace('\"', '\\\"')
|
|
}
|
|
|
|
def toRuleLines = { final File rulesFile ->
|
|
final List<String> lines = rulesFile.readLines('UTF-8')
|
|
final StringBuilder ruleLines = new StringBuilder()
|
|
for (int index = 0; index < lines.size(); index++) {
|
|
final String line = lines.get(index)
|
|
ruleLines.append(' "')
|
|
ruleLines.append(escapeForJava(line))
|
|
ruleLines.append('"')
|
|
if (index < lines.size() - 1) {
|
|
ruleLines.append(',')
|
|
}
|
|
ruleLines.append('\n')
|
|
}
|
|
return ruleLines.toString()
|
|
}
|
|
|
|
def paicehuskEngineInsertion = { final String ruleLines ->
|
|
return """
|
|
|
|
public static final String[] RULE_LINES = {
|
|
${ruleLines}
|
|
};
|
|
|
|
private static final java.util.HashMap RULES = createRulesFromEmbeddedRules();
|
|
|
|
/**
|
|
* Creates benchmark stemmer instance.
|
|
*/
|
|
public PaiceHuskLancasterStemmer() {
|
|
}
|
|
|
|
/**
|
|
* Applies Paice/Husk stemming to one token.
|
|
*
|
|
* @param token input token
|
|
* @return stemmed token
|
|
*/
|
|
public String stem(final String token) {
|
|
if (token == null) {
|
|
return null;
|
|
}
|
|
return stemWord(token, RULES, null);
|
|
}
|
|
|
|
/**
|
|
* Loads bundled rule lines directly from the generated benchmark source.
|
|
*
|
|
* @return initialized rule map
|
|
*/
|
|
private static java.util.HashMap createRulesFromEmbeddedRules() {
|
|
try {
|
|
final java.io.File ruleFile = java.io.File.createTempFile("paicehusk-rules", ".txt");
|
|
ruleFile.deleteOnExit();
|
|
try (java.io.PrintWriter writer = new java.io.PrintWriter(new java.io.FileWriter(ruleFile))) {
|
|
for (String line : RULE_LINES) {
|
|
writer.println(line);
|
|
}
|
|
}
|
|
return loadRules(ruleFile.getAbsolutePath());
|
|
} catch (Exception exception) {
|
|
throw new IllegalStateException("Unable to initialize benchmark Paice/Husk rules.", exception);
|
|
}
|
|
}
|
|
"""
|
|
}
|
|
|
|
def transformPaiceHuskSource = { final File sourceFile, final File rulesFile, final File targetFile ->
|
|
if (!sourceFile.exists()) {
|
|
throw new GradleException("Paice/Husk Java source was not available at ${sourceFile}.")
|
|
}
|
|
if (!rulesFile.exists()) {
|
|
throw new GradleException("Paice/Husk rule file was not available at ${rulesFile}.")
|
|
}
|
|
|
|
final String sourceText = sourceFile.getText('UTF-8')
|
|
String transformedText = sourceText
|
|
|
|
transformedText = 'package org.egothor.stemmer.benchmark;' + '\n\n' + transformedText
|
|
transformedText = transformedText.replaceFirst(/(?m)^\s*class\s+PaiceHusk\s*\{/, 'public final class PaiceHuskLancasterStemmer {')
|
|
transformedText = transformedText.replace('new Character(rule.letter)', 'Character.valueOf(rule.letter)')
|
|
transformedText = transformedText.replace('new Character(stem.charAt(stem.length() - 1))',
|
|
'Character.valueOf(stem.charAt(stem.length() - 1))')
|
|
transformedText = transformedText.replaceFirst(/(?m)^(\s*)static HashMap loadRules\(/,
|
|
'$1@SuppressWarnings("unchecked")\n$1static HashMap loadRules(')
|
|
|
|
final int packageEnd = transformedText.indexOf('\n', transformedText.indexOf('package org.egothor.stemmer.benchmark;'))
|
|
if (packageEnd >= 0) {
|
|
transformedText = transformedText.substring(0, packageEnd + 1) + '\n' + paicehuskGeneratedNotice + transformedText.substring(packageEnd + 1)
|
|
}
|
|
|
|
final String marker = '\n} // end class PaiceHusk'
|
|
final int markerIndex = transformedText.lastIndexOf(marker)
|
|
if (markerIndex < 0) {
|
|
throw new GradleException("Unexpected Paice/Husk source structure at ${sourceFile}.")
|
|
}
|
|
final String replacement = paicehuskEngineInsertion(toRuleLines(rulesFile))
|
|
transformedText = transformedText.substring(0, markerIndex) + '\n' + replacement + '\n}'
|
|
|
|
targetFile.parentFile.mkdirs()
|
|
targetFile.text = transformedText
|
|
}
|
|
|
|
tasks.register('downloadPaiceHuskStemmer') {
|
|
group = 'build setup'
|
|
description = 'Downloads the upstream Paice/Husk benchmark source for dynamic extraction.'
|
|
|
|
outputs.file(paicehuskDownloadFile)
|
|
|
|
doLast {
|
|
final File targetFile = paicehuskDownloadFile.get().asFile
|
|
targetFile.parentFile.mkdirs()
|
|
|
|
if (!targetFile.exists()) {
|
|
new URL(paicehuskDownloadUrl).withInputStream { inputStream ->
|
|
targetFile.withOutputStream { outputStream ->
|
|
outputStream << inputStream
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
tasks.register('extractPaiceHuskStemmer', Copy) {
|
|
group = 'build setup'
|
|
description = 'Extracts the upstream Paice/Husk benchmark archive.'
|
|
|
|
dependsOn(tasks.named('downloadPaiceHuskStemmer'))
|
|
|
|
from(zipTree(paicehuskDownloadFile))
|
|
into(paicehuskExtractDirectory)
|
|
}
|
|
|
|
tasks.register('generatePaiceHuskLancasterStemmer') {
|
|
group = 'build setup'
|
|
description = 'Generates PaiceHuskLancasterStemmer into a benchmark-only generated source directory.'
|
|
|
|
dependsOn(tasks.named('extractPaiceHuskStemmer'))
|
|
|
|
inputs.files(paicehuskJavaFile, paicehuskRulesFile)
|
|
outputs.file(paicehuskGeneratedStemmerFile)
|
|
|
|
doLast {
|
|
transformPaiceHuskSource(paicehuskJavaFile.get().asFile, paicehuskRulesFile.get().asFile, paicehuskGeneratedStemmerFile.get().asFile)
|
|
}
|
|
}
|
|
|
|
sourceSets {
|
|
jmh {
|
|
java {
|
|
srcDir(paicehuskGeneratedSourceDirectory)
|
|
}
|
|
}
|
|
}
|
|
|
|
tasks.named('compileJmhJava') {
|
|
dependsOn(tasks.named('generatePaiceHuskLancasterStemmer'))
|
|
}
|
|
|
|
eclipse {
|
|
classpath {
|
|
file {
|
|
whenMerged { classpath ->
|
|
String generatedPath = paicehuskGeneratedSourcePath.get()
|
|
|
|
classpath.entries.removeAll { entry ->
|
|
entry.hasProperty('path') && (
|
|
entry.path == generatedPath ||
|
|
paicehuskIsAbsolutePath(entry.path)
|
|
)
|
|
}
|
|
|
|
SourceFolder paicehuskEntry = new SourceFolder(generatedPath, null)
|
|
paicehuskEntry.output = 'bin/jmh'
|
|
paicehuskSourceEclipseClasspathAttributes.each { String name, String value ->
|
|
paicehuskEntry.entryAttributes[name] = value
|
|
}
|
|
classpath.entries.add(paicehuskEntry)
|
|
}
|
|
}
|
|
}
|
|
}
|