Skip to content

warning: argument -classpath is passed multiple times. Only the last value will be used #171

Closed

Description

@zlatkoc

I am trying to start the kscript in interactive mode with some dependencies and my local code. Dependencies are defined with gradle-style locators. I would like to reference my code in the classpath. Whatever I use (the classpath referencing local folder or library jar), I get the "warning: argument -classpath is passed multiple times. Only the last value will be used".

It seems to me that it is not possible to use //DEPS and //KOTLIN_OPTS at the same time. Is this a bug or a feature? I would definitely like to have //DEPS and additionally reference my local code with -classpath. I think kscript should merge these two into one -classpath sent to the kotlin executable.

My use case is to start interactive REPL for the kotlin spring library.

When I have following init.kts:

//DEPS org.springframework.boot:spring-boot-starter:2.0.4.RELEASE org.springframework.boot:spring-boot:2.0.4.RELEASE org.springframework:spring-core:5.0.8.RELEASE org.springframework:spring-aop:5.0.8.RELEASE org.springframework:spring-beans:5.0.8.RELEASE org.springframework:spring-beans:5.0.8.RELEASE org.springframework:spring-core:5.0.8.RELEASE org.springframework.boot:spring-boot-autoconfigure:2.0.4.RELEASE org.springframework.boot:spring-boot-starter-logging:2.0.4.RELEASE ch.qos.logback:logback-classic:1.2.3 ch.qos.logback:logback-core:1.2.3 org.apache.logging.log4j:log4j-to-slf4j:2.10.0 org.slf4j:slf4j-api:1.7.25 javax.annotation:javax.annotation-api:1.3.2 org.springframework:spring-core:5.0.8.RELEASE com.fasterxml.jackson.module:jackson-module-kotlin:2.9.6 com.fasterxml.jackson.core:jackson-databind:2.9.6 com.fasterxml.jackson.core:jackson-annotations:2.9.0 com.fasterxml.jackson.core:jackson-annotations:2.9.0 org.jetbrains.kotlin:kotlin-stdlib-common:1.2.70 org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.70 org.jetbrains.kotlin:kotlin-stdlib:1.2.70 org.jetbrains.kotlin:kotlin-reflect:1.2.70 org.slf4j:slf4j-api:1.7.25 ch.qos.logback:logback-classic:1.2.3 ch.qos.logback:logback-core:1.2.3 commons-io:commons-io:2.6 org.springframework:spring-web:5.1.0.RELEASE org.springframework:spring-beans:5.1.0.RELEASE com.madgag.spongycastle:core:1.51.0.0 com.google.protobuf:protobuf-java:2.6.1 com.google.guava:guava:18.0 com.google.code.findbugs:jsr305:2.0.1 net.jcip:jcip-annotations:1.0 com.lambdaworks:scrypt:1.4.0 org.bitcoinj:orchid:1.2.1 com.google.guava:guava:18.0 com.squareup.okhttp:okhttp:2.7.2
//KOTLIN_OPTS -cp build/libs/myproject.jar

And I try to start the kscript interactive REPL I get following warning:

