Exemple #1
0
// cmdInstall first calls cmdInstallPrereq() then install the
// .git/hooks/pre-commit and pre-push hooks.
//
// Silently ignore installing the hooks when running under a CI. In
// particular, circleci.com doesn't create the directory .git/hooks.
func (a *application) cmdInstall(repo scm.ReadOnlyRepo, modes []checks.Mode, noUpdate bool, prereqReady *sync.WaitGroup) (err error) {
	errCh := make(chan error, 1)
	go func() {
		defer prereqReady.Done()
		errCh <- a.cmdInstallPrereq(repo, modes, noUpdate)
	}()

	defer func() {
		if err2 := <-errCh; err == nil {
			err = err2
		}
	}()

	if checks.IsContinuousIntegration() {
		log.Printf("Running under CI; not installing hooks")
		return nil
	}
	log.Printf("Installing hooks")
	hookDir, err2 := repo.HookPath()
	if err2 != nil {
		return err2
	}
	for _, t := range []string{"pre-commit", "pre-push"} {
		// Always remove hook first if it exists, in case it's a symlink.
		p := filepath.Join(hookDir, t)
		_ = os.Remove(p)
		if err = ioutil.WriteFile(p, []byte(fmt.Sprintf(hookContent, t)), 0777); err != nil {
			return err
		}
	}
	log.Printf("Installation done")
	return nil
}
Exemple #2
0
// mainImpl implements pcg.
func mainImpl() error {
	a := application{}

	exec, args := os.Args[0], os.Args[1:]
	var commands, flags []string
	for i, arg := range args {
		if strings.HasPrefix(arg, "-") {
			flags = args[i:]
			break
		}
		commands = append(commands, arg)
	}

	if len(commands) == 0 {
		if checks.IsContinuousIntegration() {
			commands = []string{"run-hook", "continuous-integration"}
		} else {
			commands = []string{"installrun"}
		}
	}

	fs := flag.NewFlagSet(exec, flag.ExitOnError)
	verboseFlag := fs.Bool("v", checks.IsContinuousIntegration() || os.Getenv("VERBOSE") != "", "enables verbose logging output")
	allFlag := fs.Bool("a", false, "runs checks as if all files had been modified")
	againstFlag := fs.String("r", "", "runs checks on files modified since this revision, as evaluated by your scm repo")
	noUpdateFlag := fs.Bool("n", false, "disallow using go get even if a prerequisite is missing; bail out instead")
	configPathFlag := fs.String("c", "pre-commit-go.yml", "file name of the config to load")
	modeFlag := fs.String("m", "", "comma separated list of modes to process; default depends on the command")
	fs.IntVar(&a.maxConcurrent, "C", 0, "maximum number of concurrent processes")
	fs.Parse(flags)

	if *allFlag {
		if *againstFlag != "" {
			return errors.New("-a can't be used with -r")
		}
		*againstFlag = string(scm.Initial)
	}

	log.SetFlags(log.Lmicroseconds)
	if !*verboseFlag {
		log.SetOutput(ioutil.Discard)
	}

	modes, err := processModes(*modeFlag)
	if err != nil {
		return err
	}

	cwd, err := os.Getwd()
	if err != nil {
		return err
	}
	repo, err := scm.GetRepo(cwd, "")
	if err != nil {
		return err
	}

	var configPath string
	configPath, a.config = loadConfig(repo, *configPathFlag)
	log.Printf("config: %s", configPath)
	if a.maxConcurrent > 0 {
		log.Printf("using %d maximum concurrent goroutines", a.maxConcurrent)
		a.config.MaxConcurrent = a.maxConcurrent
	}

	switch cmd := commands[0]; cmd {
	case "help", "-help", "-h":
		cmd = "help"
		if *allFlag != false {
			return fmt.Errorf("-a can't be used with %s", cmd)
		}
		if *againstFlag != "" {
			return fmt.Errorf("-r can't be used with %s", cmd)
		}
		if *noUpdateFlag != false {
			return fmt.Errorf("-n can't be used with %s", cmd)
		}
		if *configPathFlag != "pre-commit-go.yml" {
			return fmt.Errorf("-m can't be used with %s", cmd)
		}
		if *modeFlag != "" {
			return fmt.Errorf("-m can't be used with %s", cmd)
		}
		b := &bytes.Buffer{}
		fs.SetOutput(b)
		fs.PrintDefaults()
		return a.cmdHelp(repo, b.String())

	case "info":
		if *allFlag != false {
			return fmt.Errorf("-a can't be used with %s", cmd)
		}
		if *againstFlag != "" {
			return fmt.Errorf("-r can't be used with %s", cmd)
		}
		if *noUpdateFlag != false {
			return fmt.Errorf("-n can't be used with %s", cmd)
		}
		return a.cmdInfo(repo, modes, configPath)

	case "install", "i":
		cmd = "install"
		if *allFlag != false {
			return fmt.Errorf("-a can't be used with %s", cmd)
		}
		if *againstFlag != "" {
			return fmt.Errorf("-r can't be used with %s", cmd)
		}
		if len(modes) == 0 {
			modes = checks.AllModes
		}
		var prereqReady sync.WaitGroup
		prereqReady.Add(1)
		return a.cmdInstall(repo, modes, *noUpdateFlag, &prereqReady)

	case "installrun":
		if len(modes) == 0 {
			modes = []checks.Mode{checks.PrePush}
		}
		// Start running all checks that do not have a prerequisite before
		// installation is completed.
		var prereqReady sync.WaitGroup
		prereqReady.Add(1)
		errCh := make(chan error, 1)
		go func() {
			errCh <- a.cmdInstall(repo, modes, *noUpdateFlag, &prereqReady)
		}()
		err := a.cmdRun(repo, modes, *againstFlag, &prereqReady)
		if err2 := <-errCh; err2 != nil {
			return err2
		}
		return err

	case "prereq", "p":
		cmd = "prereq"
		if *allFlag != false {
			return fmt.Errorf("-a can't be used with %s", cmd)
		}
		if *againstFlag != "" {
			return fmt.Errorf("-r can't be used with %s", cmd)
		}
		if len(modes) == 0 {
			modes = checks.AllModes
		}
		return a.cmdInstallPrereq(repo, modes, *noUpdateFlag)

	case "run", "r":
		cmd = "run"
		if *noUpdateFlag != false {
			return fmt.Errorf("-n can't be used with %s", cmd)
		}
		if len(modes) == 0 {
			modes = []checks.Mode{checks.PrePush}
		}
		return a.cmdRun(repo, modes, *againstFlag, &sync.WaitGroup{})

	case "run-hook":
		if modes != nil {
			return fmt.Errorf("-m can't be used with %s", cmd)
		}
		if *allFlag != false {
			return fmt.Errorf("-a can't be used with %s", cmd)
		}
		if *againstFlag != "" {
			return fmt.Errorf("-r can't be used with %s", cmd)
		}

		if len(commands) < 2 {
			return errors.New("run-hook is only meant to be used by hooks")
		}
		return a.cmdRunHook(repo, commands[1], *noUpdateFlag)

	case "version":
		if modes != nil {
			return fmt.Errorf("-m can't be used with %s", cmd)
		}
		if *allFlag != false {
			return fmt.Errorf("-a can't be used with %s", cmd)
		}
		if *againstFlag != "" {
			return fmt.Errorf("-r can't be used with %s", cmd)
		}
		if *noUpdateFlag != false {
			return fmt.Errorf("-n can't be used with %s", cmd)
		}
		fmt.Println(version)
		return nil

	case "writeconfig", "w":
		if modes != nil {
			return fmt.Errorf("-m can't be used with %s", cmd)
		}
		if *allFlag != false {
			return fmt.Errorf("-a can't be used with %s", cmd)
		}
		if *againstFlag != "" {
			return fmt.Errorf("-r can't be used with %s", cmd)
		}
		// Note that in that case, configPath is ignored and not overritten.
		return a.cmdWriteConfig(repo, *configPathFlag)

	default:
		return fmt.Errorf("unknown command %q, try 'help'", cmd)
	}
}
Exemple #3
0
// mainImpl implements pcg.
func mainImpl() error {
	if len(os.Args) == 1 {
		if checks.IsContinuousIntegration() {
			os.Args = append(os.Args, "run-hook", "continuous-integration")
		} else {
			os.Args = append(os.Args, "installrun")
		}
	}

	cmd := os.Args[1]
	copy(os.Args[1:], os.Args[2:])
	os.Args = os.Args[:len(os.Args)-1]

	verboseFlag := flag.Bool("v", checks.IsContinuousIntegration() || os.Getenv("VERBOSE") != "", "enables verbose logging output")
	allFlag := flag.Bool("a", false, "runs checks as if all files had been modified")
	againstFlag := flag.String("r", "", "runs checks on files modified since this revision, as evaluated by your scm repo")
	noUpdateFlag := flag.Bool("n", false, "disallow using go get even if a prerequisite is missing; bail out instead")
	configPathFlag := flag.String("c", "pre-commit-go.yml", "file name of the config to load")
	modeFlag := flag.String("m", "", "coma separated list of modes to process; default depends on the command")
	flag.Parse()

	if *allFlag {
		if *againstFlag != "" {
			return errors.New("-a can't be used with -r")
		}
		*againstFlag = string(scm.GitInitialCommit)
	}

	log.SetFlags(log.Lmicroseconds)
	if !*verboseFlag {
		log.SetOutput(ioutil.Discard)
	}

	modes, err := processModes(*modeFlag)
	if err != nil {
		return err
	}

	cwd, err := os.Getwd()
	if err != nil {
		return err
	}
	repo, err := scm.GetRepo(cwd, "")
	if err != nil {
		return err
	}

	configPath, config := loadConfig(repo, *configPathFlag)
	log.Printf("config: %s", configPath)

	switch cmd {
	case "help", "-help", "-h":
		cmd = "help"
		if *allFlag != false {
			return fmt.Errorf("-a can't be used with %s", cmd)
		}
		if *againstFlag != "" {
			return fmt.Errorf("-r can't be used with %s", cmd)
		}
		if *noUpdateFlag != false {
			return fmt.Errorf("-n can't be used with %s", cmd)
		}
		if *configPathFlag != "pre-commit-go.yml" {
			return fmt.Errorf("-m can't be used with %s", cmd)
		}
		if *modeFlag != "" {
			return fmt.Errorf("-m can't be used with %s", cmd)
		}
		b := &bytes.Buffer{}
		flag.CommandLine.SetOutput(b)
		flag.CommandLine.PrintDefaults()
		return cmdHelp(repo, config, b.String())

	case "info":
		if *allFlag != false {
			return fmt.Errorf("-a can't be used with %s", cmd)
		}
		if *againstFlag != "" {
			return fmt.Errorf("-r can't be used with %s", cmd)
		}
		if *noUpdateFlag != false {
			return fmt.Errorf("-n can't be used with %s", cmd)
		}
		return cmdInfo(repo, config, modes, configPath)

	case "install", "i":
		cmd = "install"
		if *allFlag != false {
			return fmt.Errorf("-a can't be used with %s", cmd)
		}
		if *againstFlag != "" {
			return fmt.Errorf("-r can't be used with %s", cmd)
		}
		if len(modes) == 0 {
			modes = checks.AllModes
		}
		var prereqReady sync.WaitGroup
		prereqReady.Add(1)
		return cmdInstall(repo, config, modes, *noUpdateFlag, &prereqReady)

	case "installrun":
		if len(modes) == 0 {
			modes = []checks.Mode{checks.PrePush}
		}
		// Start running all checks that do not have a prerequisite before
		// installation is completed.
		var prereqReady sync.WaitGroup
		prereqReady.Add(1)
		errCh := make(chan error, 1)
		go func() {
			errCh <- cmdInstall(repo, config, modes, *noUpdateFlag, &prereqReady)
		}()
		err := cmdRun(repo, config, modes, *againstFlag, &prereqReady)
		if err2 := <-errCh; err2 != nil {
			return err2
		}
		return err

	case "prereq", "p":
		cmd = "prereq"
		if *allFlag != false {
			return fmt.Errorf("-a can't be used with %s", cmd)
		}
		if *againstFlag != "" {
			return fmt.Errorf("-r can't be used with %s", cmd)
		}
		if len(modes) == 0 {
			modes = checks.AllModes
		}
		return cmdInstallPrereq(repo, config, modes, *noUpdateFlag)

	case "run", "r":
		cmd = "run"
		if *noUpdateFlag != false {
			return fmt.Errorf("-n can't be used with %s", cmd)
		}
		if len(modes) == 0 {
			modes = []checks.Mode{checks.PrePush}
		}
		return cmdRun(repo, config, modes, *againstFlag, &sync.WaitGroup{})

	case "run-hook":
		if modes != nil {
			return fmt.Errorf("-m can't be used with %s", cmd)
		}
		if *allFlag != false {
			return fmt.Errorf("-a can't be used with %s", cmd)
		}
		if *againstFlag != "" {
			return fmt.Errorf("-r can't be used with %s", cmd)
		}
		if flag.NArg() != 1 {
			return errors.New("run-hook is only meant to be used by hooks")
		}
		return cmdRunHook(repo, config, flag.Arg(0), *noUpdateFlag)

	case "version":
		if modes != nil {
			return fmt.Errorf("-m can't be used with %s", cmd)
		}
		if *allFlag != false {
			return fmt.Errorf("-a can't be used with %s", cmd)
		}
		if *againstFlag != "" {
			return fmt.Errorf("-r can't be used with %s", cmd)
		}
		if *noUpdateFlag != false {
			return fmt.Errorf("-n can't be used with %s", cmd)
		}
		fmt.Println(version)
		return nil

	case "writeconfig", "w":
		if modes != nil {
			return fmt.Errorf("-m can't be used with %s", cmd)
		}
		if *allFlag != false {
			return fmt.Errorf("-a can't be used with %s", cmd)
		}
		if *againstFlag != "" {
			return fmt.Errorf("-r can't be used with %s", cmd)
		}
		// Note that in that case, configPath is ignored and not overritten.
		return cmdWriteConfig(repo, config, *configPathFlag)

	default:
		return errors.New("unknown command, try 'help'")
	}
}