Coder Social home page Coder Social logo

ajalt / clikt Goto Github PK

View Code? Open in Web Editor NEW
2.4K 16.0 121.0 20.47 MB

Multiplatform command line interface parsing for Kotlin

Home Page: https://ajalt.github.io/clikt/

License: Apache License 2.0

Kotlin 99.55% Shell 0.33% Batchfile 0.12%
kotlin kotlin-library command-line command-line-parser option-parser argument-parser argument-parsing cli

clikt's People

Contributors

0xflotus avatar ajalt avatar andreihh avatar asemy avatar ashokgelal avatar benjamin-bader avatar bradynpoulsen avatar cketti avatar deining avatar gabrielfeo avatar goooler avatar hick209 avatar lipen avatar mataha avatar qw3ry avatar rockwotj avatar russellbanks avatar saem avatar sebastianaigner avatar sebokopter avatar sschuberth avatar stellingsimon avatar takashimatsuda avatar timmc avatar tristanlins avatar twisterrob avatar twyatt avatar virtlink avatar wolpl avatar xcq1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

clikt's Issues

Upload to maven central

Thanks for this nice library. I would be great if we can make this available on maven central as this is the default repo (or mirror) for most enterprises. May be you can enable the jcenter feature, which allow us to sync to central automatically.

subcommand does not create context when helpOptionNames is empty

When command's helpOptionNames is empty, the subcommand will not create context.

    private fun createContext(parent: Context? = null) {
        _context = Context.build(this, parent, _contextConfig)

        if (context.helpOptionNames.isEmpty()) return  // RETURN !!!
        val names = context.helpOptionNames - registeredOptionNames()
        if (names.isNotEmpty()) _options += helpOption(names, context.helpOptionMessage)

        for (command in _subcommands) {  // Create context
            command.createContext(context)
        }
    }

Creating subcommands does not work

Hi!

I'm trying to get your code example working but it fails with the following error:

src/main/kotlin/de/partyschaum/giftcard/domain/giftcard/client/clikt/GitftCard.kt: (22, 10): Expression 'subcommands' of type 'List<CliktCommand>' cannot be invoked as a function. The function 'invoke()' is not found
src/main/kotlin/de/partyschaum/giftcard/domain/giftcard/client/clikt/GitftCard.kt: (22, 10): Cannot access 'subcommands': it is invisible (private in a supertype) in 'Database'

Since I'm somewhat new to Kotlin it could be a problem on my side. Anyway, I'm stuck. In case you need more context you'll find the example code here.

Not the centre of the application

my use case for this is to NOT have CliktCommand wrap my whole application. (i.e. the main)

I want it for parsing and retrieving cl argumnets, but I don't want to inherit from it.

i.e. I want to simply have a clparser property at the top level somewhere, and use it for parsing the arguments. and then use it again for retrieving the arguments.

This is mostly possible using your 'NoRunCliktCommand' (a better name would be nice)

but there is no way I can see, from the docs, to retrieve a cl argument/option value from a NoRunCliktCommand object?

They are stored in the _options property...but I can't access it.
can we have a method in the API for doing this please.

e.g. findOption(name:String) : Option

Request for new release

I am pulling 1.5.0 from jcenter, however the fix I see in the source code to rename subcommands to _subcommands to avoid the namng conflict for internal variables is not available in the current release, making the subcommands mechanism unusable as far as i can tell. Would you be able to make a new release? Thanks.

Print default value in usage

I think the default value for options would be a very useful part of the help output, but I've not found a way to achieve this. Any trick I'm missing, or is it just not possible?

Dependencies between options?

Is there a way to make one Option dependent upon another Option?

Example: If a user specifies Option --action update, then --id Option is required.

In addition to being dependent, the Option might also have different choices and required status.

Support for nesting similar to awscli or git

Hey There,

Love the overall semantics of this library!

One thing that I find myself struggling with is the nesting of commands as described by the documentations

myapp super arg1 sub arg2

