github.com/bilus/oya@v0.0.3-0.20190301162104-da4acbd394c6/pkg/oyafile/oyafile.go (about) 1 package oyafile 2 3 import ( 4 "io" 5 "os" 6 "path" 7 "path/filepath" 8 "strings" 9 10 log "github.com/sirupsen/logrus" 11 12 "github.com/bilus/oya/pkg/raw" 13 "github.com/bilus/oya/pkg/semver" 14 "github.com/bilus/oya/pkg/task" 15 "github.com/bilus/oya/pkg/template" 16 "github.com/bilus/oya/pkg/types" 17 "github.com/pkg/errors" 18 ) 19 20 // OyaCmdOverride is used in tests, to override the path to the current oya executable. 21 // It is used to invoke other tasks from a task body. 22 // When tests are run, the current process executable path points to the test runner 23 // so it has to be overridden (with 'go run oya.go', roughly speaking). 24 var OyaCmdOverride *string 25 26 type PackReference struct { 27 ImportPath types.ImportPath 28 Version semver.Version 29 // ReplacementPath is a path relative to the root directory, when the replacement for the pack can be found, based on the Replace: directive. 30 ReplacementPath string 31 } 32 33 type PackReplacements map[types.ImportPath]string 34 35 type Oyafile struct { 36 Dir string 37 Path string 38 RootDir string 39 Shell string 40 Imports map[types.Alias]types.ImportPath 41 Tasks task.Table 42 Values template.Scope 43 Project string // Project is set for root Oyafile. 44 Ignore []string // Ignore contains directory exclusion rules. 45 Requires []PackReference 46 // Replacements map packs to local paths relative to project root directory for development based on the Replace: directive. 47 Replacements PackReplacements 48 IsBuilt bool 49 50 relPath string 51 52 OyaCmd string // OyaCmd contains the path to the current oya executable. 53 } 54 55 func New(oyafilePath string, rootDir string) (*Oyafile, error) { 56 var oyaCmd string 57 if OyaCmdOverride != nil { 58 oyaCmd = *OyaCmdOverride 59 } else { 60 var err error 61 oyaCmd, err = os.Executable() 62 if err != nil { 63 return nil, err 64 } 65 } 66 67 relPath, err := filepath.Rel(rootDir, oyafilePath) 68 log.Debug("Oyafile at ", oyafilePath) 69 if err != nil { 70 return nil, err 71 } 72 dir := path.Dir(oyafilePath) 73 return &Oyafile{ 74 Dir: filepath.Clean(dir), 75 Path: filepath.Clean(oyafilePath), 76 RootDir: filepath.Clean(rootDir), 77 Shell: "/bin/bash", 78 Imports: make(map[types.Alias]types.ImportPath), 79 Tasks: task.NewTable(), 80 Values: template.Scope{}, 81 relPath: relPath, 82 Replacements: make(PackReplacements), 83 OyaCmd: oyaCmd, 84 }, nil 85 } 86 87 func Load(oyafilePath, rootDir string) (*Oyafile, bool, error) { 88 raw, found, err := raw.Load(oyafilePath, rootDir) 89 if err != nil || !found { 90 return nil, found, err 91 } 92 oyafile, err := Parse(raw) 93 if err != nil { 94 return nil, false, wrapLoadErr(err, oyafilePath) 95 } 96 return oyafile, true, nil 97 } 98 99 func LoadFromDir(dirPath, rootDir string) (*Oyafile, bool, error) { 100 raw, found, err := raw.LoadFromDir(dirPath, rootDir) 101 if err != nil || !found { 102 return nil, found, err 103 } 104 oyafile, err := Parse(raw) 105 if err != nil { 106 return nil, false, wrapLoadErr(err, raw.Path) 107 } 108 return oyafile, true, nil 109 } 110 111 func (oyafile Oyafile) RunTask(taskName task.Name, scope template.Scope, stdout, stderr io.Writer) (bool, error) { 112 if !oyafile.IsBuilt { 113 return false, errors.Errorf("Internal error: Oyafile has not been built") 114 } 115 task, ok := oyafile.Tasks.LookupTask(taskName) 116 if !ok { 117 return false, nil 118 } 119 tasks, err := oyafile.bindTasks(taskName, task, stdout, stderr) 120 if err != nil { 121 return true, err 122 } 123 scope["Tasks"] = tasks 124 125 render, err := oyafile.bindRender(taskName, stdout, stderr) 126 if err != nil { 127 return true, err 128 } 129 scope["Render"] = render 130 131 return true, task.Exec(oyafile.Dir, scope, stdout, stderr) 132 } 133 134 func (oyafile Oyafile) Equals(other Oyafile) bool { 135 // TODO: Far from perfect, we should ensure relative vs absolute paths work. 136 // The simplest thing is probably to ensure oyafile.Dir is always absolute. 137 return filepath.Clean(oyafile.Dir) == filepath.Clean(other.Dir) 138 } 139 140 func wrapLoadErr(err error, oyafilePath string) error { 141 return errors.Wrapf(err, "error loading Oyafile %v", oyafilePath) 142 } 143 144 func (o *Oyafile) Ignores() string { 145 return strings.Join(o.Ignore, "\n") 146 } 147 148 func (o *Oyafile) RelPath() string { 149 return o.relPath 150 }