github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/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/ungtb10d/cli/v2/internal/config"
    12  	"github.com/ungtb10d/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 := cfg.Aliases()
    27  
    28  	expansion, getErr := aliases.Get(args[1])
    29  	if getErr != nil {
    30  		return
    31  	}
    32  
    33  	if strings.HasPrefix(expansion, "!") {
    34  		isShell = true
    35  		if findShFunc == nil {
    36  			findShFunc = findSh
    37  		}
    38  		shPath, shErr := findShFunc()
    39  		if shErr != nil {
    40  			err = shErr
    41  			return
    42  		}
    43  
    44  		expanded = []string{shPath, "-c", expansion[1:]}
    45  
    46  		if len(args[2:]) > 0 {
    47  			expanded = append(expanded, "--")
    48  			expanded = append(expanded, args[2:]...)
    49  		}
    50  
    51  		return
    52  	}
    53  
    54  	extraArgs := []string{}
    55  	for i, a := range args[2:] {
    56  		if !strings.Contains(expansion, "$") {
    57  			extraArgs = append(extraArgs, a)
    58  		} else {
    59  			expansion = strings.ReplaceAll(expansion, fmt.Sprintf("$%d", i+1), a)
    60  		}
    61  	}
    62  	lingeringRE := regexp.MustCompile(`\$\d`)
    63  	if lingeringRE.MatchString(expansion) {
    64  		err = fmt.Errorf("not enough arguments for alias: %s", expansion)
    65  		return
    66  	}
    67  
    68  	var newArgs []string
    69  	newArgs, err = shlex.Split(expansion)
    70  	if err != nil {
    71  		return
    72  	}
    73  
    74  	expanded = append(newArgs, extraArgs...)
    75  	return
    76  }
    77  
    78  func findSh() (string, error) {
    79  	shPath, err := findsh.Find()
    80  	if err != nil {
    81  		if errors.Is(err, exec.ErrNotFound) {
    82  			if runtime.GOOS == "windows" {
    83  				return "", errors.New("unable to locate sh to execute the shell alias with. The sh.exe interpreter is typically distributed with Git for Windows.")
    84  			}
    85  			return "", errors.New("unable to locate sh to execute shell alias with")
    86  		}
    87  		return "", err
    88  	}
    89  	return shPath, nil
    90  }