Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: Add package directive to process configuration
Extends process configuration to support the unified package directive:

- ProcessConfig: Adds 'package' to the list of valid directives
- TaskRun: Implements getPackageSpec() method with caching
- TaskBean: Adds packageSpec field for task execution

Also adds deprecation warnings when conda/pixi directives are used
with the preview.package feature enabled, encouraging migration to
the new unified syntax.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
Signed-off-by: Edmund Miller <[email protected]>
  • Loading branch information
edmundmiller and claude committed Sep 3, 2025
commit 1817f1fc84f273c0a8fdb3f23a4f995796e85048
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import groovy.transform.PackageScope
import nextflow.container.ContainerConfig
import nextflow.executor.BashWrapperBuilder
import nextflow.executor.TaskArrayExecutor
import nextflow.packages.PackageSpec
import nextflow.util.MemoryUnit
/**
* Serializable task value object. Holds configuration values required to
Expand Down Expand Up @@ -53,6 +54,8 @@ class TaskBean implements Serializable, Cloneable {

Path pixiEnv

PackageSpec packageSpec

List<String> moduleNames

Path workDir
Expand Down Expand Up @@ -141,6 +144,7 @@ class TaskBean implements Serializable, Cloneable {
this.useMicromamba = task.getCondaConfig()?.useMicromamba()
this.spackEnv = task.getSpackEnv()
this.pixiEnv = task.getPixiEnv()
this.packageSpec = task.getPackageSpec()
this.moduleNames = task.config.getModule()
this.shell = task.config.getShell() ?: BashWrapperBuilder.BASH
this.script = task.getScript()
Expand Down
42 changes: 42 additions & 0 deletions modules/nextflow/src/main/groovy/nextflow/processor/TaskRun.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ import nextflow.script.params.StdInParam
import nextflow.script.params.ValueOutParam
import nextflow.pixi.PixiCache
import nextflow.pixi.PixiConfig
import nextflow.packages.PackageManager
import nextflow.packages.PackageSpec
import nextflow.spack.SpackCache
/**
* Models a task instance
Expand Down Expand Up @@ -646,6 +648,11 @@ class TaskRun implements Cloneable {
if( !config.conda || !getCondaConfig().isEnabled() )
return null

// Show deprecation warning if new package system is enabled
if (PackageManager.isEnabled(processor.session)) {
log.warn "The 'conda' directive is deprecated when preview.package is enabled. Use 'package \"${config.conda}\", provider: \"conda\"' instead"
}

final cache = new CondaCache(getCondaConfig())
cache.getCachePathFor(config.conda as String)
}
Expand All @@ -665,6 +672,11 @@ class TaskRun implements Cloneable {
if( !config.pixi || !processor.session.getPixiConfig().isEnabled() )
return null

// Show deprecation warning if new package system is enabled
if (PackageManager.isEnabled(processor.session)) {
log.warn "The 'pixi' directive is deprecated when preview.package is enabled. Use 'package \"${config.pixi}\", provider: \"pixi\"' instead"
}

final cache = new PixiCache(processor.session.getPixiConfig())
cache.getCachePathFor(config.pixi as String)
}
Expand All @@ -690,6 +702,36 @@ class TaskRun implements Cloneable {
cache.getCachePathFor(config.spack as String, arch)
}

PackageSpec getPackageSpec() {
// note: use an explicit function instead of a closure or lambda syntax
cache0.computeIfAbsent('packageSpec', new Function<String,PackageSpec>() {
@Override
PackageSpec apply(String it) {
return getPackageSpec0()
}})
}

private PackageSpec getPackageSpec0() {
if (!PackageManager.isEnabled(processor.session))
return null

if (!config.package)
return null

def packageManager = new PackageManager(processor.session)

// Parse the package configuration
def packageDef = config.package
def defaultProvider = processor.session.config.navigate('packages.provider', 'conda') as String

try {
return PackageManager.parseSpec(packageDef, defaultProvider)
} catch (Exception e) {
log.warn "Failed to parse package specification: ${e.message}"
return null
}
}

protected ContainerInfo containerInfo() {
// note: use an explicit function instead of a closure or lambda syntax, otherwise
// when calling this method from a subclass it will result into a MissingMethodException
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class ProcessConfig implements Map<String,Object>, Cloneable {
'maxRetries',
'memory',
'module',
'package',
'penv',
'pixi',
'pod',
Expand Down