예제 #1
0
func worker(writeit bool, debug bool, mode string, files <-chan string, results chan<- int) {
	fails := 0
	for filename := range files {
		// ignore directories
		if f, err := os.Stat(filename); err != nil || f.IsDir() {
			continue
		}

		raw, err := ioutil.ReadFile(filename)
		if err != nil {
			log.Printf("Unable to read %q: %s", filename, err)
			continue
		}
		orig := string(raw)
		var updated string

		// GROSS
		isGolang := strings.HasSuffix(filename, ".go")
		if mode == "go" || (mode == "auto" && isGolang) {
			updated = misspell.ReplaceGo(orig, debug)
		} else if debug {
			updated = misspell.ReplaceDebug(orig)
		} else {
			updated = misspell.Replace(orig)
		}

		updated, changes := misspell.DiffLines(orig, updated)
		if len(changes) == 0 {
			continue
		}
		for _, diff := range changes {
			// add in filename
			diff.Filename = filename

			// output can be done by doing multiple goroutines
			// and can clobber os.Stdout.
			//
			// the log package can be used simultaneously from multiple goroutines
			var output bytes.Buffer
			if writeit {
				defaultWrite.Execute(&output, diff)
			} else {
				defaultRead.Execute(&output, diff)
			}

			// goroutine-safe print to os.Stdout
			stdout.Println(output.String())
		}

		if writeit {
			ioutil.WriteFile(filename, []byte(updated), 0)
		}
	}
	results <- fails
}
예제 #2
0
func main() {
	quiet := flag.Bool("q", false, "quiet")
	workers := flag.Int("j", 0, "Number of workers, 0 = number of CPUs")
	writeit := flag.Bool("w", false, "Overwrite file with corrections (default is just to display)")
	format := flag.String("f", "", "use Golang template for log message")
	ignores := flag.String("i", "", "ignore the following corrections, comma separated")
	mode := flag.String("source", "auto", "Source mode: auto=guess, go=golang source, text=plain or markdown-like text")
	debug := flag.Bool("debug", false, "Debug matching, very slow")
	flag.Parse()

	switch *mode {
	case "auto":
	case "go":
	case "text":
	default:
		log.Fatalf("Mode must be one of auto=guess, go=golang source, text=plain or markdown-like text")
	}
	if len(*format) > 0 {
		t, err := template.New("custom").Parse(*format)
		if err != nil {
			log.Fatalf("Unable to compile log format: %s", err)
		}
		defaultWrite = t
		defaultRead = t
	}
	if len(*ignores) > 0 {
		err := misspell.Ignore(strings.Split(*ignores, ","))
		if err != nil {
			log.Fatalf("unable to process ignores: %s", err)
		}
	}
	if *workers < 0 {
		log.Fatalf("-j must >= 0")
	}
	if *workers == 0 {
		*workers = runtime.NumCPU()
	}

	if *debug {
		*workers = 1
	}
	args := flag.Args()

	// unix style pipes: different output module
	// stdout: output of corrected text
	// stderr: output of log lines
	if len(args) == 0 {
		raw, err := ioutil.ReadAll(os.Stdin)
		if err != nil {
			log.Fatalf("Unable to read stdin")
		}
		orig := string(raw)
		var updated string
		if *mode == "go" {
			updated = misspell.ReplaceGo(orig, *debug)
		} else if *debug {
			updated = misspell.ReplaceDebug(orig)
		} else {
			updated = misspell.Replace(orig)
		}
		updated, changes := misspell.DiffLines(orig, updated)
		if !*quiet {
			for _, diff := range changes {
				diff.Filename = "stdin"
				if *writeit {
					defaultWrite.Execute(os.Stderr, diff)
				} else {
					defaultRead.Execute(os.Stderr, diff)
				}
				os.Stderr.Write([]byte("\n"))
			}
		}
		if *writeit {
			os.Stdout.Write([]byte(updated))
		}
		return
	}

	c := make(chan string, len(args))
	results := make(chan int, *workers)

	for i := 0; i < *workers; i++ {
		go worker(*writeit, *debug, *mode, c, results)
	}

	for _, filename := range args {
		c <- filename
	}
	close(c)

	count := 0
	for i := 0; i < *workers; i++ {
		changed := <-results
		count += changed
	}
	if count != 0 {
		// log.Printf("Got %d", count)
		// error
		os.Exit(1)
	}
}