@@ -12,6 +12,7 @@ import (
1212 "github.com/go-task/task/v3/internal/env"
1313 "github.com/go-task/task/v3/internal/execext"
1414 "github.com/go-task/task/v3/internal/filepathext"
15+ "github.com/go-task/task/v3/internal/fingerprint"
1516 "github.com/go-task/task/v3/internal/logger"
1617 "github.com/go-task/task/v3/internal/templater"
1718 "github.com/go-task/task/v3/internal/version"
@@ -197,19 +198,99 @@ func (c *Compiler) ResetCache() {
197198 c .dynamicCache = nil
198199}
199200
200- func (c * Compiler ) getSpecialVars (t * ast.Task , call * Call ) (map [string ]string , error ) {
201- allVars := map [string ]string {
201+ func (c * Compiler ) getSpecialVars (t * ast.Task , call * Call ) (map [string ]any , error ) {
202+ allVars := map [string ]any {
202203 "TASK_EXE" : filepath .ToSlash (os .Args [0 ]),
203204 "ROOT_TASKFILE" : filepathext .SmartJoin (c .Dir , c .Entrypoint ),
204205 "ROOT_DIR" : c .Dir ,
205206 "USER_WORKING_DIR" : c .UserWorkingDir ,
206207 "TASK_VERSION" : version .GetVersion (),
207208 }
208209 if t != nil {
210+ taskDir := filepathext .SmartJoin (c .Dir , t .Dir )
211+
209212 allVars ["TASK" ] = t .Task
210- allVars ["TASK_DIR" ] = filepathext . SmartJoin ( c . Dir , t . Dir )
213+ allVars ["TASK_DIR" ] = taskDir
211214 allVars ["TASKFILE" ] = t .Location .Taskfile
212215 allVars ["TASKFILE_DIR" ] = filepath .Dir (t .Location .Taskfile )
216+
217+ // Template and expand shell variables for both Sources and Generates
218+ envVars := env .GetEnviron ()
219+ // Add the special vars we've built so far to the cache
220+ for k , v := range allVars {
221+ envVars .Set (k , ast.Var {Value : v })
222+ }
223+ // Add taskfile variables to the cache so they're available for templating
224+ // Note: Variables that reference TASK_SOURCES or TASK_GENERATES won't work here,
225+ // but simple string variables like C_EXT: c will work fine
226+ for k , v := range c .TaskfileEnv .All () {
227+ envVars .Set (k , v )
228+ }
229+ for k , v := range c .TaskfileVars .All () {
230+ envVars .Set (k , v )
231+ }
232+ for k , v := range t .IncludeVars .All () {
233+ envVars .Set (k , v )
234+ }
235+ for k , v := range t .IncludedTaskfileVars .All () {
236+ envVars .Set (k , v )
237+ }
238+ for k , v := range t .Vars .All () {
239+ envVars .Set (k , v )
240+ }
241+ if call != nil {
242+ for k , v := range call .Vars .All () {
243+ envVars .Set (k , v )
244+ }
245+ }
246+ cache := & templater.Cache {Vars : envVars }
247+
248+ // Template Sources
249+ templatedSources := templater .ReplaceGlobs (t .Sources , cache )
250+ if err := cache .Err (); err != nil {
251+ return allVars , fmt .Errorf ("template sources: %v" , err )
252+ }
253+ // Expand shell variables in Sources and then expand globs to actual file paths
254+ expandedSources := make ([]* ast.Glob , len (templatedSources ))
255+ for i , g := range templatedSources {
256+ expanded , err := execext .ExpandLiteral (g .Glob )
257+ if err != nil {
258+ return allVars , fmt .Errorf ("expand shell variables in source glob %q: %v" , g .Glob , err )
259+ }
260+ expandedSources [i ] = & ast.Glob {Glob : expanded , Negate : g .Negate }
261+ }
262+ taskSources , err := fingerprint .Globs (taskDir , expandedSources )
263+ if err != nil {
264+ return allVars , fmt .Errorf ("expand globs: %v" , err )
265+ }
266+ // Convert absolute paths to relative paths (relative to root directory)
267+ relativeSources := make ([]string , len (taskSources ))
268+ for i , source := range taskSources {
269+ rel , err := filepath .Rel (c .Dir , source )
270+ if err != nil {
271+ // If relative path calculation fails, use the original path
272+ relativeSources [i ] = source
273+ } else {
274+ relativeSources [i ] = filepath .ToSlash (rel )
275+ }
276+ }
277+ allVars ["TASK_SOURCES" ] = relativeSources
278+
279+ // Template Generates
280+ templatedGenerates := templater .ReplaceGlobs (t .Generates , cache )
281+ if err := cache .Err (); err != nil {
282+ return allVars , fmt .Errorf ("template generates: %v" , err )
283+ }
284+ // Expand shell variables in Generates, but keep glob patterns intact
285+ taskGenerates := make ([]string , len (templatedGenerates ))
286+ for i , g := range templatedGenerates {
287+ expanded , err := execext .ExpandLiteral (g .Glob )
288+ if err != nil {
289+ return allVars , fmt .Errorf ("expand shell variables in generate glob %q: %v" , g .Glob , err )
290+ }
291+ taskGenerates [i ] = expanded
292+ }
293+ allVars ["TASK_GENERATES" ] = taskGenerates
213294 } else {
214295 allVars ["TASK" ] = ""
215296 allVars ["TASK_DIR" ] = ""
0 commit comments