// 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 }
// 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) }
// 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} }