add nextflow d30e48d

This commit is contained in:
2026-04-29 23:01:54 +02:00
parent d0b12d668d
commit 97cc9058d3
2840 changed files with 730250 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2013-2026, Seqera Labs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package nextflow
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import nextflow.plugin.BasePlugin
import org.pf4j.PluginWrapper
/**
* Nextflow cloud cache plugin
*
* @author Ben Sherman <bentshermann@gmail.com>
*/
@Slf4j
@CompileStatic
class CloudCachePlugin extends BasePlugin {
CloudCachePlugin(PluginWrapper wrapper) {
super(wrapper)
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2013-2026, Seqera Labs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package nextflow.cache
import groovy.transform.CompileStatic
import nextflow.config.spec.ConfigOption
import nextflow.config.spec.ConfigScope
import nextflow.config.spec.ScopeName
import nextflow.script.dsl.Description
/**
* Model cloud cache configuration
*
* @author Paolo Di Tommaso <paolo.ditommaso@gmail.com>
*/
@ScopeName("cloudcache")
@Description("""
The `cloudcache` scope controls the use of object storage as cache storage for workflow execution metadata.
""")
@CompileStatic
class CloudCacheConfig implements ConfigScope {
@ConfigOption
@Description("""
Enable the use of cloud cache (default: `false`).
""")
final boolean enabled
@ConfigOption
@Description("""
The path to the cloud storage bucket for cache metadata (e.g. `s3://bucket/cache`).
""")
final String path
/* required by extension point -- do not remove */
CloudCacheConfig() {}
CloudCacheConfig(Map opts) {
this.enabled = opts.enabled as boolean
this.path = opts.path as String
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2013-2026, Seqera Labs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package nextflow.cache
import java.nio.file.Path
import groovy.transform.CompileStatic
import nextflow.Global
import nextflow.Session
import nextflow.exception.AbortOperationException
import nextflow.plugin.Priority
/**
* Implements the cloud cache factory
*
* @see CloudCacheStore
*
* @author Ben Sherman <bentshermann@gmail.com>
*/
@CompileStatic
@Priority(-10)
class CloudCacheFactory extends CacheFactory {
@Override
protected CacheDB newInstance(UUID uniqueId, String runName, Path home) {
if( !uniqueId ) throw new AbortOperationException("Missing cache `uuid`")
if( !runName ) throw new AbortOperationException("Missing cache `runName`")
final path = (Global.session as Session).cloudCachePath
if( !path )
throw new IllegalArgumentException("Cloud-cache path not defined - use either -with-cloudcache run option or NXF_CLOUDCACHE_PATH environment variable")
final store = new CloudCacheStore(uniqueId, runName, path)
return new CacheDB(store)
}
}

View File

@@ -0,0 +1,160 @@
/*
* Copyright 2013-2026, Seqera Labs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package nextflow.cache
import java.nio.file.Files
import java.nio.file.NoSuchFileException
import java.nio.file.Path
import com.google.common.hash.HashCode
import groovy.transform.CompileStatic
import nextflow.exception.AbortOperationException
import nextflow.extension.FilesEx
import nextflow.util.CacheHelper
/**
* Implements the cloud cache store
*
* @author Ben Sherman <bentshermann@gmail.com>
*/
@CompileStatic
class CloudCacheStore implements CacheStore {
private final int KEY_SIZE
/** The session UUID */
private UUID uniqueId
/** The unique run name associated with this cache instance */
private String runName
/** The base path for the entire cache */
private Path basePath
/** The base path for this cache instance */
private Path dataPath
/** The path to the index file */
private Path indexPath
/** Index file input stream */
private InputStream indexReader
/** Index file output stream */
private OutputStream indexWriter
CloudCacheStore(UUID uniqueId, String runName, Path basePath) {
assert uniqueId, "Missing cloudcache 'uniqueId' argument"
assert runName, "Missing cloudcache 'runName' argument"
assert basePath, "Missing cloudcache 'basePath' argument"
this.KEY_SIZE = CacheHelper.hasher('x').hash().asBytes().size()
this.uniqueId = uniqueId
this.runName = runName
this.basePath = basePath
this.dataPath = this.basePath.resolve("$uniqueId")
this.indexPath = dataPath.resolve("index.$runName")
}
@Override
CloudCacheStore open() {
indexWriter = new BufferedOutputStream(Files.newOutputStream(indexPath))
return this
}
@Override
CloudCacheStore openForRead() {
if( !dataPath.exists() )
throw new AbortOperationException("Missing cache directory: $dataPath")
indexReader = Files.newInputStream(indexPath)
return this
}
@Override
void drop() {
dataPath.deleteDir()
}
@Override
void close() {
FilesEx.closeQuietly(indexWriter)
}
@Override
void writeIndex(HashCode key, boolean cached) {
indexWriter.write(key.asBytes())
indexWriter.write(cached ? 1 : 0)
}
@Override
void deleteIndex() {
indexPath.delete()
}
@Override
Iterator<Index> iterateIndex() {
return new Iterator<Index>() {
private Index next
{
next = fetch()
}
@Override
boolean hasNext() {
return next != null
}
@Override
Index next() {
final result = next
next = fetch()
return result
}
private Index fetch() {
byte[] key = new byte[KEY_SIZE]
if( indexReader.read(key) == -1 )
return null
final cached = indexReader.read() == 1
return new Index(HashCode.fromBytes(key), cached)
}
}
}
@Override
byte[] getEntry(HashCode key) {
try {
return getCachePath(key).bytes
}
catch( NoSuchFileException e ) {
return null
}
}
@Override
void putEntry(HashCode key, byte[] value) {
getCachePath(key).bytes = value
}
@Override
void deleteEntry(HashCode key) {
getCachePath(key).delete()
}
private Path getCachePath(HashCode key) {
dataPath.resolve(key.toString())
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2013-2026, Seqera Labs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package nextflow.cache
import spock.lang.Specification
/**
*
* @author Paolo Di Tommaso <paolo.ditommaso@gmail.com>
*/
class CloudCacheConfigTest extends Specification {
def 'should create empty config' () {
when:
def config = new CloudCacheConfig([:])
then:
!config.enabled
config.path == null
}
def 'should create config with all options' () {
when:
def config = new CloudCacheConfig([enabled: true, path: 's3://bucket/cache'])
then:
config.enabled
config.path == 's3://bucket/cache'
}
}