<commit_before>package env

import (
	"bytes"
	"fmt"
	"os/exec"
	"regexp"
	"strconv"
	"strings"

	"github.com/pkg/errors"
)

type Git struct {
	Branch      string `json:"branch" structs:"branch"`
	CommitSHA   string `json:"commit_sha" structs:"commit_sha"`
	CommittedAt int    `json:"committed_at" structs:"committed_at"`
}

func (g Git) String() string {
	out := &bytes.Buffer{}
	out.WriteString("GIT_BRANCH=")
	out.WriteString(g.Branch)
	out.WriteString("\nGIT_COMMIT_SHA=")
	out.WriteString(g.CommitSHA)
	out.WriteString("\nGIT_COMMITTED_AT=")
	out.WriteString(fmt.Sprint(g.CommittedAt))
	return out.String()
}

func findGitInfo() (Git, error) {
	_, err := exec.LookPath("git")
	if err != nil {
		// git isn't present, so load from ENV vars:
		return loadGitFromENV()
	}

	g := Git{}

	cmd := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD")
	out, err := cmd.Output()
	if err != nil {
		return g, errors.WithStack(err)
	}
	g.Branch = strings.TrimSpace(string(out))

	cmd = exec.Command("git", "log", "-1", "--pretty=format:%H")
	out, err = cmd.Output()
	if err != nil {
		return g, errors.WithStack(err)
	}
	g.CommitSHA = strings.TrimSpace(string(out))

	cmd = exec.Command("git", "log", "-1", "--pretty=format:%ct")
	out, err = cmd.Output()
	if err != nil {
		return g, errors.WithStack(err)
	}
	g.CommittedAt, err = strconv.Atoi(strings.TrimSpace(string(out)))
	if err != nil {
		return g, errors.WithStack(err)
	}
	return g, nil
}

func GitSHA(path string) (string, error) {
	args := []string{"log", "-1", "--follow", "--pretty=format:%H"}
	if path != "" {
		args = append(args, path)
	}
	cmd := exec.Command("git", args...)
	out, err := cmd.Output()
	if err != nil {
		return "", errors.WithStack(err)
	}
	return strings.TrimSpace(string(out)), nil
}

var GitBlob = func(path string) (string, error) {
	sha, err := GitSHA(path)
	if err != nil {
		return "", errors.WithStack(err)
	}
	cmd := exec.Command("git", "ls-tree", sha, "--", path)
	out, err := cmd.Output()
	if err != nil {
		return "", errors.WithStack(err)
	}
	res := strings.TrimSpace(string(out))
	matches := blobRegex.FindStringSubmatch(res)
	if len(matches) == 0 {
		return "", errors.Errorf("could not find blob id for file %s in %s", path, res)
	}
	return matches[1], nil
}

func loadGitFromENV() (Git, error) {
	g := Git{
		Branch:    findVar(gitBranchVars),
		CommitSHA: findVar(gitCommitShaVars),
	}
	var err error
	g.CommittedAt, err = strconv.Atoi(findVar(gitCommittedAtVars))
	return g, err
}

var gitBranchVars = []string{"GIT_BRANCH", "APPVEYOR_REPO_BRANCH", "BRANCH_NAME", "BUILDKITE_BRANCH", "CIRCLE_BRANCH", "CI_BRANCH", "CI_BUILD_REF_NAME", "TRAVIS_BRANCH", "WERCKER_GIT_BRANCH"}

var gitCommitShaVars = []string{"GIT_COMMIT_SHA", "APPVEYOR_REPO_COMMIT", "BUILDKITE_COMMIT", "CIRCLE_SHA1", "CI_BUILD_REF", "CI_BUILD_SHA", "CI_COMMIT", "CI_COMMIT_ID", "GIT_COMMIT", "WERCKER_GIT_COMMIT"}

var gitCommittedAtVars = []string{"GIT_COMMITTED_AT", "GIT_COMMITED_AT", "CI_COMMITTED_AT", "CI_COMMITED_AT"}

var blobRegex = regexp.MustCompile(`^\d.+\s+blob\s(\w+)`)<commit_msg>improved git error messaging and have it use relative paths<commit_after>package env

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"

	"github.com/pkg/errors"
)

type Git struct {
	Branch      string `json:"branch" structs:"branch"`
	CommitSHA   string `json:"commit_sha" structs:"commit_sha"`
	CommittedAt int    `json:"committed_at" structs:"committed_at"`
}