$ kscript --interactive init.kts
[kscript] Creating REPL from init.kts
warning: argument -classpath is passed multiple times. Only the last value will be used: /Users/zlatkoc/.m2/repository/org/springframework/boot/spring-boot-starter/2.0.4.RELEASE/spring-boot-starter-2.0.4.RELEASE.jar:/Users/zlatkoc/.m2/repository/org/yaml/snakeyaml/1.19/snakeyaml-1.19.jar:/Users/zlatkoc/.m2/repository/org/springframework/boot/spring-boot/2.0.4.RELEASE/spring-boot-2.0.4.RELEASE.jar:/Users/zlatkoc/.m2/repository/org/springframework/spring-context/5.0.8.RELEASE/spring-context-5.0.8.RELEASE.jar:/Users/zlatkoc/.m2/repository/org/springframework/spring-expression/5.0.8.RELEASE/spring-expression-5.0.8.RELEASE.jar:/Users/zlatkoc/.m2/repository/org/springframework/spring-core/5.0.8.RELEASE/spring-core-5.0.8.RELEASE.jar:/Users/zlatkoc/.m2/repository/org/springframework/spring-jcl/5.0.8.RELEASE/spring-jcl-5.0.8.RELEASE.jar:/Users/zlatkoc/.m2/repository/org/springframework/spring-aop/5.0.8.RELEASE/spring-aop-5.0.8.RELEASE.jar:/Users/zlatkoc/.m2/repository/org/springframework/spring-beans/5.1.0.RELEASE/spring-beans-5.1.0.RELEASE.jar:/Users/zlatkoc/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.0.4.RELEASE/spring-boot-autoconfigure-2.0.4.RELEASE.jar:/Users/zlatkoc/.m2/repository/org/springframework/boot/spring-boot-starter-logging/2.0.4.RELEASE/spring-boot-starter-logging-2.0.4.RELEASE.jar:/Users/zlatkoc/.m2/repository/org/slf4j/jul-to-slf4j/1.7.25/jul-to-slf4j-1.7.25.jar:/Users/zlatkoc/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar:/Users/zlatkoc/.m2/repository/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar:/Users/zlatkoc/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.10.0/log4j-to-slf4j-2.10.0.jar:/Users/zlatkoc/.m2/repository/org/apache/logging/log4j/log4j-api/2.10.0/log4j-api-2.10.0.jar:/Users/zlatkoc/.m2/repository/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar:/Users/zlatkoc/.m2/repository/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar:/Users/zlatkoc/.m2/repository/com/fasterxml/jackson/module/jackson-module-kotlin/2.9.6/jackson-module-kotlin-2.9.6.jar:/Users/zlatkoc/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.9.6/jackson-databind-2.9.6.jar:/Users/zlatkoc/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.9.6/jackson-core-2.9.6.jar:/Users/zlatkoc/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.9.0/jackson-annotations-2.9.0.jar:/Users/zlatkoc/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-common/1.2.70/kotlin-stdlib-common-1.2.70.jar:/Users/zlatkoc/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.2.70/kotlin-stdlib-jdk8-1.2.70.jar:/Users/zlatkoc/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.2.70/kotlin-stdlib-jdk7-1.2.70.jar:/Users/zlatkoc/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib/1.2.70/kotlin-stdlib-1.2.70.jar:/Users/zlatkoc/.m2/repository/org/jetbrains/annotations/13.0/annotations-13.0.jar:/Users/zlatkoc/.m2/repository/org/jetbrains/kotlin/kotlin-reflect/1.2.70/kotlin-reflect-1.2.70.jar:/Users/zlatkoc/.m2/repository/commons-io/commons-io/2.6/commons-io-2.6.jar:/Users/zlatkoc/.m2/repository/org/springframework/spring-web/5.1.0.RELEASE/spring-web-5.1.0.RELEASE.jar:/Users/zlatkoc/.m2/repository/com/madgag/spongycastle/core/1.51.0.0/core-1.51.0.0.jar:/Users/zlatkoc/.m2/repository/com/google/protobuf/protobuf-java/2.6.1/protobuf-java-2.6.1.jar:/Users/zlatkoc/.m2/repository/com/google/guava/guava/18.0/guava-18.0.jar:/Users/zlatkoc/.m2/repository/com/google/code/findbugs/jsr305/2.0.1/jsr305-2.0.1.jar:/Users/zlatkoc/.m2/repository/net/jcip/jcip-annotations/1.0/jcip-annotations-1.0.jar:/Users/zlatkoc/.m2/repository/com/lambdaworks/scrypt/1.4.0/scrypt-1.4.0.jar:/Users/zlatkoc/.m2/repository/org/bitcoinj/orchid/1.2.1/orchid-1.2.1.jar:/Users/zlatkoc/.m2/repository/com/squareup/okhttp/okhttp/2.7.2/okhttp-2.7.2.jar:/Users/zlatkoc/.m2/repository/com/squareup/okio/okio/1.6.0/okio-1.6.0.jar
Welcome to Kotlin version 1.2.71 (JRE 1.8.0_162-b12)
Type :help for help, :quit for quit
>>> import com.myproject.somepackage.SomeThing
error: unresolved reference: myproject
import com.myproject.somepackage.SomeThing
           ^

>>>

When I have just following in my init.kts:

//KOTLIN_OPTS -cp build/libs/myproject.jar

I can import classes from my local code:

