1
0
mirror of https://github.com/go-task/task.git synced 2025-03-17 21:08:01 +02:00

fix: deep copy included tasks

This commit is contained in:
Pete Davison 2022-10-02 05:45:27 +00:00
parent bb79fa1dc3
commit d33906b6e4
5 changed files with 89 additions and 10 deletions

23
taskfile/copy.go Normal file
View File

@ -0,0 +1,23 @@
package taskfile
import "golang.org/x/exp/constraints"
func deepCopySlice[T any](orig []T) []T {
if orig == nil {
return nil
}
c := make([]T, len(orig))
copy(c, orig)
return c
}
func deepCopyMap[K constraints.Ordered, V any](orig map[K]V) map[K]V {
if orig == nil {
return nil
}
c := make(map[K]V, len(orig))
for k, v := range orig {
c[k] = v
}
return c
}

View File

@ -120,6 +120,23 @@ func (it *IncludedTaskfile) UnmarshalYAML(unmarshal func(interface{}) error) err
return nil
}
// DeepCopy creates a new instance of IncludedTaskfile and copies
// data by value from the source struct.
func (it *IncludedTaskfile) DeepCopy() *IncludedTaskfile {
if it == nil {
return nil
}
return &IncludedTaskfile{
Taskfile: it.Taskfile,
Dir: it.Dir,
Optional: it.Optional,
Internal: it.Internal,
AdvancedImport: it.AdvancedImport,
Vars: it.Vars.DeepCopy(),
BaseDir: it.BaseDir,
}
}
// FullTaskfilePath returns the fully qualified path to the included taskfile
func (it *IncludedTaskfile) FullTaskfilePath() (string, error) {
return it.resolvePath(it.Taskfile)

View File

@ -39,19 +39,14 @@ func Merge(t1, t2 *Taskfile, includedTaskfile *IncludedTaskfile, namespaces ...s
t1.Tasks = make(Tasks)
}
for k, v := range t2.Tasks {
// FIXME(@andreynering): Refactor this block, otherwise we can
// have serious side-effects in the future, since we're editing
// the original references instead of deep copying them.
task := v
// We do a deep copy of the task struct here to ensure that no data can
// be changed elsewhere once the taskfile is merged.
task := v.DeepCopy()
// Set the task to internal if EITHER the included task or the included
// taskfile are marked as internal
task.Internal = task.Internal || includedTaskfile.Internal
// Deep copy the aliases so we can use them later
origAliases := make([]string, len(task.Aliases))
copy(origAliases, task.Aliases)
// Add namespaces to dependencies, commands and aliases
for _, dep := range task.Deps {
dep.Task = taskNameWithNamespace(dep.Task, namespaces...)
@ -67,8 +62,8 @@ func Merge(t1, t2 *Taskfile, includedTaskfile *IncludedTaskfile, namespaces ...s
// Add namespace aliases
if includedTaskfile != nil {
for _, namespaceAlias := range includedTaskfile.Aliases {
for _, alias := range origAliases {
task.Aliases = append(v.Aliases, taskNameWithNamespace(alias, namespaceAlias))
for _, alias := range v.Aliases {
task.Aliases = append(task.Aliases, taskNameWithNamespace(alias, namespaceAlias))
}
}
}

View File

@ -98,3 +98,35 @@ func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
t.Run = task.Run
return nil
}
// DeepCopy creates a new instance of Task and copies
// data by value from the source struct.
func (t *Task) DeepCopy() *Task {
c := &Task{
Task: t.Task,
Cmds: deepCopySlice(t.Cmds),
Deps: deepCopySlice(t.Deps),
Label: t.Label,
Desc: t.Desc,
Summary: t.Summary,
Aliases: deepCopySlice(t.Aliases),
Sources: deepCopySlice(t.Sources),
Generates: deepCopySlice(t.Generates),
Status: deepCopySlice(t.Status),
Preconditions: deepCopySlice(t.Preconditions),
Dir: t.Dir,
Vars: t.Vars.DeepCopy(),
Env: t.Env.DeepCopy(),
Silent: t.Silent,
Interactive: t.Interactive,
Internal: t.Internal,
Method: t.Method,
Prefix: t.Prefix,
IgnoreError: t.IgnoreError,
Run: t.Run,
IncludeVars: t.IncludeVars.DeepCopy(),
IncludedTaskfileVars: t.IncludedTaskfileVars.DeepCopy(),
IncludedTaskfile: t.IncludedTaskfile.DeepCopy(),
}
return c
}

View File

@ -34,6 +34,18 @@ func (vs *Vars) UnmarshalYAML(node *yaml.Node) error {
return nil
}
// 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{
Keys: deepCopySlice(vs.Keys),
Mapping: deepCopyMap(vs.Mapping),
}
}
// Merge merges the given Vars into the caller one
func (vs *Vars) Merge(other *Vars) {
_ = other.Range(func(key string, value Var) error {