github.com/mayra-cabrera/buffalo@v0.9.4-0.20170814145312-66d2e7772f11/plugins/plugins.go (about)

     1  package plugins
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  	"os"
     9  	"os/exec"
    10  	"path/filepath"
    11  	"runtime"
    12  	"strings"
    13  	"time"
    14  
    15  	"github.com/pkg/errors"
    16  )
    17  
    18  // List maps a Buffalo command to a slice of Command
    19  type List map[string]Commands
    20  
    21  // Available plugins for the `buffalo` command.
    22  // It will look in $PATH and the `./plugins` directory.
    23  //
    24  // Requirements:
    25  // * file/command must be executable
    26  // * file/command must start with `buffalo-`
    27  // * file/command must respond to `available` and return JSON of
    28  //	 plugins.Commands{}
    29  //
    30  // Caveats:
    31  // * The C:\Windows directory is excluded
    32  func Available() (List, error) {
    33  	list := List{}
    34  	paths := []string{"plugins"}
    35  	if runtime.GOOS == "windows" {
    36  		paths = append(paths, strings.Split(os.Getenv("PATH"), ";")...)
    37  	} else {
    38  		paths = append(paths, strings.Split(os.Getenv("PATH"), ":")...)
    39  	}
    40  	for _, p := range paths {
    41  		if strings.HasPrefix(strings.ToLower(p), `c:\windows`) {
    42  			continue	
    43  		}
    44  		if _, err := os.Stat(p); err != nil {
    45  			continue
    46  		}
    47  		err := filepath.Walk(p, func(path string, info os.FileInfo, err error) error {
    48  			if err != nil {
    49  				// May indicate a permissions problem with the path, skip it
    50  				return nil
    51  			}
    52  			if info.IsDir() {
    53  				return nil
    54  			}
    55  			base := filepath.Base(path)
    56  			if strings.HasPrefix(base, "buffalo-") {
    57  				commands := askBin(path)
    58  				for _, c := range commands {
    59  					bc := c.BuffaloCommand
    60  					if _, ok := list[bc]; !ok {
    61  						list[bc] = Commands{}
    62  					}
    63  					c.Binary = path
    64  					list[bc] = append(list[bc], c)
    65  				}
    66  			}
    67  			return nil
    68  		})
    69  		if err != nil {
    70  			return nil, errors.WithStack(err)
    71  		}
    72  	}
    73  	return list, nil
    74  }
    75  
    76  func askBin(path string) Commands {
    77  	commands := Commands{}
    78  	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    79  	defer cancel()
    80  	cmd := exec.CommandContext(ctx, path, "available")
    81  	bb := &bytes.Buffer{}
    82  	cmd.Stdout = bb
    83  	cmd.Stderr = bb
    84  	err := cmd.Run()
    85  	if err != nil {
    86  		fmt.Printf("[PLUGIN] error loading plugin %s: %s\n%s\n", path, err, bb.String())
    87  		return commands
    88  	}
    89  	err = json.NewDecoder(bb).Decode(&commands)
    90  	if err != nil {
    91  		fmt.Printf("[PLUGIN] error loading plugin %s: %s\n", path, err)
    92  		return commands
    93  	}
    94  	return commands
    95  }