<commit_before>package velocity

import (
	"fmt"
	"io"
	"net"
	"os"
	"strings"
	"sync"
	"time"

	"go.uber.org/zap"

	"golang.org/x/crypto/ssh/agent"

	"github.com/go-cmd/cmd"
	"github.com/velocity-ci/velocity/backend/pkg/auth"
	"golang.org/x/crypto/ssh"
)

func runCmd(shCmd []string, writer io.Writer) cmd.Status {
	opts := cmd.Options{Buffered: false, Streaming: true}
	c := cmd.NewCmdOptions(opts, shCmd[0], shCmd[1:len(shCmd)]...)
	stdout := []string{}
	stderr := []string{}
	go func() {
		for line := range c.Stdout {
			writer.Write([]byte(line))
			stdout = append(stdout, line)
		}
	}()
	go func() {
		for line := range c.Stderr {
			writer.Write([]byte(line))
			stderr = append(stderr, line)
		}
	}()

	GetLogger().Debug("running command", zap.Strings("cmd", shCmd))
	go func() {
		<-time.After(3 * time.Second)
		GetLogger().Debug("3s", zap.Strings("cmd", shCmd), zap.Strings("stdout", stdout), zap.Strings("stderr", stderr), zap.Int("status", c.Status().Exit))
		if len(stdout) < 1 {
			c.Stop()
		}
	}()
	s := c.Start()

	finalStatus := <-s
	close(c.Stdout)
	close(c.Stderr)
	finalStatus.Stdout = stdout
	finalStatus.Stderr = stderr

	fmt.Printf("%+v\n", finalStatus)

	return finalStatus
}

type SSHKeyError string

func (s SSHKeyError) Error() string {
	return string(s)
}

type HostKeyError string<commit_msg>[backend] Better debug output for cmds and waiting to close streams<commit_after>package velocity

import (
	"fmt"
	"io"
	"net"
	"os"
	"strings"
	"sync"
	"time"

	"go.uber.org/zap"

	"golang.org/x/crypto/ssh/agent"

	"github.com/go-cmd/cmd"
	"github.com/velocity-ci/velocity/backend/pkg/auth"
	"golang.org/x/crypto/ssh"
)

func runCmd(shCmd []string, writer io.Writer) cmd.Status {
	opts := cmd.Options{Buffered: false, Streaming: true}
	c := cmd.NewCmdOptions(opts, shCmd[0], shCmd[1:len(shCmd)]...)
	stdout := []string{}
	stderr := []string{}
	go func() {
		for line := range c.Stdout {
			writer.Write([]byte(line))
			stdout = append(stdout, line)
		}
	}()
	go func() {
		for line := range c.Stderr {
			writer.Write([]byte(line))
			stderr = append(stderr, line)
		}
	}()

	GetLogger().Debug("running command", zap.Strings("cmd", shCmd))
	go func() {
		<-time.After(3 * time.Second)
		if !c.Status().Complete && len(stdout) < 1 {
			GetLogger().Debug("3s", zap.Strings("cmd", shCmd), zap.Strings("stdout", stdout), zap.Strings("stderr", stderr), zap.Int("status", c.Status().Exit))
			c.Stop()
		}
	}()
	s := c.Start()

	finalStatus := <-s
	time.Sleep(10 * time.Millisecond)
	close(c.Stdout)
	close(c.Stderr)
	finalStatus.Stdout = stdout
	finalStatus.Stderr = stderr

	GetLogger().Debug("completed cmd",
		zap.String("cmd", strings.Join(shCmd, " ")),
		zap.Int("exited", finalStatus.Exit),
		zap.Strings("stdout", finalStatus.Stdout),
		zap.Strings("stderr", finalStatus.Stderr),
		zap.Float64("runtime (s)", finalStatus.Runtime),
	)

	return finalStatus
}

type SSHKeyError string

func (s SSHKeyError) Error() string {
	return string(s)
}

type HostKeyError string
{'fraction_non_alphanumeric': 0.1882510013351135, 'fraction_numerical': 0.004672897196261682, 'mean_word_length': 4.149484536082475, 'pattern_counts': {'":': 0, '<': 9, '<?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': '5972603', 'n_tokens_mistral': 1222, 'n_tokens_neox': 1145, 'n_words': 227}