# HG changeset patch
# Node ID 0ef6f340b404
# Parent  359352b67935
diff --git a/environment/environment.go b/environment/environment.go
--- a/environment/environment.go
+++ b/environment/environment.go
@@ -18,21 +18,12 @@
 package environment
 
 import (
+	"maps"
 	"strings"
 )
 
 type Environment map[string]string
 
-// splitEqual takes a string like "foo=bar" and returns it as ("foo", "bar")
-func splitEqual(value string) (string, string) {
-	parts := strings.SplitN(value, "=", 2)
-	if len(parts) == 1 {
-		return parts[0], ""
-	}
-
-	return parts[0], parts[1]
-}
-
 func New(items ...string) Environment {
 	r := Environment{}
 
@@ -41,10 +32,7 @@ func New(items ...string) Environment {
 
 func (e Environment) Copy() Environment {
 	r := Environment{}
-
-	for k, v := range e {
-		r[k] = v
-	}
+	maps.Copy(r, e)
 
 	return r
 }
@@ -52,9 +40,7 @@ func (e Environment) Copy() Environment 
 // Merge will merge another environment into the current environment
 // overwriting any existing items
 func (e Environment) Merge(env Environment) Environment {
-	for k, v := range env {
-		e[k] = v
-	}
+	maps.Copy(e, env)
 
 	return e
 }
@@ -62,7 +48,7 @@ func (e Environment) Merge(env Environme
 // MergeSlice will merge a slice of strings in key or key=value formats.
 func (e Environment) MergeSlice(items []string) Environment {
 	for _, item := range items {
-		k, v := splitEqual(item)
+		k, v, _ := strings.Cut(item, "=")
 		e[k] = v
 	}
 
diff --git a/environment/mapper.go b/environment/mapper.go
--- a/environment/mapper.go
+++ b/environment/mapper.go
@@ -41,9 +41,9 @@ func (e *envMapper) mapVariable(name str
 	}
 
 	for _, item := range e.env {
-		if parts := strings.SplitN(item, "=", 2); parts[0] == name {
-			if len(parts) == 2 {
-				return parts[1]
+		if varName, varValue, valueFound := strings.Cut(item, "="); varName == name {
+			if valueFound {
+				return varValue
 			}
 
 			return os.Getenv(name)
diff --git a/exec/generator.go b/exec/generator.go
--- a/exec/generator.go
+++ b/exec/generator.go
@@ -17,7 +17,7 @@
 package exec
 
 import (
-	"math"
+	"slices"
 	"sync"
 )
 
@@ -28,15 +28,13 @@ const (
 // Generator represents a command generator.
 type Generator struct {
 	args []string
-	next int
 	lock sync.Mutex
 }
 
 // NewGenerator creates a new generator initialized with the gives arguments.
 func NewGenerator(args ...string) *Generator {
 	g := &Generator{
-		args: make([]string, minAlloc),
-		next: 0,
+		args: make([]string, 0, minAlloc),
 	}
 
 	g.Appendv(args)
@@ -44,24 +42,6 @@ func NewGenerator(args ...string) *Gener
 	return g
 }
 
-// resize will resize the slice to the required size or minimum allocation
-// which ever is larger.
-func (g *Generator) resize(reqSize int) {
-	if g.next >= len(g.args) {
-		newSize := len(g.args)
-
-		if reqSize > minAlloc {
-			newSize += reqSize
-		} else {
-			newSize += minAlloc
-		}
-
-		newArgs := make([]string, newSize)
-		copy(newArgs, g.args)
-		g.args = newArgs
-	}
-}
-
 // Append appends the given arguments to the end of the arguments.
 func (g *Generator) Append(args ...string) {
 	g.Appendv(args)
@@ -76,11 +56,7 @@ func (g *Generator) Appendv(args []strin
 		return
 	}
 
-	for _, item := range args {
-		g.resize(1)
-		g.args[g.next] = item
-		g.next++
-	}
+	g.args = slices.Insert(g.args, len(g.args), args...)
 }
 
 // Prepend prepends the given arguments to the beginning of the arguments.
@@ -97,27 +73,7 @@ func (g *Generator) Prependv(args []stri
 		return
 	}
 
-	// allocate a new slice that's the size of the
-	newSize := int(math.Max(float64(len(args)), float64(minAlloc))) + len(g.args)
-	newArgs := make([]string, newSize)
-
-	// set our current index to 0
-	idx := 0
-
-	// add the prepended items
-	for ; idx < len(args); idx++ {
-		newArgs[idx] = args[idx]
-	}
-
-	// add the original items
-	offset := len(args)
-	for ; idx < g.next+offset; idx++ {
-		newArgs[idx] = g.args[idx-offset]
-	}
-
-	// now assign newArgs
-	g.args = newArgs
-	g.next += len(args)
+	g.args = slices.Insert(g.args, 0, args...)
 }
 
 // Command returns the currently built command.
@@ -125,10 +81,5 @@ func (g *Generator) Command() []string {
 	g.lock.Lock()
 	defer g.lock.Unlock()
 
-	ret := make([]string, g.next)
-	for i := 0; i < g.next; i++ {
-		ret[i] = g.args[i]
-	}
-
-	return ret
+	return slices.Clone(g.args)
 }
diff --git a/fs/pathspec.go b/fs/pathspec.go
--- a/fs/pathspec.go
+++ b/fs/pathspec.go
@@ -29,17 +29,13 @@ type PathSpec struct {
 // If there is no colon, then either "." (the current working directory)
 // will be returned as the destination.
 func ParsePathSpec(spec string) *PathSpec {
-	parts := strings.SplitN(spec, ":", 2)
+	src, dst, found := strings.Cut(spec, ":")
 
-	dst := parts[0]
-	if len(parts) > 1 {
-		dst = parts[1]
+	if !found {
+		dst = src
 	}
 
-	return &PathSpec{
-		src: parts[0],
-		dst: dst,
-	}
+	return &PathSpec{src: src, dst: dst}
 }
 
 func (ps *PathSpec) Source() string {
diff --git a/go.mod b/go.mod
--- a/go.mod
+++ b/go.mod
@@ -24,4 +24,4 @@ require (
 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
 )
 
-go 1.17
+go 1.21
diff --git a/tasks/clean.go b/tasks/clean.go
--- a/tasks/clean.go
+++ b/tasks/clean.go
@@ -53,20 +53,6 @@ func sanitizeFile(base, file string, env
 	return pathname, nil
 }
 
-func sanitizeFiles(base string, files, env environment.Environment) ([]string, error) {
-	list := []string{}
-	for _, file := range files {
-		sanitized, err := sanitizeFile(base, file, env)
-		if err != nil {
-			return nil, err
-		}
-
-		list = append(list, sanitized)
-	}
-
-	return list, nil
-}
-
 // Execute runs the clean task.
 func (c *Clean) Execute(name string, logger *log.Entry, env environment.Environment, rt *runtime.Runtime) error {
 	fullEnv := environment.New()
