github.com/windmilleng/wat@v0.0.2-0.20180626175338-9349b638e250/cli/wat/populate.go (about)

     1  package wat
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  
     8  	"time"
     9  
    10  	"os"
    11  
    12  	"github.com/spf13/cobra"
    13  	"github.com/windmilleng/wat/errors"
    14  )
    15  
    16  // This file contains code for both `Populate` and `List`
    17  
    18  const listTTL = time.Hour * 48
    19  
    20  var populateCmd = &cobra.Command{
    21  	Use:   "populate",
    22  	Short: "Smartly populate a list of available test commands (and associate files)",
    23  	Run:   populate,
    24  }
    25  
    26  func populate(cmd *cobra.Command, args []string) {
    27  	ctx := context.Background()
    28  
    29  	ws, err := GetOrInitWatWorkspace()
    30  	if err != nil {
    31  		ws.Fatal("GetWatWorkspace", err)
    32  	}
    33  
    34  	cmds, err := List(ctx, ws, 0 /* always fresh */)
    35  	if err != nil {
    36  		ws.Fatal("Populate", err)
    37  	}
    38  
    39  	fmt.Printf("Successfully populated %d commands.\n", len(cmds.Commands))
    40  }
    41  
    42  var listCmd = &cobra.Command{
    43  	Use:   "list",
    44  	Short: "List all the commands to choose from",
    45  	Run:   list,
    46  }
    47  
    48  func list(cmd *cobra.Command, args []string) {
    49  	ctx := context.Background()
    50  
    51  	ws, err := GetOrInitWatWorkspace()
    52  	if err != nil {
    53  		ws.Fatal("GetWatWorkspace", err)
    54  	}
    55  
    56  	cmdList, err := List(ctx, ws, listTTL)
    57  	if err != nil {
    58  		ws.Fatal("List", err)
    59  	}
    60  
    61  	encoder := json.NewEncoder(os.Stdout)
    62  	encoder.SetIndent("", "  ")
    63  	err = encoder.Encode(cmdList)
    64  	if err != nil {
    65  		ws.Fatal("Encode", err)
    66  	}
    67  }
    68  
    69  type CommandList struct {
    70  	Timestamp time.Time
    71  	Commands  []WatCommand
    72  }
    73  
    74  // Get the list of commands.
    75  //
    76  // If there are already commands on disk fresher than the ttl, return those
    77  // commands. Otherwise, generates a list of available WatCommands (i.e. command
    78  // + associated files) and writes them to disk (.wat/list).
    79  //
    80  // Set the ttl to 0 to always regenerate.
    81  func List(ctx context.Context, ws WatWorkspace, ttl time.Duration) (CommandList, error) {
    82  	if ttl > 0 {
    83  		exists, err := ws.Exists(fnameList)
    84  		if err != nil {
    85  			return CommandList{}, err
    86  		}
    87  
    88  		if exists {
    89  			cmdList, err := listFromFile(ws)
    90  			if err != nil {
    91  				return cmdList, err
    92  			}
    93  
    94  			if time.Since(cmdList.Timestamp) < ttl {
    95  				// List is current, yay!
    96  				return cmdList, nil
    97  			}
    98  		}
    99  	}
   100  
   101  	// List is stale or does not exist, (re)populate
   102  	cmds, err := populateAt(ctx, ws)
   103  	if err != nil {
   104  		return CommandList{}, fmt.Errorf("populateAt: %v", err)
   105  	}
   106  
   107  	cmdList := CommandList{
   108  		Timestamp: time.Now(),
   109  		Commands:  cmds,
   110  	}
   111  	err = cmdList.toFile(ws)
   112  	if err != nil {
   113  		return CommandList{}, fmt.Errorf("toFile: %v", err)
   114  	}
   115  
   116  	return cmdList, nil
   117  }
   118  
   119  func listFromFile(ws WatWorkspace) (cmdList CommandList, err error) {
   120  	listContents, err := ws.Read(fnameList)
   121  	if err != nil {
   122  		return cmdList, fmt.Errorf("read: %v", err)
   123  	}
   124  
   125  	err = json.Unmarshal(listContents, &cmdList)
   126  	if err != nil {
   127  		return cmdList, fmt.Errorf("json.Unmarshal: %v", err)
   128  	}
   129  	return cmdList, nil
   130  }
   131  
   132  func (cl CommandList) toFile(ws WatWorkspace) error {
   133  	j := MustJson(cl)
   134  	return ws.Write(fnameList, j)
   135  }
   136  
   137  type WatCommand struct {
   138  	Command     string
   139  	FilePattern string
   140  }
   141  
   142  func (c WatCommand) Empty() bool {
   143  	return c.Command == ""
   144  }
   145  
   146  // PrettyCmd returns a string suitable for prettily printing this cmd to terminal
   147  func (c WatCommand) PrettyCmd() string {
   148  	escapedCmd := fmt.Sprintf("%q", c.Command)
   149  	escapedCmd = escapedCmd[1 : len(escapedCmd)-1] // remove quotes
   150  	return TermBold(fmt.Sprintf("$ %s\n", escapedCmd))
   151  }
   152  
   153  func populateAt(ctx context.Context, ws WatWorkspace) ([]WatCommand, error) {
   154  	result := RunBuiltinPlugins(ctx, ws)
   155  
   156  	userResult, err := RunUserPlugins(ctx, ws)
   157  	if err != nil {
   158  		return result, errors.Propagatef(err, "RunUserPlugins")
   159  	}
   160  
   161  	result = append(result, userResult...)
   162  
   163  	// TODO: dedupe?
   164  	return result, nil
   165  }