2020-01-29 09:02:22 +02:00
|
|
|
package taskfile
|
|
|
|
|
2021-01-01 23:27:50 +02:00
|
|
|
import (
|
2022-07-26 00:10:16 +02:00
|
|
|
"fmt"
|
|
|
|
"path/filepath"
|
|
|
|
|
|
|
|
"github.com/go-task/task/v3/internal/execext"
|
2022-08-06 23:19:07 +02:00
|
|
|
"github.com/go-task/task/v3/internal/filepathext"
|
2021-01-01 23:27:50 +02:00
|
|
|
|
2022-10-14 23:44:56 +02:00
|
|
|
"golang.org/x/exp/slices"
|
2021-01-01 23:27:50 +02:00
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
)
|
2020-01-29 09:02:22 +02:00
|
|
|
|
2022-07-26 00:10:16 +02:00
|
|
|
// IncludedTaskfile represents information about included taskfiles
|
2020-02-12 09:42:00 +02:00
|
|
|
type IncludedTaskfile struct {
|
2020-02-15 16:24:06 +02:00
|
|
|
Taskfile string
|
|
|
|
Dir string
|
2021-08-11 18:28:44 +02:00
|
|
|
Optional bool
|
2022-07-22 04:16:14 +02:00
|
|
|
Internal bool
|
2022-10-02 07:07:58 +02:00
|
|
|
Aliases []string
|
2020-02-15 16:24:06 +02:00
|
|
|
AdvancedImport bool
|
2022-02-24 00:53:46 +02:00
|
|
|
Vars *Vars
|
2022-07-26 00:10:16 +02:00
|
|
|
BaseDir string // The directory from which the including taskfile was loaded; used to resolve relative paths
|
2020-01-29 09:02:22 +02:00
|
|
|
}
|
|
|
|
|
2020-02-12 09:42:00 +02:00
|
|
|
// IncludedTaskfiles represents information about included tasksfiles
|
2021-01-01 23:27:50 +02:00
|
|
|
type IncludedTaskfiles struct {
|
|
|
|
Keys []string
|
|
|
|
Mapping map[string]IncludedTaskfile
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
|
|
|
func (tfs *IncludedTaskfiles) UnmarshalYAML(node *yaml.Node) error {
|
2022-12-19 03:11:31 +02:00
|
|
|
switch node.Kind {
|
2021-01-01 23:27:50 +02:00
|
|
|
|
2022-12-19 03:11:31 +02:00
|
|
|
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 {
|
|
|
|
keyNode := node.Content[i]
|
|
|
|
valueNode := node.Content[i+1]
|
2021-01-01 23:27:50 +02:00
|
|
|
|
2022-12-19 03:11:31 +02:00
|
|
|
var v IncludedTaskfile
|
|
|
|
if err := valueNode.Decode(&v); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
tfs.Set(keyNode.Value, v)
|
2021-01-01 23:27:50 +02:00
|
|
|
}
|
2022-12-19 03:11:31 +02:00
|
|
|
return nil
|
2021-01-01 23:27:50 +02:00
|
|
|
}
|
2022-12-19 03:11:31 +02:00
|
|
|
|
|
|
|
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into included taskfiles", node.Line, node.ShortTag())
|
2021-01-01 23:27:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Len returns the length of the map
|
|
|
|
func (tfs *IncludedTaskfiles) Len() int {
|
|
|
|
if tfs == nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return len(tfs.Keys)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Merge merges the given IncludedTaskfiles into the caller one
|
|
|
|
func (tfs *IncludedTaskfiles) Merge(other *IncludedTaskfiles) {
|
2022-05-15 02:00:15 +02:00
|
|
|
_ = other.Range(func(key string, value IncludedTaskfile) error {
|
2021-01-01 23:27:50 +02:00
|
|
|
tfs.Set(key, value)
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set sets a value to a given key
|
|
|
|
func (tfs *IncludedTaskfiles) Set(key string, includedTaskfile IncludedTaskfile) {
|
|
|
|
if tfs.Mapping == nil {
|
|
|
|
tfs.Mapping = make(map[string]IncludedTaskfile, 1)
|
|
|
|
}
|
2022-09-18 01:25:55 +02:00
|
|
|
if !slices.Contains(tfs.Keys, key) {
|
2021-01-01 23:27:50 +02:00
|
|
|
tfs.Keys = append(tfs.Keys, key)
|
|
|
|
}
|
|
|
|
tfs.Mapping[key] = includedTaskfile
|
|
|
|
}
|
|
|
|
|
|
|
|
// Range allows you to loop into the included taskfiles in its right order
|
|
|
|
func (tfs *IncludedTaskfiles) Range(yield func(key string, includedTaskfile IncludedTaskfile) error) error {
|
|
|
|
if tfs == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
for _, k := range tfs.Keys {
|
|
|
|
if err := yield(k, tfs.Mapping[k]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2020-01-29 09:02:22 +02:00
|
|
|
|
2022-12-19 03:11:31 +02:00
|
|
|
func (it *IncludedTaskfile) UnmarshalYAML(node *yaml.Node) error {
|
|
|
|
switch node.Kind {
|
|
|
|
|
|
|
|
case yaml.ScalarNode:
|
|
|
|
var str string
|
|
|
|
if err := node.Decode(&str); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-01-29 09:02:22 +02:00
|
|
|
it.Taskfile = str
|
|
|
|
return nil
|
|
|
|
|
2022-12-19 03:11:31 +02:00
|
|
|
case yaml.MappingNode:
|
|
|
|
var includedTaskfile struct {
|
|
|
|
Taskfile string
|
|
|
|
Dir string
|
|
|
|
Optional bool
|
|
|
|
Internal bool
|
|
|
|
Aliases []string
|
|
|
|
Vars *Vars
|
|
|
|
}
|
|
|
|
if err := node.Decode(&includedTaskfile); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
it.Taskfile = includedTaskfile.Taskfile
|
|
|
|
it.Dir = includedTaskfile.Dir
|
|
|
|
it.Optional = includedTaskfile.Optional
|
|
|
|
it.Internal = includedTaskfile.Internal
|
|
|
|
it.Aliases = includedTaskfile.Aliases
|
|
|
|
it.AdvancedImport = true
|
|
|
|
it.Vars = includedTaskfile.Vars
|
|
|
|
return nil
|
2020-01-29 09:02:22 +02:00
|
|
|
}
|
2022-12-19 03:11:31 +02:00
|
|
|
|
|
|
|
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into included taskfile", node.Line, node.ShortTag())
|
2020-01-29 09:02:22 +02:00
|
|
|
}
|
2022-07-26 00:10:16 +02:00
|
|
|
|
2022-10-02 07:45:27 +02:00
|
|
|
// 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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-26 00:10:16 +02:00
|
|
|
// FullTaskfilePath returns the fully qualified path to the included taskfile
|
|
|
|
func (it *IncludedTaskfile) FullTaskfilePath() (string, error) {
|
|
|
|
return it.resolvePath(it.Taskfile)
|
|
|
|
}
|
|
|
|
|
|
|
|
// FullDirPath returns the fully qualified path to the included taskfile's working directory
|
|
|
|
func (it *IncludedTaskfile) FullDirPath() (string, error) {
|
|
|
|
return it.resolvePath(it.Dir)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (it *IncludedTaskfile) resolvePath(path string) (string, error) {
|
|
|
|
path, err := execext.Expand(path)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
if filepath.IsAbs(path) {
|
|
|
|
return path, nil
|
|
|
|
}
|
|
|
|
|
2022-08-06 23:19:07 +02:00
|
|
|
result, err := filepath.Abs(filepathext.SmartJoin(it.BaseDir, path))
|
2022-07-26 00:10:16 +02:00
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("task: error resolving path %s relative to %s: %w", path, it.BaseDir, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|