feat: add joinEnv and joinUrl string functions and 2 new system vars (#2408)

This commit is contained in:
Jerry Wiltse
2026-05-09 10:19:33 -04:00
committed by GitHub
parent 629a10813f
commit d9e0e04725
4 changed files with 101 additions and 18 deletions

View File

@@ -202,11 +202,13 @@ func (c *Compiler) getSpecialVars(t *ast.Task, call *Call) (map[string]string, e
// across platforms. This prevents issues with backslashes being interpreted // across platforms. This prevents issues with backslashes being interpreted
// as escape sequences when paths are used in shell commands on Windows. // as escape sequences when paths are used in shell commands on Windows.
allVars := map[string]string{ allVars := map[string]string{
"TASK_EXE": filepath.ToSlash(os.Args[0]), "TASK_EXE": filepath.ToSlash(os.Args[0]),
"ROOT_TASKFILE": filepath.ToSlash(filepathext.SmartJoin(c.Dir, c.Entrypoint)), "ROOT_TASKFILE": filepath.ToSlash(filepathext.SmartJoin(c.Dir, c.Entrypoint)),
"ROOT_DIR": filepath.ToSlash(c.Dir), "ROOT_DIR": filepath.ToSlash(c.Dir),
"USER_WORKING_DIR": filepath.ToSlash(c.UserWorkingDir), "USER_WORKING_DIR": filepath.ToSlash(c.UserWorkingDir),
"TASK_VERSION": version.GetVersion(), "TASK_VERSION": version.GetVersion(),
"PATH_LIST_SEPARATOR": string(os.PathListSeparator),
"FILE_PATH_SEPARATOR": string(os.PathSeparator),
} }
if t != nil { if t != nil {
allVars["TASK"] = t.Task allVars["TASK"] = t.Task

View File

@@ -285,7 +285,9 @@ func isEnvVar(key string, envVars map[string]bool) bool {
key == "TASKFILE_DIR" || key == "TASKFILE_DIR" ||
key == "USER_WORKING_DIR" || key == "USER_WORKING_DIR" ||
key == "ALIAS" || key == "ALIAS" ||
key == "MATCH" { key == "MATCH" ||
key == "PATH_LIST_SEPARATOR" ||
key == "FILE_PATH_SEPARATOR" {
return true return true
} }
return envVars[key] return envVars[key]

View File

@@ -3,6 +3,8 @@ package templater
import ( import (
"maps" "maps"
"math/rand/v2" "math/rand/v2"
"os"
"path"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings" "strings"
@@ -21,8 +23,8 @@ var templateFuncs template.FuncMap
func init() { func init() {
taskFuncs := template.FuncMap{ taskFuncs := template.FuncMap{
"OS": os, "OS": goos,
"ARCH": arch, "ARCH": goarch,
"numCPU": runtime.NumCPU, "numCPU": runtime.NumCPU,
"catLines": catLines, "catLines": catLines,
"splitLines": splitLines, "splitLines": splitLines,
@@ -33,6 +35,8 @@ func init() {
"splitArgs": splitArgs, "splitArgs": splitArgs,
"IsSH": IsSH, // Deprecated "IsSH": IsSH, // Deprecated
"joinPath": filepath.Join, "joinPath": filepath.Join,
"joinEnv": joinEnv,
"joinUrl": joinUrl,
"relPath": filepath.Rel, "relPath": filepath.Rel,
"absPath": filepath.Abs, "absPath": filepath.Abs,
"merge": merge, "merge": merge,
@@ -57,11 +61,11 @@ func init() {
maps.Copy(templateFuncs, taskFuncs) maps.Copy(templateFuncs, taskFuncs)
} }
func os() string { func goos() string {
return runtime.GOOS return runtime.GOOS
} }
func arch() string { func goarch() string {
return runtime.GOARCH return runtime.GOARCH
} }
@@ -95,6 +99,14 @@ func IsSH() bool {
return true return true
} }
func joinEnv(elem ...string) string {
return strings.Join(elem, string(os.PathListSeparator))
}
func joinUrl(elem ...string) string {
return path.Join(elem...)
}
func merge(base map[string]any, v ...map[string]any) map[string]any { func merge(base map[string]any, v ...map[string]any) map[string]any {
cap := len(v) cap := len(v)
for _, m := range v { for _, m := range v {

View File

@@ -249,6 +249,32 @@ tasks:
- echo "Working {{.USER_WORKING_DIR}}" - echo "Working {{.USER_WORKING_DIR}}"
``` ```
#### `FILE_PATH_SEPARATOR`
- **Type**: `string`
- **Description**: OS-specific path separator: Windows = `\`, others = `/`
::: info
> See `joinPath` in [Path Functions](#path-functions) for joining filesystem paths for use with
> file system operations.
:::
### Environment Variables
#### `PATH_LIST_SEPARATOR`
- **Type**: `string`
- **Description**: OS-specific path separator for environment variables: Windows = `;`, others = `:`
::: info
> See `joinEnv` in [Environment Variable Functions](#environment-variable-functions) for joining
> paths for use in environment variables.
:::
### Status ### Status
#### `CHECKSUM` #### `CHECKSUM`
@@ -597,9 +623,9 @@ tasks:
tasks: tasks:
platform: platform:
cmds: cmds:
- echo "OS {{OS}}" # linux, darwin, windows, etc. - echo "OS {{OS}}" # linux, darwin, windows, etc.
- echo "Architecture {{ARCH}}" # amd64, arm64, etc. - echo "Architecture {{ARCH}}" # amd64, arm64, etc.
- echo "CPU cores {{numCPU}}" # Number of CPU cores - echo "CPU cores {{numCPU}}" # Number of CPU cores
- echo "Building for {{OS}}/{{ARCH}}" - echo "Building for {{OS}}/{{ARCH}}"
``` ```
@@ -613,11 +639,52 @@ tasks:
OUTPUT_DIR: 'dist' OUTPUT_DIR: 'dist'
BINARY_NAME: 'myapp' BINARY_NAME: 'myapp'
cmds: cmds:
- echo "{{.WIN_PATH | toSlash}}" # Convert to forward slashes - echo "{{.WIN_PATH | toSlash}}" # Convert to forward slashes
- echo "{{.WIN_PATH | fromSlash}}" # Convert to OS-specific slashes - echo "{{.WIN_PATH | fromSlash}}" # Convert to OS-specific slashes
- echo "{{joinPath .OUTPUT_DIR .BINARY_NAME}}" # Join path elements - echo "{{joinPath .OUTPUT_DIR .BINARY_NAME}}" # Join path elements
- echo "Relative {{relPath .ROOT_DIR .TASKFILE_DIR}}" # Get relative path - echo "Relative {{relPath .ROOT_DIR .TASKFILE_DIR}}" # Get relative path
- echo '{{absPath "../sibling"}}' # Resolve to an absolute path - echo '{{absPath "../sibling"}}' # Resolve to an absolute path
```
#### Environment Variable Functions
```yaml
tasks:
paths:
vars:
WIN_PATH1: 'C:\Users\Person\bin'
WIN_PATH2: 'C:\Shared\bin'
cmds:
# Join paths for Windows ENV vars:
# C:\Users\Person\bin;C:\Shared\bin
- echo "{{joinEnv .WIN_PATH1 .WIN_PATH2}}"
```
```yaml
tasks:
paths:
vars:
POSIX_PATH1: '/users/person/.local/bin'
POSIX_PATH2: '/usr/bin'
cmds:
# Join paths for POSIX ENV vars:
# /users/person/.local/bin:/usr/bin
- echo "{{joinEnv .POSIX_PATH1 .POSIX_PATH2}}"
```
#### URLs
```yaml
tasks:
paths:
vars:
SERVER: 'http://localhost'
PATH1: 'path1'
PATH2: 'path2'
cmds:
# Join paths for URL:
# http://localhost/path1/path2
- echo "{{joinUrl .SERVER .PATH1 .PATH2}}"
``` ```
### Data Structure Functions ### Data Structure Functions