123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- package ast
- import (
- "strings"
- "gopkg.in/yaml.v3"
- "github.com/go-task/task/v3/errors"
- "github.com/go-task/task/v3/internal/experiments"
- "github.com/go-task/task/v3/internal/omap"
- )
- // Vars is a string[string] variables map.
- type Vars struct {
- omap.OrderedMap[string, Var]
- }
- // ToCacheMap converts Vars to a map containing only the static
- // variables
- func (vs *Vars) ToCacheMap() (m map[string]any) {
- m = make(map[string]any, vs.Len())
- _ = vs.Range(func(k string, v Var) error {
- if v.Sh != "" {
- // Dynamic variable is not yet resolved; trigger
- // <no value> to be used in templates.
- return nil
- }
- if v.Live != nil {
- m[k] = v.Live
- } else {
- m[k] = v.Value
- }
- return nil
- })
- return
- }
- // Wrapper around OrderedMap.Set to ensure we don't get nil pointer errors
- func (vs *Vars) Range(f func(k string, v Var) error) error {
- if vs == nil {
- return nil
- }
- return vs.OrderedMap.Range(f)
- }
- // Wrapper around OrderedMap.Merge to ensure we don't get nil pointer errors
- func (vs *Vars) Merge(other *Vars, include *Include) {
- if vs == nil || other == nil {
- return
- }
- _ = other.Range(func(key string, value Var) error {
- if include != nil && include.AdvancedImport {
- value.Dir = include.Dir
- }
- vs.Set(key, value)
- return nil
- })
- }
- // Wrapper around OrderedMap.Len to ensure we don't get nil pointer errors
- func (vs *Vars) Len() int {
- if vs == nil {
- return 0
- }
- return vs.OrderedMap.Len()
- }
- // DeepCopy creates a new instance of Vars and copies
- // data by value from the source struct.
- func (vs *Vars) DeepCopy() *Vars {
- if vs == nil {
- return nil
- }
- return &Vars{
- OrderedMap: vs.OrderedMap.DeepCopy(),
- }
- }
- // Var represents either a static or dynamic variable.
- type Var struct {
- Value any
- Live any
- Sh string
- Ref string
- Dir string
- }
- func (v *Var) UnmarshalYAML(node *yaml.Node) error {
- if experiments.MapVariables.Enabled {
- // This implementation is not backwards-compatible and replaces the 'sh' key with map variables
- if experiments.MapVariables.Value == "1" {
- var value any
- if err := node.Decode(&value); err != nil {
- return errors.NewTaskfileDecodeError(err, node)
- }
- // If the value is a string and it starts with $, then it's a shell command
- if str, ok := value.(string); ok {
- if str, ok = strings.CutPrefix(str, "$"); ok {
- v.Sh = str
- return nil
- }
- if str, ok = strings.CutPrefix(str, "#"); ok {
- v.Ref = str
- return nil
- }
- }
- v.Value = value
- return nil
- }
- // This implementation IS backwards-compatible and keeps the 'sh' key and allows map variables to be added under the `map` key
- if experiments.MapVariables.Value == "2" {
- switch node.Kind {
- case yaml.MappingNode:
- key := node.Content[0].Value
- switch key {
- case "sh", "ref", "map":
- var m struct {
- Sh string
- Ref string
- Map any
- }
- if err := node.Decode(&m); err != nil {
- return errors.NewTaskfileDecodeError(err, node)
- }
- v.Sh = m.Sh
- v.Ref = m.Ref
- v.Value = m.Map
- return nil
- default:
- return errors.NewTaskfileDecodeError(nil, node).WithMessage(`%q is not a valid variable type. Try "sh", "ref", "map" or using a scalar value`, key)
- }
- default:
- var value any
- if err := node.Decode(&value); err != nil {
- return errors.NewTaskfileDecodeError(err, node)
- }
- v.Value = value
- return nil
- }
- }
- }
- switch node.Kind {
- case yaml.MappingNode:
- key := node.Content[0].Value
- switch key {
- case "sh", "ref":
- var m struct {
- Sh string
- Ref string
- }
- if err := node.Decode(&m); err != nil {
- return errors.NewTaskfileDecodeError(err, node)
- }
- v.Sh = m.Sh
- v.Ref = m.Ref
- return nil
- default:
- return errors.NewTaskfileDecodeError(nil, node).WithMessage("maps cannot be assigned to variables")
- }
- default:
- var value any
- if err := node.Decode(&value); err != nil {
- return errors.NewTaskfileDecodeError(err, node)
- }
- v.Value = value
- return nil
- }
- }
|