github.com/andrewhsu/cli/v2@v2.0.1-0.20210910131313-d4b4061f5b89/pkg/cmd/alias/expand/expand.go (about)

     1  package expand
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os/exec"
     7  	"regexp"
     8  	"runtime"
     9  	"strings"
    10  
    11  	"github.com/andrewhsu/cli/v2/internal/config"
    12  	"github.com/andrewhsu/cli/v2/pkg/findsh"
    13  	"github.com/google/shlex"
    14  )
    15  
    16  // ExpandAlias processes argv to see if it should be rewritten according to a user's aliases. The
    17  // second return value indicates whether the alias should be executed in a new shell process instead
    18  // of running gh itself.
    19  func ExpandAlias(cfg config.Config, args []string, findShFunc func() (string, error)) (expanded []string, isShell bool, err error) {
    20  	if len(args) < 2 {
    21  		// the command is lacking a subcommand
    22  		return
    23  	}
    24  	expanded = args[1:]
    25  
    26  	aliases, err := cfg.Aliases()
    27  	if err != nil {
    28  		return
    29  	}
    30  
    31  	expansion, ok := aliases.Get(args[1])
    32  	if !ok {
    33  		return
    34  	}
    35  
    36  	if strings.HasPrefix(expansion, "!") {
    37  		isShell = true
    38  		if findShFunc == nil {
    39  			findShFunc = findSh
    40  		}
    41  		shPath, shErr := findShFunc()
    42  		if shErr != nil {
    43  			err = shErr
    44  			return
    45  		}
    46  
    47  		expanded = []string{shPath, "-c", expansion[1:]}
    48  
    49  		if len(args[2:]) > 0 {
    50  			expanded = append(expanded, "--")
    51  			expanded = append(expanded, args[2:]...)
    52  		}
    53  
    54  		return
    55  	}
    56  
    57  	extraArgs := []string{}
    58  	for i, a := range args[2:] {
    59  		if !strings.Contains(expansion, "$") {
    60  			extraArgs = append(extraArgs, a)
    61  		} else {
    62  			expansion = strings.ReplaceAll(expansion, fmt.Sprintf("$%d", i+1), a)
    63  		}
    64  	}
    65  	lingeringRE := regexp.MustCompile(`\$\d`)
    66  	if lingeringRE.MatchString(expansion) {
    67  		err = fmt.Errorf("not enough arguments for alias: %s", expansion)
    68  		return
    69  	}
    70  
    71  	var newArgs []string
    72  	newArgs, err = shlex.Split(expansion)
    73  	if err != nil {
    74  		return
    75  	}
    76  
    77  	expanded = append(newArgs, extraArgs...)
    78  	return
    79  }
    80  
    81  func findSh() (string, error) {
    82  	shPath, err := findsh.Find()
    83  	if err != nil {
    84  		if errors.Is(err, exec.ErrNotFound) {
    85  			if runtime.GOOS == "windows" {
    86  				return "", errors.New("unable to locate sh to execute the shell alias with. The sh.exe interpreter is typically distributed with Git for Windows.")
    87  			}
    88  			return "", errors.New("unable to locate sh to execute shell alias with")
    89  		}
    90  		return "", err
    91  	}
    92  	return shPath, nil
    93  }