kotlinsh

sh script runs from Terminal but not when called from Kotlin


so I got an application which is using a slippy map, hosted by a MapTiler server. I've wrote a little sh script called setup_server.sh to start up the server:

#! /bin/sh
./maptiler-server --workDir "./" --adminPassword "abcdefg"

This script calls a executable unix file and specifies a working directory and an admin password for the web interface. When I call this script from the terminal it all works fine. The server boots up and keeps on running. This is what the output looks like:

******@MacBook-Pro-von-****** maptiler-server-macos % sh setup_server.sh
2024-12-14T11:17:00.962Z [info]: Config file used: /Users/******/Desktop/GpxEvalApp/maptiler-server-macos/config.json
2024-12-14T11:17:02.212Z [error]: Virtual tilesets are not supported on your platform. We are working on enabling it in future versions, in the meantime, you can use docker distribution.
(node:32756) ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time
(Use `maptiler-server --trace-warnings ...` to show where the warning was created)
2024-12-14T11:17:02.948Z [info]: MapTiler Server ready on http://localhost:3650, administration on: http://localhost:3650/admin

Note: I censored my name using ****.

To run the script from within my application i use the following Kotlin code (using kscript-tools):

class ScriptExecutor {
    companion object{
        @JvmStatic
        fun execute(s: String){
            try {
                val cmd: String = "/bin/sh -c sh ./maptiler-server-macos/setup_server.sh"
                cmd.runCommand()
                //Runtime.getRuntime().exec(cmd)
            }catch (e: Exception){
                e.printStackTrace()
            }
        }
    }
}

Now the application will go into the try/catch and will call the cmd.runCommand() function. Then a new process called "bash" appears in the task manager (0,0% CPU usage, 1 Thread).

The application won't move past said function and run until manually terminated. When terminated, the "bash" process also terminates. When terminating the "bash" process the Kotlin application throws the following error:

java.lang.RuntimeException: 
    at BashResult.getOrThrow(CommandLineTool.kt:19)
    at DHCMap.subsystems.utilitys.ScriptExecutor$Companion.execute(ScriptExecutor.kt:35)
    at DHCMap.subsystems.utilitys.ScriptExecutor.execute(ScriptExecutor.kt)
    at DHCMap.Main.main(Main.java:21)

I tried different command, such as ls or date and they work perfectly fine. I also tried executing the command via Runtime.getRuntime().execc(cmd) , same outcome.

I'm running MacOS Venuta 13.6.5 and the Kotlin code is called from within Java code. I check the MacOS setting for problems with privileges but it all seems fine.

So I need a little help on why the server wont boot when executing the script from Kotlin.


Solution

  • First of all a thank you to @Slaw. Indeed consuming the output logs fixed the error. You may note I switched to using a ProcessBuilder. I tried that before but without consuming the output, but that didn't work. The new Kotlin code is the following:

    class ScriptExecutor {
    
    companion object{
    
        @JvmStatic
        fun execute(s: String){
    
            val process = ProcessBuilder("/bin/sh", s).start()
    
            // Stream output and error logs
            val output = BufferedReader(InputStreamReader(process.inputStream))
            val error = BufferedReader(InputStreamReader(process.errorStream))
    
            // Print output in the background (optional)
            Thread {
                output.lines().forEach { println(it) }
            }.start()
    
            Thread {
                error.lines().forEach { println(it) }
            }.start()
    
    
        }
    
    }}
    

    The outputs get printed to the console and the consuming is outsourced to another thread.