<commit_before>package com.github.dakusui.cmd;

import com.github.dakusui.cmd.exceptions.CommandException;
import com.github.dakusui.cmd.exceptions.CommandTimeoutException;
import com.github.dakusui.cmd.io.BasicLineReader;
import com.github.dakusui.cmd.io.LineConsumer;
import com.github.dakusui.cmd.io.LoggerLineWriter;
import com.github.dakusui.cmd.io.RingBufferedLineWriter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.concurrent.*;

public class Command {
  enum State {
    NOT_STARTED,
    STARTED,
    FINISHED
  }

  private static Logger LOGGER = LoggerFactory.getLogger(Command.class);

  private State state = State.NOT_STARTED;
  private Process proc;

  private LineConsumer stdout;

  private LineConsumer stderr;

  private int pid = -1;

  private String[] execShell;

  private String cmd;

  private RingBufferedLineWriter stdoutRingBuffer;
  private RingBufferedLineWriter stderrRingBuffer;
  private RingBufferedLineWriter stdouterrRingBuffer;

  Command(String[] execShell, String cmd) {
    this.proc = null;
    this.execShell = execShell;
    this.cmd = cmd;
  }

  public int pid() {
    if (state == State.NOT_STARTED) {
      throw new IllegalStateException(String.format("This command(%s) is not yet started.", this.cmd));
    }
    return this.pid;
  }

  private void startConsumingOutput() {
    this.stdoutRingBuffer = new RingBufferedLineWriter(100);
    this.stderrRingBuffer = new RingBufferedLineWriter(100);
    this.stdouterrRingBuffer = new RingBufferedLineWriter(100);
    this.stdout = new LineConsumer(new BasicLineReader(Charset.defaultCharset(), 0, proc.getInputStream()));
    this.stdout.addLineWriter(LoggerLineWriter.DEBUG);
    this.stdout.addLineWriter(stdoutRingBuffer);
    this.stdout.addLineWriter(stdouterrRingBuffer);
    this.stderr = new LineConsumer(new BasicLineReader(Charset.defaultCharset(), 0, proc.getErrorStream()));
    this.stderr.addLineWriter(LoggerLineWriter.DEBUG);
    this.stderr.addLineWriter(stderrRingBuffer);
    this.stderr.addLineWriter(stdouterrRingBuffer);

    this.stdout.start();
    this.stderr.start();
  }

  /**
   * Executes this command in a synchronous manner.
   * if <code>timeOut</code> is set to a value less than or equal to zero, this method
   * does never time out.
   * Otherwise times out in <code>timeOut</code> milliseconds.
   *
   * @param timeOut duration
   * @return
   * @throws CommandException The command failed during execution.
   */
  public CommandResult exec(int timeOut) throws CommandException {
    String[] execCmd = new String[this.execShell.length + 1];
    System.arraycopy(this.execShell, 0, execCmd, 0, this.execShell.length);
    execCmd[execCmd.length - 1] = this.cmd;

    try {
      this.proc = Runtime.getRuntime().exec(execCmd);
      this.startConsumingOutput();
    } catch (IOException e) {
      throw new CommandException(e);
    }
    LOGGER.debug("EXEC={}", StringUtils.join(execCmd, " "));
    this.pid = getPID(this.proc);

    this.state = State.STARTED;
    LOGGER.debug("pid={}", this.pid);

    final Callable<CommandResult> callable = new Callable<CommandResult>() {
      public CommandResult call() throws CommandException {
        return Command.this.waitFor();
      }
    };
    CommandResult ret;
    if (timeOut <= 0) {
      ret = this.waitFor();
    } else {
      ExecutorService executor = Executors.newSingleThreadExecutor();
      Future<CommandResult> future = executor.submit(callable);
      try {
        ret = future.get(timeOut, TimeUnit.MILLISECONDS);
      } catch (InterruptedException e) {
        throw new CommandException(e);
      } catch (ExecutionException e) {
        throw new CommandException(e);
      } catch (TimeoutException e) {
        throw new CommandTimeoutException(e);
      }
    }
    this.state = State.FINISHED;
    return ret;
  }

