node_file.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package taskfile
  2. import (
  3. "context"
  4. "io"
  5. "os"
  6. "path/filepath"
  7. "strings"
  8. "github.com/go-task/task/v3/internal/execext"
  9. "github.com/go-task/task/v3/internal/filepathext"
  10. "github.com/go-task/task/v3/internal/logger"
  11. )
  12. // A FileNode is a node that reads a taskfile from the local filesystem.
  13. type FileNode struct {
  14. *BaseNode
  15. Entrypoint string
  16. }
  17. func NewFileNode(l *logger.Logger, entrypoint, dir string, opts ...NodeOption) (*FileNode, error) {
  18. var err error
  19. base := NewBaseNode(dir, opts...)
  20. entrypoint, base.dir, err = resolveFileNodeEntrypointAndDir(l, entrypoint, base.dir)
  21. if err != nil {
  22. return nil, err
  23. }
  24. return &FileNode{
  25. BaseNode: base,
  26. Entrypoint: entrypoint,
  27. }, nil
  28. }
  29. func (node *FileNode) Location() string {
  30. return node.Entrypoint
  31. }
  32. func (node *FileNode) Remote() bool {
  33. return false
  34. }
  35. func (node *FileNode) Read(ctx context.Context) ([]byte, error) {
  36. f, err := os.Open(node.Location())
  37. if err != nil {
  38. return nil, err
  39. }
  40. defer f.Close()
  41. return io.ReadAll(f)
  42. }
  43. // resolveFileNodeEntrypointAndDir resolves checks the values of entrypoint and dir and
  44. // populates them with default values if necessary.
  45. func resolveFileNodeEntrypointAndDir(l *logger.Logger, entrypoint, dir string) (string, string, error) {
  46. var err error
  47. if entrypoint != "" {
  48. entrypoint, err = Exists(l, entrypoint)
  49. if err != nil {
  50. return "", "", err
  51. }
  52. if dir == "" {
  53. dir = filepath.Dir(entrypoint)
  54. }
  55. return entrypoint, dir, nil
  56. }
  57. if dir == "" {
  58. dir, err = os.Getwd()
  59. if err != nil {
  60. return "", "", err
  61. }
  62. }
  63. entrypoint, err = ExistsWalk(l, dir)
  64. if err != nil {
  65. return "", "", err
  66. }
  67. dir = filepath.Dir(entrypoint)
  68. return entrypoint, dir, nil
  69. }
  70. func (node *FileNode) ResolveEntrypoint(entrypoint string) (string, error) {
  71. // If the file is remote, we don't need to resolve the path
  72. if strings.Contains(entrypoint, "://") {
  73. return entrypoint, nil
  74. }
  75. path, err := execext.Expand(entrypoint)
  76. if err != nil {
  77. return "", err
  78. }
  79. if filepathext.IsAbs(path) {
  80. return path, nil
  81. }
  82. // NOTE: Uses the directory of the entrypoint (Taskfile), not the current working directory
  83. // This means that files are included relative to one another
  84. entrypointDir := filepath.Dir(node.Entrypoint)
  85. return filepathext.SmartJoin(entrypointDir, path), nil
  86. }
  87. func (node *FileNode) ResolveDir(dir string) (string, error) {
  88. path, err := execext.Expand(dir)
  89. if err != nil {
  90. return "", err
  91. }
  92. if filepathext.IsAbs(path) {
  93. return path, nil
  94. }
  95. // NOTE: Uses the directory of the entrypoint (Taskfile), not the current working directory
  96. // This means that files are included relative to one another
  97. entrypointDir := filepath.Dir(node.Entrypoint)
  98. return filepathext.SmartJoin(entrypointDir, path), nil
  99. }
  100. func (node *FileNode) FilenameAndLastDir() (string, string) {
  101. return "", filepath.Base(node.Entrypoint)
  102. }