mirror of
https://github.com/go-task/task.git
synced 2025-04-15 11:56:34 +02:00
feat: improve unmarshal error handling and use v3 yaml interface everywhere (#959)
This commit is contained in:
parent
e4158dc5e4
commit
491888f6c0
@ -1,5 +1,11 @@
|
||||
package taskfile
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Cmd is a task command
|
||||
type Cmd struct {
|
||||
Cmd string
|
||||
@ -16,68 +22,93 @@ type Dep struct {
|
||||
Vars *Vars
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements yaml.Unmarshaler interface
|
||||
func (c *Cmd) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
func (c *Cmd) UnmarshalYAML(node *yaml.Node) error {
|
||||
switch node.Kind {
|
||||
|
||||
case yaml.ScalarNode:
|
||||
var cmd string
|
||||
if err := unmarshal(&cmd); err == nil {
|
||||
if err := node.Decode(&cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
c.Cmd = cmd
|
||||
return nil
|
||||
}
|
||||
|
||||
case yaml.MappingNode:
|
||||
|
||||
// A command with additional options
|
||||
var cmdStruct struct {
|
||||
Cmd string
|
||||
Silent bool
|
||||
IgnoreError bool `yaml:"ignore_error"`
|
||||
}
|
||||
if err := unmarshal(&cmdStruct); err == nil && cmdStruct.Cmd != "" {
|
||||
if err := node.Decode(&cmdStruct); err == nil && cmdStruct.Cmd != "" {
|
||||
c.Cmd = cmdStruct.Cmd
|
||||
c.Silent = cmdStruct.Silent
|
||||
c.IgnoreError = cmdStruct.IgnoreError
|
||||
return nil
|
||||
}
|
||||
|
||||
// A deferred command
|
||||
var deferredCmd struct {
|
||||
Defer string
|
||||
}
|
||||
if err := unmarshal(&deferredCmd); err == nil && deferredCmd.Defer != "" {
|
||||
if err := node.Decode(&deferredCmd); err == nil && deferredCmd.Defer != "" {
|
||||
c.Defer = true
|
||||
c.Cmd = deferredCmd.Defer
|
||||
return nil
|
||||
}
|
||||
|
||||
// A deferred task call
|
||||
var deferredCall struct {
|
||||
Defer Call
|
||||
}
|
||||
if err := unmarshal(&deferredCall); err == nil && deferredCall.Defer.Task != "" {
|
||||
if err := node.Decode(&deferredCall); err == nil && deferredCall.Defer.Task != "" {
|
||||
c.Defer = true
|
||||
c.Task = deferredCall.Defer.Task
|
||||
c.Vars = deferredCall.Defer.Vars
|
||||
return nil
|
||||
}
|
||||
|
||||
// A task call
|
||||
var taskCall struct {
|
||||
Task string
|
||||
Vars *Vars
|
||||
}
|
||||
if err := unmarshal(&taskCall); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := node.Decode(&taskCall); err == nil && taskCall.Task != "" {
|
||||
c.Task = taskCall.Task
|
||||
c.Vars = taskCall.Vars
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements yaml.Unmarshaler interface
|
||||
func (d *Dep) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
return fmt.Errorf("yaml: line %d: invalid keys in command", node.Line)
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into command", node.Line, node.ShortTag())
|
||||
}
|
||||
|
||||
func (d *Dep) UnmarshalYAML(node *yaml.Node) error {
|
||||
switch node.Kind {
|
||||
|
||||
case yaml.ScalarNode:
|
||||
var task string
|
||||
if err := unmarshal(&task); err == nil {
|
||||
if err := node.Decode(&task); err != nil {
|
||||
return err
|
||||
}
|
||||
d.Task = task
|
||||
return nil
|
||||
}
|
||||
|
||||
case yaml.MappingNode:
|
||||
var taskCall struct {
|
||||
Task string
|
||||
Vars *Vars
|
||||
}
|
||||
if err := unmarshal(&taskCall); err != nil {
|
||||
if err := node.Decode(&taskCall); err != nil {
|
||||
return err
|
||||
}
|
||||
d.Task = taskCall.Task
|
||||
d.Vars = taskCall.Vars
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("cannot unmarshal %s into dependency", node.ShortTag())
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package taskfile
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
@ -32,11 +31,10 @@ type IncludedTaskfiles struct {
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (tfs *IncludedTaskfiles) UnmarshalYAML(node *yaml.Node) error {
|
||||
if node.Kind != yaml.MappingNode {
|
||||
return errors.New("task: includes is not a map")
|
||||
}
|
||||
switch node.Kind {
|
||||
|
||||
// NOTE(@andreynering): on this style of custom unmarsheling,
|
||||
case yaml.MappingNode:
|
||||
// NOTE(@andreynering): on this style of custom unmarshalling,
|
||||
// even number contains the keys, while odd numbers contains
|
||||
// the values.
|
||||
for i := 0; i < len(node.Content); i += 2 {
|
||||
@ -52,6 +50,9 @@ func (tfs *IncludedTaskfiles) UnmarshalYAML(node *yaml.Node) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into included taskfiles", node.Line, node.ShortTag())
|
||||
}
|
||||
|
||||
// Len returns the length of the map
|
||||
func (tfs *IncludedTaskfiles) Len() int {
|
||||
if tfs == nil {
|
||||
@ -92,14 +93,18 @@ func (tfs *IncludedTaskfiles) Range(yield func(key string, includedTaskfile Incl
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements yaml.Unmarshaler interface
|
||||
func (it *IncludedTaskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
func (it *IncludedTaskfile) UnmarshalYAML(node *yaml.Node) error {
|
||||
switch node.Kind {
|
||||
|
||||
case yaml.ScalarNode:
|
||||
var str string
|
||||
if err := unmarshal(&str); err == nil {
|
||||
if err := node.Decode(&str); err != nil {
|
||||
return err
|
||||
}
|
||||
it.Taskfile = str
|
||||
return nil
|
||||
}
|
||||
|
||||
case yaml.MappingNode:
|
||||
var includedTaskfile struct {
|
||||
Taskfile string
|
||||
Dir string
|
||||
@ -108,7 +113,7 @@ func (it *IncludedTaskfile) UnmarshalYAML(unmarshal func(interface{}) error) err
|
||||
Aliases []string
|
||||
Vars *Vars
|
||||
}
|
||||
if err := unmarshal(&includedTaskfile); err != nil {
|
||||
if err := node.Decode(&includedTaskfile); err != nil {
|
||||
return err
|
||||
}
|
||||
it.Taskfile = includedTaskfile.Taskfile
|
||||
@ -121,6 +126,9 @@ func (it *IncludedTaskfile) UnmarshalYAML(unmarshal func(interface{}) error) err
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into included taskfile", node.Line, node.ShortTag())
|
||||
}
|
||||
|
||||
// DeepCopy creates a new instance of IncludedTaskfile and copies
|
||||
// data by value from the source struct.
|
||||
func (it *IncludedTaskfile) DeepCopy() *IncludedTaskfile {
|
||||
|
@ -2,6 +2,8 @@ package taskfile
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Output of the Task output
|
||||
@ -17,18 +19,22 @@ func (s *Output) IsSet() bool {
|
||||
return s.Name != ""
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements yaml.Unmarshaler
|
||||
// It accepts a scalar node representing the Output.Name or a mapping node representing the OutputGroup.
|
||||
func (s *Output) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
func (s *Output) UnmarshalYAML(node *yaml.Node) error {
|
||||
switch node.Kind {
|
||||
|
||||
case yaml.ScalarNode:
|
||||
var name string
|
||||
if err := unmarshal(&name); err == nil {
|
||||
if err := node.Decode(&name); err != nil {
|
||||
return err
|
||||
}
|
||||
s.Name = name
|
||||
return nil
|
||||
}
|
||||
|
||||
case yaml.MappingNode:
|
||||
var tmp struct {
|
||||
Group *OutputGroup
|
||||
}
|
||||
if err := unmarshal(&tmp); err != nil {
|
||||
if err := node.Decode(&tmp); err != nil {
|
||||
return fmt.Errorf("task: output style must be a string or mapping with a \"group\" key: %w", err)
|
||||
}
|
||||
if tmp.Group == nil {
|
||||
@ -41,6 +47,9 @@ func (s *Output) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into output", node.Line, node.ShortTag())
|
||||
}
|
||||
|
||||
// OutputGroup is the style options specific to the Group style.
|
||||
type OutputGroup struct {
|
||||
Begin, End string
|
||||
|
@ -3,6 +3,8 @@ package taskfile
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -17,29 +19,33 @@ type Precondition struct {
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements yaml.Unmarshaler interface.
|
||||
func (p *Precondition) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var cmd string
|
||||
func (p *Precondition) UnmarshalYAML(node *yaml.Node) error {
|
||||
switch node.Kind {
|
||||
|
||||
if err := unmarshal(&cmd); err == nil {
|
||||
case yaml.ScalarNode:
|
||||
var cmd string
|
||||
if err := node.Decode(&cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Sh = cmd
|
||||
p.Msg = fmt.Sprintf("`%s` failed", cmd)
|
||||
return nil
|
||||
}
|
||||
|
||||
case yaml.MappingNode:
|
||||
var sh struct {
|
||||
Sh string
|
||||
Msg string
|
||||
}
|
||||
|
||||
if err := unmarshal(&sh); err != nil {
|
||||
if err := node.Decode(&sh); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Sh = sh.Sh
|
||||
p.Msg = sh.Msg
|
||||
if p.Msg == "" {
|
||||
p.Msg = fmt.Sprintf("%s failed", sh.Sh)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into precondition", node.Line, node.ShortTag())
|
||||
}
|
||||
|
@ -1,5 +1,11 @@
|
||||
package taskfile
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Tasks represents a group of tasks
|
||||
type Tasks map[string]*Task
|
||||
|
||||
@ -39,19 +45,29 @@ func (t *Task) Name() string {
|
||||
return t.Task
|
||||
}
|
||||
|
||||
func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
func (t *Task) UnmarshalYAML(node *yaml.Node) error {
|
||||
switch node.Kind {
|
||||
|
||||
// Shortcut syntax for a task with a single command
|
||||
case yaml.ScalarNode:
|
||||
var cmd Cmd
|
||||
if err := unmarshal(&cmd); err == nil && cmd.Cmd != "" {
|
||||
if err := node.Decode(&cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
t.Cmds = append(t.Cmds, &cmd)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Shortcut syntax for a simple task with a list of commands
|
||||
case yaml.SequenceNode:
|
||||
var cmds []*Cmd
|
||||
if err := unmarshal(&cmds); err == nil && len(cmds) > 0 {
|
||||
if err := node.Decode(&cmds); err != nil {
|
||||
return err
|
||||
}
|
||||
t.Cmds = cmds
|
||||
return nil
|
||||
}
|
||||
|
||||
// Full task object
|
||||
case yaml.MappingNode:
|
||||
var task struct {
|
||||
Cmds []*Cmd
|
||||
Deps []*Dep
|
||||
@ -75,15 +91,15 @@ func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
IgnoreError bool `yaml:"ignore_error"`
|
||||
Run string
|
||||
}
|
||||
if err := unmarshal(&task); err != nil {
|
||||
if err := node.Decode(&task); err != nil {
|
||||
return err
|
||||
}
|
||||
t.Cmds = task.Cmds
|
||||
t.Deps = task.Deps
|
||||
t.Label = task.Label
|
||||
t.Desc = task.Desc
|
||||
t.Aliases = task.Aliases
|
||||
t.Summary = task.Summary
|
||||
t.Aliases = task.Aliases
|
||||
t.Sources = task.Sources
|
||||
t.Generates = task.Generates
|
||||
t.Status = task.Status
|
||||
@ -102,6 +118,9 @@ func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into task", node.Line, node.ShortTag())
|
||||
}
|
||||
|
||||
// DeepCopy creates a new instance of Task and copies
|
||||
// data by value from the source struct.
|
||||
func (t *Task) DeepCopy() *Task {
|
||||
|
@ -3,6 +3,8 @@ package taskfile
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Taskfile represents a Taskfile.yml
|
||||
@ -21,8 +23,10 @@ type Taskfile struct {
|
||||
Interval string
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements yaml.Unmarshaler interface
|
||||
func (tf *Taskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
func (tf *Taskfile) UnmarshalYAML(node *yaml.Node) error {
|
||||
switch node.Kind {
|
||||
|
||||
case yaml.MappingNode:
|
||||
var taskfile struct {
|
||||
Version string
|
||||
Expansions int
|
||||
@ -37,11 +41,9 @@ func (tf *Taskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
Run string
|
||||
Interval string
|
||||
}
|
||||
|
||||
if err := unmarshal(&taskfile); err != nil {
|
||||
if err := node.Decode(&taskfile); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tf.Version = taskfile.Version
|
||||
tf.Expansions = taskfile.Expansions
|
||||
tf.Output = taskfile.Output
|
||||
@ -54,7 +56,6 @@ func (tf *Taskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
tf.Dotenv = taskfile.Dotenv
|
||||
tf.Run = taskfile.Run
|
||||
tf.Interval = taskfile.Interval
|
||||
|
||||
if tf.Expansions <= 0 {
|
||||
tf.Expansions = 2
|
||||
}
|
||||
@ -67,6 +68,9 @@ func (tf *Taskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into taskfile", node.Line, node.ShortTag())
|
||||
}
|
||||
|
||||
// ParsedVersion returns the version as a float64
|
||||
func (tf *Taskfile) ParsedVersion() (float64, error) {
|
||||
v, err := strconv.ParseFloat(tf.Version, 64)
|
||||
|
@ -1,7 +1,7 @@
|
||||
package taskfile
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
"gopkg.in/yaml.v3"
|
||||
@ -13,13 +13,11 @@ type Vars struct {
|
||||
Mapping map[string]Var
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (vs *Vars) UnmarshalYAML(node *yaml.Node) error {
|
||||
if node.Kind != yaml.MappingNode {
|
||||
return errors.New("task: vars is not a map")
|
||||
}
|
||||
switch node.Kind {
|
||||
|
||||
// NOTE(@andreynering): on this style of custom unmarsheling,
|
||||
case yaml.MappingNode:
|
||||
// NOTE(@andreynering): on this style of custom unmarshalling,
|
||||
// even number contains the keys, while odd numbers contains
|
||||
// the values.
|
||||
for i := 0; i < len(node.Content); i += 2 {
|
||||
@ -35,6 +33,9 @@ func (vs *Vars) UnmarshalYAML(node *yaml.Node) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into variables", node.Line, node.ShortTag())
|
||||
}
|
||||
|
||||
// DeepCopy creates a new instance of Vars and copies
|
||||
// data by value from the source struct.
|
||||
func (vs *Vars) DeepCopy() *Vars {
|
||||
@ -116,20 +117,27 @@ type Var struct {
|
||||
Dir string
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements yaml.Unmarshaler interface.
|
||||
func (v *Var) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
func (v *Var) UnmarshalYAML(node *yaml.Node) error {
|
||||
switch node.Kind {
|
||||
|
||||
case yaml.ScalarNode:
|
||||
var str string
|
||||
if err := unmarshal(&str); err == nil {
|
||||
if err := node.Decode(&str); err != nil {
|
||||
return err
|
||||
}
|
||||
v.Static = str
|
||||
return nil
|
||||
}
|
||||
|
||||
case yaml.MappingNode:
|
||||
var sh struct {
|
||||
Sh string
|
||||
}
|
||||
if err := unmarshal(&sh); err != nil {
|
||||
if err := node.Decode(&sh); err != nil {
|
||||
return err
|
||||
}
|
||||
v.Sh = sh.Sh
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into variable", node.Line, node.ShortTag())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user