...

Source file src/edge-infra.dev/pkg/tools/dlog/cmd/create.go

Documentation: edge-infra.dev/pkg/tools/dlog/cmd

     1  package cmd
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"context"
     7  	"fmt"
     8  	"os"
     9  	"path/filepath"
    10  	"strings"
    11  	"time"
    12  
    13  	"edge-infra.dev/pkg/lib/cli/rags"
    14  	"edge-infra.dev/pkg/lib/cli/sink"
    15  	"edge-infra.dev/pkg/tools/dlog"
    16  )
    17  
    18  // TODO: automatically increment based on last dlog (eg 0004 is biggest is 0003)
    19  // TODO: allow setting more pieces of frontmatter on create
    20  
    21  func newCreateCmd() *sink.Command {
    22  	var (
    23  		dir, template string
    24  		tags          []string
    25  	)
    26  
    27  	cmd := &sink.Command{
    28  		Use:   "create [flags] <file>",
    29  		Short: "Create decision logs from a template.",
    30  		Flags: []*rags.Rag{
    31  			dirFlag(&dir),
    32  			templateFlag(&template),
    33  			{
    34  				Name:  "tags",
    35  				Usage: "Comma separated list of tags to apply to new dlog. Can be provided multiple times",
    36  				Value: &rags.StringSet{Var: &tags},
    37  			},
    38  		},
    39  		Exec: func(_ context.Context, r sink.Run) error {
    40  			if len(r.Args()) != 1 {
    41  				return fmt.Errorf("a name for the decision log file is required")
    42  			}
    43  
    44  			p := filepath.Join(dir, r.Args()[0])
    45  			_, err := os.Stat(p)
    46  			if err == nil {
    47  				return fmt.Errorf("%s already exists", p)
    48  			}
    49  
    50  			t, err := os.Open(template)
    51  			if err != nil {
    52  				return fmt.Errorf("failed to open template %s: %w", template, err)
    53  			}
    54  
    55  			return createDLog(p, t, time.Now(), tags)
    56  		},
    57  	}
    58  
    59  	return cmd
    60  }
    61  
    62  func createDLog(path string, t *os.File, d time.Time, tags []string) error {
    63  	buf := new(bytes.Buffer)
    64  	scanner := bufio.NewScanner(t)
    65  	for scanner.Scan() {
    66  		text := scanner.Text()
    67  		// Cheat here by updating the frontmatter in string form to avoid
    68  		// encoding roundtrip and losing comments in the template describing
    69  		// frontmatter elements
    70  		if strings.HasPrefix(text, "date:") {
    71  			buf.WriteString(fmt.Sprintf("date: %s", dlog.Time{Time: d}))
    72  			buf.WriteString("\n")
    73  			continue
    74  		}
    75  		if len(tags) > 0 && strings.HasPrefix(text, "tags:") {
    76  			buf.WriteString(fmt.Sprintf(
    77  				"tags: [%s]",
    78  				// Rebuild string for consistent spacing
    79  				strings.Join(tags, ", ")),
    80  			)
    81  			buf.WriteString("\n")
    82  			continue
    83  		}
    84  
    85  		buf.WriteString(text)
    86  		buf.WriteString("\n")
    87  	}
    88  	if scanner.Err() != nil {
    89  		return fmt.Errorf("failed to read template %s: %w", t.Name(), scanner.Err())
    90  	}
    91  
    92  	f, err := os.Create(path)
    93  	if err != nil {
    94  		return fmt.Errorf("failed to create %s: %w", path, err)
    95  	}
    96  	if _, err := buf.WriteTo(f); err != nil {
    97  		return fmt.Errorf("failed to write %s: %w", path, err)
    98  	}
    99  	return nil
   100  }
   101  

View as plain text