Code Monkey home page Code Monkey logo

kotlin-process's Introduction

kotlin-process License Build codecov

Functional Kotlin friendly way to create external system processes by leveraging:

Installation central

repositories {
    mavenCentral()
}

dependencies {
    // Check the ๐Ÿ” maven central badge ๐Ÿ” for the latest $kotlinProcessVersion
    implementation("com.github.pgreze:kotlin-process:$kotlinProcessVersion")
}

Or in your kotlin script:

@file:DependsOn("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
@file:DependsOn("com.github.pgreze:kotlin-process:$kotlinProcessVersion")

Usage

Launch a script and consume its results

Starts a program and prints its stdout/stderr outputs to the terminal:

import com.github.pgreze.process.process
import kotlinx.coroutines.runBlocking

runBlocking {
    val res = process("echo", "hello world")

    check(res.resultCode == 0)

    // By default process output is displayed in the console.
    check(res.output == emptyList<String>())
}

The next step would probably be to capture the output stream, in order to process some data from our own-made script:

val output = process(
    "./my-script.sh", arg1, arg2,

    // Capture stdout lines to do some operations after
    stdout = Redirect.CAPTURE,

    // Default value: prints to System.err
    stderr = Redirect.PRINT,

).unwrap() // Fails if the resultCode != 0

// TODO: process the output
println("Success:\n${output.joinToString("\n")}")

Notice that if you want to capture both stdout and stderr, there will be no way to differentiate them in the returned output:

val res = process(
    "./long-and-dangerous.sh", arg1, arg2,

    // Both streams will be captured,
    // preserving their orders but mixing them in the given output.
    stdout = Redirect.CAPTURE,
    stderr = Redirect.CAPTURE,

    // Allows to consume line by line without delay the provided output.
    consumer = { line -> TODO("process $line") },
)

println("Script finished with result=${res.resultCode}")
println("stdout+stderr:\n" + res.output.joinToString("\n"))

It's also possible to redirect an output stream to a file, or manually by consuming a Flow instance.

import com.github.pgreze.process.Redirect
import com.github.pgreze.process.process
import java.io.File
import java.util.Collections
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking

val errLines = Collections.synchronizedList(mutableListOf<String>())
val res = process(
    "./my-script.sh", arg1, arg2,

    // You can save the execution result in a file,
    stdout = Redirect.ToFile(File("my-input.txt")),

    // If you want to handle this stream yourself,
    // a Flow<String> instance can be used.
    stderr = Redirect.Consume { flow -> flow.toList(errLines) },
)

The last but not least, you can just silence a stream with Redirect.SILENT ๐Ÿ˜ถ

Control the environment

Several other options are available to control the script environment:

import com.github.pgreze.process.InputSource
import java.io.File

val res = process(
    "./my-script.sh",
    
    // Provides the input as a string, similar to:
    // $ echo "hello world" | my-script.sh
    stdin = InputSource.fromString("hello world"),

    // Inject custom environment variables:
    env = mapOf("MY_ENV_VARIABLE" to "42"),

    // Override the working directory:
    directory = File("./a/directory"),
)

There are other ways to provide the process input:

// From a file:
process(
    "./my-script.sh",
    stdin = InputSource.FromFile(File("my-input.txt")),
)

// From an InputStream:
process(
    "./my-script.sh",
    stdin = InputSource.fromInputStream(myInputStream)),
)

// Manually by using the raw OutputStream:
process(
    "./my-script.sh",
    stdin = InputSource.FromStream { out: OutputStream ->
        out.write("hello world\n".toByteArray())
        out.flush()
    },
)

Alternative(s)

  1. https://github.com/jakubriegel/kotlin-shell
  2. https://github.com/lordcodes/turtle

kotlin-process's People

Contributors

furubarug avatar pgreze avatar sebastianaigner 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

Watchers

 avatar  avatar  avatar

kotlin-process's Issues

Feature Request: Kotlin Multiplatform

Either implementation, or at minimum an API that could be used to implement process handling in node or native builds.

kotlin-process is a nice API and successfully hides the ProcessBuilder API.

Please specify license of the project

Hey,

Sorry for dropping in, I tried checking the license of this project but couldn't find any. Could you please add appropriate license headers + LICENSE file if your project is available under some license?

Thanks

Missing a way to inherit input

As InputSource is a sealed class, which only translates to Redirect.from or Redirect.PIPE, I see no way to start the process with Redirect.INHERIT. Leaving stdin empty leads to using the default of Redirect.PIPE. This makes it very difficult to run interactive commands with dynamic input.

Perhaps you could add a class Inherited : InputSource() which is mapped to ProcessBuilder.Redirect.INHERIT by toNative()? Instead of "Inherit(ed)" it could also be named something like FromParent to be more in line with the other names.

Close process on coroutine cancelation

I have another app that I run alongside my application, and I want it to be closed with my application, for this currently I use Runtime.exec, but I was thinking of trying out this library as Runtime.exec has issues with the way I am using it. It doesn't seem to close the attached process on coroutine cancellation though, which I feel would fit with the way the library is built.

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.