<commit_before>package authorship

import (
	"fmt"
	"log"
	"sort"
	"time"

	"github.com/sourcegraph/go-nnz/nnz"

	"sourcegraph.com/sourcegraph/srcgraph/config"
	"sourcegraph.com/sourcegraph/srcgraph/graph"
	"sourcegraph.com/sourcegraph/srcgraph/grapher2"
	"sourcegraph.com/sourcegraph/srcgraph/repo"
	"sourcegraph.com/sourcegraph/srcgraph/vcsutil"
)

func ComputeSourceUnit(g *grapher2.Output, b *vcsutil.BlameOutput, c *config.Repository) (*SourceUnitOutput, error) {
	var getAuthors = func(file string, start, end int) (map[string]*AuthorshipInfo, map[string]int, error) {
		hunks, present := b.HunkMap[file]
		if !present {
			log.Printf("No hunk for file %q", file)
			return nil, nil, nil
		}

		authorsByEmail := make(map[string]*AuthorshipInfo)
		charsByEmail := make(map[string]int)
		for _, h := range hunks {
			if h.CharStart <= end && h.CharEnd > start {
				commit, present := b.CommitMap[h.CommitID]
				if !present {
					return nil, nil, fmt.Errorf("no commit ID %q for hunk %+v", h.CommitID, h)
				}

				nchars := min(end, h.CharEnd) - max(start, h.CharStart)
				if a, present := authorsByEmail[commit.Author.Email]; present {
					// user contributed to 2+ hunks for this
					if a.LastCommitDate.Before(commit.AuthorDate) {
						// take most recent author date
						a.LastCommitDate = commit.AuthorDate.In(time.UTC)
						a.LastCommitID = commit.ID
					}
					charsByEmail[commit.Author.Email] += nchars
				} else {
					authorsByEmail[commit.Author.Email] = &AuthorshipInfo{
						AuthorEmail:    commit.Author.Email,
						LastCommitDate: commit.AuthorDate.In(time.UTC),
						LastCommitID:   commit.ID,
					}
					charsByEmail[commit.Author.Email] = nchars
				}
			}
		}
		return authorsByEmail, charsByEmail, nil
	}

	var o SourceUnitOutput
	o.Symbols = make(map[graph.SymbolPath][]*SymbolAuthorship, len(g.Symbols))

	for _, sym := range g.Symbols {
		authors, chars, err := getAuthors(sym.File, sym.DefStart, sym.DefEnd)
		if err != nil {<commit_msg>dont treat lack of a commit as fatal (go stdlib fails here)<commit_after>package authorship

import (
	"log"
	"sort"
	"time"

	"github.com/sourcegraph/go-nnz/nnz"

	"sourcegraph.com/sourcegraph/srcgraph/config"
	"sourcegraph.com/sourcegraph/srcgraph/graph"
	"sourcegraph.com/sourcegraph/srcgraph/grapher2"
	"sourcegraph.com/sourcegraph/srcgraph/repo"
	"sourcegraph.com/sourcegraph/srcgraph/vcsutil"
)

func ComputeSourceUnit(g *grapher2.Output, b *vcsutil.BlameOutput, c *config.Repository) (*SourceUnitOutput, error) {
	var getAuthors = func(file string, start, end int) (map[string]*AuthorshipInfo, map[string]int, error) {
		hunks, present := b.HunkMap[file]
		if !present {
			log.Printf("No hunk for file %q", file)
			return nil, nil, nil
		}

		authorsByEmail := make(map[string]*AuthorshipInfo)
		charsByEmail := make(map[string]int)
		for _, h := range hunks {
			if h.CharStart <= end && h.CharEnd > start {
				commit, present := b.CommitMap[h.CommitID]
				if !present {
					log.Printf("warning: no commit ID %q for hunk %+v in file %s", h.CommitID, h, file)
				}

				nchars := min(end, h.CharEnd) - max(start, h.CharStart)
				if a, present := authorsByEmail[commit.Author.Email]; present {
					// user contributed to 2+ hunks for this
					if a.LastCommitDate.Before(commit.AuthorDate) {
						// take most recent author date
						a.LastCommitDate = commit.AuthorDate.In(time.UTC)
						a.LastCommitID = commit.ID
					}
					charsByEmail[commit.Author.Email] += nchars
				} else {
					authorsByEmail[commit.Author.Email] = &AuthorshipInfo{
						AuthorEmail:    commit.Author.Email,
						LastCommitDate: commit.AuthorDate.In(time.UTC),
						LastCommitID:   commit.ID,
					}
					charsByEmail[commit.Author.Email] = nchars
				}
			}
		}
		return authorsByEmail, charsByEmail, nil
	}

	var o SourceUnitOutput
	o.Symbols = make(map[graph.SymbolPath][]*SymbolAuthorship, len(g.Symbols))

	for _, sym := range g.Symbols {
		authors, chars, err := getAuthors(sym.File, sym.DefStart, sym.DefEnd)
		if err != nil {
{'fraction_non_alphanumeric': 0.13072709163346613, 'fraction_numerical': 0.00149402390438247, 'mean_word_length': 3.6709302325581397, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, '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': '2842385', 'n_tokens_mistral': 1626, 'n_tokens_neox': 1405, 'n_words': 294}