Skip to content

Commit

Permalink
Fix support for micromamba (#4302) [ci fast]
Browse files Browse the repository at this point in the history

Signed-off-by: Ben Sherman <[email protected]>
Signed-off-by: jorgee <[email protected]>
Signed-off-by: Paolo Di Tommaso <[email protected]>
Co-authored-by: Jorge Ejarque <[email protected]>
Co-authored-by: jorgee <[email protected]>
Co-authored-by: Paolo Di Tommaso <[email protected]>
  • Loading branch information
4 people authored Oct 26, 2024
1 parent 92e6977 commit 1243130
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,8 @@ class CondaCache {
def cmd
if( isYamlFilePath(condaEnv) ) {
final target = isYamlUriPath(condaEnv) ? condaEnv : Escape.path(makeAbsolute(condaEnv))
cmd = "${binaryName} env create --prefix ${Escape.path(prefixPath)} --file ${target}"
final yesOpt = binaryName == 'micromamba' ? '--yes ' : ''
cmd = "${binaryName} env create ${yesOpt}--prefix ${Escape.path(prefixPath)} --file ${target}"
}
else if( isTextFilePath(condaEnv) ) {
cmd = "${binaryName} create ${opts}--yes --quiet --prefix ${Escape.path(prefixPath)} --file ${Escape.path(makeAbsolute(condaEnv))}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -533,10 +533,13 @@ class BashWrapperBuilder {
private String getCondaActivateSnippet() {
if( !condaEnv )
return null
def result = "# conda environment\n"
result += 'source $(conda info --json | awk \'/conda_prefix/ { gsub(/"|,/, "", $2); print $2 }\')'
result += "/bin/activate ${Escape.path(condaEnv)}\n"
return result
final command = useMicromamba
? 'eval "$(micromamba shell hook --shell bash)" && micromamba activate'
: 'source $(conda info --json | awk \'/conda_prefix/ { gsub(/"|,/, "", $2); print $2 }\')/bin/activate'
return """\
# conda environment
${command} ${Escape.path(condaEnv)}
""".stripIndent()
}

private String getSpackActivateSnippet() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class TaskBean implements Serializable, Cloneable {

Path condaEnv

Boolean useMicromamba

Path spackEnv

List<String> moduleNames
Expand Down Expand Up @@ -131,6 +133,7 @@ class TaskBean implements Serializable, Cloneable {
this.environment = task.getEnvironment()

this.condaEnv = task.getCondaEnv()
this.useMicromamba = task.getCondaConfig()?.useMicromamba()
this.spackEnv = task.getSpackEnv()
this.moduleNames = task.config.getModule()
this.shell = task.config.getShell() ?: BashWrapperBuilder.BASH
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package nextflow.processor

import nextflow.conda.CondaConfig

import java.nio.file.FileSystems
import java.nio.file.NoSuchFileException
import java.nio.file.Path
Expand Down Expand Up @@ -967,5 +969,9 @@ class TaskRun implements Cloneable {
TaskBean toTaskBean() {
return new TaskBean(this)
}

CondaConfig getCondaConfig() {
return processor.session.getCondaConfig()
}
}

107 changes: 107 additions & 0 deletions modules/nextflow/src/test/groovy/nextflow/conda/CondaCacheTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,33 @@ class CondaCacheTest extends Specification {

}

def 'should create a conda environment - using micromamba' () {

given:
def ENV = 'bwa=1.1.1'
def PREFIX = Files.createTempDirectory('foo')
def cache = Spy(new CondaCache(useMicromamba: true))

when:
// the prefix directory exists ==> no mamba command is executed
def result = cache.createLocalCondaEnv(ENV)
then:
1 * cache.condaPrefixPath(ENV) >> PREFIX
0 * cache.isYamlFilePath(ENV)
0 * cache.runCommand(_)
result == PREFIX

when:
PREFIX.deleteDir()
result = cache.createLocalCondaEnv0(ENV, PREFIX)
then:
1 * cache.isYamlFilePath(ENV)
0 * cache.makeAbsolute(_)
1 * cache.runCommand("micromamba create --yes --quiet --prefix $PREFIX $ENV") >> null
result == PREFIX

}

def 'should create a conda environment using mamba and remote lock file' () {

given:
Expand All @@ -265,6 +292,32 @@ class CondaCacheTest extends Specification {
1 * cache.runCommand("mamba env create --prefix $PREFIX --file $ENV") >> null
result == PREFIX

}
def 'should create a conda environment using micromamba and remote lock file' () {

given:
def ENV = 'http://foo.com/some/file-lock.yml'
def PREFIX = Files.createTempDirectory('foo')
def cache = Spy(new CondaCache(useMicromamba: true))

when:
// the prefix directory exists ==> no mamba command is executed
def result = cache.createLocalCondaEnv(ENV)
then:
1 * cache.condaPrefixPath(ENV) >> PREFIX
0 * cache.isYamlFilePath(ENV)
0 * cache.runCommand(_)
result == PREFIX

when:
PREFIX.deleteDir()
result = cache.createLocalCondaEnv0(ENV, PREFIX)
then:
1 * cache.isYamlFilePath(ENV)
0 * cache.makeAbsolute(_)
1 * cache.runCommand("micromamba env create --yes --prefix $PREFIX --file $ENV") >> null
result == PREFIX

}

def 'should create conda env with options' () {
Expand Down Expand Up @@ -301,6 +354,23 @@ class CondaCacheTest extends Specification {
result == PREFIX
}

def 'should create conda env with options - using micromamba' () {
given:
def ENV = 'bwa=1.1.1'
def PREFIX = Paths.get('/foo/bar')
and:
def cache = Spy(new CondaCache(useMicromamba: true, createOptions: '--this --that'))

when:
def result = cache.createLocalCondaEnv0(ENV, PREFIX)
then:
1 * cache.isYamlFilePath(ENV)
1 * cache.isTextFilePath(ENV)
0 * cache.makeAbsolute(_)
1 * cache.runCommand("micromamba create --this --that --yes --quiet --prefix $PREFIX $ENV") >> null
result == PREFIX
}

def 'should create conda env with channels' () {
given:
def ENV = 'bwa=1.1.1'
Expand Down Expand Up @@ -336,6 +406,24 @@ class CondaCacheTest extends Specification {

}

def 'should create a conda env with a yaml file - using micromamba' () {

given:
def ENV = 'foo.yml'
def PREFIX = Paths.get('/conda/envs/my-env')
def cache = Spy(new CondaCache(useMicromamba: true))

when:
def result = cache.createLocalCondaEnv0(ENV, PREFIX)
then:
1 * cache.isYamlFilePath(ENV)
0 * cache.isTextFilePath(ENV)
1 * cache.makeAbsolute(ENV) >> Paths.get('/usr/base').resolve(ENV)
1 * cache.runCommand( "micromamba env create --yes --prefix $PREFIX --file /usr/base/foo.yml" ) >> null
result == PREFIX

}

def 'should create a conda env with a text file' () {

given:
Expand All @@ -355,6 +443,25 @@ class CondaCacheTest extends Specification {

}

def 'should create a conda env with a text file - using micromamba' () {

given:
def ENV = 'foo.txt'
def PREFIX = Paths.get('/conda/envs/my-env')
and:
def cache = Spy(new CondaCache(useMicromamba: true, createOptions: '--this --that'))

when:
def result = cache.createLocalCondaEnv0(ENV, PREFIX)
then:
1 * cache.isYamlFilePath(ENV)
1 * cache.isTextFilePath(ENV)
1 * cache.makeAbsolute(ENV) >> Paths.get('/usr/base').resolve(ENV)
1 * cache.runCommand( "micromamba create --this --that --yes --quiet --prefix $PREFIX --file /usr/base/foo.txt" ) >> null
result == PREFIX

}

def 'should get options from the config' () {

when:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -781,7 +781,24 @@ class BashWrapperBuilderTest extends Specification {
# conda environment
source $(conda info --json | awk '/conda_prefix/ { gsub(/"|,/, "", $2); print $2 }')/bin/activate /some/conda/env/foo
'''.stripIndent()
}

def 'should create micromamba activate snippet' () {

when:
def binding = newBashWrapperBuilder().makeBinding()
then:
binding.conda_activate == null
binding.containsKey('conda_activate')

when:
def CONDA = Paths.get('/some/conda/env/foo')
binding = newBashWrapperBuilder([condaEnv: CONDA, 'useMicromamba': true]).makeBinding()
then:
binding.conda_activate == '''\
# conda environment
eval "$(micromamba shell hook --shell bash)" && micromamba activate /some/conda/env/foo
'''.stripIndent()
}

def 'should create spack activate snippet' () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package nextflow.processor
import java.nio.file.Paths

import nextflow.Session
import nextflow.conda.CondaConfig
import nextflow.container.ContainerConfig
import nextflow.executor.Executor
import nextflow.script.ProcessConfig
Expand Down Expand Up @@ -69,6 +70,7 @@ class TaskBeanTest extends Specification {
task.getEnvironment() >> [alpha: 'one', beta: 'xxx', gamma: 'yyy']
task.getContainer() >> 'busybox:latest'
task.getContainerConfig() >> [docker: true, registry: 'x']
task.getCondaConfig() >> new CondaConfig([useMicromamba:true], [:])

when:
def bean = new TaskBean(task)
Expand Down Expand Up @@ -99,6 +101,8 @@ class TaskBeanTest extends Specification {
bean.stageInMode == 'link'
bean.stageOutMode == 'rsync'

bean.useMicromamba == true

}

def 'should clone task bean' () {
Expand Down

0 comments on commit 1243130

Please sign in to comment.