func (g Git) String() string {
	out := &bytes.Buffer{}
	out.WriteString("GIT_BRANCH=")
	out.WriteString(g.Branch)
	out.WriteString("\nGIT_COMMIT_SHA=")
	out.WriteString(g.CommitSHA)
	out.WriteString("\nGIT_COMMITTED_AT=")
	out.WriteString(fmt.Sprint(g.CommittedAt))
	return out.String()
}

func findGitInfo() (Git, error) {
	_, err := exec.LookPath("git")
	if err != nil {
		// git isn't present, so load from ENV vars:
		return loadGitFromENV()
	}

	g := Git{}

	cmd := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD")
	cmd.Stderr = os.Stderr
	out, err := cmd.Output()
	if err != nil {
		return g, errors.WithStack(err)
	}
	g.Branch = strings.TrimSpace(string(out))

	cmd = exec.Command("git", "log", "-1", "--pretty=format:%H")
	cmd.Stderr = os.Stderr
	out, err = cmd.Output()
	if err != nil {
		return g, errors.WithStack(err)
	}
	g.CommitSHA = strings.TrimSpace(string(out))

	cmd = exec.Command("git", "log", "-1", "--pretty=format:%ct")
	cmd.Stderr = os.Stderr
	out, err = cmd.Output()
	if err != nil {
		return g, errors.WithStack(err)
	}
	g.CommittedAt, err = strconv.Atoi(strings.TrimSpace(string(out)))
	if err != nil {
		return g, errors.WithStack(err)
	}
	return g, nil
}

func GitSHA(path string) (string, error) {
	args := []string{"log", "-1", "--follow", "--pretty=format:%H"}
	if path != "" {
		if pwd, err := os.Getwd(); err == nil {
			path = strings.TrimPrefix(path, pwd)
			path = filepath.Join(".", path)
		}
		args = append(args, path)
	}
	cmd := exec.Command("git", args...)
	cmd.Stderr = os.Stderr
	out, err := cmd.Output()
	if err != nil {
		return "", errors.WithStack(err)
	}
	return strings.TrimSpace(string(out)), nil
}

var GitBlob = func(path string) (string, error) {
	sha, err := GitSHA(path)
	if err != nil {
		return "", errors.WithStack(err)
	}
	cmd := exec.Command("git", "ls-tree", sha, "--", path)
	cmd.Stderr = os.Stderr
	out, err := cmd.Output()
	if err != nil {
		return "", errors.WithStack(err)
	}
	res := strings.TrimSpace(string(out))
	matches := blobRegex.FindStringSubmatch(res)
	if len(matches) == 0 {
		return "", errors.Errorf("could not find blob id for file %s in %s", path, res)
	}
	return matches[1], nil
}

func loadGitFromENV() (Git, error) {
	g := Git{
		Branch:    findVar(gitBranchVars),
		CommitSHA: findVar(gitCommitShaVars),
	}
	var err error
	g.CommittedAt, err = strconv.Atoi(findVar(gitCommittedAtVars))
	return g, err
}

var gitBranchVars = []string{"GIT_BRANCH", "APPVEYOR_REPO_BRANCH", "BRANCH_NAME", "BUILDKITE_BRANCH", "CIRCLE_BRANCH", "CI_BRANCH", "CI_BUILD_REF_NAME", "TRAVIS_BRANCH", "WERCKER_GIT_BRANCH"}

var gitCommitShaVars = []string{"GIT_COMMIT_SHA", "APPVEYOR_REPO_COMMIT", "BUILDKITE_COMMIT", "CIRCLE_SHA1", "CI_BUILD_REF", "CI_BUILD_SHA", "CI_COMMIT", "CI_COMMIT_ID", "GIT_COMMIT", "WERCKER_GIT_COMMIT"}

var gitCommittedAtVars = []string{"GIT_COMMITTED_AT", "GIT_COMMITED_AT", "CI_COMMITTED_AT", "CI_COMMITED_AT"}

var blobRegex = regexp.MustCompile(`^\d.+\s+blob\s(\w+)`)
{'fraction_non_alphanumeric': 0.17972636815920398, 'fraction_numerical': 0.0018656716417910447, 'mean_word_length': 4.68788682581786, 'pattern_counts': {'":': 0, '<': 3, '<?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': '5338853', 'n_tokens_mistral': 2618, 'n_tokens_neox': 2570, 'n_words': 530}