Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
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
73 changes: 70 additions & 3 deletions modules/nextflow/src/main/groovy/nextflow/cli/CmdPlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import org.eclipse.jgit.api.Git
*/
@CompileStatic
@Parameters(commandDescription = "Execute plugin-specific commands")
class CmdPlugin extends CmdBase {
class CmdPlugin extends CmdBase implements UsageAware {

@Override
String getName() {
Expand All @@ -51,10 +51,77 @@ class CmdPlugin extends CmdBase {
@Parameter(names = ['-template'], description = 'Plugin template version to use', hidden = true)
String templateVersion = 'v0.3.0'

/**
* Print the command usage help
*/
@Override
void usage() {
usage(args)
}

/**
* Print the command usage help
*
* @param args The arguments as entered by the user
*/
@Override
void usage(List<String> args) {
List<String> result = []
if( !args ) {
generalUsage(result)
}
else {
switch( args[0] ) {
case 'install':
result << 'Install a plugin'
result << 'Usage: nextflow plugin install <pluginId,...>'
result << ''
break
case 'create':
result << 'Create a new plugin project from the official template'
result << 'Usage: nextflow plugin create [<plugin name> <provider name> [project path]]'
result << ''
result << 'When no arguments are provided, the command prompts interactively for the required values.'
result << ''
break
default:
if( args[0].contains(CMD_SEP) ) {
result << 'Execute a plugin-specific command'
result << 'Usage: nextflow plugin <plugin-name>:<command> [args]'
result << ''
result << 'See the documentation of the individual plugin for its available commands.'
result << ''
}
else {
// print the reason of the failure, then fall back to the general usage
result << "Unknown plugin sub-command: ${args[0]}".toString()
result << ''
generalUsage(result)
}
}
}
println result.join('\n').toString()
}

private void generalUsage(List<String> result) {
result << this.getClass().getAnnotation(Parameters).commandDescription()
result << 'Usage: nextflow plugin <sub-command> [options]'
result << ''
result << 'Commands:'
result << ' install <pluginId,...> Install a plugin'
result << ' create [<name> <provider> [dir]] Create a new plugin project from the template'
result << ' <plugin-name>:<command> [args] Execute a plugin-specific command'
result << ''
result << 'See the documentation of an individual plugin for its plugin-specific commands.'
result << ''
}

@Override
void run() {
if( !args )
throw new AbortOperationException("Missing plugin command - usage: nextflow plugin install <pluginId,..>")
if( !args ) {
Comment thread
ewels marked this conversation as resolved.
usage()
return
}
// setup plugins system
Plugins.init()
Runtime.addShutdownHook((it)-> Plugins.stop())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* 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.cli

import spock.lang.Specification
/**
*
* @author Paolo Di Tommaso <paolo.ditommaso@gmail.com>
*/
class CmdPluginUsageTest extends Specification {

private String capture(List<String> args) {
final cmd = new CmdPlugin(args: args)
final buffer = new ByteArrayOutputStream()
final origOut = System.out
System.setOut(new PrintStream(buffer))
try {
cmd.usage(args)
}
finally {
System.setOut(origOut)
}
return buffer.toString()
}

def 'should print the general usage when no args are given' () {
when:
def out = capture([])
then:
out.contains('Usage: nextflow plugin <sub-command> [options]')
out.contains('install <pluginId,...>')
out.contains('create [<name> <provider> [dir]]')
out.contains('<plugin-name>:<command> [args]')
}

def 'should print the install usage' () {
when:
def out = capture(['install'])
then:
out.contains('Usage: nextflow plugin install <pluginId,...>')
}

def 'should print the create usage' () {
when:
def out = capture(['create'])
then:
out.contains('Usage: nextflow plugin create [<plugin name> <provider name> [project path]]')
}

def 'should print the plugin-specific command usage for the colon form' () {
when:
def out = capture(['nf-hello:greet'])
then:
out.contains('Usage: nextflow plugin <plugin-name>:<command> [args]')
and: 'it does not abort claiming the command is unknown'
!out.contains('Unknown plugin sub-command')
}

def 'should print the failure reason followed by the general usage for an unknown sub-command' () {
when:
def out = capture(['instal'])
then:
out.contains('Unknown plugin sub-command: instal')
and: 'the reason is printed before the general usage'
out.indexOf('Unknown plugin sub-command: instal') < out.indexOf('Usage: nextflow plugin <sub-command> [options]')
}

}
Loading