Beispiel #1
0
// LocalConfigFileAbsolutePath returns the absolute path
// of the local configuration directory.
func LocalConfigDirectoryAbsolutePath() (string, error) {
	root, err := gitutil.RepositoryRootAbsolutePath()
	if err != nil {
		return "", err
	}
	return filepath.Join(root, LocalConfigDirname), nil
}
Beispiel #2
0
// Check whether SalsaFlow git hook is used. Prompts user to install our hook if it isn't.
//
// When the force argument is set to true, the hook is replaced when though the version matches.
func CheckAndUpsert(hookType HookType, force bool) error {
	// Declade some variables so that we can use goto.
	var confirmed bool

	// Ping the git hook with our secret argument.
	repoRoot, err := gitutil.RepositoryRootAbsolutePath()
	if err != nil {
		return err
	}

	hookDestPath := filepath.Join(repoRoot, ".git", "hooks", string(hookType))

	// Try to get the hook version.
	stdout, _, _ := shell.Run(hookDestPath, "-"+versionFlag)

	// In case the versions match, we are done here (unless force).
	installedVersion, err := version.Parse(strings.TrimSpace(stdout.String()))
	if !force && installedVersion != nil && installedVersion.String() == metadata.Version {
		return nil
	}

	// Get the hook executable absolute path. It's supposed to be installed
	// in the same directory as the salsaflow executable itself.
	task := "Get the executable folder absolute path"
	binDir, err := osext.ExecutableFolder()
	if err != nil {
		return errs.NewError(task, err)
	}
	hookExecutable := filepath.Join(binDir, getHookFileName(hookType))

	// Check whether there is a hook already present in the repository.
	// If there is no hook or there is a SalsaFlow hook returning a different version string,
	// we don't have to ask the user, we can just install the hook.
	task = fmt.Sprintf("Check whether there is a git %v hook already installed", hookType)
	if _, err := os.Stat(hookDestPath); err != nil {
		if os.IsNotExist(err) {
			return copyHook(hookType, hookExecutable, hookDestPath)
		}
		return errs.NewError(task, err)
	}
	if installedVersion != nil || force {
		return copyHook(hookType, hookExecutable, hookDestPath)
	}

	// Prompt the user to confirm the SalsaFlow git commit-task hook.
	task = fmt.Sprintf("Prompt the user to confirm the %v hook", hookType)
	confirmed, err = prompt.Confirm(`
I need my own git ` + string(hookType) + ` hook to be placed in the repository.
Shall I create or replace your current ` + string(hookType) + ` hook?`)
	fmt.Println()
	if err != nil {
		return errs.NewError(task, err)
	}
	if !confirmed {
		// User stubbornly refuses to let us overwrite their webhook.
		// Inform the init has failed and let them do their thing.
		fmt.Printf(`I need the hook in order to do my job!

Please make sure the executable located at

  %v

runs as your `+string(hookType)+` hook and run me again!

`, hookExecutable)
		return errs.NewError(task, fmt.Errorf("SalsaFlow git %v hook not detected", hookType))
	}

	return copyHook(hookType, hookExecutable, hookDestPath)
}
Beispiel #3
0
// Commands returns *exec.Command for the given script name and args.
func Command(scriptName string, args ...string) (*exec.Cmd, error) {
	// Make sure this is a script name, not a path.
	if strings.Contains(scriptName, "/") {
		return nil, fmt.Errorf("not a script name: %v", scriptName)
	}

	// Get the list of available scripts.
	root, err := gitutil.RepositoryRootAbsolutePath()
	if err != nil {
		return nil, err
	}

	scriptsDirPath := filepath.Join(root, config.LocalConfigDirname, ScriptDirname)

	scriptsDir, err := os.Open(scriptsDirPath)
	if err != nil {
		return nil, err
	}
	defer scriptsDir.Close()

	scripts, err := scriptsDir.Readdirnames(-1)
	if err != nil {
		return nil, err
	}

	// Choose the first available script for the given script name.
	// Return a command for that script based on the file extension and platform.
	currentPlatformId := runners.ParsePlatform(runtime.GOOS)

	for _, script := range scripts {
		// To understand the loop:
		//   script     = ${base}.${ext}
		//   base       = ${name}_${platform}
		//   (=> script = ${name}_${platform}.${ext})

		// Get the file extension.
		ext := filepath.Ext(script)
		if ext == "" {
			continue
		}

		// Get the file base, i.e. the filename without the file extension.
		base := script[:len(script)-len(ext)]

		// In case the whole base matches, this is a cross-platform script and we are done.
		// Otherwise we have to parse the base further and decide what to do.
		var platformId runners.Platform
		if base == scriptName {
			platformId = currentPlatformId
		} else {
			// Split the base.
			parts := strings.Split(base, "_")

			// Make sure the platform matches the current platform.
			platform := parts[len(parts)-1]
			platformId = runners.ParsePlatform(platform)
			if platformId != currentPlatformId {
				continue
			}

			// Make sure the name matches the requested script name.
			name := base[:len(base)-len(platform)-1]
			if name != scriptName {
				continue
			}
		}

		// Get the runner for the given file extension.
		// ext contains the dot, which we need to drop.
		runner := runners.GetRunner(ext[1:], platformId)
		if runner == nil {
			continue
		}
		cmd := runner.NewCommand(filepath.Join(scriptsDirPath, script))
		cmd.Args = append(cmd.Args, args...)
		cmd.Dir = root
		return cmd, nil
	}

	return nil, &ErrNotFound{scriptName}
}