Skip to content

Commit

Permalink
Add containerOptions map [ci fast]
Browse files Browse the repository at this point in the history
  • Loading branch information
pditommaso committed Dec 2, 2021
1 parent c664e63 commit 5e9c1cc
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,13 @@ class TaskConfig extends LazyMap implements Cloneable {

Map getContainerOptionsMap() {
def opts = get('containerOptions')
return opts instanceof Map ? opts : Collections.emptyMap()
if( opts instanceof Map )
return opts
if( opts instanceof CharSequence )
return CmdLineHelper.parseGnuArgs(opts.toString())
if( opts!=null )
throw new IllegalArgumentException("Invalid `containerOptions` directive value: $opts [${opts.getClass().getName()}]")
return Collections.emptyMap()
}

/**
Expand Down
66 changes: 61 additions & 5 deletions modules/nf-commons/src/main/nextflow/util/CmdLineHelper.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,29 @@
*/

package nextflow.util

import java.util.regex.Pattern

/**
*
* Implement command line parsing helpers
*
* @author Paolo Di Tommaso <paolo.ditommaso@gmail.com>
*/
class CmdLineHelper {

def List<String> args
static private Pattern CLI_OPT = ~/--(\w+)(?:\W.*)?$|-([a-zA-Z])(?:\W.*)?$/

private List<String> args

CmdLineHelper( String cmdLineToBeParsed ) {
args = splitter(cmdLineToBeParsed ?: '')
}

def boolean contains(String argument) {
private boolean contains(String argument) {
return args.indexOf(argument) != -1
}

def getArg( String argument ) {
private getArg( String argument ) {
def pos = args.indexOf(argument)
if( pos == -1 ) return null

Expand All @@ -55,7 +61,7 @@ class CmdLineHelper {
}
}

def asList( String argument, String splitter=',' ) {
private asList( String argument, String splitter=',' ) {
def val = getArg(argument)
if( !val ) return val

Expand Down Expand Up @@ -112,4 +118,54 @@ class CmdLineHelper {
return result.join(' ')
}

/**
* Parse command line and returns the options formatted using GNU tyle as a map object.
*
* @param cmdline
* The command line as single string
* @return
* A map object holding the option key-value pairs
*/
static Map<String,String> parseGnuArgs(String cmdline) {
final BLANK = ' ' as char
final EQUALS = '=' as char
final result = new LinkedHashMap<String,String>()

if( !cmdline )
return result

final tokenizer = new QuoteStringTokenizer(cmdline, BLANK, EQUALS);
String opt = null
String last = null
while( tokenizer.hasNext() ) {
final String token = tokenizer.next()
if( !token || token=='--')
continue
final matcher = CLI_OPT.matcher(token)
if( matcher.matches() ) {
if( opt ) {
result.put(opt, 'true')
}
opt = matcher.group(1) ?: matcher.group(2)
}
else {
if( !opt ) {
if( !last ) continue
// append the value to the previous option
def x = result[last] ? result[last] + ' ' + token : token
result[last] = x
}
else {
result[opt] = token
last = opt
opt = null
}
}
}

if( opt )
result[opt] = 'true'

return result
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ package nextflow.util
* @author Paolo Di Tommaso <paolo.ditommaso@gmail.com>
*
*/
public class QuoteStringTokenizer implements Iterator<String>, Iterable<String> {
class QuoteStringTokenizer implements Iterator<String>, Iterable<String> {

private List<Character> chars = Arrays.<Character>asList(' ' as Character);

Expand Down
66 changes: 66 additions & 0 deletions modules/nf-commons/src/test/nextflow/util/CmdLineHelperTest.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2020-2021, 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.util

import spock.lang.Specification
import spock.lang.Unroll

/**
*
* @author Paolo Di Tommaso <paolo.ditommaso@gmail.com>
*/
class CmdLineHelperTest extends Specification{

@Unroll
def 'should parse command line' () {
expect:
CmdLineHelper.splitter(SOURCE) == EXPECTED

where:
SOURCE | EXPECTED
"foo bar baz" | ['foo','bar','baz']
"foo 'this that'" | ['foo', 'this that']
}

@Unroll
def 'should parse args' () {
expect:
CmdLineHelper.parseGnuArgs(SOURCE) == EXPECTED

where:
SOURCE | EXPECTED
'a b c' | [:]
'a -b c' | [b:'c']
'a -b -1' | [b:'-1']
'-a b -1' | [a:'b -1']
"-a 'b -1'" | [a:'b -1']
"-a='b -1'" | [a:'b -1']
'-a "b c"' | [a:'b c']
'-a="b c"' | [a:'b c']
and:
'--foo 1' | [foo: '1']
'--foo 1 --bar 2' | [foo: '1', bar: '2']
'--foo 1 2 3 --bar 4' | [foo: '1 2 3', bar: '4']
'--foo 1 2 3 --bar' | [foo: '1 2 3', bar: 'true']
'--foo --bar' | [foo: 'true', bar: 'true']
and:
// single non-gnu is not capture
'--foo 1 -bar 2' | [foo: '1 -bar 2']
}

}

0 comments on commit 5e9c1cc

Please sign in to comment.