Skip to content
This repository has been archived by the owner on Aug 10, 2021. It is now read-only.

New CLI tool #3085

Merged
merged 12 commits into from
Jul 22, 2019
Merged

New CLI tool #3085

merged 12 commits into from
Jul 22, 2019

Conversation

LepilkinaElena
Copy link
Contributor

Please, review style of usage new CLI tool that we discuss. Work in progress, I'll replace it and add to default libraries of K/N compiler, add more tests.
There is no all features we discussed https://jetbrains.quip.com/izMpAJIY2djt/CLI-design-meeting, but I amn't sure if we should cover most features in one moment.

But still your comments about approach of usage and design are appreciated.
I don't know if libraries require JavaDocs, I looked mostly in compiler, there is no JavaDocs.

?: error("Option $name is expected to be double number. $value is provided.\n$helpMessage") }
}

class Choice(val values: List<kotlin.String>) : ArgType<kotlin.String>(true) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't some characters be prohibited in values such as spaces and commas?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I amn't sure why we should provide such limitations, it can be any string value. What problems do you see?

Copy link
Member

@ilya-g ilya-g left a comment

Choose a reason for hiding this comment

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

In general, it would be easier to review, if you had a design document about this somewhere. Then some of the questions that arise during the review could be answered by that document. For example now it's unclear which features are not implemented yet and which are intentionally omitted.

My first impressions of this design are:

  • hard to correspond terms argument to positional arguments and option to named arguments.
  • different style of subcommand declaration: subcommand parsers inherit Subcommand, but root parser just instantiate ArgParser.
  • callback invocation style of subcommands (abstract fun execute) is dubious. What if I want to parse arguments, then find what is the invoked subcommand and switch based on its type?
  • it would be convenient if an argument with non-null default value could be obtained as non-nullable, e.g. val x: String by argument(ArgType.String, "x", defaultValue="y")
  • missing multivalue argument can default to an empty list
  • having to specify the full parameter name in combination with delegation of the same named property violates DRY principle
  • it might be more convenient to specify default argument value in the target type rather than in string form

@LepilkinaElena
Copy link
Contributor Author

LepilkinaElena commented Jun 23, 2019

now it's unclear which features are not implemented yet and which are intentionally omitted.

I just marked features in document from design meeting https://jetbrains.quip.com/izMpAJIY2djt/CLI-design-meeting. Should I create one more detailed document or add details to this one?

hard to correspond terms argument to positional arguments and option to named arguments

As far as I know argument/option are well-known terms in this area, that are used in most part of such libraries. Why their are hard? Arguments are also be named.

different style of subcommand declaration: subcommand parsers inherit Subcommand, but root parser just instantiate ArgParser

What design would you suggest? I looked at

val cli = CommandLineInterface("testNestedCommands", addHelp = false)

        val commons = cli.helpEntriesGroup("Common arguments:")
        commons.help()
        val commonFlag by commons.flagArgument("--common", "common flag for foo and bar")

        val fooCmd = CommandLineInterface("foo")
        val fooX by fooCmd.positionalArgument("X", "X argument for foo")
        val fooY by fooCmd.positionalArgument("Y", "Y argument for foo")

        val barCmd = CommandLineInterface("bar")
        val barX by barCmd.positionalArgument("X", "X argument for bar")
        val barFlag by barCmd.flagArgument("--flag", "flag argument for bar")

        cli.subcommands("COMMAND", "Available subcommands:",
                Subcommand(fooCmd, "foo subcommand", { foo(commonFlag, fooX, fooY) }),
                Subcommand(barCmd, "bar subcommand", { bar(commonFlag, barX, barFlag) })
        )

But I see here problems with setting common options for different subcommands, I should repeat them and it's hard to understand what is common part. Also when user have many options he gets functions with big number of parameters, that looks very bad.

callback invocation style of subcommands (abstract fun execute) is dubious. What if I want to parse arguments, then find what is the invoked subcommand and switch based on its type?

It's connected with previous point. But here I don't understand use case, switch is made by parser, all what you need you can do in action.

having to specify the full parameter name in combination with delegation of the same named property violates DRY principle

There are cases when name differs. I can add overload without name.

@LepilkinaElena
Copy link
Contributor Author

Document with design decisions https://jetbrains.quip.com/gXgYABJEbiwt/Kotlin-CLI-design

