2018-07-22 16:05:47 -03:00
package read
import (
2018-10-13 17:52:09 -03:00
"errors"
2018-07-22 16:05:47 -03:00
"fmt"
2020-08-03 16:18:38 -06:00
"github.com/joho/godotenv"
2018-07-22 16:05:47 -03:00
"os"
"path/filepath"
"runtime"
2018-11-04 21:23:35 -02:00
"github.com/go-task/task/v2/internal/taskfile"
2020-05-17 16:03:03 -03:00
"github.com/go-task/task/v2/internal/templater"
2018-07-22 16:05:47 -03:00
2020-03-28 11:27:49 -03:00
"gopkg.in/yaml.v3"
2018-07-22 16:05:47 -03:00
)
2019-01-21 14:56:14 +05:00
var (
// ErrIncludedTaskfilesCantHaveIncludes is returned when a included Taskfile contains includes
ErrIncludedTaskfilesCantHaveIncludes = errors . New ( "task: Included Taskfiles can't have includes. Please, move the include to the main Taskfile" )
2020-08-03 16:18:38 -06:00
ErrIncludedTaskfilesCantHaveDotenvs = errors . New ( "task: Included Taskfiles can't have dotenv declarations. Please, move the dotenv declaration to the main Taskfile" )
2019-01-21 14:56:14 +05:00
)
2018-10-13 17:52:09 -03:00
2018-07-22 16:05:47 -03:00
// Taskfile reads a Taskfile for a given directory
2019-07-21 10:54:09 -03:00
func Taskfile ( dir string , entrypoint string ) ( * taskfile . Taskfile , error ) {
path := filepath . Join ( dir , entrypoint )
2018-09-22 17:29:18 -03:00
if _ , err := os . Stat ( path ) ; err != nil {
2019-07-21 10:54:09 -03:00
return nil , fmt . Errorf ( ` task: No Taskfile found on "%s". Use "task --init" to create a new one ` , path )
2018-09-22 17:29:18 -03:00
}
2018-07-22 16:05:47 -03:00
t , err := readTaskfile ( path )
if err != nil {
2018-09-22 17:29:18 -03:00
return nil , err
2018-07-22 16:05:47 -03:00
}
2020-05-17 16:03:03 -03:00
v , err := t . ParsedVersion ( )
if err != nil {
return nil , err
}
2020-08-03 16:18:38 -06:00
if v >= 3.0 {
if len ( t . Dotenv ) > 0 {
for _ , envFile := range t . Dotenv {
var envFilePath string
if filepath . IsAbs ( envFile ) {
envFilePath = envFile
} else {
envFilePath = filepath . Join ( dir , envFile )
}
if err = godotenv . Load ( envFilePath ) ; err != nil {
return nil , err
}
}
}
}
2020-01-29 10:03:06 +03:00
for namespace , includedTask := range t . Includes {
2020-05-17 16:03:03 -03:00
if v >= 3.0 {
tr := templater . Templater { Vars : & taskfile . Vars { } , RemoveNoValue : true }
includedTask = taskfile . IncludedTaskfile {
Taskfile : tr . Replace ( includedTask . Taskfile ) ,
Dir : tr . Replace ( includedTask . Dir ) ,
AdvancedImport : includedTask . AdvancedImport ,
}
if err := tr . Err ( ) ; err != nil {
return nil , err
}
}
2020-02-15 18:07:09 +03:00
if filepath . IsAbs ( includedTask . Taskfile ) {
path = includedTask . Taskfile
} else {
path = filepath . Join ( dir , includedTask . Taskfile )
}
2018-09-09 22:29:29 -03:00
info , err := os . Stat ( path )
if err != nil {
return nil , err
}
if info . IsDir ( ) {
path = filepath . Join ( path , "Taskfile.yml" )
}
includedTaskfile , err := readTaskfile ( path )
if err != nil {
return nil , err
}
2018-10-13 17:52:09 -03:00
if len ( includedTaskfile . Includes ) > 0 {
return nil , ErrIncludedTaskfilesCantHaveIncludes
}
2020-01-29 10:03:06 +03:00
2020-08-03 16:18:38 -06:00
if v >= 3.0 {
if len ( includedTaskfile . Dotenv ) > 0 {
return nil , ErrIncludedTaskfilesCantHaveDotenvs
}
}
2020-02-15 17:24:06 +03:00
if includedTask . AdvancedImport {
for _ , task := range includedTaskfile . Tasks {
if ! filepath . IsAbs ( task . Dir ) {
task . Dir = filepath . Join ( includedTask . Dir , task . Dir )
}
2020-02-15 16:40:42 +03:00
}
2020-01-29 10:03:06 +03:00
}
2018-09-09 22:29:29 -03:00
if err = taskfile . Merge ( t , includedTaskfile , namespace ) ; err != nil {
return nil , err
}
}
2020-05-17 15:42:27 -03:00
if v < 3.0 {
path = filepath . Join ( dir , fmt . Sprintf ( "Taskfile_%s.yml" , runtime . GOOS ) )
if _ , err = os . Stat ( path ) ; err == nil {
osTaskfile , err := readTaskfile ( path )
if err != nil {
return nil , err
}
if err = taskfile . Merge ( t , osTaskfile ) ; err != nil {
return nil , err
}
2018-07-22 16:05:47 -03:00
}
}
for name , task := range t . Tasks {
task . Task = name
}
return t , nil
}
func readTaskfile ( file string ) ( * taskfile . Taskfile , error ) {
f , err := os . Open ( file )
if err != nil {
return nil , err
}
var t taskfile . Taskfile
return & t , yaml . NewDecoder ( f ) . Decode ( & t )
}