<commit_before>package util

import (
	"fmt"
	"os"

	execplus "github.com/Originate/go-execplus"
	shellwords "github.com/mattn/go-shellwords"
	"github.com/pkg/errors"
)

// Run runs the given command, waits for the process to finish and
// returns the output string and error (if any)
func Run(dir string, commandWords ...string) (string, error) {
	if len(commandWords) == 1 {
		var err error
		commandWords, err = ParseCommand(commandWords[0])
		if err != nil {
			return "", err
		}
	}
	cmdPlus := execplus.NewCmdPlus(commandWords...)
	cmdPlus.SetDir(dir)
	err := cmdPlus.Run()
	return cmdPlus.Output, err
}

// RunAndLog runs the given command, logs the process to the given
// channel, waits for the process to finish and returns an error (if any)
func RunAndLog(dir string, env []string, logChannel chan string, commandWords ...string) error {
	if len(commandWords) == 1 {
		var err error
		commandWords, err = ParseCommand(commandWords[0])
		if err != nil {
			return err
		}
	}
	cmdPlus := execplus.NewCmdPlus(commandWords...)
	cmdPlus.SetDir(dir)
	cmdPlus.SetEnv(append(env, os.Environ()...))
	ConnectLogChannel(cmdPlus, logChannel)
	return cmdPlus.Run()
}

// RunSeries runs each command in commands and returns an error if any
func RunSeries(dir string, commands [][]string) error {
	for _, command := range commands {
		if output, err := Run(dir, command...); err != nil {
			return errors.Wrap(err, fmt.Sprintf("Command Failed:\nCommand: %s\nOutput:\n%s\n\n'", command, output))
		}
	}
	return nil
}

// ParseCommand parses the command string into a string array
func ParseCommand(command string) ([]string, error) {
	return shellwords.Parse(command)
}

// ConnectLogChannel connects a log channel that wants to receive only each new output
func ConnectLogChannel(cmdPlus *execplus.CmdPlus, logChannel chan string) {
	outputChannel, _ := cmdPlus.GetOutputChannel()
	go func() {
		for {
			outputChunk := <-outputChannel
			if outputChunk.Chunk != "" {
				logChannel <- outputChunk.Chunk
			}
		}
	}()
}<commit_msg>improve error message by wrapping errors (#419)<commit_after>package util

import (
	"os"
	"strings"

	execplus "github.com/Originate/go-execplus"
	shellwords "github.com/mattn/go-shellwords"
	"github.com/pkg/errors"
)

// Run runs the given command, waits for the process to finish and
// returns the output string and error (if any)
func Run(dir string, commandWords ...string) (string, error) {
	if len(commandWords) == 1 {
		var err error
		commandWords, err = ParseCommand(commandWords[0])
		if err != nil {
			return "", err
		}
	}
	cmdPlus := execplus.NewCmdPlus(commandWords...)
	cmdPlus.SetDir(dir)
	if err := cmdPlus.Run(); err != nil {
		return cmdPlus.Output, errors.Wrapf(err, "Error running '%s'. Output:\n%s", strings.Join(commandWords, " "), cmdPlus.Output)
	}
	return cmdPlus.Output, nil
}

// RunAndLog runs the given command, logs the process to the given
// channel, waits for the process to finish and returns an error (if any)
func RunAndLog(dir string, env []string, logChannel chan string, commandWords ...string) error {
	if len(commandWords) == 1 {
		var err error
		commandWords, err = ParseCommand(commandWords[0])
		if err != nil {
			return err
		}
	}
	cmdPlus := execplus.NewCmdPlus(commandWords...)
	cmdPlus.SetDir(dir)
	cmdPlus.SetEnv(append(env, os.Environ()...))
	ConnectLogChannel(cmdPlus, logChannel)
	if err := cmdPlus.Run(); err != nil {
		return errors.Wrapf(err, "Error running '%s'. Output:\n%s", strings.Join(commandWords, " "), cmdPlus.Output)
	}
	return nil
}

// RunSeries runs each command in commands and returns an error if any
func RunSeries(dir string, commands [][]string) error {
	for _, command := range commands {
		if _, err := Run(dir, command...); err != nil {
			return err
		}
	}
	return nil
}

// ParseCommand parses the command string into a string array
func ParseCommand(command string) ([]string, error) {
	return shellwords.Parse(command)
}

// ConnectLogChannel connects a log channel that wants to receive only each new output
func ConnectLogChannel(cmdPlus *execplus.CmdPlus, logChannel chan string) {
	outputChannel, _ := cmdPlus.GetOutputChannel()
	go func() {
		for {
			outputChunk := <-outputChannel
			if outputChunk.Chunk != "" {
				logChannel <- outputChunk.Chunk
			}
		}
	}()
}
{'fraction_non_alphanumeric': 0.1253501400560224, 'fraction_numerical': 0.0025676937441643324, 'mean_word_length': 4.035252643948296, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, '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': '2814070', 'n_tokens_mistral': 1454, 'n_tokens_neox': 1347, 'n_words': 427}