@LepilkinaElena LepilkinaElena requested review from olonho and ilya-g July 8, 2019 17:29

def commonSrc = new File("$projectDir/src/main")

targetList.each { target ->
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not use the MPP plugin to build the klib too?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After discussion decided to postpone because of crossDist targets.

build.gradle Outdated Show resolved Hide resolved
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$buildKotlinVersion"
compile "org.jetbrains.kotlin:kotlin-compiler:$buildKotlinVersion"
compile project(':Interop:Indexer')
compile "org.jetbrains.kotlin:kotlin-native-shared:$konanVersion"
compile files("$rootDir/defaultLibraries/kliopt/build/libs/kliopt-jvm.jar")
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not just project("defaultLibraries:kliopt")?

@LepilkinaElena LepilkinaElena changed the title WIP: New CLI tool New CLI tool Jul 15, 2019
@LepilkinaElena
Copy link
Contributor Author

There also some new things in https://jetbrains.quip.com/gXgYABJEbiwt/Kotlin-CLI-design

@ilmat192
Copy link
Contributor

Approve the Gradle-related part.

open class CommonInteropArguments(val argParser: ArgParser) {
val verbose by argParser.option(ArgType.Boolean, description = "Enable verbose logging output", defaultValue = false)
val flavor by argParser.option(ArgType.Choice(listOf("jvm", "native", "wasm")), description = "Interop target",
defaultValue = "jvm")
Copy link
Contributor

Choose a reason for hiding this comment

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

BTW, this shall be changed to native.

Copy link
Contributor Author

@LepilkinaElena LepilkinaElena Jul 16, 2019

Choose a reason for hiding this comment

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

As I understood here is jvm, because this flavor is default in NativeInteropPlugin which we actively use in compiler exactly for jvm.
Change this? May be in separate review?

@@ -89,12 +89,13 @@ SHARED_JAR="${KONAN_HOME}/konan/lib/shared.jar"
EXTRACTED_METADATA_JAR="${KONAN_HOME}/konan/lib/konan.metadata.jar"
EXTRACTED_SERIALIZER_JAR="${KONAN_HOME}/konan/lib/konan.serializer.jar"
KLIB_JAR="${KONAN_HOME}/konan/lib/klib.jar"
KLIOPT_JAR="${KONAN_HOME}/konan/lib/kliopt-jvm.jar"
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure if I like this approach. Can we avoid adding new JARs and repack to fewer JARs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We discussed with Ilya, we need to think about right repacking all jars, but for now it's only possible approach without big refactoring.

* annotating that usage with the [UseExperimental] annotation, e.g. `@UseExperimental(ExperimentalCli::class)`,
* or by using the compiler argument `-Xuse-experimental=org.jetbrains.kliopt.ExperimentalCli`.
*/
@Experimental(level = Experimental.Level.ERROR)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why so harsh?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Set another level? I made same wsy as is done for stdlib in example which @ilya-g sent.

Copy link
Member

Choose a reason for hiding this comment

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

Given that the library itself is not stable, I don't insist that the level should be error as it is in stdlib experimental annotations. Here we use it as a marker of a less designed part of API.

Copy link
Member

@ilya-g ilya-g left a comment

Choose a reason for hiding this comment

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

I don't mind merging it in Native as an internal tool, but further design review is required before promoting this tool in public.

* annotating that usage with the [UseExperimental] annotation, e.g. `@UseExperimental(ExperimentalCli::class)`,
* or by using the compiler argument `-Xuse-experimental=org.jetbrains.kliopt.ExperimentalCli`.
*/
@Experimental(level = Experimental.Level.ERROR)
Copy link
Member

Choose a reason for hiding this comment

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

Given that the library itself is not stable, I don't insist that the level should be error as it is in stdlib experimental annotations. Here we use it as a marker of a less designed part of API.

@LepilkinaElena
Copy link
Contributor Author

further design review is required before promoting this tool in public

@ilya-g I've already added in this review mechanism for endorsed libraries and add kliot as first.
Now this library is accessible from code on Kotlin/Native, so it isn't internal.

What should be next steps in design to get approval to merge this PR fully?

@LepilkinaElena LepilkinaElena merged commit 3c2a5b0 into master Jul 22, 2019
@LepilkinaElena LepilkinaElena deleted the arg_parser branch July 23, 2019 07:55
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants