github.com/bilus/oya@v0.0.3-0.20190301162104-da4acbd394c6/pkg/project/project.go (about) 1 package project 2 3 import ( 4 "io" 5 "path/filepath" 6 7 "github.com/bilus/oya/pkg/oyafile" 8 "github.com/bilus/oya/pkg/raw" 9 "github.com/bilus/oya/pkg/task" 10 "github.com/bilus/oya/pkg/template" 11 "github.com/pkg/errors" 12 log "github.com/sirupsen/logrus" 13 ) 14 15 // TODO: Duplicated in oyafile module. 16 type Project struct { 17 RootDir string 18 installDir string 19 dependencies Deps 20 } 21 22 func Detect(workDir, installDir string) (*Project, error) { 23 detectedRootDir, found, err := detectRoot(workDir) 24 if err != nil { 25 return nil, err 26 } 27 if !found { 28 return nil, ErrNoProject{Path: workDir} 29 } 30 return &Project{ 31 RootDir: detectedRootDir, 32 installDir: installDir, 33 dependencies: nil, // lazily-loaded in Deps() 34 }, nil 35 } 36 37 func (p *Project) Run(workDir string, taskName task.Name, recurse, useChangeset bool, scope template.Scope, stdout, stderr io.Writer) error { 38 log.Debugf("Task %q at %v", taskName, workDir) 39 40 targets, err := p.RunTargets(workDir, recurse, useChangeset) 41 if err != nil { 42 return err 43 } 44 45 if len(targets) == 0 { 46 return nil 47 } 48 49 dependencies, err := p.Deps() 50 if err != nil { 51 return err 52 } 53 54 foundAtLeastOneTask := false 55 for _, o := range targets { 56 err = o.Build(dependencies) 57 if err != nil { 58 return errors.Wrapf(err, "error in %v", o.Path) 59 } 60 found, err := o.RunTask(taskName, scope, stdout, stderr) 61 if err != nil { 62 return errors.Wrapf(err, "error in %v", o.Path) 63 } 64 if found { 65 foundAtLeastOneTask = found 66 } 67 } 68 if !foundAtLeastOneTask { 69 return ErrNoTask{ 70 Task: taskName, 71 } 72 } 73 return nil 74 } 75 76 func (p *Project) RunTargets(workDir string, recurse, useChangeset bool) ([]*oyafile.Oyafile, error) { 77 if useChangeset { 78 changes, err := p.Changeset(workDir) 79 if err != nil { 80 return nil, err 81 } 82 83 if len(changes) == 0 { 84 return nil, nil 85 } 86 87 if !recurse { 88 return p.oneTargetIn(workDir) 89 } else { 90 return changes, nil 91 } 92 } else { 93 if !recurse { 94 return p.oneTargetIn(workDir) 95 } else { 96 return p.List(workDir) 97 } 98 } 99 } 100 101 func (p *Project) oneTargetIn(dir string) ([]*oyafile.Oyafile, error) { 102 o, err := p.oyafileIn(dir) 103 if err != nil { 104 return nil, err 105 } 106 return []*oyafile.Oyafile{o}, nil 107 } 108 109 func (p *Project) oyafileIn(dir string) (*oyafile.Oyafile, error) { 110 o, found, err := oyafile.LoadFromDir(dir, p.RootDir) 111 if err != nil { 112 return nil, err 113 } 114 if !found { 115 return nil, ErrNoOyafile{Path: dir} 116 } 117 return o, nil 118 } 119 120 func (p *Project) rawOyafileIn(dir string) (*raw.Oyafile, error) { 121 o, found, err := raw.LoadFromDir(dir, p.RootDir) 122 if err != nil { 123 return nil, err 124 } 125 if !found { 126 return nil, ErrNoOyafile{Path: dir} 127 } 128 129 return o, nil 130 } 131 132 func (p *Project) Oyafile(oyafilePath string) (*oyafile.Oyafile, bool, error) { 133 return oyafile.Load(oyafilePath, p.RootDir) 134 } 135 136 func (p *Project) Values() (template.Scope, error) { 137 oyafilePath := filepath.Join(p.RootDir, "Oyafile") 138 o, found, err := p.Oyafile(oyafilePath) 139 if err != nil { 140 return template.Scope{}, err 141 } 142 if !found { 143 return template.Scope{}, ErrNoOyafile{Path: oyafilePath} 144 } 145 return template.Scope{ 146 "Project": o.Project, 147 }, nil 148 } 149 150 // detectRoot attempts to detect the root project directory marked by 151 // root Oyafile, i.e. one containing Project: directive. 152 // It walks the directory tree, starting from startDir, going upwards, 153 // looking for root. 154 func detectRoot(startDir string) (string, bool, error) { 155 path := startDir 156 maxParts := 256 157 for i := 0; i < maxParts; i++ { 158 raw, found, err := raw.LoadFromDir(path, path) // "Guess" path is the root dir. 159 if err == nil && found { 160 isRoot, err := raw.IsRoot() 161 if err != nil { 162 return "", false, err 163 } 164 if isRoot { 165 return path, true, nil 166 } 167 } 168 169 if path == "/" { 170 break 171 } 172 path = filepath.Dir(path) 173 } 174 175 return "", false, nil 176 }