func main() { defer glog.Flush() diffConfig := &dm.DifferencerConfig{} diffConfig.CreateFlags(flag.CommandLine) flag.Parse() // Scan the arguments list goioutil.InitGOMAXPROCS() cfg := spew.NewDefaultConfig() cfg.SortKeys = true cfg.Dump("Spew config:\n", cfg) cmd := filepath.Base(os.Args[0]) glog.V(1).Infoln("cmd =", cmd) ctrl := GoRtnCntrl{ stopCh: make(chan bool), wg: &sync.WaitGroup{}, } var stats dm.LeadingWhitespaceStatistics fileCh := make(chan *dm.File, runtime.NumCPU()) ctrl.wg.Add(1) go collectStats(fileCh, &stats, ctrl) textFileCh := make(chan string, runtime.NumCPU()) ctrl.wg.Add(1) go readAllFiles(runtime.NumCPU(), textFileCh, fileCh, ctrl) ftiCtrl := ctrl ftiCtrl.wg = &sync.WaitGroup{} ftiMgr := MakeFileTypeInfoManager(ftiCtrl) ctrl.wg.Add(1) expandArgsToTextFiles(flag.Args(), textFileCh, runtime.NumCPU(), ftiMgr, ctrl) // Wait for the main pipeline to complete. ctrl.wg.Wait() close(ctrl.stopCh) // Wait for the file type info manager to shutdown. ftiCtrl.wg.Wait() fmt.Println("Non-text extensions discovered:") cfg.Dump(ftiMgr.nonTextTypes) fmt.Println("Text extensions discovered:") cfg.Dump(ftiMgr.textTypes) fmt.Println() fmt.Println() stats.ComputeFractions() fmt.Println("Whitespace info:") cfg.Dump(stats) }
// Must be single threaded (w.r.t. stats access). func collectStats(fileCh chan *dm.File, stats *dm.LeadingWhitespaceStatistics, ctrl GoRtnCntrl) { defer ctrl.wg.Done() for { select { case <-ctrl.stopCh: return case file, ok := <-fileCh: if !ok { return } stats.AddFile(file) } } }