# Example: let 'fluffy' be the argument denoting the resource I am trying to create
# pets is a super command, with subcommands: create/delete
# i.e. this is how we are forced to write the input
myapp pets fluffy create

# this is the desired state of how it intuitively works
myapp pets create fluffy

# real life example:
git remote add URL
# not
git remote URL add

# another real life example
aws ec2 launch-instance myinstance
# not
aws ec2 myinstance launch instance

Argument based on Option

Is it possible to provide/capture an argument based on the value of a toggle.

e.g.
java -jar inventory.jar scrape --source remotehttps

java -jar inventory.jar scrape --source fakefromfilesysem /home/me/thewholeweb/

scrape is the command. source is an option. when source is fakefromfilesystem capture a path argument?

stderr instead of stdout in some cases

I would consider printing messages into stderr in some cases. Namely by exceptions in CliktCommand.main():

  • PrintHelpMessage => stdout
  • PrintMessage => stdout
  • UsageError => stderr
  • CliktError => stderr
  • Abort => stderr

For example GNU command ls also prints to stderr when an invalid option is given.

I always thought stdout should be used for interesting command output (data) and stderr for messages (errors, logs).

Options --help and --version are correct to print to stdout, because that's the currently requested command behavior. But if we pass an invalid option, the error message and the following usage help should be printed in stderr in my optinion.

How to use command like './hello' ?

I create an IDEA gradle project and write sample code like the README shows, but when I run command ./hello at root of project, it's not work and I got this error:

Java/WorkSpace/CliktDemo 
➜ ./src/main/kotlin/Hello.kt --count=3
./src/main/kotlin/Hello.kt: line 1: import: command not found
...

then I clone the project and build it, it's work only when I run command ./runsample copy --help, not like the README says ./hello --help, did i miss something?

How to nest with dynamic subcommands

I'm trying to create a fairly complex CLI app and like the approach of the Dynamic Subcommand Example, but I'm not able to figure how how to properly have subcommands of my modules.

For my main file:

class Sample : CliktCommand(
	help = """Sample Main App"""
	) {
	override fun run(){
	}
}

@JvmStatic
fun main(args: Array<String>) {
    val kodein = Kodein {
        bind() from setBinding<CliktCommand>()
        import(containersModule)
    }

    val commands: Set<CliktCommand> by kodein.instance()

    Sample().subcommands(commands).main(args)
}

In the containers:

class Containers : CliktCommand(
    help = """Container Operations"""
) {
    override fun run() {
    }
}

class List : CliktCommand() {
    override fun run() {
        echo("Hi")
    }
}

val containersModule = Kodein.Module("containers") {
    bind<CliktCommand>().inSet() with provider {
        Containers().subcommands(List())
    }
}

I'd like to have the main app, ./sample have submodules and those submodules have commands such as:

./sample containers list

The above code samples has an Unresolved reference: subcommands for Containers().subcommands(List()). What is the proper way to have an imported module have subcommands?

Required multiple arguments doesn't work

Say I have an argument as follows:

private val urls: List<String> by argument("urls", help="Some list of URLs.").multiple(true)

No exception is thrown when the argument is not provided in the CLI. I believe an exception should definitely be thrown in this case. Is there something I'm missing or is this a bug?

Thanks :)

Support for REPL

Is there a support for REPL? If so, is there an example for the same??

Documentation for RawOption.file seems wrong

Documentation says:

 * @param writable If false, fail of the given path is not writable
 * @param readable If false, fail of the given path is not readable

but the code it runs is

if (writable && !it.canWrite()) fail("$name \"$it\" is not writable.")
if (readable && !it.canRead()) fail("$name \"$it\" is not readable.")

Add option/argument converters for java.nio.Path

java.nio.Path supplants java.io.File in JDK 8+; it would be quite useful to be able to have options of this type, e.g. with a path extension to RawArgument/RawOption. This would be presumably identical to the .file(...) API:

/**
 * Convert the option to a [Path].
 *
 * @param exists If true, fail if the given path does not exist
 * @param fileOkay If false, fail if the given path is a file
 * @param folderOkay If false, fail if the given path is not a directory
 * @param writable If true, fail if the given path is not writable
 * @param readable If true, fail if the given path is not readable
 * @param fileSystem If specified, the [FileSystem] with which to resolve paths.
 */
