<commit_before>package timeout

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"syscall"
	"time"
)

type Timeout struct {
	PreserveStatus bool
	Duration       uint64
	KillAfter      uint64
	Signal         os.Signal
	Command        string
	CommandArgs    []string
}

const (
	exitTimedOut = 124
	exitKilled   = 137
)

func (tio *Timeout) Run() int {
	ch, stdoutPipe, stderrPipe, err := tio.RunCommand()
	if err != nil {
		panic(fmt.Sprintf("something went wrong: %+v", err))
	}
	defer func() {
		stdoutPipe.Close()
		stderrPipe.Close()
	}()

	go readAndOut(stdoutPipe, os.Stdout)
	go readAndOut(stderrPipe, os.Stderr)

	return <-ch
}

func (tio *Timeout) prepareCmd() *exec.Cmd {
	args := tio.CommandArgs
	return exec.Command(tio.Command, args...)
}

func (tio *Timeout) RunCommand() (exitChan chan int, stdoutPipe, stderrPipe io.ReadCloser, err error) {
	cmd := tio.prepareCmd()
	if err != nil {
		return
	}

	stdoutPipe, err = cmd.StdoutPipe()
	if err != nil {
		return
	}
	stderrPipe, err = cmd.StderrPipe()
	if err != nil {
		return
	}
	if err = cmd.Start(); err != nil {
		return
	}

	exitChan = make(chan int)
	go func() {
		exitChan <- tio.handleTimeout(cmd)
	}()

	return
}

func (tio *Timeout) handleTimeout(cmd *exec.Cmd) int {
	exit := 0
	timedOut := false
	exitChan := getExitChan(cmd)

	if tio.Duration > 0 {
		select {
		case exit = <-exitChan:
		case <-time.After(time.Duration(tio.Duration) * time.Second):
			cmd.Process.Signal(tio.Signal)
			timedOut = true
			exit = exitTimedOut
		}
	} else {
		exit = <-exitChan
	}

	killed := false
	if timedOut {
		tmpExit := 0
		if tio.KillAfter > 0 {
			select {
			case tmpExit = <-exitChan:
			case <-time.After(time.Duration(tio.KillAfter) * time.Second):
				cmd.Process.Kill()
				killed = true
				exit = exitKilled
			}
		} else {
			tmpExit = <-exitChan
		}
		if tio.PreserveStatus && !killed {
			exit = tmpExit
		}
	}

	return exit
}

func getExitChan(cmd *exec.Cmd) chan int {
	ch := make(chan int)
	go func() {
		exit := 0
		err := cmd.Wait()
		if err != nil {
			if exiterr, ok := err.(*exec.ExitError); ok {
				if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
					exit = status.ExitStatus()
				}
			} else {
				exit = -1
			}
		}
		ch <- exit
	}()
	return ch
}

func readAndOut(r io.Reader, f *os.File) {
	s := bufio.NewScanner(r)
	for s.Scan() {
		fmt.Fprintln(f, s.Text())
	}
}

var durRe = regexp.MustCompile("^([0-9]+)([smhd])?$")<commit_msg>use raw string literal for regexp<commit_after>package timeout

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"syscall"
	"time"
)

type Timeout struct {
	PreserveStatus bool
	Duration       uint64
	KillAfter      uint64
	Signal         os.Signal
	Command        string
	CommandArgs    []string
}

const (
	exitTimedOut = 124
	exitKilled   = 137
)

func (tio *Timeout) Run() int {
	ch, stdoutPipe, stderrPipe, err := tio.RunCommand()
	if err != nil {
		panic(fmt.Sprintf("something went wrong: %+v", err))
	}
	defer func() {
		stdoutPipe.Close()
		stderrPipe.Close()
	}()

	go readAndOut(stdoutPipe, os.Stdout)
	go readAndOut(stderrPipe, os.Stderr)

	return <-ch
}

func (tio *Timeout) prepareCmd() *exec.Cmd {
	args := tio.CommandArgs
	return exec.Command(tio.Command, args...)
}

func (tio *Timeout) RunCommand() (exitChan chan int, stdoutPipe, stderrPipe io.ReadCloser, err error) {
	cmd := tio.prepareCmd()
	if err != nil {
		return
	}

	stdoutPipe, err = cmd.StdoutPipe()
	if err != nil {
		return
	}
	stderrPipe, err = cmd.StderrPipe()
	if err != nil {
		return
	}
	if err = cmd.Start(); err != nil {
		return
	}

	exitChan = make(chan int)
	go func() {
		exitChan <- tio.handleTimeout(cmd)
	}()

	return
}

func (tio *Timeout) handleTimeout(cmd *exec.Cmd) int {
	exit := 0
	timedOut := false
	exitChan := getExitChan(cmd)

	if tio.Duration > 0 {
		select {
		case exit = <-exitChan:
		case <-time.After(time.Duration(tio.Duration) * time.Second):
			cmd.Process.Signal(tio.Signal)
			timedOut = true
			exit = exitTimedOut
		}
	} else {
		exit = <-exitChan
	}

	killed := false
	if timedOut {
		tmpExit := 0
		if tio.KillAfter > 0 {
			select {
			case tmpExit = <-exitChan:
			case <-time.After(time.Duration(tio.KillAfter) * time.Second):
				cmd.Process.Kill()
				killed = true
				exit = exitKilled
			}
		} else {
			tmpExit = <-exitChan
		}
		if tio.PreserveStatus && !killed {
			exit = tmpExit
		}
	}

	return exit
}

func getExitChan(cmd *exec.Cmd) chan int {
	ch := make(chan int)
	go func() {
		exit := 0
		err := cmd.Wait()
		if err != nil {
			if exiterr, ok := err.(*exec.ExitError); ok {
				if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
					exit = status.ExitStatus()
				}
			} else {
				exit = -1
			}
		}
		ch <- exit
	}()
	return ch
}

func readAndOut(r io.Reader, f *os.File) {
	s := bufio.NewScanner(r)
	for s.Scan() {
		fmt.Fprintln(f, s.Text())
	}
}

var durRe = regexp.MustCompile(`^([0-9]+)([smhd])?$`)
{'fraction_non_alphanumeric': 0.15022330491270808, 'fraction_numerical': 0.007308160779537149, 'mean_word_length': 2.9542536115569824, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 7, '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': '1585199', 'n_tokens_mistral': 2187, 'n_tokens_neox': 1940, 'n_words': 462}