Skip to content

Commit 726bf48

Browse files
Warn when file() matches a collection of files (#5507)
--------- Signed-off-by: Ben Sherman <[email protected]> Co-authored-by: Chris Hakkaart <[email protected]>
1 parent 01e1888 commit 726bf48

File tree

3 files changed

+23
-15
lines changed

3 files changed

+23
-15
lines changed

docs/reference/stdlib-namespaces.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ The global namespace contains globally available constants and functions.
5656
:::
5757
: Stop the pipeline execution and return an exit code and optional error message.
5858

59-
`file( filePattern: String, [options] ) -> Path | List<Path>`
60-
: Get a file from a file name or glob pattern. Returns a collection of files if the glob pattern yields zero or multiple files.
59+
`file( filePattern: String, [options] ) -> Path`
60+
: Get a file from a file name or glob pattern.
6161

6262
: The following options are available:
6363

@@ -79,10 +79,13 @@ The global namespace contains globally available constants and functions.
7979
`type: String`
8080
: Type of paths returned, can be `'file'`, `'dir'` or `'any'` (default: `'file'`)
8181

82-
: See also: {ref}`channel.fromPath <channel-path>`.
82+
: :::{note}
83+
This function returns a collection if the glob pattern yields zero or multiple files. Use `files()` to get a collection of files.
84+
:::
8385

8486
`files( filePattern: String, [options] ) -> List<Path>`
8587
: Get a collection of files from a file name or glob pattern. Supports the same options as `file()`.
88+
: See also: {ref}`channel.fromPath <channel-path>`.
8689

8790
`groupKey( key, size: int ) -> GroupKey`
8891
: Create a grouping key to use with the {ref}`operator-grouptuple` operator.

modules/nextflow/src/main/groovy/nextflow/Nextflow.groovy

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,7 @@ class Nextflow {
6767
return SysEnv.get(name)
6868
}
6969

70-
static private fileNamePattern( FilePatternSplitter splitter, Map opts ) {
71-
70+
private static List<Path> fileNamePattern( FilePatternSplitter splitter, Map opts ) {
7271
final scheme = splitter.scheme
7372
final target = scheme ? "$scheme://$splitter.parent" : splitter.parent
7473
final folder = toCanonicalPath(target)
@@ -77,15 +76,14 @@ class Nextflow {
7776
if( opts == null ) opts = [:]
7877
if( !opts.type ) opts.type = 'file'
7978

80-
def result = new LinkedList()
79+
def result = new LinkedList<Path>()
8180
try {
8281
FileHelper.visitFiles(opts, folder, pattern) { Path it -> result.add(it) }
8382
}
8483
catch (NoSuchFileException e) {
8584
log.debug "No such file or directory: $folder -- Skipping visit"
8685
}
8786
return result
88-
8987
}
9088

9189
static private String str0(value) {
@@ -113,11 +111,16 @@ class Nextflow {
113111
* @param path A file path eventually including a glob pattern e.g. /some/path/file*.txt
114112
* @return An instance of {@link Path} when a single file is matched or a list of {@link Path}s
115113
*/
116-
static file( Map options = null, def filePattern ) {
117-
114+
static file(Map options = null, def filePattern) {
118115
if( !filePattern )
119-
throw new IllegalArgumentException("Argument of `file` function cannot be ${filePattern==null?'null':'empty'}")
116+
throw new IllegalArgumentException("Argument of `file()` function cannot be ${filePattern==null?'null':'empty'}")
117+
final result = file0(options, filePattern)
118+
if( result instanceof Collection && result.size() != 1 && NF.isSyntaxParserV2() )
119+
log.warn "The `file()` function was called with a glob pattern that matched a collection of files -- use `files()` instead."
120+
return result
121+
}
120122

123+
private static file0( Map options = null, def filePattern ) {
121124
final path = filePattern as Path
122125
final glob = options?.containsKey('glob') ? options.glob as boolean : isGlobAllowed(path)
123126
if( !glob ) {
@@ -140,9 +143,11 @@ class Nextflow {
140143
return result
141144
}
142145

143-
static files( Map options=null, def path ) {
144-
def result = file(options, path)
145-
return result instanceof List ? result : [result]
146+
static Collection<Path> files(Map options=null, def filePattern) {
147+
if( !filePattern )
148+
throw new IllegalArgumentException("Argument of `files()` function cannot be ${filePattern==null?'null':'empty'}")
149+
final result = file0(options, filePattern)
150+
return result instanceof Collection ? result : [result]
146151
}
147152

148153

modules/nextflow/src/test/groovy/nextflow/NextflowTest.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,13 @@ class NextflowTest extends Specification {
8585
Nextflow.file(null)
8686
then:
8787
e = thrown(IllegalArgumentException)
88-
e.message == 'Argument of `file` function cannot be null'
88+
e.message == 'Argument of `file()` function cannot be null'
8989

9090
when:
9191
Nextflow.file('')
9292
then:
9393
e = thrown(IllegalArgumentException)
94-
e.message == 'Argument of `file` function cannot be empty'
94+
e.message == 'Argument of `file()` function cannot be empty'
9595
}
9696

9797
def 'should return http path' () {

0 commit comments

Comments
 (0)