fun RawOption.path(
    exists: Boolean = false,
    fileOkay: Boolean = true,
    folderOkay: Boolean = true,
    writable: Boolean = false,
    readable: Boolean = false,
    filesystem: FileSystems.getDefault()): NullableOption<Path, Path>

The only real difference here is the addition of a FileSystem param, which can be safely defaulted 99% of the time.

I'm using something like this internally at present; happy to open a PR if there are no objections to the API.

Support for interchangeable I/O environments

I think it would be great if Clikt could support different I/O environments, not just the standard I/O provided by the System class. This would make it much more flexible, as it could use be used within other applications that provide its own CLI.

Support manual paragraph breaks in help output.

Not an issue, rather a question:

Example

CliktCommand(help = "Sentence1.\nSentence2.")

Will generate help text without the newline characters. I have tried \n and \r. Am I asking for the impossible (im not familiar with cli low lvl impl) or am I doing something wrong?

I am trying this with gitbash on Windows.

Cannot provide default for multi-argument property

default() doesn't work after applying multiple() and multiple() doesn't work after applying default().

I have a list of things that the user can provide, but if none are provided I want to default the list to be something non-empty.

installDist to create script with Clikt

I was reading all the documentation and saw the following:

An easier way to do development is to used the installDist task provided by the plugin. This builds all the distribution scripts in your build folder, which you can then execute normally. See Clikt’s runsample script for an example of this approach.

I saw the "run sample script" which is calling to installDist but there have not nothing documentation about this into the readme. Where could I read something about this?

Regards

NonInteractiveCliktConsole only reads in the first line from an input file

Currently the NonInteractiveCliktConsole only reads in the first line of any input file passed as the input stream.

This can be fixed by caching the buffered reader like I have below.

class NonInteractiveCliktConsole : CliktConsole {
    private val bufferedReader by lazy {
        System.`in`.bufferedReader()
    }

    override fun promptForLine(prompt: String, hideInput: Boolean) = try {
        print(prompt, false)
        bufferedReader.readLine()
    } catch (err: IOException) {
        null
    }

    override fun print(text: String, error: Boolean) {
        if (error) {
            System.err
        } else {
            System.out
        }.print(text)
    }

    override val lineSeparator: String get() = System.lineSeparator()
}

I'm using version 1.5.0.

Make 'prompt' option non eager

Hello,

I would like to let the user of the command line decide if he enters the password via the keyboard or if he specifies it via an environment variable.

My program looks like

class PromptDemo : CliktCommand(name="prompt") {
    private val pwdViaKeyboard by option().prompt(
            text = "Please enter your password",
            default = null
    )

    private val pwdViaEnv by option()

    val pwd : String
        get() {
            if(pwdViaKeyBoard!=null) {
                return pwdViaKeyBoard
            }
            else if (pwdViaEnv!=null) {
                val pwd = System.getenv(pwdViaKeyBoard)
                if(pwd!=null) return pwd
            }

            throw IllegalArgumentException("You have to specify a password.")
        }

    override fun run() {
        println("pwd: '$pwd'")
    }
}

fun main(args: Array<String>) {
    PromptDemo().main(args)
}

My expectation would be that, when I enter
prompt --pwd-via-env PWD
and have set the env variable PWD to foo, that I would get
pwd: 'foo'

But I get
Please enter your password:.

My expectation would be that only when I specify the option --pwd-via-keyboard I would get the password prompt.

Could you add an additional parameter in the prompt() option which lets me evaluate the option, only when the user has required it (via specifying this option)?

Best regards,
Dieter

Customizing exit codes

Thanks for writing this library. I was wondering if you have / would consider making it possible to test error handling and custom return codes?

The idea is when implementing a CliktComand or including it into another library / framework for their users would want to do the following:

  • Provide a facility for custom exit codes, making it easier for automation down the road to use that to make decisions, for instance some errors might be worth retrying
  • Test that error messages and codes are being generated correctly, this is mostly checking exception logic