$ kscript --interactive init.kts
[kscript] Creating REPL from init.kts
Welcome to Kotlin version 1.2.71 (JRE 1.8.0_162-b12)
Type :help for help, :quit for quit
>>> import com.myproject.somepackage.SomeThing
>>> 

Activity

  1. holgerbrandl commented on Sep 28, 2018

    @holgerbrandl
    Collaborator

    I wonder why we don't the see warning when executing the script with kscript init.kts? There's clearly the same duplication happening there.

    Anyway, I see your point and agree,.

    We could address it properly by fixing #127, but this seems a bit too much given the beauty of your workaround.

    To fix it as you suggested, we would need to parse the the aggregated KOTLIN_OPTS, pull out (and remove) all classpath settings, and finally append them to the `classpath variable in https://github.com/holgerbrandl/kscript/blob/4bd118b881b4d97257562ea3d3045713107fdc44/src/main/kotlin/kscript/app/Kscript.kt#L146

    Before doing this we should ping the kotlin team on https://youtrack.jetbrains.net/oauth?state=%2Fissues%2FKT about whether multiple cp arguments should be legit or not, and why the repl invokation behavior differs from the application-invocation behavior. In java multiple cp arguments seem possible, see https://stackoverflow.com/questions/45291354/specifying-multiple-cp-or-classpath-entries-on-java-command-line . Could you do so, and potentially even provide the fix from above as PR? :-)

  2. DALDEI commented on Apr 19, 2019

    @DALDEI

    This is my #1 ... #100 use case for kscript and I cant get it to work.
    Case: developing a library /app and want to run a .kts script using the current built code directory tree.
    Ive tried publishing to custom maven repo (gradle resolves fine but MavenRepository does not), adding a classpath doesnt do it (see related issue)

  3. DALDEI commented on May 10, 2019

    @DALDEI

    I took a stab at fixing this -- came close but no cigar -- but close.
    My 'hack' of an idea, which is still viable but needs to be tweaked, is to work around the 'feature' of kotlin and kotlinc in a crude but effective way. I attempted this in the .kt code but it failed due to the mixture annotation and command line parsing and the early conversion of argument lists to strings making it difficult --- its not trivial to 'undo' concatenating shell arguments into seperate args short of running the shell. ('quoting is hard' Unquoting even harder). But here's trick.
    Just prior to calling kotlin and kotlinc with the full command line, scan for and modify all "-cp" and "-classpath" options replacing them with a single one. I tested this crudely with a shell script and may try a better version. The concept should work and can be done without subprocess creation in shell.
    How to invoke the code is an option -- the easiest would be to replace occurances of "kotlin" and "kotlinc" commands with private scripts like 'kscript-kotlin" -- another would be to modify the path to point to a local version of kotlinc/kotlin. Part of the work can be done in the current kscript -- but not all as there is subprocess callouts to "kotlinc" that need adjusting.

    Basic shell pseudocode -- could be more concise and doesnt cover windows etc .. ( my other kotlin fix did, but didnt handle re-evalating strings back to individual args correctly )

    Another option is to do a hacky regex just prior to calling println or kotlinc in the .kt code
    that does the same -- extract all "-cpclasspath" and merge them -- but thats still problematic due to issues with spaces in paths etc which is hard to do with regex.

    BETTER option is to catch all generation of classpaths 'upstream' and keep them seperate from the command line string, defering generation of the "-cp" options until the end.

    
    ##########
    declare -A beforeCP afterCP 
    while [ $# -gt 0 ] ; do 
       case "$1" ; in 
       -cp | -classpath)  
            if [ -z "$CLASSPATH" ] ; then 
              CLASSPATH="$2"  
             else
                "CLASSPATH="${CLASSPATH}:$2"
              fi
              shift ;;
        *)  if [ -z "$CLASSPATH" ] ; then beforeCP+=("$2") else afterCP+=("$2") ;;
    shift
    esac
    
    eval "${beforeCP[@]}"  -classpath "$CLASSPATH" "${afterCP[@]}"
    
    
    
  4. holgerbrandl commented on May 14, 2019

    @holgerbrandl
    Collaborator

    Thanks for the suggestion. In general, I think we should stay away from shell as much as possible to ease cross-platform portability.

  5. holgerbrandl commented on Jun 21, 2019

    @holgerbrandl
    Collaborator

    Closed because of inactivity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions