diff --git a/CHANGELOG.md b/CHANGELOG.md index ba3357c9..6e3eb128 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # New ## Bug Fixes: +- Eliminated `Unrecognized config option` warnings under Nextflow's v2 syntax parser by registering `CO2FootprintConfig` as an extension point and aligning the nested file-config scopes with the v2 `ConfigScope` discovery rules ## Misc: diff --git a/build.gradle b/build.gradle index beee7a78..4f885e8e 100644 --- a/build.gradle +++ b/build.gradle @@ -107,7 +107,8 @@ nextflowPlugin { className = 'nextflow.co2footprint.CO2FootprintPlugin' extensionPoints = [ 'nextflow.co2footprint.CO2FootprintFactory', - 'nextflow.co2footprint.CO2FootprintExtension' + 'nextflow.co2footprint.CO2FootprintExtension', + 'nextflow.co2footprint.CO2FootprintConfig' ] } diff --git a/src/main/nextflow/co2footprint/CO2FootprintConfig.groovy b/src/main/nextflow/co2footprint/CO2FootprintConfig.groovy index d81d2777..a7160828 100644 --- a/src/main/nextflow/co2footprint/CO2FootprintConfig.groovy +++ b/src/main/nextflow/co2footprint/CO2FootprintConfig.groovy @@ -57,23 +57,19 @@ class CO2FootprintConfig implements ConfigScope { private final String timestamp = TraceHelper.launchTimestampFmt() private final String executor - @ConfigOption(types=[Map]) @Description('Configuration for the trace file.') final TraceFileConfig trace - @ConfigOption(types=[Map]) @Description('Configuration for the summary file.') final SummaryFileConfig summary - @ConfigOption(types=[Map]) @Description('Configuration for the report file.') final ReportFileConfig report - @ConfigOption(types=[Map]) @Description('Configuration for the provenance data/machine-readable file.') final ProvenanceFileConfig provenance - @ConfigOption(types=[GString]) + @ConfigOption @Description('Location GeoCode from Electricity maps.') final String location @@ -81,19 +77,19 @@ class CO2FootprintConfig implements ConfigScope { @Description('Location-based carbon intensity (CI).') final CiRecord ci - @ConfigOption(types=[Number]) + @ConfigOption @Description('Market-based carbon intensity (CI).') final BigDecimal ciMarket - @ConfigOption(types=[GString]) + @ConfigOption @Description('Electricity-maps API token.') final String emApiKey - @ConfigOption(types=[Number]) + @ConfigOption @Description('Power usage effectiveness (PUE) of the data centre.') BigDecimal pue - @ConfigOption(types=[Number]) + @ConfigOption @Description('Power draw of memory [W per GB].') final BigDecimal powerdrawMem @@ -101,15 +97,15 @@ class CO2FootprintConfig implements ConfigScope { @Description('Turns off pattern matching of CPU names.') final Boolean ignoreCpuModel - @ConfigOption(types=[Number]) + @ConfigOption @Description('Default powerdraw of the CPU.') final BigDecimal powerdrawCpuDefault - @ConfigOption(types=[String, GString]) + @ConfigOption @Description('Path to a custom CPU TDP file.') final Path customCpuTdpFile - @ConfigOption(types=[GString]) + @ConfigOption @Description('Type of computer on which the workflow is run [\'local\', \'compute cluster\', \'\'].') String machineType @@ -117,6 +113,12 @@ class CO2FootprintConfig implements ConfigScope { @Description('A power model function that takes the parameter `coreUsage`.') final Closure cpuPowerModel + /** + * No-arg constructor required by Nextflow's v2 config parser to + * discover and validate config options at parse time. + */ + CO2FootprintConfig() {} + /** * Loads configuration from a map and sets up defaults and fallbacks. * Also sets up CPU and CI data sources and assigns machine type and PUE. diff --git a/src/main/nextflow/co2footprint/Config/BaseFileConfig.groovy b/src/main/nextflow/co2footprint/Config/BaseFileConfig.groovy index 75dd1e6d..9828131b 100644 --- a/src/main/nextflow/co2footprint/Config/BaseFileConfig.groovy +++ b/src/main/nextflow/co2footprint/Config/BaseFileConfig.groovy @@ -2,9 +2,6 @@ package nextflow.co2footprint.Config import groovy.util.logging.Slf4j import nextflow.co2footprint.CO2FootprintConfig -import nextflow.config.spec.ConfigOption -import nextflow.script.dsl.Description - import java.nio.file.Path /** @@ -18,36 +15,51 @@ import java.nio.file.Path class BaseFileConfig { final String name final String ending - - @ConfigOption(types=[String, GString]) - @Description('Path to the file.') - final Path file - - @ConfigOption - @Description('Whether to enable the file creation.') - final Boolean enabled - - @ConfigOption - @Description('Whether to overwrite a file if it already exists.') - final Boolean overwrite + final boolean defaultEnabled protected final LinkedHashSet usedKeys = [] as LinkedHashSet + /** * Parses a file-based sub-configuration for nf-co2footprint and sets up defaults and fallbacks. * - * @param fileConfigMap User-provided configuration options - * @param timestamp Timestamp for generating default filenames * @param subConfigName Name of the configuration scope * @param fileEnding Output file extension (default: txt) - * @param defaultEnabled Whether to enable the file by default (default: true) */ - BaseFileConfig(Map fileConfigMap, String timestamp, String subConfigName, String fileEnding='txt', boolean defaultEnabled=true){ + BaseFileConfig(String subConfigName, String fileEnding, boolean defaultEnabled=true){ this.name = subConfigName this.ending = fileEnding ?: 'txt' + this.defaultEnabled = defaultEnabled + } - file = Path.of(CO2FootprintConfig.getCollect('file', fileConfigMap, usedKeys) as String ?: "co2footprint_${name}_${timestamp}.${ending}") - enabled = fileConfigMap.containsKey('enabled') ? CO2FootprintConfig.getCollect('enabled', fileConfigMap, usedKeys) : defaultEnabled - overwrite = fileConfigMap.containsKey('overwrite') ? CO2FootprintConfig.getCollect('overwrite', fileConfigMap, usedKeys) : true + /** + * Define a file path from the given config map and timestamp, as well as predefined variables. + * + * @param fileConfig The general config of this file. + * @param timestamp A timestamp string. + * @return The path to the file. + */ + protected Path defineFile(Map fileConfig, String timestamp) { + return Path.of(CO2FootprintConfig.getCollect('file', fileConfig, usedKeys) as String ?: "co2footprint_${name}_${timestamp}.${ending}") + } + + /** + * Define whether the construction of this file is enabled. + * + * @param fileConfig The general config of this file. + * @return Whether or not to write the file. + */ + protected boolean defineEnabled(Map fileConfig) { + return fileConfig.containsKey('enabled') ? CO2FootprintConfig.getCollect('enabled', fileConfig, usedKeys) : defaultEnabled + } + + /** + * Define whether an existing file should be overwritten. + * + * @param fileConfig The general config of this file. + * @return Whether or not to overwrite the file. + */ + protected boolean defineOverwrite(Map fileConfig) { + return fileConfig.containsKey('overwrite') ? CO2FootprintConfig.getCollect('overwrite', fileConfig, usedKeys) : true } } diff --git a/src/main/nextflow/co2footprint/Config/ProvenanceFileConfig.groovy b/src/main/nextflow/co2footprint/Config/ProvenanceFileConfig.groovy index 52a66773..fb04156d 100644 --- a/src/main/nextflow/co2footprint/Config/ProvenanceFileConfig.groovy +++ b/src/main/nextflow/co2footprint/Config/ProvenanceFileConfig.groovy @@ -3,19 +3,35 @@ package nextflow.co2footprint.Config import nextflow.co2footprint.CO2FootprintConfig import nextflow.config.spec.ConfigOption import nextflow.config.spec.ConfigScope -import nextflow.config.spec.ScopeName import nextflow.script.dsl.Description -@ScopeName('co2footprint.provenance') +import java.nio.file.Path + @Description('The `co2footprint.provenance` scope allows you to configure the data/machine-actionable file of the `nf-co2footprint` plugin.') class ProvenanceFileConfig extends BaseFileConfig implements ConfigScope { + @ConfigOption + @Description('Path to the file.') + final Path file + + @ConfigOption + @Description('Whether to enable the file creation.') + final Boolean enabled + + @ConfigOption + @Description('Whether to overwrite a file if it already exists.') + final Boolean overwrite + @ConfigOption @Description('Whether only emission metrics should be reported in the provenance file.') final boolean emissionMetricsOnly ProvenanceFileConfig(Map provenanceFileConfig, String timestamp=null) { - super(provenanceFileConfig, timestamp, 'provenance', 'json', false) + super('provenance', 'json', false) + + file = defineFile(provenanceFileConfig, timestamp) + enabled = defineEnabled(provenanceFileConfig) + overwrite = defineOverwrite(provenanceFileConfig) emissionMetricsOnly = provenanceFileConfig.containsKey('emissionMetricsOnly') ? CO2FootprintConfig.getCollect('emissionMetricsOnly', provenanceFileConfig, usedKeys) as boolean : diff --git a/src/main/nextflow/co2footprint/Config/ReportFileConfig.groovy b/src/main/nextflow/co2footprint/Config/ReportFileConfig.groovy index 4577e19e..292500c0 100644 --- a/src/main/nextflow/co2footprint/Config/ReportFileConfig.groovy +++ b/src/main/nextflow/co2footprint/Config/ReportFileConfig.groovy @@ -3,19 +3,36 @@ package nextflow.co2footprint.Config import nextflow.co2footprint.CO2FootprintConfig import nextflow.config.spec.ConfigOption import nextflow.config.spec.ConfigScope -import nextflow.config.spec.ScopeName import nextflow.script.dsl.Description -@ScopeName('co2footprint.report') +import java.nio.file.Path + @Description('The `co2footprint.report` scope allows you to configure the report file of the `nf-co2footprint` plugin.') -class ReportFileConfig extends BaseFileConfig implements ConfigScope{ +class ReportFileConfig extends BaseFileConfig implements ConfigScope { + + @ConfigOption + @Description('Path to the file.') + final Path file + + @ConfigOption + @Description('Whether to enable the file creation.') + final Boolean enabled + + @ConfigOption + @Description('Whether to overwrite a file if it already exists.') + final Boolean overwrite @ConfigOption @Description('The number of maximum tasks that is displayed in the report.') final Integer maxTasks ReportFileConfig(Map reportFileConfig, String timestamp=null) { - super(reportFileConfig, timestamp, 'report', 'html') + super('report', 'html') + + file = defineFile(reportFileConfig, timestamp) + enabled = defineEnabled(reportFileConfig) + overwrite = defineOverwrite(reportFileConfig) + maxTasks = reportFileConfig.containsKey('maxTasks') ? CO2FootprintConfig.getCollect('maxTasks', reportFileConfig, usedKeys) as Integer : 10_000 diff --git a/src/main/nextflow/co2footprint/Config/SummaryFileConfig.groovy b/src/main/nextflow/co2footprint/Config/SummaryFileConfig.groovy index 7ea6555c..0b79daab 100644 --- a/src/main/nextflow/co2footprint/Config/SummaryFileConfig.groovy +++ b/src/main/nextflow/co2footprint/Config/SummaryFileConfig.groovy @@ -1,15 +1,33 @@ package nextflow.co2footprint.Config import nextflow.co2footprint.CO2FootprintConfig +import nextflow.config.spec.ConfigOption import nextflow.config.spec.ConfigScope -import nextflow.config.spec.ScopeName import nextflow.script.dsl.Description -@ScopeName('co2footprint.summary') +import java.nio.file.Path + @Description('The `co2footprint.summary` scope allows you to configure the summary file of the `nf-co2footprint` plugin.') -class SummaryFileConfig extends BaseFileConfig implements ConfigScope{ +class SummaryFileConfig extends BaseFileConfig implements ConfigScope { + + @ConfigOption + @Description('Path to the file.') + final Path file + + @ConfigOption + @Description('Whether to enable the file creation.') + final Boolean enabled + + @ConfigOption + @Description('Whether to overwrite a file if it already exists.') + final Boolean overwrite + SummaryFileConfig(Map summaryFileConfig, String timestamp=null) { - super(summaryFileConfig, timestamp, 'summary', 'txt') + super('summary', 'txt') + + file = defineFile(summaryFileConfig, timestamp) + enabled = defineEnabled(summaryFileConfig) + overwrite = defineOverwrite(summaryFileConfig) CO2FootprintConfig.checkKeyUsage(summaryFileConfig, usedKeys) } diff --git a/src/main/nextflow/co2footprint/Config/TraceFileConfig.groovy b/src/main/nextflow/co2footprint/Config/TraceFileConfig.groovy index c9f37748..463cfdec 100644 --- a/src/main/nextflow/co2footprint/Config/TraceFileConfig.groovy +++ b/src/main/nextflow/co2footprint/Config/TraceFileConfig.groovy @@ -1,15 +1,33 @@ package nextflow.co2footprint.Config import nextflow.co2footprint.CO2FootprintConfig +import nextflow.config.spec.ConfigOption import nextflow.config.spec.ConfigScope -import nextflow.config.spec.ScopeName import nextflow.script.dsl.Description -@ScopeName('co2footprint.trace') +import java.nio.file.Path + @Description('The `co2footprint.trace` scope allows you to configure the trace file of the `nf-co2footprint` plugin.') -class TraceFileConfig extends BaseFileConfig implements ConfigScope{ +class TraceFileConfig extends BaseFileConfig implements ConfigScope { + + @ConfigOption + @Description('Path to the file.') + final Path file + + @ConfigOption + @Description('Whether to enable the file creation.') + final Boolean enabled + + @ConfigOption + @Description('Whether to overwrite a file if it already exists.') + final Boolean overwrite + TraceFileConfig(Map traceFileConfig, String timestamp=null) { - super(traceFileConfig, timestamp, 'trace', 'txt') + super('trace', 'txt') + + file = defineFile(traceFileConfig, timestamp) + enabled = defineEnabled(traceFileConfig) + overwrite = defineOverwrite(traceFileConfig) CO2FootprintConfig.checkKeyUsage(traceFileConfig, usedKeys) }