Challenges & Possible Solutions

Challenges I've encountered so far and some thoughts towards a solution, but those solutions themselves have accompanying issues:

  • main functions in CliktCommand are final making it hard
  • main(List), parse, and run do not return numbers so exit codes can't be seamlessly passed through
  • CliktError, Abort, and friends don't accept return codes -- these should probably be optional parameters (defaulted to current codes)
  • main(List) calls exitProcess making the logic not testable indirectly (less of a concern for library consumers) but going down a path of an extensible and testable strategy it might be worth returning the exit code to main(Array) and it having a single exitProcess:
fun main(argv: List<String>): Int { /* snip */ }

fun main(argv: Array<String>) = exitProcess(main(argv.asList()))

I can completely understanding being hesitant about adding return parameters to these functions as they're the entry point everyone uses, but the breakage should be very easy to fix. I can create a speculative pull request if you want to see what a possible set of changes might look like and we can see what options there might be.

What I've Tried

Below is an example where I've done it from as a consumer of the library, this is within the broader context of me creating a tiny web framework mimicking Dropwizard's single fat jar which allows you to run migrations, start an application server, add custom sub-commands, etc...

import com.github.ajalt.clikt.core.CliktCommand
import kotlin.system.exitProcess

abstract class Command (
        help: String = "",
        epilog: String = "",
        name: String? = null,
        invokeWithoutSubcommand: Boolean = false
    ): CliktCommand(
        help = help,
        epilog = epilog,
        name = name,
        invokeWithoutSubcommand = invokeWithoutSubcommand) {

    companion object {
        const val SUCCESS = 0
        const val COMMAND_PARSING_ERROR = 1 // used by Clikt
        const val ERROR_WHILE_COMMAND_RUNNING = 2
    }

    /**
     * Implement [doRun] and don't use [main]
     */
    final override fun run() {
        val exitCode = try {
            doRun()
        } catch (e: Exception) {
            exceptionHandler(e)
        }

        exitProcess(exitCode)
    }
    
    abstract fun doRun(): Int
    
    open fun exceptionHandler(e: Exception) = ERROR_WHILE_COMMAND_RUNNING
}

Create a option with not required

How can I build a option not required?
Every option will ask user to input even it has default value.
I wanna use default value when user do not wanna input this option.
thanks

How to finish the build ?

Hi,
I'm not able to find a good explaination on how to build the final command line tool.

I'm aware that we need basically a wrapper around our finished Java 'Application' to call it from the command line.

  1. I don't know how to build that finished Java Package ( Basically I don't know how to bring it so far to even use java -jar ...). How is that accomplished ?
  2. Are there prebuild wrapper or caller to just use it like a regular windows command line tool ?

The Docs are not really clear for a beginner like me.
Regards !

Implement options that generate auto completions for popular shells

Popular shells support programmable auto completions:

Clikt could provide options - much like the --version and --help options - that would output the commands that specify auto completion for a given shell.

Example:

my-program --generate-auto-completion=bash > /usr/local/etc/bash_completion

If the value of this option (bash in this example) is omitted, the shell is determined from the value of the SHELL env var.

Print help message if no parameters present

It would be nice if there would be an option that prints the help message, if no parameters are present.

At least I did not find any easy way to check for no parameters?

My request is similar to the sub commands behavior (if non given the help message is printed), but I also want it if no parameter is provided for a sub command, like
"./tool subcommand" -> should print help message

Clikt doesn't print the correct help upon subcommand parse failure

If I make a subcommand (e.g. sub) with a required argument, and then do ./tool sub, it prints the following:

Usage: tool [OPTIONS] COMMAND [ARGS]...

Error: Missing argument "ARGUMENT".

The usage printed is for the main command, but the error concerns the subcommand. It's not immediately clear that the argument missing actually belongs to the subcommand, unless you do ./tool sub -h:

Usage: sub [OPTIONS] ARGUMENT

<help omitted>

