mirror of
https://github.com/go-task/task.git
synced 2025-03-19 21:17:46 +02:00
fix: orderedmap race condition (#1972)
This commit is contained in:
parent
2965841eb7
commit
fd3532812e
@ -140,11 +140,11 @@ func ReplaceVarsWithExtra(vars *ast.Vars, cache *Cache, extra map[string]any) *a
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var newVars ast.Vars
|
newVars := ast.NewVars()
|
||||||
_ = vars.Range(func(k string, v ast.Var) error {
|
_ = vars.Range(func(k string, v ast.Var) error {
|
||||||
newVars.Set(k, ReplaceVarWithExtra(v, cache, extra))
|
newVars.Set(k, ReplaceVarWithExtra(v, cache, extra))
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
return &newVars
|
return newVars
|
||||||
}
|
}
|
||||||
|
@ -183,7 +183,7 @@ func TestRequires(t *testing.T) {
|
|||||||
buff.Reset()
|
buff.Reset()
|
||||||
require.NoError(t, e.Setup())
|
require.NoError(t, e.Setup())
|
||||||
|
|
||||||
vars := &ast.Vars{}
|
vars := ast.NewVars()
|
||||||
vars.Set("foo", ast.Var{Value: "bar"})
|
vars.Set("foo", ast.Var{Value: "bar"})
|
||||||
require.NoError(t, e.Run(context.Background(), &ast.Call{
|
require.NoError(t, e.Run(context.Background(), &ast.Call{
|
||||||
Task: "missing-var",
|
Task: "missing-var",
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/elliotchance/orderedmap/v2"
|
"github.com/elliotchance/orderedmap/v2"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
@ -8,8 +10,9 @@ import (
|
|||||||
"github.com/go-task/task/v3/internal/deepcopy"
|
"github.com/go-task/task/v3/internal/deepcopy"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
// Include represents information about included taskfiles
|
// Include represents information about included taskfiles
|
||||||
type Include struct {
|
Include struct {
|
||||||
Namespace string
|
Namespace string
|
||||||
Taskfile string
|
Taskfile string
|
||||||
Dir string
|
Dir string
|
||||||
@ -21,14 +24,19 @@ type Include struct {
|
|||||||
Vars *Vars
|
Vars *Vars
|
||||||
Flatten bool
|
Flatten bool
|
||||||
}
|
}
|
||||||
|
// Includes is an ordered map of namespaces to includes.
|
||||||
// Includes represents information about included taskfiles
|
Includes struct {
|
||||||
type Includes struct {
|
|
||||||
om *orderedmap.OrderedMap[string, *Include]
|
om *orderedmap.OrderedMap[string, *Include]
|
||||||
|
mutex sync.RWMutex
|
||||||
}
|
}
|
||||||
|
// An IncludeElement is a key-value pair that is used for initializing an
|
||||||
|
// Includes structure.
|
||||||
|
IncludeElement orderedmap.Element[string, *Include]
|
||||||
|
)
|
||||||
|
|
||||||
type IncludeElement orderedmap.Element[string, *Include]
|
// NewIncludes creates a new instance of Includes and initializes it with the
|
||||||
|
// provided set of elements, if any. The elements are added in the order they
|
||||||
|
// are passed.
|
||||||
func NewIncludes(els ...*IncludeElement) *Includes {
|
func NewIncludes(els ...*IncludeElement) *Includes {
|
||||||
includes := &Includes{
|
includes := &Includes{
|
||||||
om: orderedmap.NewOrderedMap[string, *Include](),
|
om: orderedmap.NewOrderedMap[string, *Include](),
|
||||||
@ -39,20 +47,31 @@ func NewIncludes(els ...*IncludeElement) *Includes {
|
|||||||
return includes
|
return includes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Len returns the number of includes in the Includes map.
|
||||||
func (includes *Includes) Len() int {
|
func (includes *Includes) Len() int {
|
||||||
if includes == nil || includes.om == nil {
|
if includes == nil || includes.om == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
defer includes.mutex.RUnlock()
|
||||||
|
includes.mutex.RLock()
|
||||||
return includes.om.Len()
|
return includes.om.Len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get returns the value the the include with the provided key and a boolean
|
||||||
|
// that indicates if the value was found or not. If the value is not found, the
|
||||||
|
// returned include is a zero value and the bool is false.
|
||||||
func (includes *Includes) Get(key string) (*Include, bool) {
|
func (includes *Includes) Get(key string) (*Include, bool) {
|
||||||
if includes == nil || includes.om == nil {
|
if includes == nil || includes.om == nil {
|
||||||
return &Include{}, false
|
return &Include{}, false
|
||||||
}
|
}
|
||||||
|
defer includes.mutex.RUnlock()
|
||||||
|
includes.mutex.RLock()
|
||||||
return includes.om.Get(key)
|
return includes.om.Get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set sets the value of the include with the provided key to the provided
|
||||||
|
// value. If the include already exists, its value is updated. If the include
|
||||||
|
// does not exist, it is created.
|
||||||
func (includes *Includes) Set(key string, value *Include) bool {
|
func (includes *Includes) Set(key string, value *Include) bool {
|
||||||
if includes == nil {
|
if includes == nil {
|
||||||
includes = NewIncludes()
|
includes = NewIncludes()
|
||||||
@ -60,9 +79,14 @@ func (includes *Includes) Set(key string, value *Include) bool {
|
|||||||
if includes.om == nil {
|
if includes.om == nil {
|
||||||
includes.om = orderedmap.NewOrderedMap[string, *Include]()
|
includes.om = orderedmap.NewOrderedMap[string, *Include]()
|
||||||
}
|
}
|
||||||
|
defer includes.mutex.Unlock()
|
||||||
|
includes.mutex.Lock()
|
||||||
return includes.om.Set(key, value)
|
return includes.om.Set(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Range calls the provided function for each include in the map. The function
|
||||||
|
// receives the include's key and value as arguments. If the function returns
|
||||||
|
// an error, the iteration stops and the error is returned.
|
||||||
func (includes *Includes) Range(f func(k string, v *Include) error) error {
|
func (includes *Includes) Range(f func(k string, v *Include) error) error {
|
||||||
if includes == nil || includes.om == nil {
|
if includes == nil || includes.om == nil {
|
||||||
return nil
|
return nil
|
||||||
@ -77,6 +101,9 @@ func (includes *Includes) Range(f func(k string, v *Include) error) error {
|
|||||||
|
|
||||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||||
func (includes *Includes) UnmarshalYAML(node *yaml.Node) error {
|
func (includes *Includes) UnmarshalYAML(node *yaml.Node) error {
|
||||||
|
if includes == nil || includes.om == nil {
|
||||||
|
*includes = *NewIncludes()
|
||||||
|
}
|
||||||
switch node.Kind {
|
switch node.Kind {
|
||||||
case yaml.MappingNode:
|
case yaml.MappingNode:
|
||||||
// NOTE: orderedmap does not have an unmarshaler, so we have to decode
|
// NOTE: orderedmap does not have an unmarshaler, so we have to decode
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/elliotchance/orderedmap/v2"
|
"github.com/elliotchance/orderedmap/v2"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
@ -12,13 +13,25 @@ import (
|
|||||||
"github.com/go-task/task/v3/internal/filepathext"
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tasks represents a group of tasks
|
type (
|
||||||
type Tasks struct {
|
// Tasks is an ordered map of task names to Tasks.
|
||||||
|
Tasks struct {
|
||||||
om *orderedmap.OrderedMap[string, *Task]
|
om *orderedmap.OrderedMap[string, *Task]
|
||||||
|
mutex sync.RWMutex
|
||||||
}
|
}
|
||||||
|
// A TaskElement is a key-value pair that is used for initializing a Tasks
|
||||||
|
// structure.
|
||||||
|
TaskElement orderedmap.Element[string, *Task]
|
||||||
|
// MatchingTask represents a task that matches a given call. It includes the
|
||||||
|
// task itself and a list of wildcards that were matched.
|
||||||
|
MatchingTask struct {
|
||||||
|
Task *Task
|
||||||
|
Wildcards []string
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
type TaskElement orderedmap.Element[string, *Task]
|
// NewTasks creates a new instance of Tasks and initializes it with the provided
|
||||||
|
// set of elements, if any. The elements are added in the order they are passed.
|
||||||
func NewTasks(els ...*TaskElement) *Tasks {
|
func NewTasks(els ...*TaskElement) *Tasks {
|
||||||
tasks := &Tasks{
|
tasks := &Tasks{
|
||||||
om: orderedmap.NewOrderedMap[string, *Task](),
|
om: orderedmap.NewOrderedMap[string, *Task](),
|
||||||
@ -29,20 +42,31 @@ func NewTasks(els ...*TaskElement) *Tasks {
|
|||||||
return tasks
|
return tasks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Len returns the number of variables in the Tasks map.
|
||||||
func (tasks *Tasks) Len() int {
|
func (tasks *Tasks) Len() int {
|
||||||
if tasks == nil || tasks.om == nil {
|
if tasks == nil || tasks.om == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
defer tasks.mutex.RUnlock()
|
||||||
|
tasks.mutex.RLock()
|
||||||
return tasks.om.Len()
|
return tasks.om.Len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get returns the value the the task with the provided key and a boolean that
|
||||||
|
// indicates if the value was found or not. If the value is not found, the
|
||||||
|
// returned task is a zero value and the bool is false.
|
||||||
func (tasks *Tasks) Get(key string) (*Task, bool) {
|
func (tasks *Tasks) Get(key string) (*Task, bool) {
|
||||||
if tasks == nil || tasks.om == nil {
|
if tasks == nil || tasks.om == nil {
|
||||||
return &Task{}, false
|
return &Task{}, false
|
||||||
}
|
}
|
||||||
|
defer tasks.mutex.RUnlock()
|
||||||
|
tasks.mutex.RLock()
|
||||||
return tasks.om.Get(key)
|
return tasks.om.Get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set sets the value of the task with the provided key to the provided value.
|
||||||
|
// If the task already exists, its value is updated. If the task does not exist,
|
||||||
|
// it is created.
|
||||||
func (tasks *Tasks) Set(key string, value *Task) bool {
|
func (tasks *Tasks) Set(key string, value *Task) bool {
|
||||||
if tasks == nil {
|
if tasks == nil {
|
||||||
tasks = NewTasks()
|
tasks = NewTasks()
|
||||||
@ -50,9 +74,14 @@ func (tasks *Tasks) Set(key string, value *Task) bool {
|
|||||||
if tasks.om == nil {
|
if tasks.om == nil {
|
||||||
tasks.om = orderedmap.NewOrderedMap[string, *Task]()
|
tasks.om = orderedmap.NewOrderedMap[string, *Task]()
|
||||||
}
|
}
|
||||||
|
defer tasks.mutex.Unlock()
|
||||||
|
tasks.mutex.Lock()
|
||||||
return tasks.om.Set(key, value)
|
return tasks.om.Set(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Range calls the provided function for each task in the map. The function
|
||||||
|
// receives the task's key and value as arguments. If the function returns an
|
||||||
|
// error, the iteration stops and the error is returned.
|
||||||
func (tasks *Tasks) Range(f func(k string, v *Task) error) error {
|
func (tasks *Tasks) Range(f func(k string, v *Task) error) error {
|
||||||
if tasks == nil || tasks.om == nil {
|
if tasks == nil || tasks.om == nil {
|
||||||
return nil
|
return nil
|
||||||
@ -65,10 +94,13 @@ func (tasks *Tasks) Range(f func(k string, v *Task) error) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keys returns a slice of all the keys in the Tasks map.
|
||||||
func (tasks *Tasks) Keys() []string {
|
func (tasks *Tasks) Keys() []string {
|
||||||
if tasks == nil {
|
if tasks == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
defer tasks.mutex.RUnlock()
|
||||||
|
tasks.mutex.RLock()
|
||||||
var keys []string
|
var keys []string
|
||||||
for pair := tasks.om.Front(); pair != nil; pair = pair.Next() {
|
for pair := tasks.om.Front(); pair != nil; pair = pair.Next() {
|
||||||
keys = append(keys, pair.Key)
|
keys = append(keys, pair.Key)
|
||||||
@ -76,10 +108,13 @@ func (tasks *Tasks) Keys() []string {
|
|||||||
return keys
|
return keys
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Values returns a slice of all the values in the Tasks map.
|
||||||
func (tasks *Tasks) Values() []*Task {
|
func (tasks *Tasks) Values() []*Task {
|
||||||
if tasks == nil {
|
if tasks == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
defer tasks.mutex.RUnlock()
|
||||||
|
tasks.mutex.RLock()
|
||||||
var values []*Task
|
var values []*Task
|
||||||
for pair := tasks.om.Front(); pair != nil; pair = pair.Next() {
|
for pair := tasks.om.Front(); pair != nil; pair = pair.Next() {
|
||||||
values = append(values, pair.Value)
|
values = append(values, pair.Value)
|
||||||
@ -87,11 +122,10 @@ func (tasks *Tasks) Values() []*Task {
|
|||||||
return values
|
return values
|
||||||
}
|
}
|
||||||
|
|
||||||
type MatchingTask struct {
|
// FindMatchingTasks returns a list of tasks that match the given call. A task
|
||||||
Task *Task
|
// matches a call if its name is equal to the call's task name or if it matches
|
||||||
Wildcards []string
|
// a wildcard pattern. The function returns a list of MatchingTask structs, each
|
||||||
}
|
// containing a task and a list of wildcards that were matched.
|
||||||
|
|
||||||
func (t *Tasks) FindMatchingTasks(call *Call) []*MatchingTask {
|
func (t *Tasks) FindMatchingTasks(call *Call) []*MatchingTask {
|
||||||
if call == nil {
|
if call == nil {
|
||||||
return nil
|
return nil
|
||||||
@ -117,6 +151,8 @@ func (t *Tasks) FindMatchingTasks(call *Call) []*MatchingTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t1 *Tasks) Merge(t2 *Tasks, include *Include, includedTaskfileVars *Vars) error {
|
func (t1 *Tasks) Merge(t2 *Tasks, include *Include, includedTaskfileVars *Vars) error {
|
||||||
|
defer t2.mutex.RUnlock()
|
||||||
|
t2.mutex.RLock()
|
||||||
err := t2.Range(func(name string, v *Task) error {
|
err := t2.Range(func(name string, v *Task) error {
|
||||||
// We do a deep copy of the task struct here to ensure that no data can
|
// We do a deep copy of the task struct here to ensure that no data can
|
||||||
// be changed elsewhere once the taskfile is merged.
|
// be changed elsewhere once the taskfile is merged.
|
||||||
@ -207,6 +243,9 @@ func (t1 *Tasks) Merge(t2 *Tasks, include *Include, includedTaskfileVars *Vars)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tasks) UnmarshalYAML(node *yaml.Node) error {
|
func (t *Tasks) UnmarshalYAML(node *yaml.Node) error {
|
||||||
|
if t == nil || t.om == nil {
|
||||||
|
*t = *NewTasks()
|
||||||
|
}
|
||||||
switch node.Kind {
|
switch node.Kind {
|
||||||
case yaml.MappingNode:
|
case yaml.MappingNode:
|
||||||
// NOTE: orderedmap does not have an unmarshaler, so we have to decode
|
// NOTE: orderedmap does not have an unmarshaler, so we have to decode
|
||||||
|
@ -2,6 +2,7 @@ package ast
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/elliotchance/orderedmap/v2"
|
"github.com/elliotchance/orderedmap/v2"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
@ -11,52 +12,74 @@ import (
|
|||||||
"github.com/go-task/task/v3/internal/experiments"
|
"github.com/go-task/task/v3/internal/experiments"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Vars is a string[string] variables map.
|
type (
|
||||||
type Vars struct {
|
// Vars is an ordered map of variable names to values.
|
||||||
|
Vars struct {
|
||||||
om *orderedmap.OrderedMap[string, Var]
|
om *orderedmap.OrderedMap[string, Var]
|
||||||
|
mutex sync.RWMutex
|
||||||
}
|
}
|
||||||
|
// A VarElement is a key-value pair that is used for initializing a Vars
|
||||||
|
// structure.
|
||||||
|
VarElement orderedmap.Element[string, Var]
|
||||||
|
)
|
||||||
|
|
||||||
type VarElement orderedmap.Element[string, Var]
|
// NewVars creates a new instance of Vars and initializes it with the provided
|
||||||
|
// set of elements, if any. The elements are added in the order they are passed.
|
||||||
func NewVars(els ...*VarElement) *Vars {
|
func NewVars(els ...*VarElement) *Vars {
|
||||||
vs := &Vars{
|
vars := &Vars{
|
||||||
om: orderedmap.NewOrderedMap[string, Var](),
|
om: orderedmap.NewOrderedMap[string, Var](),
|
||||||
}
|
}
|
||||||
for _, el := range els {
|
for _, el := range els {
|
||||||
vs.Set(el.Key, el.Value)
|
vars.Set(el.Key, el.Value)
|
||||||
}
|
}
|
||||||
return vs
|
return vars
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vs *Vars) Len() int {
|
// Len returns the number of variables in the Vars map.
|
||||||
if vs == nil || vs.om == nil {
|
func (vars *Vars) Len() int {
|
||||||
|
if vars == nil || vars.om == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return vs.om.Len()
|
defer vars.mutex.RUnlock()
|
||||||
|
vars.mutex.RLock()
|
||||||
|
return vars.om.Len()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vs *Vars) Get(key string) (Var, bool) {
|
// Get returns the value the the variable with the provided key and a boolean
|
||||||
if vs == nil || vs.om == nil {
|
// that indicates if the value was found or not. If the value is not found, the
|
||||||
|
// returned variable is a zero value and the bool is false.
|
||||||
|
func (vars *Vars) Get(key string) (Var, bool) {
|
||||||
|
if vars == nil || vars.om == nil {
|
||||||
return Var{}, false
|
return Var{}, false
|
||||||
}
|
}
|
||||||
return vs.om.Get(key)
|
defer vars.mutex.RUnlock()
|
||||||
|
vars.mutex.RLock()
|
||||||
|
return vars.om.Get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vs *Vars) Set(key string, value Var) bool {
|
// Set sets the value of the variable with the provided key to the provided
|
||||||
if vs == nil {
|
// value. If the variable already exists, its value is updated. If the variable
|
||||||
vs = NewVars()
|
// does not exist, it is created.
|
||||||
|
func (vars *Vars) Set(key string, value Var) bool {
|
||||||
|
if vars == nil {
|
||||||
|
vars = NewVars()
|
||||||
}
|
}
|
||||||
if vs.om == nil {
|
if vars.om == nil {
|
||||||
vs.om = orderedmap.NewOrderedMap[string, Var]()
|
vars.om = orderedmap.NewOrderedMap[string, Var]()
|
||||||
}
|
}
|
||||||
return vs.om.Set(key, value)
|
defer vars.mutex.Unlock()
|
||||||
|
vars.mutex.Lock()
|
||||||
|
return vars.om.Set(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vs *Vars) Range(f func(k string, v Var) error) error {
|
// Range calls the provided function for each variable in the map. The function
|
||||||
if vs == nil || vs.om == nil {
|
// receives the variable's key and value as arguments. If the function returns
|
||||||
|
// an error, the iteration stops and the error is returned.
|
||||||
|
func (vars *Vars) Range(f func(k string, v Var) error) error {
|
||||||
|
if vars == nil || vars.om == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
for pair := vs.om.Front(); pair != nil; pair = pair.Next() {
|
for pair := vars.om.Front(); pair != nil; pair = pair.Next() {
|
||||||
if err := f(pair.Key, pair.Value); err != nil {
|
if err := f(pair.Key, pair.Value); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -64,11 +87,13 @@ func (vs *Vars) Range(f func(k string, v Var) error) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToCacheMap converts Vars to a map containing only the static
|
// ToCacheMap converts Vars to an unordered map containing only the static
|
||||||
// variables
|
// variables
|
||||||
func (vs *Vars) ToCacheMap() (m map[string]any) {
|
func (vars *Vars) ToCacheMap() (m map[string]any) {
|
||||||
m = make(map[string]any, vs.Len())
|
defer vars.mutex.RUnlock()
|
||||||
for pair := vs.om.Front(); pair != nil; pair = pair.Next() {
|
vars.mutex.RLock()
|
||||||
|
m = make(map[string]any, vars.Len())
|
||||||
|
for pair := vars.om.Front(); pair != nil; pair = pair.Next() {
|
||||||
if pair.Value.Sh != nil && *pair.Value.Sh != "" {
|
if pair.Value.Sh != nil && *pair.Value.Sh != "" {
|
||||||
// Dynamic variable is not yet resolved; trigger
|
// Dynamic variable is not yet resolved; trigger
|
||||||
// <no value> to be used in templates.
|
// <no value> to be used in templates.
|
||||||
@ -83,31 +108,38 @@ func (vs *Vars) ToCacheMap() (m map[string]any) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrapper around OrderedMap.Merge to ensure we don't get nil pointer errors
|
// Merge loops over other and merges it values with the variables in vars. If
|
||||||
func (vs *Vars) Merge(other *Vars, include *Include) {
|
// the include parameter is not nil and its it is an advanced import, the
|
||||||
if vs == nil || vs.om == nil || other == nil {
|
// directory is set set to the value of the include parameter.
|
||||||
|
func (vars *Vars) Merge(other *Vars, include *Include) {
|
||||||
|
if vars == nil || vars.om == nil || other == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
defer other.mutex.RUnlock()
|
||||||
|
other.mutex.RLock()
|
||||||
for pair := other.om.Front(); pair != nil; pair = pair.Next() {
|
for pair := other.om.Front(); pair != nil; pair = pair.Next() {
|
||||||
if include != nil && include.AdvancedImport {
|
if include != nil && include.AdvancedImport {
|
||||||
pair.Value.Dir = include.Dir
|
pair.Value.Dir = include.Dir
|
||||||
}
|
}
|
||||||
vs.om.Set(pair.Key, pair.Value)
|
vars.om.Set(pair.Key, pair.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy creates a new instance of Vars and copies
|
|
||||||
// data by value from the source struct.
|
|
||||||
func (vs *Vars) DeepCopy() *Vars {
|
func (vs *Vars) DeepCopy() *Vars {
|
||||||
if vs == nil {
|
if vs == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
defer vs.mutex.RUnlock()
|
||||||
|
vs.mutex.RLock()
|
||||||
return &Vars{
|
return &Vars{
|
||||||
om: deepcopy.OrderedMap(vs.om),
|
om: deepcopy.OrderedMap(vs.om),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vs *Vars) UnmarshalYAML(node *yaml.Node) error {
|
func (vs *Vars) UnmarshalYAML(node *yaml.Node) error {
|
||||||
|
if vs == nil || vs.om == nil {
|
||||||
|
*vs = *NewVars()
|
||||||
|
}
|
||||||
vs.om = orderedmap.NewOrderedMap[string, Var]()
|
vs.om = orderedmap.NewOrderedMap[string, Var]()
|
||||||
switch node.Kind {
|
switch node.Kind {
|
||||||
case yaml.MappingNode:
|
case yaml.MappingNode:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user