diff --git a/cmd/task/task.go b/cmd/task/task.go index 060f9716..9b29c912 100644 --- a/cmd/task/task.go +++ b/cmd/task/task.go @@ -125,12 +125,12 @@ func run() error { log.Warnf("%s\n", err.Error()) } - var taskSorter sort.TaskSorter + var taskSorter sort.Sorter switch flags.TaskSort { case "none": - taskSorter = &sort.Noop{} + taskSorter = nil case "alphanumeric": - taskSorter = &sort.AlphaNumeric{} + taskSorter = sort.AlphaNumeric } e := task.Executor{ diff --git a/go.mod b/go.mod index 2cc31f08..4605ac6d 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/chainguard-dev/git-urls v1.0.2 github.com/davecgh/go-spew v1.1.1 github.com/dominikbraun/graph v0.23.0 - github.com/elliotchance/orderedmap/v2 v2.7.0 + github.com/elliotchance/orderedmap/v3 v3.1.0 github.com/fatih/color v1.18.0 github.com/go-git/go-billy/v5 v5.6.2 github.com/go-git/go-git/v5 v5.13.2 diff --git a/go.sum b/go.sum index 674052fd..c2384acc 100644 --- a/go.sum +++ b/go.sum @@ -7,14 +7,10 @@ github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lpr github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk= -github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4= github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= -github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE= -github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= -github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E= -github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I= +github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= +github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/chroma/v2 v2.15.0 h1:LxXTQHFoYrstG2nnV9y2X5O94sOBzf0CIUpSTbpxvMc= github.com/alecthomas/chroma/v2 v2.15.0/go.mod h1:gUhVLrPDXPtp/f+L1jo9xepo9gL4eLwRuGAunSZMkio= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= @@ -34,16 +30,14 @@ github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGL github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= -github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo= github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc= -github.com/elazarl/goproxy v1.2.3 h1:xwIyKHbaP5yfT6O9KIeYJR5549MXRQkoQMRXGztz8YQ= -github.com/elazarl/goproxy v1.2.3/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64= -github.com/elliotchance/orderedmap/v2 v2.7.0 h1:WHuf0DRo63uLnldCPp9ojm3gskYwEdIIfAUVG5KhoOc= -github.com/elliotchance/orderedmap/v2 v2.7.0/go.mod h1:85lZyVbpGaGvHvnKa7Qhx7zncAdBIBq6u56Hb1PRU5Q= +github.com/elazarl/goproxy v1.4.0 h1:4GyuSbFa+s26+3rmYNSuUVsx+HgPrV1bk1jXI0l9wjM= +github.com/elazarl/goproxy v1.4.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ= +github.com/elliotchance/orderedmap/v3 v3.1.0 h1:j4DJ5ObEmMBt/lcwIecKcoRxIQUEnw0L804lXYDt/pg= +github.com/elliotchance/orderedmap/v3 v3.1.0/go.mod h1:G+Hc2RwaZvJMcS4JpGCOyViCnGeKf0bTYCGTO4uhjSo= 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= @@ -52,14 +46,10 @@ 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= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.6.1 h1:u+dcrgaguSSkbjzHwelEjc0Yj300NUevrrPphk/SoRA= -github.com/go-git/go-billy/v5 v5.6.1/go.mod h1:0AsLr1z2+Uksi4NlElmMblP5rPcDZNRCD8ujZCRR2BE= github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM= github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.13.1 h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M= -github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc= github.com/go-git/go-git/v5 v5.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0= github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A= github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= @@ -102,16 +92,10 @@ github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELU github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= -github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= -github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= github.com/otiai10/copy v1.14.1 h1:5/7E6qsUMBaH5AnQ0sSLzzTg1oTECmcCmT6lvF45Na8= github.com/otiai10/copy v1.14.1/go.mod h1:oQwrEDDOci3IM8dJF0d8+jnbfPDllW6vUjNc3DoZm9I= -github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= -github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs= github.com/otiai10/mint v1.6.3/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= -github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= -github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -129,8 +113,6 @@ 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/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -147,8 +129,6 @@ 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= @@ -156,12 +136,8 @@ golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbR golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -173,17 +149,9 @@ 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/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= golang.org/x/sys v0.30.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/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/help.go b/help.go index 622ef17b..e7a024fb 100644 --- a/help.go +++ b/help.go @@ -128,18 +128,14 @@ func (e *Executor) ListTaskNames(allTasks bool) error { w = e.Stdout } - // Get the list of tasks and sort them - tasks := e.Taskfile.Tasks.Values() - // Sort the tasks if e.TaskSorter == nil { - e.TaskSorter = &sort.AlphaNumericWithRootTasksFirst{} + e.TaskSorter = sort.AlphaNumericWithRootTasksFirst } - e.TaskSorter.Sort(tasks) // Create a list of task names taskNames := make([]string, 0, e.Taskfile.Tasks.Len()) - for _, task := range tasks { + for task := range e.Taskfile.Tasks.Values(e.TaskSorter) { if (allTasks || task.Desc != "") && !task.Internal { taskNames = append(taskNames, strings.TrimRight(task.Task, ":")) for _, alias := range task.Aliases { diff --git a/internal/compiler/compiler.go b/internal/compiler/compiler.go index 527163ac..3afe9b6e 100644 --- a/internal/compiler/compiler.go +++ b/internal/compiler/compiler.go @@ -103,30 +103,42 @@ func (c *Compiler) getVariables(t *ast.Task, call *ast.Call, evaluateShVars bool taskRangeFunc = getRangeFunc(dir) } - if err := c.TaskfileEnv.Range(rangeFunc); err != nil { - return nil, err - } - if err := c.TaskfileVars.Range(rangeFunc); err != nil { - return nil, err - } - if t != nil { - if err := t.IncludeVars.Range(rangeFunc); err != nil { + for k, v := range c.TaskfileEnv.All() { + if err := rangeFunc(k, v); err != nil { return nil, err } - if err := t.IncludedTaskfileVars.Range(taskRangeFunc); err != nil { + } + for k, v := range c.TaskfileVars.All() { + if err := rangeFunc(k, v); err != nil { return nil, err } } + if t != nil { + for k, v := range t.IncludeVars.All() { + if err := rangeFunc(k, v); err != nil { + return nil, err + } + } + for k, v := range t.IncludedTaskfileVars.All() { + if err := taskRangeFunc(k, v); err != nil { + return nil, err + } + } + } if t == nil || call == nil { return result, nil } - if err := call.Vars.Range(rangeFunc); err != nil { - return nil, err + for k, v := range call.Vars.All() { + if err := rangeFunc(k, v); err != nil { + return nil, err + } } - if err := t.Vars.Range(taskRangeFunc); err != nil { - return nil, err + for k, v := range t.Vars.All() { + if err := taskRangeFunc(k, v); err != nil { + return nil, err + } } return result, nil diff --git a/internal/deepcopy/deepcopy.go b/internal/deepcopy/deepcopy.go index c42dd141..ecd36180 100644 --- a/internal/deepcopy/deepcopy.go +++ b/internal/deepcopy/deepcopy.go @@ -3,7 +3,7 @@ package deepcopy import ( "reflect" - "github.com/elliotchance/orderedmap/v2" + "github.com/elliotchance/orderedmap/v3" ) type Copier[T any] interface { diff --git a/internal/sort/sorter.go b/internal/sort/sorter.go index 4c1016cc..e3b9842c 100644 --- a/internal/sort/sorter.go +++ b/internal/sort/sorter.go @@ -3,42 +3,38 @@ package sort import ( "sort" "strings" - - "github.com/go-task/task/v3/taskfile/ast" ) -type TaskSorter interface { - Sort([]*ast.Task) -} +// A Sorter is any function that sorts a set of tasks. +type Sorter func(items []string, namespaces []string) []string -type Noop struct{} - -func (s *Noop) Sort(tasks []*ast.Task) {} - -type AlphaNumeric struct{} - -// Tasks that are not namespaced should be listed before tasks that are. -// We detect this by searching for a ':' in the task name. -func (s *AlphaNumeric) Sort(tasks []*ast.Task) { - sort.Slice(tasks, func(i, j int) bool { - return tasks[i].Task < tasks[j].Task +// AlphaNumeric sorts the JSON output so that tasks are in alpha numeric order +// by task name. +func AlphaNumeric(items []string, namespaces []string) []string { + sort.Slice(items, func(i, j int) bool { + return items[i] < items[j] }) + return items } -type AlphaNumericWithRootTasksFirst struct{} - -// Tasks that are not namespaced should be listed before tasks that are. -// We detect this by searching for a ':' in the task name. -func (s *AlphaNumericWithRootTasksFirst) Sort(tasks []*ast.Task) { - sort.Slice(tasks, func(i, j int) bool { - iContainsColon := strings.Contains(tasks[i].Task, ":") - jContainsColon := strings.Contains(tasks[j].Task, ":") +// AlphaNumericWithRootTasksFirst sorts the JSON output so that tasks are in +// alpha numeric order by task name. It will also ensure that tasks that are not +// namespaced will be listed before tasks that are. We detect this by searching +// for a ':' in the task name. +func AlphaNumericWithRootTasksFirst(items []string, namespaces []string) []string { + if len(namespaces) > 0 { + return AlphaNumeric(items, namespaces) + } + sort.Slice(items, func(i, j int) bool { + iContainsColon := strings.Contains(items[i], ":") + jContainsColon := strings.Contains(items[j], ":") if iContainsColon == jContainsColon { - return tasks[i].Task < tasks[j].Task + return items[i] < items[j] } if !iContainsColon && jContainsColon { return true } return false }) + return items } diff --git a/internal/sort/sorter_test.go b/internal/sort/sorter_test.go index 52ab1005..e55f0f0f 100644 --- a/internal/sort/sorter_test.go +++ b/internal/sort/sorter_test.go @@ -4,39 +4,37 @@ import ( "testing" "github.com/stretchr/testify/assert" - - "github.com/go-task/task/v3/taskfile/ast" ) func TestAlphaNumericWithRootTasksFirst_Sort(t *testing.T) { t.Parallel() - task1 := &ast.Task{Task: "task1"} - task2 := &ast.Task{Task: "task2"} - task3 := &ast.Task{Task: "ns1:task3"} - task4 := &ast.Task{Task: "ns2:task4"} - task5 := &ast.Task{Task: "task5"} - task6 := &ast.Task{Task: "ns3:task6"} + item1 := "a-item1" + item2 := "m-item2" + item3 := "ns1:item3" + item4 := "ns2:item4" + item5 := "z-item5" + item6 := "ns3:item6" tests := []struct { name string - tasks []*ast.Task - want []*ast.Task + items []string + want []string }{ { - name: "no namespace tasks sorted alphabetically first", - tasks: []*ast.Task{task3, task2, task1}, - want: []*ast.Task{task1, task2, task3}, + name: "no namespace items sorted alphabetically first", + items: []string{item3, item2, item1}, + want: []string{item1, item2, item3}, }, { - name: "namespace tasks sorted alphabetically after non-namespaced tasks", - tasks: []*ast.Task{task3, task4, task5}, - want: []*ast.Task{task5, task3, task4}, + name: "namespace items sorted alphabetically after non-namespaced items", + items: []string{item3, item4, item5}, + want: []string{item5, item3, item4}, }, { - name: "all tasks sorted alphabetically with root tasks first", - tasks: []*ast.Task{task6, task5, task4, task3, task2, task1}, - want: []*ast.Task{task1, task2, task5, task3, task4, task6}, + name: "all items sorted alphabetically with root items first", + items: []string{item6, item5, item4, item3, item2, item1}, + want: []string{item1, item2, item5, item3, item4, item6}, }, } @@ -44,9 +42,8 @@ func TestAlphaNumericWithRootTasksFirst_Sort(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - s := &AlphaNumericWithRootTasksFirst{} - s.Sort(tt.tasks) - assert.Equal(t, tt.want, tt.tasks) + AlphaNumericWithRootTasksFirst(tt.items, nil) + assert.Equal(t, tt.want, tt.items) }) } } @@ -54,22 +51,22 @@ func TestAlphaNumericWithRootTasksFirst_Sort(t *testing.T) { func TestAlphaNumeric_Sort(t *testing.T) { t.Parallel() - task1 := &ast.Task{Task: "task1"} - task2 := &ast.Task{Task: "task2"} - task3 := &ast.Task{Task: "ns1:task3"} - task4 := &ast.Task{Task: "ns2:task4"} - task5 := &ast.Task{Task: "task5"} - task6 := &ast.Task{Task: "ns3:task6"} + item1 := "a-item1" + item2 := "m-item2" + item3 := "ns1:item3" + item4 := "ns2:item4" + item5 := "z-item5" + item6 := "ns3:item6" tests := []struct { name string - tasks []*ast.Task - want []*ast.Task + items []string + want []string }{ { - name: "all tasks sorted alphabetically", - tasks: []*ast.Task{task3, task2, task5, task1, task4, task6}, - want: []*ast.Task{task3, task4, task6, task1, task2, task5}, + name: "all items sorted alphabetically", + items: []string{item3, item2, item5, item1, item4, item6}, + want: []string{item1, item2, item3, item4, item6, item5}, }, } @@ -77,9 +74,8 @@ func TestAlphaNumeric_Sort(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - s := &AlphaNumeric{} - s.Sort(tt.tasks) - assert.Equal(t, tt.tasks, tt.want) + AlphaNumeric(tt.items, nil) + assert.Equal(t, tt.want, tt.items) }) } } diff --git a/internal/templater/templater.go b/internal/templater/templater.go index 3f3ab20e..e5265b81 100644 --- a/internal/templater/templater.go +++ b/internal/templater/templater.go @@ -141,10 +141,9 @@ func ReplaceVarsWithExtra(vars *ast.Vars, cache *Cache, extra map[string]any) *a } newVars := ast.NewVars() - _ = vars.Range(func(k string, v ast.Var) error { + for k, v := range vars.All() { newVars.Set(k, ReplaceVarWithExtra(v, cache, extra)) - return nil - }) + } return newVars } diff --git a/setup.go b/setup.go index e038640c..7a358480 100644 --- a/setup.go +++ b/setup.go @@ -100,12 +100,9 @@ func (e *Executor) setupFuzzyModel() { model.SetThreshold(1) // because we want to build grammar based on every task name var words []string - for _, taskName := range e.Taskfile.Tasks.Keys() { - words = append(words, taskName) - - for _, task := range e.Taskfile.Tasks.Values() { - words = slices.Concat(words, task.Aliases) - } + for name, task := range e.Taskfile.Tasks.All(nil) { + words = append(words, name) + words = slices.Concat(words, task.Aliases) } model.Train(words) @@ -222,12 +219,11 @@ func (e *Executor) readDotEnvFiles() error { return err } - err = env.Range(func(key string, value ast.Var) error { - if _, ok := e.Taskfile.Env.Get(key); !ok { - e.Taskfile.Env.Set(key, value) + for k, v := range env.All() { + if _, ok := e.Taskfile.Env.Get(k); !ok { + e.Taskfile.Env.Set(k, v) } - return nil - }) + } return err } @@ -245,7 +241,7 @@ func (e *Executor) setupConcurrencyState() { e.taskCallCount = make(map[string]*int32, e.Taskfile.Tasks.Len()) e.mkdirMutexMap = make(map[string]*sync.Mutex, e.Taskfile.Tasks.Len()) - for _, k := range e.Taskfile.Tasks.Keys() { + for k := range e.Taskfile.Tasks.Keys(nil) { e.taskCallCount[k] = new(int32) e.mkdirMutexMap[k] = &sync.Mutex{} } diff --git a/task.go b/task.go index c8639197..5bb4c1ea 100644 --- a/task.go +++ b/task.go @@ -74,7 +74,7 @@ type Executor struct { Compiler *compiler.Compiler Output output.Output OutputStyle ast.Output - TaskSorter sort.TaskSorter + TaskSorter sort.Sorter UserWorkingDir string EnableVersionCheck bool @@ -475,7 +475,7 @@ func (e *Executor) GetTask(call *ast.Call) (*ast.Task, error) { // If didn't find one, search for a task with a matching alias var matchingTask *ast.Task var aliasedTasks []string - for _, task := range e.Taskfile.Tasks.Values() { + for task := range e.Taskfile.Tasks.Values(nil) { if slices.Contains(task.Aliases, call.Task) { aliasedTasks = append(aliasedTasks, task.Task) matchingTask = task @@ -511,8 +511,13 @@ func (e *Executor) GetTaskList(filters ...FilterFunc) ([]*ast.Task, error) { // Create an error group to wait for each task to be compiled var g errgroup.Group + // Sort the tasks + if e.TaskSorter == nil { + e.TaskSorter = sort.AlphaNumericWithRootTasksFirst + } + // Filter tasks based on the given filter functions - for _, task := range e.Taskfile.Tasks.Values() { + for task := range e.Taskfile.Tasks.Values(e.TaskSorter) { var shouldFilter bool for _, filter := range filters { if filter(task) { @@ -541,12 +546,6 @@ func (e *Executor) GetTaskList(filters ...FilterFunc) ([]*ast.Task, error) { return nil, err } - // Sort the tasks - if e.TaskSorter == nil { - e.TaskSorter = &sort.AlphaNumericWithRootTasksFirst{} - } - e.TaskSorter.Sort(tasks) - return tasks, nil } diff --git a/taskfile/ast/graph.go b/taskfile/ast/graph.go index 31d189e0..cb30093d 100644 --- a/taskfile/ast/graph.go +++ b/taskfile/ast/graph.go @@ -116,14 +116,5 @@ func (tfg *TaskfileGraph) Merge() (*Taskfile, error) { return nil, err } - _ = rootVertex.Taskfile.Tasks.Range(func(name string, task *Task) error { - if task == nil { - task = &Task{} - rootVertex.Taskfile.Tasks.Set(name, task) - } - task.Task = name - return nil - }) - return rootVertex.Taskfile, nil } diff --git a/taskfile/ast/include.go b/taskfile/ast/include.go index 55d45a2e..894fd23d 100644 --- a/taskfile/ast/include.go +++ b/taskfile/ast/include.go @@ -1,9 +1,10 @@ package ast import ( + "iter" "sync" - "github.com/elliotchance/orderedmap/v2" + "github.com/elliotchance/orderedmap/v3" "gopkg.in/yaml.v3" "github.com/go-task/task/v3/errors" @@ -84,19 +85,31 @@ func (includes *Includes) Set(key string, value *Include) bool { return includes.om.Set(key, value) } +// All returns an iterator that loops over all task key-value pairs. // 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) All() iter.Seq2[string, *Include] { if includes == nil || includes.om == nil { - return nil + return func(yield func(string, *Include) bool) {} } - for pair := includes.om.Front(); pair != nil; pair = pair.Next() { - if err := f(pair.Key, pair.Value); err != nil { - return err - } + return includes.om.AllFromFront() +} + +// Keys returns an iterator that loops over all task keys. +func (includes *Includes) Keys() iter.Seq[string] { + if includes == nil || includes.om == nil { + return func(yield func(string) bool) {} } - return nil + return includes.om.Keys() +} + +// Values returns an iterator that loops over all task values. +func (includes *Includes) Values() iter.Seq[*Include] { + if includes == nil || includes.om == nil { + return func(yield func(*Include) bool) {} + } + return includes.om.Values() } // UnmarshalYAML implements the yaml.Unmarshaler interface. diff --git a/taskfile/ast/matrix.go b/taskfile/ast/matrix.go index e5e2a8b6..e6b9f173 100644 --- a/taskfile/ast/matrix.go +++ b/taskfile/ast/matrix.go @@ -1,7 +1,9 @@ package ast import ( - "github.com/elliotchance/orderedmap/v2" + "iter" + + "github.com/elliotchance/orderedmap/v3" "gopkg.in/yaml.v3" "github.com/go-task/task/v3/errors" @@ -48,16 +50,28 @@ func (matrix *Matrix) Set(key string, value []any) bool { return matrix.om.Set(key, value) } -func (matrix *Matrix) Range(f func(k string, v []any) error) error { +// All returns an iterator that loops over all task key-value pairs. +func (matrix *Matrix) All() iter.Seq2[string, []any] { if matrix == nil || matrix.om == nil { - return nil + return func(yield func(string, []any) bool) {} } - for pair := matrix.om.Front(); pair != nil; pair = pair.Next() { - if err := f(pair.Key, pair.Value); err != nil { - return err - } + return matrix.om.AllFromFront() +} + +// Keys returns an iterator that loops over all task keys. +func (matrix *Matrix) Keys() iter.Seq[string] { + if matrix == nil || matrix.om == nil { + return func(yield func(string) bool) {} } - return nil + return matrix.om.Keys() +} + +// Values returns an iterator that loops over all task values. +func (matrix *Matrix) Values() iter.Seq[[]any] { + if matrix == nil || matrix.om == nil { + return func(yield func([]any) bool) {} + } + return matrix.om.Values() } func (matrix *Matrix) DeepCopy() *Matrix { diff --git a/taskfile/ast/tasks.go b/taskfile/ast/tasks.go index 0acb5f7a..d088cd99 100644 --- a/taskfile/ast/tasks.go +++ b/taskfile/ast/tasks.go @@ -2,15 +2,17 @@ package ast import ( "fmt" + "iter" "slices" "strings" "sync" - "github.com/elliotchance/orderedmap/v2" + "github.com/elliotchance/orderedmap/v3" "gopkg.in/yaml.v3" "github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/internal/filepathext" + "github.com/go-task/task/v3/internal/sort" ) type ( @@ -79,47 +81,47 @@ func (tasks *Tasks) Set(key string, value *Task) bool { 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 { - if tasks == nil || tasks.om == nil { - return nil +// All returns an iterator that loops over all task key-value pairs in the order +// specified by the sorter. +func (t *Tasks) All(sorter sort.Sorter) iter.Seq2[string, *Task] { + if t == nil || t.om == nil { + return func(yield func(string, *Task) bool) {} } - for pair := tasks.om.Front(); pair != nil; pair = pair.Next() { - if err := f(pair.Key, pair.Value); err != nil { - return err + if sorter == nil { + return t.om.AllFromFront() + } + return func(yield func(string, *Task) bool) { + for _, key := range sorter(slices.Collect(t.om.Keys()), nil) { + el := t.om.GetElement(key) + if !yield(el.Key, el.Value) { + return + } } } - return nil } -// Keys returns a slice of all the keys in the Tasks map. -func (tasks *Tasks) Keys() []string { - if tasks == nil { - return nil +// Keys returns an iterator that loops over all task keys in the order specified +// by the sorter. +func (t *Tasks) Keys(sorter sort.Sorter) iter.Seq[string] { + return func(yield func(string) bool) { + for k := range t.All(sorter) { + if !yield(k) { + return + } + } } - defer tasks.mutex.RUnlock() - tasks.mutex.RLock() - var keys []string - for pair := tasks.om.Front(); pair != nil; pair = pair.Next() { - keys = append(keys, pair.Key) - } - return keys } -// Values returns a slice of all the values in the Tasks map. -func (tasks *Tasks) Values() []*Task { - if tasks == nil { - return nil +// Values returns an iterator that loops over all task values in the order +// specified by the sorter. +func (t *Tasks) Values(sorter sort.Sorter) iter.Seq[*Task] { + return func(yield func(*Task) bool) { + for _, v := range t.All(sorter) { + if !yield(v) { + return + } + } } - defer tasks.mutex.RUnlock() - tasks.mutex.RLock() - var values []*Task - for pair := tasks.om.Front(); pair != nil; pair = pair.Next() { - values = append(values, pair.Value) - } - return values } // FindMatchingTasks returns a list of tasks that match the given call. A task @@ -138,22 +140,21 @@ func (t *Tasks) FindMatchingTasks(call *Call) []*MatchingTask { } // Attempt a wildcard match // For now, we can just nil check the task before each loop - _ = t.Range(func(key string, value *Task) error { + for _, value := range t.All(nil) { if match, wildcards := value.WildcardMatch(call.Task); match { matchingTasks = append(matchingTasks, &MatchingTask{ Task: value, Wildcards: wildcards, }) } - return nil - }) + } return matchingTasks } 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 { + for name, v := range t2.All(nil) { // 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() @@ -162,9 +163,9 @@ func (t1 *Tasks) Merge(t2 *Tasks, include *Include, includedTaskfileVars *Vars) task.Internal = task.Internal || (include != nil && include.Internal) taskName := name - // if the task is in the exclude list, don't add it to the merged taskfile and early return + // if the task is in the exclude list, don't add it to the merged taskfile if slices.Contains(include.Excludes, name) { - return nil + continue } if !include.Flatten { @@ -219,9 +220,7 @@ func (t1 *Tasks) Merge(t2 *Tasks, include *Include, includedTaskfileVars *Vars) } // Add the task to the merged taskfile t1.Set(taskName, task) - - return nil - }) + } // If the included Taskfile has a default task, is not flattened and the // parent namespace has no task with a matching name, we can add an alias so @@ -239,7 +238,7 @@ func (t1 *Tasks) Merge(t2 *Tasks, include *Include, includedTaskfileVars *Vars) } } - return err + return nil } func (t *Tasks) UnmarshalYAML(node *yaml.Node) error { diff --git a/taskfile/ast/vars.go b/taskfile/ast/vars.go index e48aa341..f6203464 100644 --- a/taskfile/ast/vars.go +++ b/taskfile/ast/vars.go @@ -1,9 +1,10 @@ package ast import ( + "iter" "sync" - "github.com/elliotchance/orderedmap/v2" + "github.com/elliotchance/orderedmap/v3" "gopkg.in/yaml.v3" "github.com/go-task/task/v3/errors" @@ -70,19 +71,28 @@ func (vars *Vars) Set(key string, value Var) bool { return vars.om.Set(key, value) } -// Range calls the provided function for each variable in the map. The function -// 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 { +// All returns an iterator that loops over all task key-value pairs. +func (vars *Vars) All() iter.Seq2[string, Var] { if vars == nil || vars.om == nil { - return nil + return func(yield func(string, Var) bool) {} } - for pair := vars.om.Front(); pair != nil; pair = pair.Next() { - if err := f(pair.Key, pair.Value); err != nil { - return err - } + return vars.om.AllFromFront() +} + +// Keys returns an iterator that loops over all task keys. +func (vars *Vars) Keys() iter.Seq[string] { + if vars == nil || vars.om == nil { + return func(yield func(string) bool) {} } - return nil + return vars.om.Keys() +} + +// Values returns an iterator that loops over all task values. +func (vars *Vars) Values() iter.Seq[Var] { + if vars == nil || vars.om == nil { + return func(yield func(Var) bool) {} + } + return vars.om.Values() } // ToCacheMap converts Vars to an unordered map containing only the static @@ -91,16 +101,16 @@ func (vars *Vars) ToCacheMap() (m map[string]any) { defer vars.mutex.RUnlock() 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 != "" { + for k, v := range vars.All() { + if v.Sh != nil && *v.Sh != "" { // Dynamic variable is not yet resolved; trigger // to be used in templates. return nil } - if pair.Value.Live != nil { - m[pair.Key] = pair.Value.Live + if v.Live != nil { + m[k] = v.Live } else { - m[pair.Key] = pair.Value.Value + m[k] = v.Value } } return diff --git a/taskfile/reader.go b/taskfile/reader.go index f2f5394c..8ee6f268 100644 --- a/taskfile/reader.go +++ b/taskfile/reader.go @@ -187,7 +187,7 @@ func (r *Reader) include(node Node) error { var g errgroup.Group // Loop over each included taskfile - _ = vertex.Taskfile.Includes.Range(func(namespace string, include *ast.Include) error { + for _, include := range vertex.Taskfile.Includes.All() { vars := compiler.GetEnviron() vars.Merge(vertex.Taskfile.Vars, nil) // Start a goroutine to process each included Taskfile @@ -264,8 +264,7 @@ func (r *Reader) include(node Node) error { } return err }) - return nil - }) + } // Wait for all the go routines to finish return g.Wait() @@ -299,7 +298,7 @@ func (r *Reader) readNode(node Node) (*ast.Taskfile, error) { // Set the taskfile/task's locations tf.Location = node.Location() - for _, task := range tf.Tasks.Values() { + for task := range tf.Tasks.Values(nil) { // If the task is not defined, create a new one if task == nil { task = &ast.Task{} diff --git a/variables.go b/variables.go index e515aea6..91c3ad82 100644 --- a/variables.go +++ b/variables.go @@ -110,21 +110,17 @@ func (e *Executor) compiledTask(call *ast.Call, evaluateShVars bool) (*ast.Task, new.Env.Merge(templater.ReplaceVars(dotenvEnvs, cache), nil) new.Env.Merge(templater.ReplaceVars(origTask.Env, cache), nil) if evaluateShVars { - err = new.Env.Range(func(k string, v ast.Var) error { + for k, v := range new.Env.All() { // If the variable is not dynamic, we can set it and return if v.Value != nil || v.Sh == nil { new.Env.Set(k, ast.Var{Value: v.Value}) - return nil + continue } static, err := e.Compiler.HandleDynamicVar(v, new.Dir, env.GetFromVars(new.Env)) if err != nil { - return err + return nil, err } new.Env.Set(k, ast.Var{Value: static}) - return nil - }) - if err != nil { - return nil, err } } @@ -306,7 +302,7 @@ func itemsFromFor( // If the variable is dynamic, then it hasn't been resolved yet // and we can't use it as a list. This happens when fast compiling a task // for use in --list or --list-all etc. - if ok && v.Sh == nil { + if ok && v.Value != nil && v.Sh == nil { switch value := v.Value.(type) { case string: if f.Split != "" { @@ -347,7 +343,7 @@ func product(inputMap *ast.Matrix) []map[string]any { result := []map[string]any{{}} // Iterate over each slice in the slices - _ = inputMap.Range(func(key string, slice []any) error { + for key, slice := range inputMap.All() { var newResult []map[string]any // For each combination in the current result @@ -367,8 +363,7 @@ func product(inputMap *ast.Matrix) []map[string]any { // Update result with the new combinations result = newResult - return nil - }) + } return result }