Options:
  -h, --help  Show this message and exit

I think this should be changed to it's clear where the argument is coming from.

`print` and `println` instead of `echo` on CliktCommand

After having built some CLI's lately using the library, I'm wondering if it would be beneficial to just expose print and println methods to mimic printing to the screen directly with System.out or System.err but in scope with the console's Context instead

Example proposed methods:

protected fun println() = echo("")
protected fun println(message: String) = echo(message)
protected fun println(message: Any?) = echo(message?.toString())

protected fun print(message: String) = echo(message, trailingNewLine = false)
protected fun print(message: Any?) = echo(message?.toString(), trailingNewLine = false)

We could also consider just exposing a out and err PrintStream on the CliktCommand type

class CliktCommand(...) {
    protected val out: PrintStream by lazyPrintStream { echo(it, trailingNewLine = false) }
    protected val err: PrintStream by lazyPrintStream { echo(it, trailingNewLine = false, err = true) }

    ...

    private inline fun lazyPrintStream(output: (String) -> Unit): Lazy<PrintStream> = lazy(LazyThreadSafetyMode.NONE) {
        PrintStream(object : OutputStream() {
            override fun write(b: Int) {
                output(b.toByte().toChar().toString())
            }
        })
    }
}

at which point we could just alias the recommended methods above to go to out by default

protected fun println() = out.println()
protected fun println(message: String) = out.println(message)
protected fun println(message: Any?) = out.println(message?.toString())

protected fun print(message: String) = out.print(message)
protected fun print(message: Any?) = out.print(message?.toString())

Add a way to deprecate argument

Hello,

First, thanks a lot for this great tool!

In one of my CLI, I decided to change slightly the API and I want to deprecated some options.

It would be nice if this could be supported out of the box by Clikt.

class MyCommand : CliktCommand() {

  val oldFlag by option("--old-api").convert { it.toBoolean() }.deprecated("Use --new-api instead")
  val newFlag by option("--new-api").flag()

  override fun run() {
     if (oldFlag ?: newFlag) println("Hello world")
  }
}

Then if one run --old-api true, the program would not crash, but display a warning message:

WARNING: The option '--old-api' is deprecated: Use --new-api instead

Running --help could either not show the option at all, or explicitly state it is deprecated.

Eventually deprecatedcould take a severity argument (warning or error) where the "error" level would make the program crash with a nice and explicit error message in case the deprecated api has been used.

What do you think?

Help is truncated running from executable jar

There is a difference in behavior using CliKt from executable jar. In case of running it without required options error message doesn't contain full information.
Example:

class Cli : CliktCommand(help = """
    Run --help to show required options
""".trimIndent()) {
    val apiKey: String by option(help = "Mailgun Private API Key").required()
    val domain: String by option(help = "Sending domain").required()
    val fromUser: String by option(help = "User name in From email field").required()
    val fromEmail: String by option(help = "User email in From email field").required()
    val toEmail: String by option(help = "Concrete email or mailing list").required()
    val subject: String by option(help = "Subject of email").required()
    val htmlFile: String by option(help = "Name of bundled template").required()

    override fun run() = Unit
}

fun main(args: Array<String>) {
    Cli().main(args)
}

Running this from executable jar like this:

java -jar target/mailgun-sender-0.0.1-SNAPSHOT-jar-with-dependencies.jar

results in the following output:

→ java -jar target/mailgun-sender-0.0.1-SNAPSHOT-jar-with-dependencies.jar                    
Usage: cli [OPTIONS]

Error: Missing option "--api-key".

But the following is expected:

Usage: cli [OPTIONS]

  Run --help to show required options

Options:
  --api-key TEXT     Mailgun Private API Key
  --domain TEXT      Sending domain
  --from-user TEXT   User name in From email field
  --from-email TEXT  User email in From email field
  --to-email TEXT    Concrete email or mailing list
  --subject TEXT     Subject of email
  --html-file TEXT   Name of bundled template
  -h, --help         Show this message and exit

Add option to override the Pattern used to split environment variables

