From 5b727dc14c6794a07283611a34712c2f5a0f296b Mon Sep 17 00:00:00 2001 From: 42atomys Date: Sun, 19 Jan 2025 18:14:59 +0100 Subject: [PATCH 1/3] chore: migrate template engine to sprout v1.0.0 --- go.mod | 16 +- go.sum | 28 ++- internal/templater/funcs.go | 123 ++++------ internal/templater/taskfunc/functions.go | 228 ++++++++++++++++++ .../taskfunc/functions_linux_test.go | 70 ++++++ internal/templater/taskfunc/functions_test.go | 112 +++++++++ .../taskfunc/functions_windows_test.go | 70 ++++++ internal/templater/taskfunc/task_func.go | 74 ++++++ 8 files changed, 625 insertions(+), 96 deletions(-) create mode 100644 internal/templater/taskfunc/functions.go create mode 100644 internal/templater/taskfunc/functions_linux_test.go create mode 100644 internal/templater/taskfunc/functions_test.go create mode 100644 internal/templater/taskfunc/functions_windows_test.go create mode 100644 internal/templater/taskfunc/task_func.go diff --git a/go.mod b/go.mod index a8962768fb..e524fbeb82 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/go-task/task/v3 -go 1.22.0 +go 1.23.3 require ( github.com/Ladicle/tabwriter v1.0.0 @@ -13,7 +13,7 @@ require ( github.com/fatih/color v1.18.0 github.com/go-git/go-billy/v5 v5.6.1 github.com/go-git/go-git/v5 v5.13.1 - github.com/go-task/slim-sprig/v3 v3.0.0 + github.com/go-sprout/sprout v1.0.0 github.com/go-task/template v0.1.0 github.com/joho/godotenv v1.5.1 github.com/mattn/go-zglob v0.0.6 @@ -25,13 +25,13 @@ require ( github.com/stretchr/testify v1.10.0 github.com/zeebo/xxh3 v1.0.2 golang.org/x/sync v0.10.0 - golang.org/x/term v0.27.0 + golang.org/x/term v0.28.0 gopkg.in/yaml.v3 v3.0.1 mvdan.cc/sh/v3 v3.10.0 ) require ( - dario.cat/mergo v1.0.0 // indirect + dario.cat/mergo v1.0.1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/ProtonMail/go-crypto v1.1.3 // indirect github.com/cloudflare/circl v1.3.7 // indirect @@ -45,17 +45,21 @@ require ( github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/muesli/cancelreader v0.2.2 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/skeema/knownhosts v1.3.0 // indirect + github.com/spf13/cast v1.7.1 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect - golang.org/x/crypto v0.31.0 // indirect + golang.org/x/crypto v0.32.0 // indirect golang.org/x/mod v0.18.0 // indirect golang.org/x/net v0.33.0 // indirect - golang.org/x/sys v0.28.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/text v0.21.0 // indirect golang.org/x/tools v0.22.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) diff --git a/go.sum b/go.sum index 15a4f051fd..dd6e529e1c 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Ladicle/tabwriter v1.0.0 h1:DZQqPvMumBDwVNElso13afjYLNp0Z7pHqHnu0r4t9Dg= github.com/Ladicle/tabwriter v1.0.0/go.mod h1:c4MdCjxQyTbGuQO/gvqJ+IA/89UEwrsD6hUCW98dyp4= github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= @@ -42,6 +42,8 @@ github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= @@ -54,8 +56,8 @@ github.com/go-git/go-git/v5 v5.13.1 h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc= github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= -github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= -github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/go-sprout/sprout v1.0.0 h1:4uxG1fZbUxfXB2OsjwzyIOK4lZQEhsksib17vVAZqOs= +github.com/go-sprout/sprout v1.0.0/go.mod h1:I6ifgKakZI/NOkFyZueoS5N0qENvI5ZWcWT7oM34vsE= github.com/go-task/template v0.1.0 h1:ym/r2G937RZA1bsgiWedNnY9e5kxDT+3YcoAnuIetTE= github.com/go-task/template v0.1.0/go.mod h1:RgwRaZK+kni/hJJ7/AaOE2lPQFPbAdji/DyhC6pxo4k= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -86,8 +88,12 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-zglob v0.0.6 h1:mP8RnmCgho4oaUYDIDn6GNxYk+qJGUs8fJLn+twYj2A= github.com/mattn/go-zglob v0.0.6/go.mod h1:MxxjyoXXnMxfIpxTK2GAkw1w8glPsQILx3N5wrKakiY= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= @@ -113,6 +119,8 @@ github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY= github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -129,8 +137,8 @@ github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= @@ -149,11 +157,11 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= +golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= diff --git a/internal/templater/funcs.go b/internal/templater/funcs.go index 79c837a3c3..0ea9dcc9d1 100644 --- a/internal/templater/funcs.go +++ b/internal/templater/funcs.go @@ -1,90 +1,53 @@ package templater import ( - "path/filepath" - "runtime" - "strings" - - "github.com/davecgh/go-spew/spew" - "mvdan.cc/sh/v3/shell" - "mvdan.cc/sh/v3/syntax" - - sprig "github.com/go-task/slim-sprig/v3" + "github.com/go-sprout/sprout" + "github.com/go-sprout/sprout/registry/backward" + "github.com/go-sprout/sprout/registry/checksum" + "github.com/go-sprout/sprout/registry/conversion" + "github.com/go-sprout/sprout/registry/encoding" + "github.com/go-sprout/sprout/registry/env" + "github.com/go-sprout/sprout/registry/filesystem" + "github.com/go-sprout/sprout/registry/maps" + "github.com/go-sprout/sprout/registry/network" + "github.com/go-sprout/sprout/registry/numeric" + "github.com/go-sprout/sprout/registry/random" + "github.com/go-sprout/sprout/registry/reflect" + "github.com/go-sprout/sprout/registry/regexp" + "github.com/go-sprout/sprout/registry/slices" + "github.com/go-sprout/sprout/registry/std" + "github.com/go-sprout/sprout/registry/strings" + "github.com/go-sprout/sprout/registry/time" + taskfunc "github.com/go-task/task/v3/internal/templater/taskfunc" "github.com/go-task/template" ) var templateFuncs template.FuncMap func init() { - taskFuncs := template.FuncMap{ - "OS": func() string { return runtime.GOOS }, - "ARCH": func() string { return runtime.GOARCH }, - "numCPU": func() int { return runtime.NumCPU() }, - "catLines": func(s string) string { - s = strings.ReplaceAll(s, "\r\n", " ") - return strings.ReplaceAll(s, "\n", " ") - }, - "splitLines": func(s string) []string { - s = strings.ReplaceAll(s, "\r\n", "\n") - return strings.Split(s, "\n") - }, - "fromSlash": func(path string) string { - return filepath.FromSlash(path) - }, - "toSlash": func(path string) string { - return filepath.ToSlash(path) - }, - "exeExt": func() string { - if runtime.GOOS == "windows" { - return ".exe" - } - return "" - }, - "shellQuote": func(str string) (string, error) { - return syntax.Quote(str, syntax.LangBash) - }, - "splitArgs": func(s string) ([]string, error) { - return shell.Fields(s, nil) - }, - // IsSH is deprecated. - "IsSH": func() bool { return true }, - "joinPath": func(elem ...string) string { - return filepath.Join(elem...) - }, - "relPath": func(basePath, targetPath string) (string, error) { - return filepath.Rel(basePath, targetPath) - }, - "merge": func(base map[string]any, v ...map[string]any) map[string]any { - cap := len(v) - for _, m := range v { - cap += len(m) - } - result := make(map[string]any, cap) - for k, v := range base { - result[k] = v - } - for _, m := range v { - for k, v := range m { - result[k] = v - } - } - return result - }, - "spew": func(v any) string { - return spew.Sdump(v) - }, - } - - // aliases - taskFuncs["q"] = taskFuncs["shellQuote"] - - // Deprecated aliases for renamed functions. - taskFuncs["FromSlash"] = taskFuncs["fromSlash"] - taskFuncs["ToSlash"] = taskFuncs["toSlash"] - taskFuncs["ExeExt"] = taskFuncs["exeExt"] - - templateFuncs = template.FuncMap(sprig.TxtFuncMap()) - for k, v := range taskFuncs { - templateFuncs[k] = v - } + handler := sprout.New( + sprout.WithRegistries( + // Library registries + backward.NewRegistry(), + checksum.NewRegistry(), + conversion.NewRegistry(), + encoding.NewRegistry(), + env.NewRegistry(), + filesystem.NewRegistry(), + maps.NewRegistry(), + network.NewRegistry(), + numeric.NewRegistry(), + random.NewRegistry(), + reflect.NewRegistry(), + regexp.NewRegistry(), + slices.NewRegistry(), + std.NewRegistry(), + strings.NewRegistry(), + time.NewRegistry(), + // Own registry + taskfunc.NewRegistry(), + ), + ) + + templateFuncs = template.FuncMap(handler.Build()) } diff --git a/internal/templater/taskfunc/functions.go b/internal/templater/taskfunc/functions.go new file mode 100644 index 0000000000..bf22cd8f23 --- /dev/null +++ b/internal/templater/taskfunc/functions.go @@ -0,0 +1,228 @@ +package taskfunc + +import ( + "path/filepath" + "runtime" + "strings" + + "github.com/davecgh/go-spew/spew" + "mvdan.cc/sh/v3/shell" + "mvdan.cc/sh/v3/syntax" +) + +// OS returns the running program's operating system target: one of +// "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "plan9", +// "solaris", or "windows". +// +// Returns: +// +// string - the operating system target of the running program. +func (*GoTaskRegistry) OS() string { + return runtime.GOOS +} + +// ARCH returns the running program's architecture target: one of "386", "amd64", +// "arm", "arm64", "ppc64", "ppc64le", "mips", "mipsle", "mips64", "mips64le", +// "s390", "s390x". +// +// Returns: +// +// string - the architecture target of the running program. +func (*GoTaskRegistry) ARCH() string { + return runtime.GOARCH +} + +// NumCPU returns the number of logical CPUs usable by the current process. +// +// Returns: +// +// int - the number of logical CPUs. +func (*GoTaskRegistry) NumCPU() int { + return runtime.NumCPU() +} + +// CatLines replaces Unix (`\n`) and Windows (`\r\n`) styled newlines with a space. +// This is useful to ensure the string is a single line regardless of the newline style. +// +// Parameters: +// +// s - the string to replace newlines in. +// +// Returns: +// +// string - the string with newlines replaced by spaces. +func (*GoTaskRegistry) CatLines(s string) string { + s = strings.ReplaceAll(s, "\r\n", " ") + return strings.ReplaceAll(s, "\n", " ") +} + +// SplitLines splits Unix (`\n`) and Windows (`\r\n`) styled newlines. +// This is useful to split a string into lines regardless of the newline style. +// +// Parameters: +// +// s - the string to split into lines. +// +// Returns: +// +// []string - the string split into lines. +func (*GoTaskRegistry) SplitLines(s string) []string { + s = strings.ReplaceAll(s, "\r\n", "\n") + return strings.Split(s, "\n") +} + +// FromSlash converts a string from a slash (`/`) path format to a platform-specific +// path format. Does nothing on Unix, but on Windows converts a string from a slash +// path format to a backslash path format. +// +// Parameters: +// +// path - the string to convert. +// +// Returns: +// +// string - the path in a platform-specific format. +func (*GoTaskRegistry) FromSlash(path string) string { + return filepath.FromSlash(path) +} + +// ToSlash converts a string from a platform-specific path format to a slash +// path format. Does nothing on Unix, but on Windows converts a string from a +// backslash path format to a slash path format. +// +// Parameters: +// +// path - the string to convert. +// +// Returns: +// +// string - the path in a slash path format. +func (*GoTaskRegistry) ToSlash(path string) string { + return filepath.ToSlash(path) +} + +// ExeExt returns the appropriate executable file extension for the current +// operating system. On Windows, it returns ".exe", while on other operating +// systems, it returns an empty string. +// +// Returns: +// +// string - the executable file extension for the current OS. + +func (*GoTaskRegistry) ExeExt() string { + if runtime.GOOS == "windows" { + return ".exe" + } + return "" +} + +// ShellQuote quotes a string to make it safe for use in shell scripts. +// It assumes the Bash dialect. +// +// Parameters: +// +// str - the string to quote. +// +// Returns: +// +// string - the quoted string. +// error - an error if unable to quote the string. +func (*GoTaskRegistry) ShellQuote(str string) (string, error) { + return syntax.Quote(str, syntax.LangBash) +} + +// SplitArgs splits a string as if it were a command's arguments. Task uses +// [this Go function](https://pkg.go.dev/mvdan.cc/sh/v3@v3.4.0/shell#Fields). +// +// Parameters: +// +// s - the string to split into arguments. +// +// Returns: +// +// []string - the string split into arguments. +// error - an error if unable to split the string. +func (*GoTaskRegistry) SplitArgs(s string) ([]string, error) { + return shell.Fields(s, nil) +} + +// ! IsSH is deprecated. +func (*GoTaskRegistry) IsSH() bool { + return true +} + +// JoinPath joins any number of arguments into a path. The same as Go's +// [filepath.Join](https://pkg.go.dev/path/filepath#Join). +// +// Parameters: +// +// elem - the elements to join together. +// +// Returns: +// +// string - the joined path. +func (*GoTaskRegistry) JoinPath(elem ...string) string { + return filepath.Join(elem...) +} + +// RelPath converts an absolute target path into a relative path, based on a base path. +// This function utilizes Go's filepath.Rel to perform the conversion. +// +// Parameters: +// +// basePath - the base path from which the relative path is calculated. +// targetPath - the absolute path to be converted into a relative path. +// +// Returns: +// +// string - the relative path from basePath to targetPath. +// error - an error if the paths cannot be made relative. + +func (*GoTaskRegistry) RelPath(basePath, targetPath string) (string, error) { + return filepath.Rel(basePath, targetPath) +} + +// Merge creates a new map that is a copy of the first map with the keys of each +// subsequent map merged into it. If there is a duplicate key, the value of the +// last map with that key is used. +// +// Parameters: +// +// base - the base map to merge subsequent maps into. +// v - the maps to merge into the base map. +// +// Returns: +// +// map[string]any - the merged map. +func (*GoTaskRegistry) Merge(base map[string]any, v ...map[string]any) map[string]any { + cap := len(v) + for _, m := range v { + cap += len(m) + } + result := make(map[string]any, cap) + for k, v := range base { + result[k] = v + } + for _, m := range v { + for k, v := range m { + result[k] = v + } + } + + return result +} + +// Spew returns the Go representation of a specific variable. Useful for +// debugging. Uses the [davecgh/go-spew](https://github.com/davecgh/go-spew) +// package. +// +// Parameters: +// +// v - the variable to dump. +// +// Returns: +// +// string - the dumped variable. +func (*GoTaskRegistry) Spew(v any) string { + return spew.Sdump(v) +} diff --git a/internal/templater/taskfunc/functions_linux_test.go b/internal/templater/taskfunc/functions_linux_test.go new file mode 100644 index 0000000000..02076c6cc0 --- /dev/null +++ b/internal/templater/taskfunc/functions_linux_test.go @@ -0,0 +1,70 @@ +package taskfunc_test + +import ( + "testing" + + "github.com/go-sprout/sprout/pesticide" + taskfunc "github.com/go-task/task/v3/internal/templater/taskfunc" +) + +func TestOs(t *testing.T) { + tc := []pesticide.TestCase{ + {Input: `{{ os }}`, ExpectedOutput: "linux"}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} + +func TestArch(t *testing.T) { + tc := []pesticide.TestCase{ + {Input: `{{ arch }}`, ExpectedOutput: "amd64"}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} + +func TestFromSlash(t *testing.T) { + tc := []pesticide.TestCase{ + {Input: `{{ fromSlash "a/b" }}`, ExpectedOutput: "a/b"}, + {Input: `{{ fromSlash "a\\b" }}`, ExpectedOutput: "a\\b"}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} + +func TestToSlash(t *testing.T) { + tc := []pesticide.TestCase{ + {Input: `{{ toSlash "a\\b" }}`, ExpectedOutput: "a\\b"}, + {Input: `{{ toSlash "a/b" }}`, ExpectedOutput: "a/b"}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} + +func TestExeExt(t *testing.T) { + tc := []pesticide.TestCase{ + {Input: `{{ exeExt }}`, ExpectedOutput: ""}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} + +func TestJoinPath(t *testing.T) { + tc := []pesticide.TestCase{ + {Input: `{{ joinPath "a" "b" }}`, ExpectedOutput: "a/b"}, + {Input: `{{ joinPath "a/b" "c" }}`, ExpectedOutput: "a/b/c"}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} + +func TestRelPath(t *testing.T) { + tc := []pesticide.TestCase{ + {Input: `{{ relPath "/a" "/a/b/c" }}`, ExpectedOutput: "b/c"}, + {Input: `{{ relPath "\\a" "\\b\\c" }}`, ExpectedOutput: "../\\b\\c"}, + {Input: `{{ relPath "/a/b" "/a/b/c" }}`, ExpectedOutput: "c"}, + {Input: `{{ relPath "/a" "./b/c" }}`, ExpectedErr: "relPath: Rel: can't make ./b/c relative to /a"}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} diff --git a/internal/templater/taskfunc/functions_test.go b/internal/templater/taskfunc/functions_test.go new file mode 100644 index 0000000000..abdbd742d6 --- /dev/null +++ b/internal/templater/taskfunc/functions_test.go @@ -0,0 +1,112 @@ +package taskfunc_test + +import ( + "fmt" + "runtime" + "testing" + + "github.com/go-sprout/sprout/pesticide" + taskfunc "github.com/go-task/task/v3/internal/templater/taskfunc" +) + +func TestNumCPUs(t *testing.T) { + expected := runtime.NumCPU() + + tc := []pesticide.TestCase{ + {Input: `{{ numCPU }}`, ExpectedOutput: fmt.Sprint(expected)}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} + +func TestCatLines(t *testing.T) { + tc := []pesticide.TestCase{ + {Input: `{{ catLines "a\nb" }}`, ExpectedOutput: "a b"}, + {Input: `{{ catLines "a\r\nb" }}`, ExpectedOutput: "a b"}, + {Input: `{{ catLines "a\nb\n" }}`, ExpectedOutput: "a b "}, + {Input: `{{ catLines "a\nb\r\n" }}`, ExpectedOutput: "a b "}, + {Input: `{{ catLines "a\r\nb\n\n" }}`, ExpectedOutput: "a b "}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} + +func TestSplitLines(t *testing.T) { + tc := []pesticide.TestCase{ + {Input: `{{ splitLines "a\nb" }}`, ExpectedOutput: "[a b]"}, + {Input: `{{ splitLines "a\r\nb" }}`, ExpectedOutput: "[a b]"}, + {Input: `{{ splitLines "a\nb\n" }}`, ExpectedOutput: "[a b ]"}, + {Input: `{{ splitLines "a\nb\r\n" }}`, ExpectedOutput: "[a b ]"}, + {Input: `{{ splitLines "a\r\nb\n\n" }}`, ExpectedOutput: "[a b ]"}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} + +func TestShellQuote(t *testing.T) { + tc := []pesticide.TestCase{ + {Input: `{{ shellQuote "a b" }}`, ExpectedOutput: "'a b'"}, + {Input: `{{ shellQuote "a b c" }}`, ExpectedOutput: "'a b c'"}, + {Input: `{{ shellQuote "a'b" }}`, ExpectedOutput: "\"a'b\""}, + {Input: `{{ shellQuote "a\"b" }}`, ExpectedOutput: "'a\"b'"}, + {Name: "TestAlias", Input: `{{ q "a b" }}`, ExpectedOutput: "'a b'"}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} + +func TestSplitArgs(t *testing.T) { + tc := []pesticide.TestCase{ + {Input: `{{ splitArgs "a b" }}`, ExpectedOutput: "[a b]"}, + {Input: `{{ splitArgs "a b c" }}`, ExpectedOutput: "[a b c]"}, + {Input: `{{ splitArgs "ab" }}`, ExpectedOutput: "[ab]"}, + {Name: "TestSpaceArg", Input: `{{ splitArgs "'a b' c" | join "-" }}`, ExpectedOutput: "a b-c"}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} + +func TestMergeArgs(t *testing.T) { + var dest map[string]any + + tc := []pesticide.TestCase{ + {Name: "TestEmpty", Input: `{{merge .}}`, ExpectedOutput: "map[]"}, + {Name: "TestWithOneMap", Input: `{{merge .}}`, ExpectedOutput: "map[a:1 b:2]", Data: map[string]any{"a": 1, "b": 2}}, + {Name: "TestWithTwoMaps", Input: `{{merge .Dest .Src1}}`, ExpectedOutput: "map[a:1 b:2 c:3 d:4]", Data: map[string]any{"Dest": map[string]any{"a": 1, "b": 2}, "Src1": map[string]any{"c": 3, "d": 4}}}, + {Name: "TestWithOverwrite", Input: `{{merge .Dest .Src1}}`, ExpectedOutput: "map[a:3 b:2 d:4]", Data: map[string]any{"Dest": map[string]any{"a": 1, "b": 2}, "Src1": map[string]any{"a": 3, "d": 4}}}, + {Name: "TestWithZeroValues", Input: `{{merge .Dest .Src1}}`, ExpectedOutput: "map[a:2 b:true c:3 d:4]", Data: map[string]any{"Dest": map[string]any{"a": 0, "b": false}, "Src1": map[string]any{"a": 2, "b": true, "c": 3, "d": 4}}}, + {Name: "TestWithNotEnoughArgs", Input: `{{merge .}}`, ExpectedOutput: "map[a:1]", Data: map[string]any{"a": 1}}, + {Name: "TestWithDestNonInitialized", Input: `{{merge .A .B}}`, ExpectedOutput: "map[b:2]", Data: map[string]any{"A": dest, "B": map[string]any{"b": 2}}}, + {Name: "TestWithDestNotMap", Input: `{{merge .A .B}}`, Data: map[string]any{"A": 1, "B": map[string]any{"b": 2}}, ExpectedErr: "wrong type for value"}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} + +func TestSpew(t *testing.T) { + + dict := map[string]any{"a": 1} + spewDictOutput := `(map[string]interface {}) (len=1) { + (string) (len=1) "a": (int) 1 +} +` + list := []any{1} + spewListOutput := `([]interface {}) (len=1 cap=1) { + (int) 1 +} +` + strukt := struct{ A int }{1} + spewStruktOutput := `(struct { A int }) { + A: (int) 1 +} +` + + tc := []pesticide.TestCase{ + {Input: `{{ spew .V }}`, ExpectedOutput: spewDictOutput, Data: map[string]any{"V": dict}}, + {Input: `{{ spew .V }}`, ExpectedOutput: spewListOutput, Data: map[string]any{"V": list}}, + {Input: `{{ spew .V }}`, ExpectedOutput: spewStruktOutput, Data: map[string]any{"V": strukt}}, + {Input: `{{ spew .V }}`, ExpectedOutput: "(interface {}) \n"}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} diff --git a/internal/templater/taskfunc/functions_windows_test.go b/internal/templater/taskfunc/functions_windows_test.go new file mode 100644 index 0000000000..0ebfe26e3c --- /dev/null +++ b/internal/templater/taskfunc/functions_windows_test.go @@ -0,0 +1,70 @@ +package taskfunc_test + +import ( + "testing" + + "github.com/go-sprout/sprout/pesticide" + taskfunc "github.com/go-task/task/v3/internal/templater/taskfunc" +) + +func TestOs(t *testing.T) { + tc := []pesticide.TestCase{ + {Input: `{{ os }}`, ExpectedOutput: "windows"}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} + +func TestArch(t *testing.T) { + tc := []pesticide.TestCase{ + {Input: `{{ arch }}`, ExpectedOutput: "amd64"}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} + +func TestFromSlash(t *testing.T) { + tc := []pesticide.TestCase{ + {Input: `{{ fromSlash "a/b" }}`, ExpectedOutput: "a\\b"}, + {Input: `{{ fromSlash "a\\b" }}`, ExpectedOutput: "a\\b"}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} + +func TestToSlash(t *testing.T) { + tc := []pesticide.TestCase{ + {Input: `{{ toSlash "a\\b" }}`, ExpectedOutput: "a/b"}, + {Input: `{{ toSlash "a/b" }}`, ExpectedOutput: "a/b"}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} + +func TestExeExt(t *testing.T) { + tc := []pesticide.TestCase{ + {Input: `{{ exeExt }}`, ExpectedOutput: ".exe"}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} + +func TestJoinPath(t *testing.T) { + tc := []pesticide.TestCase{ + {Input: `{{ joinPath "a" "b" }}`, ExpectedOutput: "a\\b"}, + {Input: `{{ joinPath "a\\b" "c" }}`, ExpectedOutput: "a\\b\\c"}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} + +func TestRelPath(t *testing.T) { + tc := []pesticide.TestCase{ + {Input: `{{ relPath "/a" "/a/b/c" }}`, ExpectedOutput: "b\\c"}, + {Input: `{{ relPath "\\a" "\\b\\c" }}`, ExpectedOutput: "..\\b\\c"}, + {Input: `{{ relPath "/a/b" "/a/b/c" }}`, ExpectedOutput: "c"}, + {Input: `{{ relPath "/a" "./b/c" }}`, ExpectedErr: "relPath: Rel: can't make ./b/c relative to /a"}, + } + + pesticide.RunTestCases(t, taskfunc.NewRegistry(), tc) +} diff --git a/internal/templater/taskfunc/task_func.go b/internal/templater/taskfunc/task_func.go new file mode 100644 index 0000000000..2dc9f60ad5 --- /dev/null +++ b/internal/templater/taskfunc/task_func.go @@ -0,0 +1,74 @@ +package taskfunc + +import ( + "github.com/go-sprout/sprout" +) + +// GoTaskRegistry struct implements the Registry interface, +// providing a way to register functions and aliases for go-task templates. +type GoTaskRegistry struct { + handler sprout.Handler // Embedding Handler for shared functionality +} + +// NewRegistry initializes and returns a new instance of your registry. +func NewRegistry() *GoTaskRegistry { + return &GoTaskRegistry{} +} + +// UID provides a unique identifier for your registry. +func (gtr *GoTaskRegistry) UID() string { + return "go-task/task.gotaskregistry" +} + +// LinkHandler connects the Handler to your registry, enabling runtime functionalities. +func (gtr *GoTaskRegistry) LinkHandler(fh sprout.Handler) error { + gtr.handler = fh + return nil +} + +// RegisterFunctions adds the provided functions into the given function map. +// This method is called by an Handler to register all functions of a registry. +func (gtr *GoTaskRegistry) RegisterFunctions(funcsMap sprout.FunctionMap) error { + sprout.AddFunction(funcsMap, "os", gtr.OS) + sprout.AddFunction(funcsMap, "arch", gtr.ARCH) + sprout.AddFunction(funcsMap, "numCPU", gtr.NumCPU) + sprout.AddFunction(funcsMap, "catLines", gtr.CatLines) + sprout.AddFunction(funcsMap, "splitLines", gtr.SplitLines) + sprout.AddFunction(funcsMap, "fromSlash", gtr.FromSlash) + sprout.AddFunction(funcsMap, "toSlash", gtr.ToSlash) + sprout.AddFunction(funcsMap, "exeExt", gtr.ExeExt) + sprout.AddFunction(funcsMap, "shellQuote", gtr.ShellQuote) + sprout.AddFunction(funcsMap, "splitArgs", gtr.SplitArgs) + sprout.AddFunction(funcsMap, "IsSH", gtr.IsSH) + sprout.AddFunction(funcsMap, "joinPath", gtr.JoinPath) + sprout.AddFunction(funcsMap, "relPath", gtr.RelPath) + // sprout.AddFunction(funcsMap, "merge", gtr.Merge) // can be replaced by maps.mergeOverwrite + sprout.AddFunction(funcsMap, "spew", gtr.Spew) + + return nil +} + +// RegisterAliases adds the provided aliases into the given alias map. +// method is called by an Handler to register all aliases of a registry. +func (gtr *GoTaskRegistry) RegisterAliases(aliasMap sprout.FunctionAliasMap) error { + sprout.AddAlias(aliasMap, "shellQuote", "q") + // Overwriting aliases + sprout.AddAlias(aliasMap, "mergeOverwrite", "merge") + // Deprecated aliases + sprout.AddAlias(aliasMap, "fromSlash", "FromSlash") + sprout.AddAlias(aliasMap, "toSlash", "ToSlash") + sprout.AddAlias(aliasMap, "exeExt", "ExeExt") + sprout.AddAlias(aliasMap, "os", "OS") + sprout.AddAlias(aliasMap, "arch", "ARCH") + return nil +} + +func (gtr *GoTaskRegistry) RegisterNotices(notices *[]sprout.FunctionNotice) error { + sprout.AddNotice(notices, sprout.NewDeprecatedNotice("IsSH", "This function is deprecated. Consider removing it from your templates.")) + sprout.AddNotice(notices, sprout.NewDeprecatedNotice("FromSlash", "Use `fromSlash` instead.")) + sprout.AddNotice(notices, sprout.NewDeprecatedNotice("ToSlash", "Use `toSlash` instead.")) + sprout.AddNotice(notices, sprout.NewDeprecatedNotice("ExeExt", "Use `exeExt` instead.")) + sprout.AddNotice(notices, sprout.NewDeprecatedNotice("OS", "Use `os` instead.")) + sprout.AddNotice(notices, sprout.NewDeprecatedNotice("ARCH", "Use `arch` instead.")) + return nil +} From 64424a94b1ee34a0d3ae6ea43be7604b9f89939b Mon Sep 17 00:00:00 2001 From: 42atomys Date: Sun, 19 Jan 2025 20:13:10 +0100 Subject: [PATCH 2/3] fix: backward compatibility incomplete --- internal/templater/funcs.go | 68 +++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/internal/templater/funcs.go b/internal/templater/funcs.go index 0ea9dcc9d1..201400f6c4 100644 --- a/internal/templater/funcs.go +++ b/internal/templater/funcs.go @@ -24,8 +24,70 @@ import ( var templateFuncs template.FuncMap +// BACKWARDS COMPATIBILITY +// The following functions are provided for backwards compatibility with the +// original sprig methods. They are not recommended for use in new code. +var bc_registerSprigFuncs = sprout.FunctionAliasMap{ + "dateModify": []string{"date_modify"}, // ! Deprecated: Should use dateModify instead + "dateInZone": []string{"date_in_zone"}, // ! Deprecated: Should use dateInZone instead + "mustDateModify": []string{"must_date_modify"}, // ! Deprecated: Should use mustDateModify instead + "ellipsis": []string{"abbrev"}, // ! Deprecated: Should use ellipsis instead + "ellipsisBoth": []string{"abbrevboth"}, // ! Deprecated: Should use ellipsisBoth instead + "trimAll": []string{"trimall"}, // ! Deprecated: Should use trimAll instead + "append": []string{"push"}, // ! Deprecated: Should use append instead + "mustAppend": []string{"mustPush"}, // ! Deprecated: Should use mustAppend instead + "list": []string{"tuple"}, // ! Deprecated: Should use list instead + "max": []string{"biggest"}, // ! Deprecated: Should use max instead + "toUpper": []string{"upper", "toupper", "uppercase"}, // ! Deprecated: Should use toUpper instead + "toLower": []string{"lower", "tolower", "lowercase"}, // ! Deprecated: Should use toLower instead + "add": []string{"addf"}, // ! Deprecated: Should use add instead + "add1": []string{"add1f"}, // ! Deprecated: Should use add1 instead + "sub": []string{"subf"}, // ! Deprecated: Should use sub instead + "toTitleCase": []string{"title", "titlecase"}, // ! Deprecated: Should use toTitleCase instead + "toPascalCase": []string{"camelcase"}, // ! Deprecated: Should use toPascalCase instead + "toSnakeCase": []string{"snake", "snakecase"}, // ! Deprecated: Should use toSnakeCase instead + "toKebabCase": []string{"kebab", "kebabcase"}, // ! Deprecated: Should use toKebabCase instead + "swapCase": []string{"swapcase"}, // ! Deprecated: Should use swapCase instead + "base64Encode": []string{"b64enc"}, // ! Deprecated: Should use base64Encode instead + "base64Decode": []string{"b64dec"}, // ! Deprecated: Should use base64Decode instead + "base32Encode": []string{"b32enc"}, // ! Deprecated: Should use base32Encode instead + "base32Decode": []string{"b32dec"}, // ! Deprecated: Should use base32Decode instead + "pathBase": []string{"base"}, // ! Deprecated: Should use pathBase instead + "pathDir": []string{"dir"}, // ! Deprecated: Should use pathDir instead + "pathExt": []string{"ext"}, // ! Deprecated: Should use pathExt instead + "pathClean": []string{"clean"}, // ! Deprecated: Should use pathClean instead + "pathIsAbs": []string{"isAbs"}, // ! Deprecated: Should use pathIsAbs instead + "expandEnv": []string{"expandenv"}, // ! Deprecated: Should use expandEnv instead + "dateAgo": []string{"ago"}, // ! Deprecated: Should use dateAgo instead + "strSlice": []string{"toStrings"}, // ! Deprecated: Should use strSlice instead + "toInt": []string{"int", "atoi"}, // ! Deprecated: Should use toInt instead + "toInt64": []string{"int64"}, // ! Deprecated: Should use toInt64 instead + "toFloat64": []string{"float64"}, // ! Deprecated: Should use toFloat64 instead + "toOctal": []string{"toDecimal"}, // ! Deprecated: Should use toOctal instead +} + +// prepareBackwardCompatibilityOpts returns a slice of sprout.HandlerOption that +// registers old sprig function names as aliases for their new names and adds +// deprecation notices to the old names. This is required to ensure backward +// compatibility with older versions of go-task that used the old sprig names. +func prepareBackwardCompatibilityOpts() []sprout.HandlerOption[*sprout.DefaultHandler] { + var opts = make([]sprout.HandlerOption[*sprout.DefaultHandler], (len(bc_registerSprigFuncs)+8)*2) // 8 represents multiple aliases for specific functions + + for originalFunction, aliases := range bc_registerSprigFuncs { + opts = append(opts, sprout.WithAlias(originalFunction, aliases...)) + + for _, alias := range aliases { + opts = append(opts, sprout.WithNotices(sprout.NewDeprecatedNotice(alias, "please use `"+originalFunction+"` instead"))) + } + } + + return opts +} + +// \ BACKWARDS COMPATIBILITY + func init() { - handler := sprout.New( + opts := []sprout.HandlerOption[*sprout.DefaultHandler]{ sprout.WithRegistries( // Library registries backward.NewRegistry(), @@ -47,7 +109,9 @@ func init() { // Own registry taskfunc.NewRegistry(), ), - ) + } + opts = append(opts, prepareBackwardCompatibilityOpts()...) + handler := sprout.New(opts...) templateFuncs = template.FuncMap(handler.Build()) } From 8f2a0519d3cd9d01970f1b05d7ddaaf66d655d69 Mon Sep 17 00:00:00 2001 From: 42atomys Date: Sun, 19 Jan 2025 20:13:24 +0100 Subject: [PATCH 3/3] docs: update docs to reflect library change --- website/docs/reference/templating.mdx | 463 ++++++++++++++------------ website/docs/usage.mdx | 2 +- 2 files changed, 260 insertions(+), 205 deletions(-) diff --git a/website/docs/reference/templating.mdx b/website/docs/reference/templating.mdx index 98d45bae00..a8e5b0439a 100644 --- a/website/docs/reference/templating.mdx +++ b/website/docs/reference/templating.mdx @@ -155,218 +155,274 @@ itself][go-template-functions]: | `println` | An alias for `fmt.Sprintln`. | | `urlquery` | Returns the escaped value of the textual representation of its arguments in a form suitable for embedding in a URL query. This function is unavailable in [html/template][html/template], with a few exceptions. | -### Slim-Sprig Functions +### Sprout Functions In addition to the built-in functions, Task also provides a set of functions -imported via the [slim-sprig][slim-sprig] package. We only provide a very basic +imported via the [sprout project][sprout-repo] package. We only provide a very basic description here for completeness. For detailed usage, please refer to the -[slim-sprig documentation][slim-sprig]: +[sprout documentation][sprout-docs]: + +#### [Checksum Functions][checksum-functions] + +| Function | Description | +| ------------ | -------------------------------------- | +| `sha1Sum` | Computes a string's SHA1 digest. | +| `sha256Sum` | Computes a string's SHA256 digest. | +| `sha512Sum` | Computes a string's SHA512 digest. | +| `adler32Sum` | Computes a string's Adler-32 checksum. | +| `md5Sum` | Computes a string's MD5 checksum. | + +#### [Type Conversion Functions][conversion-functions] + +| Function | Description | +| ------------- | ------------------------------------------------------- | +| `toBool` | Converts a value to a boolean. | +| `toInt` | Converts a value to an integer. | +| `toInt64` | Converts a value to an int64. | +| `toUint` | Converts a value to an unsigned integer. | +| `toUint64` | Converts a value to an unsigned int64. | +| `toFloat64` | Converts a value to a float64. | +| `toOctal` | Converts a value to an octal. | +| `toString` | Converts to a string. | +| `toDate` | Converts a string to a date/time. | +| `toLocalDate` | Converts a string to a date/time in the local timezone. | +| `toDuration` | Converts a string to a duration. | + +#### [Encoding Functions][encoding-functions] + +| Function | Description | +| -------------- | ------------------------------------------------------------------ | +| `base64Encode` | Encodes a string into base 64. | +| `base64Decode` | Decodes a string from base 64. | +| `base32Encode` | Encodes a string into base 32. | +| `base32Decode` | Decodes a string from base 32. | +| `fromJSON` | Decodes a JSON string into an object. | +| `toJSON` | Encodes an object as a JSON string. | +| `toPrettyJSON` | Encodes an object as a JSON string with new lines and indentation. | +| `toRawJSON` | Encodes an object as a JSON string with HTML characters unescaped. | +| `fromYAML` | Decodes a YAML string into an object. | +| `toYAML` | Encodes an object as a YAML string. | +| `toIndentYAML` | Encodes an object as a YAML string with indentation. | + +#### [Environment Functions][env-functions] + +| Function | Description | +| ----------- | --------------------------------------------- | +| `env` | Reads an environment variable. | +| `expandEnv` | Substitutes environment variables in a string | + +#### [Path and Filepath Functions][filesystem-functions] + +| Function | Description | +| ----------- | ----------------------------------------- | +| `pathBase` | Returns the last element of a path. | +| `pathDir` | Returns the directory of a path. | +| `pathExt` | Returns the file extension of a path. | +| `pathClean` | Cleans up a path. | +| `pathIsAbs` | Checks if a path is absolute. | +| `osBase` | Returns the last element of a filepath. | +| `osDir` | Returns the directory of a filepath. | +| `osExt` | Returns the file extension of a filepath. | +| `osClean` | Cleans up a filepath. | +| `osIsAbs` | Checks if a filepath is absolute. | + +#### [Maps Functions][maps-functions] + +| Function | Description | +| ---------------- | ------------------------------------------------------------------------------------------ | +| `dict` | Creates a dictionary from a set of key/value pairs. | +| `get` | Gets the value from the dictionary with the given key. | +| `set` | Adds a new key/value pair to a dictionary. | +| `unset` | Deletes a key from a dictionary. | +| `hasKey` | Returns true if a dictionary contains the given key. | +| `pluck` | Gets a list of all of the matching values in a set of maps given a key. | +| `dig` | Returns the value in a nested map given a path of keys. | +| `merge` | Merges two or more dictionaries into one. | +| `mergeOverwrite` | Identical to `merge`, but giving precedence from right to left. | +| `keys` | Returns a list of all of the keys in a dictionary. | +| `pick` | Creates a new dictionary containing only the given keys of an existing map. | +| `omit` | Creates a new dictionary containing all the keys of an existing map except the ones given. | +| `values` | Returns a list of all the values in a dictionary. | + +#### [Network Functions][network-functions] + +| Function | Description | +| ------------------- | ------------------------------------------------------------- | +| `parseIP` | Parses a string as an IP address. | +| `parseMAC` | Parses a string as a MAC address. | +| `parseCIDR` | Parses a string as a CIDR notation. | +| `ipVersion` | Returns the IP version of an IP address. | +| `ipIsLoopback` | Returns true if the IP address is a loopback address. | +| `ipIsGlobalUnicast` | Returns true if the IP address is a global unicast address. | +| `ipIsMulticast` | Returns true if the IP address is a multicast address. | +| `ipIsPrivate` | Returns true if the IP address is a private address. | +| `ipIncrement` | Increments an IP address by 1. | +| `ipDecrement` | Decrements an IP address by 1. | +| `cidrContains` | Returns true if the CIDR block contains the given IP address. | +| `cidrSize` | Returns the number of IP addresses in a CIDR block. | +| `cidrRangeList` | Returns a list of all IP addresses in a CIDR block. | +| `cidrFirst` | Returns the first IP address in a CIDR block. | +| `cidrLast` | Returns the last IP address in a CIDR block. | +| `cidrOverlap` | Returns true if two CIDR blocks overlap. | + +#### [Numeric Functions][numeric-functions] + +| Function | Description | +| --------- | ------------------------------------------------------------------------------------------------------- | +| `floor` | Returns the greatest float value less than or equal to input value | +| `ceil` | Returns the greatest float value greater than or equal to input value | +| `round` | Returns a float value with the remainder rounded to the given number to digits after the decimal point. | +| `add` | Sum a set of numbers. | +| `add1` | Increments a number by 1. | +| `sub` | Subtracts one number from another. | +| `mul` | Multiplies a set of numbers. | +| `mulf` | Multiplies a set of numbers and returns the result as a float. | +| `div` | Performs integer division. | +| `divf` | Performs division and returns the result as a float. | +| `mod` | Modulo. | +| `min` | Returns the smallest of a set of integers. | +| `minf` | Returns the smallest of a set of floats. | +| `max` | Returns the largest of a set of integers. | +| `maxf` | Returns the largest of a set of floats. | + +#### [Random Functions][random-functions] + +| Function | Description | +| -------------- | --------------------------------------------------------- | +| `randAlphaNum` | Generates a random alphanumeric string of a given length. | +| `randAlpha` | Generates a random alphabetic string of a given length. | +| `randAscii` | Generates a random ASCII string of a given length. | +| `randNumeric` | Generates a random numeric string of a given length. | +| `randBytes` | Generates a random byte slice of a given length. | +| `randInt` | Generates a random integer between a given range. | + +#### [Reflection Functions][reflection-functions] + +| Function | Description | +| ------------ | ------------------------------------------------------ | +| `typeIs` | Verifies that a value is of a particular type. | +| `typeIsLike` | Identical to `typeIs`, but also dereferences pointers. | +| `typeOf` | Returns the underlying type of a value. | +| `kindIs` | Verifies that a value is a particular kind. | +| `kindOf` | Returns the kind of a value. | +| `hasField` | Checks if a struct has a field with the given name. | +| `deepEqual` | Returns true if two values are "deeply equal". | +| `deepCopy` | Creates a deep copy of a value. | + +#### [Regular Expression Functions][regexp-functions] + +| Function | Description | +| ------------------------- | ----------------------------------------------------------------------------------------- | +| `regexpFind` | Searches a string for a regular expression and returns the first match. | +| `regexpFindAll` | Searches a string for all matches of a regular expression. | +| `regexpMatch` | Tests a string for a regular expression match. | +| `regexpSplit` | Splits a string into a list of substrings using a regular expression for n split. | +| `regexpReplaceAll` | Replaces all matches of a regular expression in a string with a replacement. | +| `regexpReplaceAllLiteral` | Replaces all matches of a regular expression in a string with a literal replacement. |` +| `regexpQuoteMeta` | Returns a string that escapes all regular expression metacharacters. | +| `regexpFindGroups` | Searches a string for a regular expression and returns the first match with groups. | +| `regexpFindAllGroups` | Searches a string for all matches of a regular expression with groups. | +| `regexpFindNamed` | Searches a string for a regular expression and returns the first match with named groups. | +| `regexpFindAllNamed` | Searches a string for all matches of a regular expression with named groups. | + +#### [Slices Functions][slices-functions] + +| Function | Description | +| -------------- | --------------------------------------------------------------------------- | +| `list` | Creates a list from a set of values. | +| `append` | Adds a new value to the end of the list. | +| `prepend` | Adds a new value to the start of the list. | +| `concat` | Joins two or more lists together. | +| `chunk` | Splits a list into chunks of given size. | +| `uniq` | Generate a list with all of the duplicates removed. | +| `compact` | Removes entries with empty values. | +| `flatten` | Flattens a list of lists into a single list. | +| `flattenDepth` | Flattens a list of lists into a single list to a given depth. | +| `slice` | Returns a partial copy of a list given start and end parameters. | +| `has` | Tests to see if a list has a particular element. | +| `without` | Filters matching items out of a list. | +| `rest` | Gets all values except the first value in the list. | +| `initial` | Get all values except the last value in the list. | +| `first` | Gets the first value in a list. | +| `last` | Gets the last value in the list. | +| `reverse` | Reverses the order of a list. | +| `sortAlpha` | Sorts a list of strings into alphabetical (lexicographical) order. | +| `strSlice` | Converts a list of any type to a list of their string representations. | +| `until` | Builds a range of integers. | +| `untilStep` | Builds a range of integers, but allows you to define a start, stop and step | + +#### [Standard Functions][std-functions] + +| Function | Description | +| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `default` | Uses a default value if the given value is considered "zero" or "empty". | +| `empty` | Returns true if a value is considered "zero" or "empty". | +| `all` | Returns true if all values are non-empty. | +| `any` | Returns true if any value is non-empty. | +| `coalesce` | Takes a list of values and returns the first non-empty one. | +| `ternary` | The function mimics the ternary conditional operator found in many programming languages. It returns trueValue if the condition is true; otherwise, it returns falseValue. | +| `cat` | Concatenates multiple strings together into one, separating them with spaces. | #### [String Functions][string-functions] | Function | Description | | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `nospace` | Removes all spaces from a string. | | `trim` | Removes space from either side of a string. | | `trimAll` | Removes given characters from the front or back of a string. | -| `trimSuffix` | Trims just the suffix from a string. | | `trimPrefix` | Trims just the prefix from a string. | -| `upper` | Converts the entire string to uppercase. | -| `lower` | Converts the entire string to lowercase. | -| `title` | Converts to title case. | -| `repeat` | Repeats a string multiple times. | -| `substr` | Gets a substring from a string. | -| `trunc` | Truncates a string. | +| `trimSuffix` | Trims just the suffix from a string. | | `contains` | Tests to see if one string is contained inside of another. | | `hasPrefix` | Tests whether a string has a given prefix. | | `hasSuffix` | Tests whether a string has a given suffix. | +| `toUpper` | Converts the entire string to uppercase. | +| `toLower` | Converts the entire string to lowercase. | +| `replace` | Replaces a string. | +| `repeat` | Repeats a string multiple times. | +| `join` | Joins a list of strings into a single string, with the given separator. | +| `trunc` | Truncates a string. | +| `shuffle` | Shuffles a string. | +| `ellipsis` | Adds an ellipsis to the end of a string. | +| `ellipsisBoth` | Adds an ellipsis to the beginning and end of a string. | +| `initials` | Returns the initials of a string. | +| `plural` | Pluralizes a string. | +| `wrap` | Wraps a string to a given width. | +| `wrapWith` | Wraps a string to a given width, but with a given prefix. | | `quote` | Wraps a string in double quotes. | | `squote` | Wraps a string in single quotes. | -| `cat` | Concatenates multiple strings together into one, separating them with spaces. | +| `toCamelCase` | Converts a string to camel case. | +| `toKebabCase` | Converts a string to kebab case. | +| `toPascalCase` | Converts a string to pascal case. | +| `toDotCase` | Converts a string to dot case. | +| `toPathCase` | Converts a string to path case. | +| `toConstantCase` | Converts a string to constant case. | +| `toSnakeCase` | Converts a string to snake case. | +| `toTitleCase` | Converts a string to title case. | +| `untitle` | Converts the first letter of each word in a string to lowercase. | +| `swapCase` | Swaps the case of each letter in a string. | +| `capitalize` | Capitalizes the first letter of a string. | +| `uncapitalize` | Uncapitalizes the first letter of a string. | +| `split` | Splits a string into a map of strings where each key is an index. | +| `splitn` | Identical to `split`, but stops splitting after `n` values. | +| `substr` | Gets a substring from a string. | | `indent` | Indents every line in a given string to the specified indent width. | | `nindent` | Identical to `indent`, but prepends a new line to the beginning of the string. | -| `replace` | Replaces a string. | -| `plural` | Pluralizes a string. | -| `regexMatch`\* | Returns true if the input string contains any match of the regular expression. | -| `regexFindAll`\* | Returns a slice of all matches of the regular expression in the input string. | -| `regexFind`\* | Returns the first (left most) match of the regular expression in the input string. | -| `regexReplaceAll`\* | Returns a copy of the input string, replacing matches of the Regexp with the replacement string replacement. | -| `regexReplaceAllLiteral`\* | Returns a copy of the input string, replacing matches of the Regexp with the replacement string replacement without expanding `$`. | -| `regexSplit`\* | Slices the input string into substrings separated by the expression and returns a slice of the substrings between those expression matches. | -| `regexQuoteMeta`\* | Returns a string that escapes all regular expression metacharacters inside the argument text. | - -#### [String Slice Functions][string-list-functions] - -| Function | Description | -| ----------- | ----------------------------------------------------------------------- | -| `join` | Joins a list of strings into a single string, with the given separator. | -| `splitList` | Splits a string into a list of strings. | -| `split` | Splits a string into a map of strings where each key is an index. | -| `splitn` | Identical to `split`, but stops splitting after `n` values. | -| `sortAlpha` | Sorts a list of strings into alphabetical (lexicographical) order. | - -#### [Integer Functions][math-functions] - -| Function | Description | -| --------- | ------------------------------------------------------------------------------------------------------- | -| `add` | Sum a set of numbers. | -| `add1` | Increments a number by 1. | -| `sub` | Subtracts one number from another. | -| `div` | Performs integer division. | -| `mod` | Modulo. | -| `mul` | Multiplies a set of numbers. | -| `max` | Returns the largest of a set of integers. | -| `min` | Returns the smallest of a set of integers. | -| `floor` | Returns the greatest float value less than or equal to input value | -| `ceil` | Returns the greatest float value greater than or equal to input value | -| `round` | Returns a float value with the remainder rounded to the given number to digits after the decimal point. | -| `randInt` | Returns a random integer value from min (inclusive) to max (exclusive). | - -#### [Integer Slice Functions][integer-list-functions] +| `seq` | Generates a sequence of numbers as a string, allowing for customizable start, end, and step values, similar to the Unix seq command. | -| Function | Description | -| ----------- | --------------------------------------------------------------------------- | -| `until` | Builds a range of integers. | -| `untilStep` | Builds a range of integers, but allows you to define a start, stop and step | -| `seq` | Works like the bash `seq` command. | - -#### [Date Functions][date-functions] +#### [Date Functions][time-functions] | Function | Description | | ---------------- | ------------------------------------------------------------------------------ | -| `now` | Gets the current date/time. | -| `ago` | Returns the duration since the given date/time. | | `date` | Formats a date. | | `dateInZone` | Identical to `date`, but with the given timezone. | | `duration` | Formats the number of seconds into a string. | -| `durationRound` | Identical to `duration`, but rounds the duration to the most significant unit. | +| `dateAgo` | Returns the duration since the given date/time. | +| `now` | Gets the current date/time. | | `unixEpoch` | Returns the seconds since the unix epoch for the given date/time. | -| `dateModify`\* | Modifies a date using the given input string. | +| `dateModify` | Modifies a date using the given input string. | +| `durationRound` | Identical to `duration`, but rounds the duration to the most significant unit. | | `htmlDate` | Formats a date for inserting into an HTML date picker input field. | | `htmlDateInZone` | Identical to `htmlDate`, but with the given timezone. | -| `toDate`\* | Converts a string to a date/time. | - -#### [Default Functions][default-functions] - -| Function | Description | -| ---------- | ------------------------------------------------------------------------ | -| `default` | Uses a default value if the given value is considered "zero" or "empty". | -| `empty` | Returns true if a value is considered "zero" or "empty". | -| `coalesce` | Takes a list of values and returns the first non-empty one. | -| `all` | Returns true if all values are non-empty. | -| `any` | Returns true if any value is non-empty. | -| `ternary` | The ternary function takes two values, and a test value. If the test value is true, the first value will be returned. If the test value is empty, the second value will be returned. | - -#### [Encoding Functions][encoding-functions] - -| Function | Description | -| ---------------- | ------------------------------------------------------------------ | -| `fromJson`\* | Decodes a JSON string into an object. | -| `toJson`\* | Encodes an object as a JSON string. | -| `toPrettyJson`\* | Encodes an object as a JSON string with new lines and indentation. | -| `toRawJson`\* | Encodes an object as a JSON string with HTML characters unescaped. | -| `b64enc` | Encodes a string into base 64. | -| `b64dec` | Decodes a string from base 64. | -| `b32enc` | Encodes a string into base 32. | -| `b32dec` | Decodes a string from base 32. | - -#### [List Functions][list-functions] - -| Function | Description | -| ----------- | ---------------------------------------------------------------- | -| `list` | Creates a list from a set of values. | -| `first`\* | Gets the first value in a list. | -| `rest`\* | Gets all values except the first value in the list. | -| `last`\* | Gets the last value in the list. | -| `initial`\* | Get all values except the last value in the list. | -| `append`\* | Adds a new value to the end of the list. | -| `prepend`\* | Adds a new value to the start of the list. | -| `concat` | Joins two or more lists together. | -| `reverse`\* | Reverses the order of a list. | -| `uniq`\* | Generate a list with all of the duplicates removed. | -| `without`\* | Filters matching items out of a list. | -| `has`\* | Tests to see if a list has a particular element. | -| `compact`\* | Removes entries with empty values. | -| `slice`\* | Returns a partial copy of a list given start and end parameters. | -| `chunk` | Splits a list into chunks of given size. | - -#### [Dictionary Functions][dictionary-functions] - -| Function | Description | -| ------------------ | ------------------------------------------------------------------------------------------ | -| `dict` | Creates a dictionary from a set of key/value pairs. | -| `get` | Gets the value from the dictionary with the given key. | -| `set` | Adds a new key/value pair to a dictionary. | -| `unset` | Deletes a key from a dictionary. | -| `hasKey` | Returns true if a dictionary contains the given key. | -| `pluck` | Gets a list of all of the matching values in a set of maps given a key. | -| `dig` | Returns the value in a nested map given a path of keys. | -| `merge`\* | Merges two or more dictionaries into one. | -| `mergeOverwrite`\* | Identical to `merge`, but giving precedence from right to left. | -| `keys` | Returns a list of all of the keys in a dictionary. | -| `pick` | Creates a new dictionary containing only the given keys of an existing map. | -| `omit` | Creates a new dictionary containing all the keys of an existing map except the ones given. | -| `values` | Returns a list of all the values in a dictionary. | - -#### [Type Conversion Functions][type-conversion-functions] - -| Function | Description | -| ----------- | ------------------------------------------------------ | -| `atoi` | Converts a string to an integer. | -| `float64` | Converts to a float64. | -| `int` | Converts to an int at the system's width. | -| `int64` | Converts to an int64. | -| `toDecimal` | Converts a unix octal to a int64. | -| `toString` | Converts to a string. | -| `toStrings` | Converts a list, slice, or array to a list of strings. | -| `toStrings` | Produces a slice of strings from any list. | -| `toDecimal` | Given a unix octal permission, produce a decimal. | - -#### [Path and Filepath Functions][path-functions] - -| Function | Description | -| --------- | ----------------------------------------- | -| `base` | Returns the last element of a path. | -| `dir` | Returns the directory of a path. | -| `clean` | Cleans up a path. | -| `ext` | Returns the file extension of a path. | -| `isAbs` | Checks if a path is absolute. | -| `osBase` | Returns the last element of a filepath. | -| `osDir` | Returns the directory of a filepath. | -| `osClean` | Cleans up a filepath. | -| `osExt` | Returns the file extension of a filepath. | -| `osIsAbs` | Checks if a filepath is absolute. | - -#### [Flow Control Functions][flow-control-functions] - -| Function | Description | -| -------- | ----------------------------------------------------------------------------- | -| `fail` | Unconditionally returns an empty string and an error with the specified text. | - -#### [OS Functions][os-functions] - -| Function | Description | -| ----------- | --------------------------------------------- | -| `env` | Reads an environment variable. | -| `expandenv` | Substitutes environment variables in a string | - -#### [Reflection Functions][reflection-functions] - -| Function | Description | -| ------------ | ------------------------------------------------------ | -| `kindOf` | Returns the kind of a value. | -| `kindIs` | Verifies that a value is a particular kind. | -| `typeOf` | Returns the underlying type of a value. | -| `typeIs` | Verifies that a value is of a particular type. | -| `typeIsLike` | Identical to `typeIs`, but also dereferences pointers. | -| `deepEqual` | Returns true if two values are "deeply equal". | - -#### [Cryptographic and Security Functions][crypto-functions] - -| Function | Description | -| ------------ | -------------------------------------- | -| `sha1sum` | Computes a string's SHA1 digest. | -| `sha256sum` | Computes a string's SHA256 digest. | -| `adler32sum` | Computes a string's Adler-32 checksum. | ### Task Functions @@ -374,8 +430,8 @@ Lastly, Task itself provides a few functions: | Function | Description | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `OS` | Returns the operating system. Possible values are `windows`, `linux`, `darwin` (macOS) and `freebsd`. | -| `ARCH` | Returns the architecture Task was compiled to: `386`, `amd64`, `arm` or `s390x`. | +| `os` | Returns the operating system. Possible values are `windows`, `linux`, `darwin` (macOS) and `freebsd`. | +| `arch` | Returns the architecture Task was compiled to: `386`, `amd64`, `arm` or `s390x`. | | `numCPU` | Returns the number of logical CPU's usable by the current process. | | `splitLines` | Splits Unix (`\n`) and Windows (`\r\n`) styled newlines. | | `catLines` | Replaces Unix (`\n`) and Windows (`\r\n`) styled newlines with a space. | @@ -386,28 +442,27 @@ Lastly, Task itself provides a few functions: | `splitArgs` | Splits a string as if it were a command's arguments. Task uses [this Go function](https://pkg.go.dev/mvdan.cc/sh/v3@v3.4.0/shell#Fields). | | `joinPath` | Joins any number of arguments into a path. The same as Go's [filepath.Join](https://pkg.go.dev/path/filepath#Join). | | `relPath` | Converts an absolute path (second argument) into a relative path, based on a base path (first argument). The same as Go's [filepath.Rel](https://pkg.go.dev/path/filepath#Rel). | -| `merge` | Creates a new map that is a copy of the first map with the keys of each subsequent map merged into it. If there is a duplicate key, the value of the last map with that key is used. | | `spew` | Returns the Go representation of a specific variable. Useful for debugging. Uses the [davecgh/go-spew](https://github.com/davecgh/go-spew) package. | {/* prettier-ignore-start */} [text/template]: https://pkg.go.dev/text/template [html/template]: https://pkg.go.dev/html/template [go-template-functions]: https://pkg.go.dev/text/template#hdr-Functions -[slim-sprig]: https://go-task.github.io/slim-sprig/ -[os-functions]: https://go-task.github.io/slim-sprig/os.html -[string-functions]: https://go-task.github.io/slim-sprig/strings.html -[string-list-functions]: https://go-task.github.io/slim-sprig/string_slice.html -[math-functions]: https://go-task.github.io/slim-sprig/math.html -[integer-list-functions]: https://go-task.github.io/slim-sprig/integer_slice.html -[date-functions]: https://go-task.github.io/slim-sprig/date.html -[default-functions]: https://go-task.github.io/slim-sprig/defaults.html -[encoding-functions]: https://go-task.github.io/slim-sprig/encoding.html -[list-functions]: https://go-task.github.io/slim-sprig/lists.html -[dictionary-functions]: https://go-task.github.io/slim-sprig/dicts.html -[type-conversion-functions]: https://go-task.github.io/slim-sprig/conversion.html -[path-functions]: https://go-task.github.io/slim-sprig/paths.html -[flow-control-functions]: https://go-task.github.io/slim-sprig/flow_control.html -[os-functions]: https://go-task.github.io/slim-sprig/os.html -[reflection-functions]: https://go-task.github.io/slim-sprig/reflection.html -[crypto-functions]: https://go-task.github.io/slim-sprig/crypto.html +[sprout-repo]: https://github.com/go-sprout/sprout +[sprout-docs]: https://sprout.atom.codes/ +[checksum-functions]: https://sprout.atom.codes/registries/checksum +[conversion-functions]: https://sprout.atom.codes/registries/conversion +[encoding-functions]: https://sprout.atom.codes/registries/encoding +[env-functions]: https://sprout.atom.codes/registries/env +[filesystem-functions]: https://sprout.atom.codes/registries/filesystem +[maps-functions]: https://sprout.atom.codes/registries/maps +[network-functions]: https://sprout.atom.codes/registries/network +[numeric-functions]: https://sprout.atom.codes/registries/numeric +[random-functions]: https://sprout.atom.codes/registries/random +[reflection-functions]: https://sprout.atom.codes/registries/reflect +[regexp-functions]: https://sprout.atom.codes/registries/regexp +[slices-functions]: https://sprout.atom.codes/registries/slices +[std-functions]: https://sprout.atom.codes/registries/std +[string-functions]: https://sprout.atom.codes/registries/strings +[time-functions]: https://sprout.atom.codes/registries/time {/* prettier-ignore-end */} diff --git a/website/docs/usage.mdx b/website/docs/usage.mdx index aab62912d1..0ed4416928 100644 --- a/website/docs/usage.mdx +++ b/website/docs/usage.mdx @@ -525,7 +525,7 @@ includes: Vars declared in the included Taskfile have preference over the variables in the including Taskfile! If you want a variable in an included Taskfile to be overridable, use the -[default function](https://go-task.github.io/slim-sprig/defaults.html): +[default function](https://sprout.atom.codes/registries/std#default): `MY_VAR: '{{.MY_VAR | default "my-default-value"}}'`. :::