<commit_before>/*
   Copyright 2017 <NAME>.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package batect.os

import batect.logging.Logger
import java.io.InputStreamReader

class ProcessRunner(private val logger: Logger) {
    // NOTESTS (for input / output redirection)
    // The Docker CLI behaves differently if stdin, stdout or stderr are redirected.
    // For example, the fancy progress display while pulling an image is disabled if it detects that
    // stdout is redirected.
    // So we have to make sure that we don't redirect them.
    // However, while in theory we could use something like http://stackoverflow.com/a/911213/1668119
    // to test this, JUnit, Gradle and a dozen other things redirect the output of our tests, which means
    // that that method wouldn't work.
    // I can't find a nice way to test this. Once we move to using the Docker API directly,
    // this whole method becomes unnecessary anyway, so I'm not too concerned about this.
    fun run(command: Iterable<String>): Int {
        logger.debug {
            message("Starting process.")
            data("command", command)
        }

        val exitCode = ProcessBuilder(command.toList())
            .redirectOutput(ProcessBuilder.Redirect.INHERIT)
            .redirectInput(ProcessBuilder.Redirect.INHERIT)
            .redirectError(ProcessBuilder.Redirect.INHERIT)
            .start()
            .waitFor()

        logger.debug {
            message("Process exited.")
            data("command", command)
            data("exitCode", exitCode)
        }

        return exitCode
    }

    fun runAndCaptureOutput(command: Iterable<String>): ProcessOutput {
        logger.debug {
            message("Starting process.")
            data("command", command)
        }

        val process = ProcessBuilder(command.toList())
                .redirectErrorStream(true)
                .redirectInput(ProcessBuilder.Redirect.INHERIT)
                .start()

        val exitCode = process.waitFor()
        val output = InputStreamReader(process.inputStream).readText()

        logger.debug {
            message("Process exited.")
            data("command", command)
            data("exitCode", exitCode)
        }

        return ProcessOutput(exitCode, output)
    }

    fun <T> runAndProcessOutput(command: Iterable<String>, outputProcessor: (String) -> OutputProcessing<T>): RunAndProcessOutputResult<T> {
        logger.debug {
            message("Starting process.")
            data("command", command)
        }

        val process = ProcessBuilder(command.toList())
                .redirectErrorStream(true)
                .start()

        try {
            val reader = InputStreamReader(process.inputStream)

            reader.useLines { lines ->
                for (line in lines) {<commit_msg>Log output of tasks.<commit_after>/*
   Copyright 2017 <NAME>.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package batect.os

import batect.logging.Logger
import java.io.InputStreamReader

class ProcessRunner(private val logger: Logger) {
    // NOTESTS (for input / output redirection)
    // The Docker CLI behaves differently if stdin, stdout or stderr are redirected.
    // For example, the fancy progress display while pulling an image is disabled if it detects that
    // stdout is redirected.
    // So we have to make sure that we don't redirect them.
    // However, while in theory we could use something like http://stackoverflow.com/a/911213/1668119
    // to test this, JUnit, Gradle and a dozen other things redirect the output of our tests, which means
    // that that method wouldn't work.
    // I can't find a nice way to test this. Once we move to using the Docker API directly,
    // this whole method becomes unnecessary anyway, so I'm not too concerned about this.
    fun run(command: Iterable<String>): Int {
        logger.debug {
            message("Starting process.")
            data("command", command)
        }

        val exitCode = ProcessBuilder(command.toList())
            .redirectOutput(ProcessBuilder.Redirect.INHERIT)
            .redirectInput(ProcessBuilder.Redirect.INHERIT)
            .redirectError(ProcessBuilder.Redirect.INHERIT)
            .start()
            .waitFor()

        logger.debug {
            message("Process exited.")
            data("command", command)
            data("exitCode", exitCode)
        }

        return exitCode
    }

    fun runAndCaptureOutput(command: Iterable<String>): ProcessOutput {
        logger.debug {
            message("Starting process.")
            data("command", command)
        }

        val process = ProcessBuilder(command.toList())
                .redirectErrorStream(true)
                .redirectInput(ProcessBuilder.Redirect.INHERIT)
                .start()

        val exitCode = process.waitFor()
        val output = InputStreamReader(process.inputStream).readText()

        logger.debug {
            message("Process exited.")
            data("command", command)
            data("exitCode", exitCode)
            data("output", output)
        }

        return ProcessOutput(exitCode, output)
    }

    fun <T> runAndProcessOutput(command: Iterable<String>, outputProcessor: (String) -> OutputProcessing<T>): RunAndProcessOutputResult<T> {
        logger.debug {
            message("Starting process.")
            data("command", command)
        }

        val process = ProcessBuilder(command.toList())
                .redirectErrorStream(true)
                .start()

        try {
            val reader = InputStreamReader(process.inputStream)

            reader.useLines { lines ->
                for (line in lines) {
{'fraction_non_alphanumeric': 0.08519511468573131, 'fraction_numerical': 0.006255585344057194, 'mean_word_length': 2.332506203473945, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4432442', 'n_tokens_mistral': 1722, 'n_tokens_neox': 1633, 'n_words': 583}