package main import ( "fmt" "os" "os/exec" "path/filepath" "sort" "strings" "github.com/hhatto/gocloc" ) func main() { out, err := exec.Command("git", "ls-files").Output() if err != nil { fmt.Fprintf(os.Stderr, "git ls-files: %v\n", err) os.Exit(1) } allFiles := strings.Split(strings.TrimSpace(string(out)), "\n") var files []string for _, f := range allFiles { f = strings.TrimSpace(f) if f == "" { continue } norm := filepath.ToSlash(f) if strings.HasPrefix(norm, "vendor/") || strings.Contains(norm, "/vendor/") { continue } files = append(files, f) } opts := gocloc.NewClocOptions() langs := gocloc.NewDefinedLanguages() // gocloc maps "TypeScript" instead of "ts" in its Exts table extAliases := map[string]string{ "ts": "TypeScript", } total := gocloc.NewLanguage("TOTAL", []string{}, [][]string{{"", ""}}) languages := make(map[string]*gocloc.Language) clocFiles := make(map[string]*gocloc.ClocFile) for _, file := range files { file = strings.TrimSpace(file) if file == "" { continue } ext := filepath.Ext(file) if ext == "" { continue } ext = ext[1:] langName, ok := gocloc.Exts[ext] if !ok { langName, ok = extAliases[ext] if !ok { continue } } def := langs.Langs[langName] if def == nil { continue } cf := gocloc.AnalyzeFile(file, def, opts) cf.Lang = langName clocFiles[file] = cf if _, exists := languages[langName]; !exists { languages[langName] = gocloc.NewLanguage(def.Name, []string{}, [][]string{{"", ""}}) } lang := languages[langName] lang.Files = append(lang.Files, file) lang.Code += cf.Code lang.Comments += cf.Comments lang.Blanks += cf.Blanks total.Code += cf.Code total.Comments += cf.Comments total.Blanks += cf.Blanks } type row struct { Name string Files int Code int32 Comments int32 Blanks int32 } var rows []row for name, lang := range languages { rows = append(rows, row{ Name: name, Files: len(lang.Files), Code: lang.Code, Comments: lang.Comments, Blanks: lang.Blanks, }) } sort.Slice(rows, func(i, j int) bool { return rows[i].Code > rows[j].Code }) divider := "-------------------------------------------------------------------------------" fmt.Println(divider) fmt.Printf("%-25s %10s %10s %10s %10s\n", "Language", "Files", "Code", "Comment", "Blank") fmt.Println(divider) for _, r := range rows { fmt.Printf("%-25s %10d %10d %10d %10d\n", r.Name, r.Files, r.Code, r.Comments, r.Blanks) } fmt.Println(divider) fmt.Printf("%-25s %10d %10d %10d %10d\n", "Total", len(clocFiles), total.Code, total.Comments, total.Blanks, ) fmt.Println(divider) }