  private int getPID(Process proc) {
    int ret = -1;
    try {
      Field f = proc.getClass().getDeclaredField("pid");
      f.setAccessible(true);
      try {
        ret = Integer.parseInt(f.get(this.proc).toString());
      } finally {
        f.setAccessible(false);
      }
    } catch (IllegalAccessException e) {<commit_msg>Fix one thread leak bug<commit_after>package com.github.dakusui.cmd;

import com.github.dakusui.cmd.exceptions.CommandException;
import com.github.dakusui.cmd.exceptions.CommandTimeoutException;
import com.github.dakusui.cmd.io.BasicLineReader;
import com.github.dakusui.cmd.io.LineConsumer;
import com.github.dakusui.cmd.io.LoggerLineWriter;
import com.github.dakusui.cmd.io.RingBufferedLineWriter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.concurrent.*;

public class Command {
  enum State {
    NOT_STARTED,
    STARTED,
    FINISHED
  }

  private static Logger LOGGER = LoggerFactory.getLogger(Command.class);

  private State state = State.NOT_STARTED;
  private Process proc;

  private LineConsumer stdout;

  private LineConsumer stderr;

  private int pid = -1;

  private String[] execShell;

  private String cmd;

  private RingBufferedLineWriter stdoutRingBuffer;
  private RingBufferedLineWriter stderrRingBuffer;
  private RingBufferedLineWriter stdouterrRingBuffer;

  Command(String[] execShell, String cmd) {
    this.proc = null;
    this.execShell = execShell;
    this.cmd = cmd;
  }

  public int pid() {
    if (state == State.NOT_STARTED) {
      throw new IllegalStateException(String.format("This command(%s) is not yet started.", this.cmd));
    }
    return this.pid;
  }

  private void startConsumingOutput() {
    this.stdoutRingBuffer = new RingBufferedLineWriter(100);
    this.stderrRingBuffer = new RingBufferedLineWriter(100);
    this.stdouterrRingBuffer = new RingBufferedLineWriter(100);
    this.stdout = new LineConsumer(new BasicLineReader(Charset.defaultCharset(), 0, proc.getInputStream()));
    this.stdout.addLineWriter(LoggerLineWriter.DEBUG);
    this.stdout.addLineWriter(stdoutRingBuffer);
    this.stdout.addLineWriter(stdouterrRingBuffer);
    this.stderr = new LineConsumer(new BasicLineReader(Charset.defaultCharset(), 0, proc.getErrorStream()));
    this.stderr.addLineWriter(LoggerLineWriter.DEBUG);
    this.stderr.addLineWriter(stderrRingBuffer);
    this.stderr.addLineWriter(stdouterrRingBuffer);

    this.stdout.start();
    this.stderr.start();
  }

  /**
   * Executes this command in a synchronous manner.
   * if <code>timeOut</code> is set to a value less than or equal to zero, this method
   * does never time out.
   * Otherwise times out in <code>timeOut</code> milliseconds.
   *
   * @param timeOut duration
   * @return
   * @throws CommandException The command failed during execution.
   */
  public CommandResult exec(int timeOut) throws CommandException {
    String[] execCmd = new String[this.execShell.length + 1];
    System.arraycopy(this.execShell, 0, execCmd, 0, this.execShell.length);
    execCmd[execCmd.length - 1] = this.cmd;

    try {
      this.proc = Runtime.getRuntime().exec(execCmd);
      this.startConsumingOutput();
    } catch (IOException e) {
      throw new CommandException(e);
    }
    LOGGER.debug("EXEC={}", StringUtils.join(execCmd, " "));
    this.pid = getPID(this.proc);

    this.state = State.STARTED;
    LOGGER.debug("pid={}", this.pid);

    final Callable<CommandResult> callable = new Callable<CommandResult>() {
      public CommandResult call() throws CommandException {
        return Command.this.waitFor();
      }
    };
    CommandResult ret;
    if (timeOut <= 0) {
      ret = this.waitFor();
    } else {
      ExecutorService executor = Executors.newSingleThreadExecutor();
      Future<CommandResult> future = executor.submit(callable);
      try {
        ret = future.get(timeOut, TimeUnit.MILLISECONDS);
      } catch (InterruptedException e) {
        throw new CommandException(e);
      } catch (ExecutionException e) {
        throw new CommandException(e);
      } catch (TimeoutException e) {
        throw new CommandTimeoutException(e);
      } finally {
        executor.shutdownNow();
      }
    }
    this.state = State.FINISHED;
    return ret;
  }

  private int getPID(Process proc) {
    int ret = -1;
    try {
      Field f = proc.getClass().getDeclaredField("pid");
      f.setAccessible(true);
      try {
        ret = Integer.parseInt(f.get(this.proc).toString());
      } finally {
        f.setAccessible(false);
      }
    } catch (IllegalAccessException e) {
{'fraction_non_alphanumeric': 0.1100160440064176, 'fraction_numerical': 0.00481320192528077, 'mean_word_length': 3.593157894736842, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '928694', 'n_tokens_mistral': 2713, 'n_tokens_neox': 2622, 'n_words': 574}