Skip to content

Commit

Permalink
Remove some TODOs (#491)
Browse files Browse the repository at this point in the history
  • Loading branch information
adambabik authored Feb 10, 2024
1 parent c6b7703 commit 6d3dce1
Show file tree
Hide file tree
Showing 13 changed files with 200 additions and 144 deletions.
4 changes: 1 addition & 3 deletions internal/cmd/print.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (

"github.com/pkg/errors"
"github.com/spf13/cobra"

"github.com/stateful/runme/internal/project"
)

func printCmd() *cobra.Command {
Expand All @@ -24,7 +22,7 @@ func printCmd() *cobra.Command {
}

task, err := lookupTaskWithPrompt(cmd, args[0], tasks)
if project.IsTaskNotFoundError(err) && !fAllowUnnamed {
if isTaskNotFoundError(err) && !fAllowUnnamed {
fAllowUnnamed = true
goto generateBlocks
} else if err != nil {
Expand Down
60 changes: 58 additions & 2 deletions internal/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func runCmd() *cobra.Command {
for _, arg := range args {
task, err := lookupTaskWithPrompt(cmd, arg, tasks)
if err != nil {
if project.IsTaskNotFoundError(err) && !fAllowUnnamed {
if isTaskNotFoundError(err) && !fAllowUnnamed {
fAllowUnnamed = true
goto searchBlocks
}
Expand Down Expand Up @@ -461,13 +461,69 @@ func (p RunBlockPrompt) View() string {
return blockPromptAppStyle.Render(content)
}

type errTaskWithFilenameNotFound struct {
queryFile string
}

func (e errTaskWithFilenameNotFound) Error() string {
return fmt.Sprintf("unable to find file in project matching regex %q", e.queryFile)
}

type errTaskWithNameNotFound struct {
queryName string
}

func (e errTaskWithNameNotFound) Error() string {
return fmt.Sprintf("unable to find any script named %q", e.queryName)
}

func isTaskNotFoundError(err error) bool {
return errors.As(err, &errTaskWithFilenameNotFound{}) || errors.As(err, &errTaskWithNameNotFound{})
}

func filterTasksByFileAndTaskName(tasks []project.Task, queryFile, queryName string) ([]project.Task, error) {
fileMatcher, err := project.CompileRegex(queryFile)
if err != nil {
return nil, err
}

var results []project.Task

foundFile := false

for _, task := range tasks {
if !fileMatcher.MatchString(task.DocumentPath) {
continue
}

foundFile = true

// This is expected that the task name query is
// matched exactly.
if queryName != task.CodeBlock.Name() {
continue
}

results = append(results, task)
}

if len(results) == 0 {
if !foundFile {
return nil, &errTaskWithFilenameNotFound{queryFile: queryFile}
}
return nil, &errTaskWithNameNotFound{queryName: queryName}
}

return results, nil
}

func lookupTaskWithPrompt(cmd *cobra.Command, query string, tasks []project.Task) (task project.Task, err error) {
queryFile, queryName, err := splitRunArgument(query)
if err != nil {
return task, err
}

filteredTasks, err := project.FilterTasksByFileAndTaskName(tasks, queryFile, queryName)
filteredTasks, err := filterTasksByFileAndTaskName(tasks, queryFile, queryName)
if err != nil {
return task, err
}
Expand Down
3 changes: 1 addition & 2 deletions internal/cmd/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (

"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/stateful/runme/internal/project"
"github.com/stateful/runme/internal/tasks"
)

Expand All @@ -24,7 +23,7 @@ func tasksCmd() *cobra.Command {

task, err := lookupTaskWithPrompt(cmd, args[0], projTasks)
if err != nil {
if project.IsTaskNotFoundError(err) && !fAllowUnnamed {
if isTaskNotFoundError(err) && !fAllowUnnamed {
fAllowUnnamed = true
goto generateBlocks
}
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/tui.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ func (m *tuiModel) filterCodeBlocks() {
oldSelection = m.tasks[m.cursor]
}

m.tasks, _ = project.FilterTasks(m.unfilteredTasks, func(t project.Task) (bool, error) {
m.tasks, _ = project.FilterTasksByFn(m.unfilteredTasks, func(t project.Task) (bool, error) {
if !m.allowUnknown && t.CodeBlock.IsUnknown() {
return false, nil
}
Expand Down
7 changes: 4 additions & 3 deletions internal/document/document.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,12 @@ func (d *Document) splitSource() {
d.content = item.Value(d.source)
d.contentOffset = item.start
case parsedItemError:
// TODO(adamb): handle this error somehow
if !errors.Is(item.err, errParseFrontmatter) {
if errors.Is(item.err, errParseRawFrontmatter) {
d.parseFrontmatterErr = item.err
} else {
d.splitSourceErr = item.err
return
}
return
}
}
})
Expand Down
10 changes: 2 additions & 8 deletions internal/document/frontmatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,17 +144,11 @@ func (f *Frontmatter) ensureID() {
f.Runme.ID = ulid.GenerateID()
}

baseVersion := version.BaseVersion()
if baseVersion == "v99.9" || baseVersion == "v0.0" {
return
if v, ok := version.BaseVersionAuthoritative(); ok {
f.Runme.Version = v
}
f.Runme.Version = baseVersion
}

// TODO(adamb): Frontmatter can return (nil, nil) which indicates that
// there is no error, but also that there is no FrontMatter. It is not
// the best API. Consider adding HasFrontmatter() and returning an error
// if there is none from this method.
func (d *Document) Frontmatter() (*Frontmatter, error) {
d.splitSource()

Expand Down
8 changes: 4 additions & 4 deletions internal/document/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func ParseSections(source []byte) (result ParsedSections, _ error) {
result.ContentOffset = item.start
result.Content = item.Value(source)
case parsedItemError:
if errors.Is(item.err, errParseFrontmatter) {
if errors.Is(item.err, errParseRawFrontmatter) {
return ParsedSections{
Content: source,
}, nil
Expand Down Expand Up @@ -155,11 +155,11 @@ loop:

switch {
case r == '+':
return parseFrontMatter(l, byte(r))
return parseRawFrontmatter(l, byte(r))
case r == '-':
return parseFrontMatter(l, byte(r))
return parseRawFrontmatter(l, byte(r))
case r == '{':
return parseFrontMatterJSON
return parseRawFrontmatterJSON
case r == '\ufeff':
// skip
case !unicode.IsSpace(r) && !isEOL(r):
Expand Down
12 changes: 6 additions & 6 deletions internal/document/parser_frontmatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import (
"errors"
)

var errParseFrontmatter = errors.New("failed to parse frontmatter")
var errParseRawFrontmatter = errors.New("failed to extract frontmatter")

func parseFrontMatter(l *itemParser, delimiter byte) parserStateFunc {
// lexFrontMatter was trigger when a dilimiter was observer.
// According to the spec, there must be three delimiter characters.
// parseRawFrontmatter is a parser state function that extracts the frontmatter with
// "---" or "+++" delimiters. According to the spec, there must be three delimiter characters.
func parseRawFrontmatter(l *itemParser, delimiter byte) parserStateFunc {
for i := 0; i < 2; i++ {
if r := l.next(); r != rune(delimiter) {
l.error(errParseFrontmatter)
l.error(errParseRawFrontmatter)
return nil
}
}
Expand Down Expand Up @@ -43,7 +43,7 @@ func parseFrontMatter(l *itemParser, delimiter byte) parserStateFunc {
return parseContent
}

func parseFrontMatterJSON(l *itemParser) parserStateFunc {
func parseRawFrontmatterJSON(l *itemParser) parserStateFunc {
l.backup()

var (
Expand Down
27 changes: 9 additions & 18 deletions internal/project/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"io/fs"
"os"
"path/filepath"
"reflect"
"strings"

"github.com/go-git/go-billy/v5"
Expand Down Expand Up @@ -69,17 +68,11 @@ type LoadEvent struct {
Data any
}

// TODO(adamb): add more robust implementation.
//
// Consider switching away from reflection
// as this method is used in hot code path.
func (e LoadEvent) extractDataValue(val any) {
reflect.ValueOf(val).Elem().Set(reflect.ValueOf(e.Data))
}

func ExtractDataFromLoadEvent[T any](event LoadEvent) T {
var data T
event.extractDataValue(&data)
data, ok := event.Data.(T)
if !ok {
panic("invariant: incompatible types")
}
return data
}

Expand Down Expand Up @@ -534,12 +527,12 @@ func (p *Project) LoadEnv() ([]string, error) {
}

func (p *Project) LoadEnvAsMap() (map[string]string, error) {
// For file-based projects, there are no envs to read.
// For file-based projects, there are no env to read.
if p.fs == nil {
return nil, nil
}

envs := make(map[string]string)
env := make(map[string]string)

for _, envFile := range p.envFilesReadOrder {
bytes, err := util.ReadFile(p.fs, envFile)
Expand All @@ -555,15 +548,13 @@ func (p *Project) LoadEnvAsMap() (map[string]string, error) {

parsed, err := godotenv.UnmarshalBytes(bytes)
if err != nil {
// silently fail for now
// TODO(mxs): come up with better solution
continue
return nil, errors.WithStack(err)
}

for k, v := range parsed {
envs[k] = v
env[k] = v
}
}

return envs, nil
return env, nil
}
3 changes: 2 additions & 1 deletion internal/project/project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import (
"path/filepath"
"testing"

"github.com/stateful/runme/internal/project/testdata"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/stateful/runme/internal/project/testdata"
)

func TestExtractDataFromLoadEvent(t *testing.T) {
Expand Down
Loading

0 comments on commit 6d3dce1

Please sign in to comment.