Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate wiki markup for updating curator documentation #1018

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 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
3 changes: 2 additions & 1 deletion .idea/runConfigurations/Gemma_CLI.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1,312 changes: 1,312 additions & 0 deletions gemma-cli-wiki.txt

Large diffs are not rendered by default.

49 changes: 24 additions & 25 deletions gemma-cli/src/main/java/ubic/gemma/core/apps/GemmaCLI.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public class GemmaCLI {
HELP_ALL_OPTION = "ha",
COMPLETION_OPTION = "c",
COMPLETION_SHELL_OPTION = "cs",
COMPLETION_WIKI_OPTION = "cw",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a single COMPLETION_SYNTAX_OPTION would be nicer for covering both shell and wiki?

VERSION_OPTION = "version",
LOGGER_OPTION = "logger",
VERBOSITY_OPTION = "v",
Expand Down Expand Up @@ -81,6 +82,7 @@ public static void main( String[] args ) {
.addOption( HELP_ALL_OPTION, "help-all", false, "Show complete help with all available CLI commands" )
.addOption( COMPLETION_OPTION, "completion", false, "Generate a completion script" )
.addOption( COMPLETION_SHELL_OPTION, "completion-shell", true, "Indicate which shell to generate completion for. Only fish and bash are supported" )
.addOption( COMPLETION_WIKI_OPTION, "completion-wiki", false, "Produce Wiki markup to update curator documentation" )
.addOption( VERSION_OPTION, "version", false, "Show Gemma version" )
.addOption( otherLogOpt )
.addOption( logOpt )
Expand Down Expand Up @@ -179,38 +181,35 @@ public static void main( String[] args ) {

if ( commandLine.hasOption( COMPLETION_OPTION ) ) {
CompletionGenerator completionGenerator;
String shellName;
if ( commandLine.hasOption( COMPLETION_SHELL_OPTION ) ) {
shellName = commandLine.getOptionValue( COMPLETION_SHELL_OPTION );
if ( commandLine.hasOption( COMPLETION_WIKI_OPTION ) ) {
completionGenerator = new WikiCompletionGenerator( options, commandGroups );
} else {
// attempt to guess the intended shell from $SHELL
String shell = System.getenv( "SHELL" );
if ( StringUtils.isNotBlank( shell ) ) {
shellName = Paths.get( System.getenv( "SHELL" ) ).getFileName().toString();
String shellName;
if ( commandLine.hasOption( COMPLETION_SHELL_OPTION ) ) {
shellName = commandLine.getOptionValue( COMPLETION_SHELL_OPTION );
} else {
System.err.println( "The $SHELL environment variable is not set, could not determine the shell to generate completion for." );
// attempt to guess the intended shell from $SHELL
String shell = System.getenv( "SHELL" );
if ( StringUtils.isNotBlank( shell ) ) {
shellName = Paths.get( System.getenv( "SHELL" ) ).getFileName().toString();
} else {
System.err.println( "The $SHELL environment variable is not set, could not determine the shell to generate completion for." );
System.exit( 1 );
return;
}
}
if ( shellName.equals( "bash" ) ) {
completionGenerator = new BashCompletionGenerator( options, commandGroups );
} else if ( shellName.equals( "fish" ) ) {
completionGenerator = new FishCompletionGenerator( options, commandGroups );
} else {
System.err.printf( "Completion is not support for %s.%n", shellName );
System.exit( 1 );
return;
}
}
if ( shellName.equals( "bash" ) ) {
completionGenerator = new BashCompletionGenerator( commandsByName.keySet() );
} else if ( shellName.equals( "fish" ) ) {
completionGenerator = new FishCompletionGenerator( commandsByName.keySet() );
} else {
System.err.printf( "Completion is not support for %s.%n", shellName );
System.exit( 1 );
return;
}
PrintWriter completionWriter = new PrintWriter( System.out );
completionGenerator.beforeCompletion( completionWriter );
completionGenerator.generateCompletion( options, completionWriter );
for ( SortedMap<String, CLI> group : commandGroups.values() ) {
for ( CLI cli : group.values() ) {
completionGenerator.generateSubcommandCompletion( cli.getCommandName(), cli.getOptions(), cli.getShortDesc(), cli.allowPositionalArguments(), completionWriter );
}
}
completionGenerator.afterCompletion( completionWriter );
completionGenerator.generateCompletion( completionWriter );
completionWriter.flush();
System.exit( 0 );
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package ubic.gemma.core.util;

import org.apache.commons.cli.Options;
import ubic.gemma.core.apps.GemmaCLI;

import javax.annotation.Nullable;
import java.io.PrintWriter;
import java.util.Map;
import java.util.SortedMap;

public abstract class AbstractCompletionGenerator implements CompletionGenerator {

protected final Options generalOptions;
private final SortedMap<GemmaCLI.CommandGroup, SortedMap<String, CLI>> commands;

protected AbstractCompletionGenerator( Options generalOptions, SortedMap<GemmaCLI.CommandGroup, SortedMap<String, CLI>> commands ) {
this.generalOptions = generalOptions;
this.commands = commands;
}

@Override
public void generateCompletion( PrintWriter completionWriter ) {
generateGeneralCompletion( generalOptions, completionWriter );
for ( Map.Entry<GemmaCLI.CommandGroup, SortedMap<String, CLI>> group : commands.entrySet() ) {
for ( CLI cli : group.getValue().values() ) {
generateSubcommandCompletion( cli.getCommandName(), cli.getOptions(), cli.getShortDesc(), cli.allowPositionalArguments(), completionWriter );
}
}
}

protected abstract void generateGeneralCompletion( Options options, PrintWriter writer );

protected abstract void generateSubcommandCompletion( String subcommand, Options subcommandOptions, @Nullable String subcommandDescription, boolean allowsPositionalArguments, PrintWriter writer );
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import ubic.gemma.core.apps.GemmaCLI;

import javax.annotation.Nullable;
import java.io.File;
import java.io.PrintWriter;
import java.util.*;
import java.util.stream.Collectors;

public class BashCompletionGenerator implements CompletionGenerator {
public class BashCompletionGenerator extends AbstractCompletionGenerator {

private static final String INDENT = " ";

Expand All @@ -23,22 +24,26 @@ public class BashCompletionGenerator implements CompletionGenerator {
*/
private String indent = "";

public BashCompletionGenerator( Set<String> subcommands ) {
this.subcommands = subcommands;
public BashCompletionGenerator( Options generalOptions, SortedMap<GemmaCLI.CommandGroup, SortedMap<String, CLI>> commands ) {
super( generalOptions, commands );
this.subcommands = commands.values().stream().map( Map::keySet ).flatMap( Collection::stream ).collect( Collectors.toSet() );
}

@Override
public void beforeCompletion( PrintWriter writer ) {
public void generateCompletion( PrintWriter writer ) {
writer.println( "function __gemma_cli_complete() {" );
pushIndent();
writer.append( indent ).println( "COMPREPLY=()" );
writer.append( indent ).println( "words=\"${COMP_WORDS[*]}\"" );
writer.append( indent ).println( "current_option=\"${COMP_WORDS[$COMP_CWORD-1]}\"" );

super.generateCompletion( writer );
popIndent();
writer.println( "}" );
writer.println( "complete -o filenames -o bashdefault -F __gemma_cli_complete gemma-cli" );
}

@Override
public void generateCompletion( Options options, PrintWriter writer ) {
protected void generateGeneralCompletion( Options options, PrintWriter writer ) {
writer.append( indent )
.printf( "if ! [[ \" $words \" =~ ' '(%s)' ' ]]; then%n",
subcommands.stream().map( String::trim ).map( this::quoteRegex ).collect( Collectors.joining( "|" ) ) );
Expand All @@ -50,7 +55,12 @@ public void generateCompletion( Options options, PrintWriter writer ) {
}

@Override
public void generateSubcommandCompletion( String subcommand, Options subcommandOptions, @Nullable String subcommandDescription, boolean allowsPositionalArguments, PrintWriter writer ) {
protected void generateCommandGroupSection( GemmaCLI.CommandGroup commandGroup, PrintWriter writer ) {

}

@Override
protected void generateSubcommandCompletion( String subcommand, Options subcommandOptions, @Nullable String subcommandDescription, boolean allowsPositionalArguments, PrintWriter writer ) {
writer.append( indent ).printf( "if [[ \" $words \" =~ %s ]]; then%n", quoteIfNecessary( " " + subcommand.trim() + " " ) );
pushIndent();
generateWordsFromOptions( subcommandOptions, writer );
Expand Down Expand Up @@ -126,13 +136,6 @@ private void popIndent() {
indent = indent.substring( 0, indent.length() - INDENT.length() );
}

@Override
public void afterCompletion( PrintWriter writer ) {
popIndent();
writer.println( "}" );
writer.println( "complete -o filenames -o bashdefault -F __gemma_cli_complete gemma-cli" );
}

private String quoteRegex( String s ) {
// FIXME: properly escape regex characters in command name
return s;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,8 @@
package ubic.gemma.core.util;

import org.apache.commons.cli.Options;

import javax.annotation.Nullable;
import java.io.IOException;
import java.io.PrintWriter;

public interface CompletionGenerator {

default void beforeCompletion( PrintWriter writer ) {
}

void generateCompletion( Options options, PrintWriter writer );

void generateSubcommandCompletion( String subcommand, Options subcommandOptions, @Nullable String subcommandDescription, boolean allowsPositionalArguments, PrintWriter writer );

default void afterCompletion( PrintWriter writer ) {

}
void generateCompletion( PrintWriter completionWriter );
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,30 @@
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.lang3.StringUtils;
import ubic.gemma.core.apps.GemmaCLI;

import java.io.File;
import java.io.PrintWriter;
import java.util.Set;
import java.util.Collection;
import java.util.Map;
import java.util.SortedMap;
import java.util.stream.Collectors;

/**
* Generates fish completion script.
* @author poirigui
*/
public class FishCompletionGenerator implements CompletionGenerator {
public class FishCompletionGenerator extends AbstractCompletionGenerator {

private final String allSubcommands;

public FishCompletionGenerator( Set<String> allSubcommands ) {
this.allSubcommands = allSubcommands.stream().filter( StringUtils::isNotBlank ).collect( Collectors.joining( " " ) );
public FishCompletionGenerator( Options generalOptions, SortedMap<GemmaCLI.CommandGroup, SortedMap<String, CLI>> commands ) {
super( generalOptions, commands );
this.allSubcommands = commands.values().stream().map( Map::keySet ).flatMap( Collection::stream ).filter( StringUtils::isNotBlank ).collect( Collectors.joining( " " ) );
}

@Override
public void generateCompletion( Options options, PrintWriter writer ) {
protected void generateGeneralCompletion( Options options, PrintWriter writer ) {
for ( Option o : options.getOptions() ) {
writer.printf( "complete -c gemma-cli -n %s %s%s%s%s%n",
// prevents global options from being suggested after a subcommand
Expand All @@ -35,7 +39,12 @@ public void generateCompletion( Options options, PrintWriter writer ) {
}

@Override
public void generateSubcommandCompletion( String subcommand, Options subcommandOptions, String subcommandDescription, boolean allowsPositionalArguments, PrintWriter writer ) {
protected void generateCommandGroupSection( GemmaCLI.CommandGroup commandGroup, PrintWriter writer ) {
// TODO: check if fish supports grouping commands
}

@Override
protected void generateSubcommandCompletion( String subcommand, Options subcommandOptions, String subcommandDescription, boolean allowsPositionalArguments, PrintWriter writer ) {
// -f prevents files from being suggested as subcommand
// FIXME: add -k, but the order has to be reversed
writer.printf( "complete -c gemma-cli -n %s -f -a %s%s%n",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package ubic.gemma.core.util;

import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.lang3.StringUtils;
import ubic.gemma.core.apps.GemmaCLI;

import javax.annotation.Nullable;
import java.io.PrintWriter;
import java.util.SortedMap;
import java.util.stream.Collectors;

/**
* Generator that produce Wiki markup to update user documentation at a glance.
* <p>
* This generator specifically produces <a href="https://confluence.atlassian.com/doc/confluence-wiki-markup-251003035.html">Confluence Wiki Markup</a>.
* @author poirigui
*/
public class WikiCompletionGenerator extends AbstractCompletionGenerator {

private final SortedMap<GemmaCLI.CommandGroup, SortedMap<String, CLI>> commands;

public WikiCompletionGenerator( Options generalOptions, SortedMap<GemmaCLI.CommandGroup, SortedMap<String, CLI>> commands ) {
super( generalOptions, commands );
this.commands = commands;
}

@Override
public void generateCompletion( PrintWriter writer ) {
for ( GemmaCLI.CommandGroup commandGroup : commands.keySet() ) {
writer.printf( "h2. %s%n", commandGroup.name() );
writer.println();
for ( CLI c : commands.get( commandGroup ).values() ) {
writer.printf( "[%s]%s%n", c.getCommandName(), StringUtils.isNotBlank( c.getShortDesc() ) ? " - " + c.getShortDesc() : "" );
}
writer.println();
}
super.generateCompletion( writer );
}

@Override
protected void generateGeneralCompletion( Options options, PrintWriter writer ) {
writer.printf( "h2. General Options%n" );
writer.println();
generateOptionTable( options, writer );
}

@Override
protected void generateSubcommandCompletion( String subcommand, Options subcommandOptions, @Nullable String subcommandDescription, boolean allowsPositionalArguments, PrintWriter writer ) {
writer.printf( "h2. %s%n", subcommand );
writer.println();
if ( StringUtils.isNotBlank( subcommandDescription ) ) {
writer.printf( "%s%n", subcommandDescription );
writer.println();
}
writer.printf( "{{Usage: gemma-cli %s %s%s}}%n", subcommand,
inlineSummaryOfOptions( subcommandOptions ),
allowsPositionalArguments ? " ARGS..." : "" );
writer.println();
generateOptionTable( subcommandOptions, writer );
}

private String inlineSummaryOfOptions( Options options ) {
return options.getOptions().stream()
.map( this::inlineSummaryOfOption )
.collect( Collectors.joining( " " ) );
}

private String inlineSummaryOfOption( Option option ) {
StringBuilder sb = new StringBuilder();
if ( !option.isRequired() ) {
sb.append( '[' );
}
sb.append( "-" ).append( option.getOpt() );
if ( option.getLongOpt() != null ) {
sb.append( ",--" ).append( option.getLongOpt() );
}
if ( option.hasArg() ) {
sb.append( "=" );
sb.append( option.getArgName() != null ? option.getArgName() : "ARG" );
}
if ( !option.isRequired() ) {
sb.append( ']' );
}
return sb.toString();
}

private void generateOptionTable( Options options, PrintWriter writer ) {
writer.println( "||Flags||Description||" );
for ( Option option : options.getOptions() ) {
writer.printf( "|{{%s%s}}|%s|%n", "-" + option.getOpt(),
option.getLongOpt() != null ? ",--" + option.getLongOpt() : "",
option.getDescription() );
}
writer.println();
}
}
Loading