I have a case where I need to add a "multiple" option via environment variable and some of these are going to contain spaces.

It looks like my only option at this point is to add my own hacky whitespace escape scheme. I'd prefer to just change the split character to a comma. Can you add the envvarSplit pattern parameter to the "option" function?

Feature request: Ability to reuse options (and option groups) across commands

It would be great if I could define options/arguments that I'll use in a lot of commands in just one place, and reuse them from multiple CliktCommand subclasses.


I have a number of subcommands that all require that the program be run in the context of a project directory, specified on the command line:

    val baseDir by option("--dir",
        help = "Path to your Spelunk directory (defaults to current directory)")
        .file(exists = true, readable = true, folderOkay = true, fileOkay = false)
        .default(Paths.get("").toFile())

I'd prefer not to have to copy that chunk of code to a bunch of different subcommand classes, and instead would like to have one instance of that delegate that I can reference from multiple places. (Or one thing that will manufacture it.)

I think the most straightforward way would be to have an option entry point function that isn't an extension method.CliktCommand.optionis an extension, so it can only be created in the context of a CliktCommand. Having a static method would bypass this issue.


Current workarounds:

  • Inheritance: An intermediate abstract class that implements CliktCommand and holds some delegated properties. This works when commands come in clusters, and will share in groups of fields.
  • Instantiate OptionWithValues directly, which is rather fragile and requires reimplementing a few lines from the library.
  • Silly hacks like creating an anonymous CliktCommand instance with properties holding (not using) the desired delegates, and referencing those delegates from elsewhere:
class CommonArgs {
    companion object {
        val baseDirDelegate = object : NoRunCliktCommand() {
            val opt = option("--dir",
                help = "Path to your Spelunk directory (defaults to current directory)")
                .file(exists = true, readable = true, folderOkay = true, fileOkay = false)
                .default(Paths.get("").toFile())
        }.opt
    }
}

// Use it elsewhere:
val baseDir: File by CommonArgs.baseDirDelegate

Add public CI and code coverage tracking

