Search code examples
jvmkotlin-script

How to determine why process fails in kotlin script


I am developing a kotlin script which executes code on the platform which it is running on. Platform code is called using this method from the script:

fun exec(command: String, vararg arguments: String, runLive: Boolean = !isDebug): OutputStream {
    val allArgs = arguments.joinToString(" ")

    if (runLive) {
        val process = Runtime.getRuntime().exec(command, arguments)
        val exitCode = process.waitFor()

        if (exitCode != 0) {
            val platformError = String(BufferedInputStream(process.errorStream).readAllBytes(), Charset.defaultCharset())
            throw IllegalStateException("Execution of '$command $allArgs' failed with exit code $exitCode!\n$platformError")
        }

        return process.outputStream
    } else {
        println("$command $allArgs")

        return object : OutputStream() {
            override fun write(b: Int) {
                println("dummy $b")
            }
        }
    }
}

In the script, I try to get all the tags for a git repository using this call:

exec(command = "git", "tag", runLive = true)

When the command fails, how can process.errorStream be read? The output now is not readable and the script failure says:

java.lang.IllegalStateException: Execution of 'git tag' failed with exit code 1!

    at Snap_tag_main.exec(snap-tag.main.kts:75)
    at Snap_tag_main.<init>(snap-tag.main.kts:64)

Solution

  • Not all commands use the error stream when displaying errors. The solution is to bring both the input stream as well as the output stream like this:

            if (exitCode != 0) {
                val platformMessages = """
                    ${String(BufferedInputStream(process.inputStream).readAllBytes(), Charset.defaultCharset())}
                    ${String(BufferedInputStream(process.errorStream).readAllBytes(), Charset.defaultCharset())}
                """.trimIndent().trim()
    
                throw IllegalStateException("Execution of '$command $allArgs' failed with exit code $exitCode!\n$platformMessages\n---")
            }
    

    The failure message now looks like

    java.lang.IllegalStateException: Execution of 'git tag' failed with exit code 1!
    usage: git [--version] [--help] [-C <path>] [-c <name>=<value>]
               [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
               [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]
               [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
               [--super-prefix=<path>] [--config-env=<name>=<envvar>]
               <command> [<args>]
    
    These are common Git commands used in various situations:
    
    start a working area (see also: git help tutorial)
       clone     Clone a repository into a new directory
       init      Create an empty Git repository or reinitialize an existing one
    
    work on the current change (see also: git help everyday)
       add       Add file contents to the index
       mv        Move or rename a file, a directory, or a symlink
       restore   Restore working tree files
       rm        Remove files from the working tree and from the index
    
    examine the history and state (see also: git help revisions)
       bisect    Use binary search to find the commit that introduced a bug
       diff      Show changes between commits, commit and working tree, etc
       grep      Print lines matching a pattern
       log       Show commit logs
       show      Show various types of objects
       status    Show the working tree status
    
    grow, mark and tweak your common history
       branch    List, create, or delete branches
       commit    Record changes to the repository
       merge     Join two or more development histories together
       rebase    Reapply commits on top of another base tip
       reset     Reset current HEAD to the specified state
       switch    Switch branches
       tag       Create, list, delete or verify a tag object signed with GPG
    
    collaborate (see also: git help workflows)
       fetch     Download objects and refs from another repository
       pull      Fetch from and integrate with another repository or a local branch
       push      Update remote refs along with associated objects
    
    'git help -a' and 'git help -g' list available subcommands and some
    concept guides. See 'git help <command>' or 'git help <concept>'
    to read about a specific subcommand or concept.
    See 'git help git' for an overview of the system.
    ---
        at Snap_tag_main.exec(snap-tag.main.kts:82)
        at Snap_tag_main.<init>(snap-tag.main.kts:66)