Hi! I really like this library and it would be really useful in a tool I develop (right now I use picocli but that's a bit cumbersome in Kotlin), but I'm a bit reluctant to adopt Clikt.

Right now, there is no public information regarding how well-tested is Clikt (I could go through the codebase and tests, but that's time consuming).

I would really appreciate if you could add at least some public continuous integration and code coverage tracking (Gradle with Jacoco and any of the free-for-open-source services like Codecov and Travis-CI would be fine). I would like to know that the library is reasonably tested and stable and that you intend to support it before committing to use it in my projects.

Let me know what are your plans with the library. Thanks!

Documentation on mocking for unit-test

Hello, I'm trying to write a unit-test for my class, but I cannot find any documentation on it. In particular, there are two questions I'm struggling with:

  1. How to provide a dummy test values (fixtures) for the options?
  2. How to instantiate the class inheriting from CliktCommand without running its run() method?

Example code:

import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.parameters.options.convert
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.options.required
import io.mockk.mockk
import org.junit.jupiter.api.Test
import java.time.LocalDate

class Foo : CliktCommand() {
    val day: LocalDate by option().convert { str -> LocalDate.parse(str) }.required()

    override fun run() {
        val service = connectToRealBillingService()
        doOtherStuff(service)
    }

    fun connectToRealBillingService(): BillingService {
        throw IllegalStateException("Shoudln't be called in tests")
    }

    fun doOtherStuff(service: BillingService): String {
        // Stuff to test
        return "$service with ${day.dayOfWeek}"
    }
}

internal class FooTest {
    @Test
    fun testDoStuff() {
        val unit = Foo()
        val actual = unit.doOtherStuff(mockk<BillingService>()) // NPE on day.dayOfWeek
    }

    @Test
    fun testDoStuff2() {
        val unit = Foo()
        unit.parse(listOf("--day=2019-01-01")) // Calls connectToRealBillingService()
        // and maybe calls other functions I don't want to test here (I'm testing doStuff(), not run())
    }
}

`file(exists = true)` does not fail if option is not specified

I'm unclear as to the intention of the exists flag. I expected that an unspecified file argument would not exist, and therefore would result in an option-reading failure; on the contrary, clikt seems happy to yield a null file in this case. Is that intentional? Why wouldn't an existence requirement imply a non-null requirement?

How do you store or return the cl-arguments

How do I return the command line arguments that are processed in the run() function. I built a map that contains all the arguments within the run functions but I am not able to return that to the main function.

Unidiomatic use of exceptions in public API

Hi, first of all I want to say that this is a great library with an elegant API, thank you for writing it.

One thing that I want to nitpick is the use of exceptions in the public API. Exceptions live outside of the Kotlin type system (especially because exceptions are unchecked in Kotlin) and I'm not sure that incorrect user input should necessarily be considered exceptional. A simple sealed class which simulates an Either type would be a good solution.

Examples of exception abuse:

I understand that there is more than one way to do things, so maybe you've chosen this design intentionally (in which case just ignore this ;) ), I'm just raising this issue in case you haven't really considered it. I'd also be happy to implement this in a PR.

Arguments should not be treated like options

PlaintextHelpFormatter prints message incorrectly

I used this library to make my cli program, but the help message printed incorrectly like this:

  -L, --lorem-ipsum                
                                   It is lorem ipsum text, just ignore it. I
                                   think it
                                   doesn't
                                   works
                                   correctly.

I expected help message like this:

  -L, --lorem-ipsum                
                                   It is lorem ipsum text, just ignore it. I
                                   think it doesn't works correctly.

So I traced that why the help message formats incorrectly. And I found the reason. If the length of local variable subsequentIndent of Extension method StringBuilder.appendDefinitionList (in PlaintextHelpFormatter.kt) is so long, The help message format broken. And I traced why. It's the problem of StringBuilder.wrapParagraph (in text.kt). It must resets the length of local variable currentWidth to 0, but it resets to subsequentIndent.length. So I changed the code. And it works.

Could you fix the code I pointed out? It would make this project more useful.

(Sorry for my bad english. Thank you for reading this article, which may be disrespectful or annoying.)

Argument values with '=' char in them

I am using this excellent library to pass JDBC connection info to my application. Unfortunately this leads to
the error "Error: no such option:" in the case when the JDBC URL contains an equals sign. How can I handle this case properly?
Here is an example of what happens:

λ java -jar database-consistency-checker-1.0.jar jdbc:test:host:port:schema/option1=value1
Usage: database-consistency-checker [OPTIONS] jdbcUrl dbUser dbSchema COMMAND
                                    [ARGS]...

Error: no such option: "jdbc:test:host:port:schema/option1".

Main method is not static in class

While using shadow I got the following error:

Task :runShadow FAILED
Error: Main method is not static in class com.github.ajalt.clikt.core.CliktCommand, please define the main method as:
   public static void main(String[] args)

My gradle config:

plugins {
    id 'org.jetbrains.kotlin.jvm' version '1.3.21'
    id 'org.jetbrains.dokka' version '0.9.18'
    id 'com.github.johnrengelman.shadow' version '5.0.0'
    id 'application'
}

repositories {
    jcenter()
    mavenCentral()
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
    implementation 'com.github.ajalt:clikt:1.7.0'
    compile "org.apache.spark:spark-core_2.12:2.4.0"
    compile "org.apache.spark:spark-graphx_2.12:2.4.0"
    compile 'org.apache.spark:spark-sql_2.12:2.4.1'
    compile 'ch.cern.sparkmeasure:spark-measure_2.11:0.13'
    testImplementation('org.junit.jupiter:junit-jupiter-api:5.4.2')
    testRuntime('org.junit.jupiter:junit-jupiter-engine:5.4.2')
}

dokka {
    outputFormat = 'javadoc'
    outputDirectory = "$buildDir/javadoc"
}

mainClassName = "com.company.project.module.Cli"

test {
    useJUnitPlatform()
}

shadowJar {
    zip64 true
}
version = "0.0.1"

Could you provide an sample integrating Shadow with Clikt?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.