github.com/bilus/oya@v0.0.3-0.20190301162104-da4acbd394c6/pkg/changeset/changeset.go (about) 1 package changeset 2 3 import ( 4 "bytes" 5 "fmt" 6 "path/filepath" 7 "strings" 8 9 "github.com/bilus/oya/pkg/oyafile" 10 "github.com/bilus/oya/pkg/task" 11 "github.com/bilus/oya/pkg/template" 12 log "github.com/sirupsen/logrus" 13 ) 14 15 // Calculate gets changeset from each Oyafile by invoking their Changeset: tasks 16 // and parsing the output. 17 func Calculate(candidates []*oyafile.Oyafile) ([]*oyafile.Oyafile, error) { 18 if len(candidates) == 0 { 19 return candidates, nil 20 } 21 22 var changeset []*oyafile.Oyafile 23 for _, candidate := range candidates { 24 oyafiles, err := calculateChangeset(candidate) 25 if err != nil { 26 return nil, err 27 } 28 changeset = append(changeset, oyafiles...) 29 } 30 31 return unique(changeset), nil 32 } 33 34 func execChangesetTask(workDir string, changesetTask task.Task) ([]string, error) { 35 stdout := bytes.NewBuffer(nil) 36 stderr := bytes.NewBuffer(nil) 37 38 err := changesetTask.Exec(workDir, template.Scope{}, stdout, stderr) 39 if err != nil { 40 return nil, err 41 } 42 // TODO: We shouldn't be ignoring stderr. 43 return parseChangeset(stdout.String()) 44 } 45 46 func calculateChangeset(currOyafile *oyafile.Oyafile) ([]*oyafile.Oyafile, error) { 47 changesetTask, ok := currOyafile.Tasks.LookupTask("Changeset") 48 if !ok { 49 return nil, nil 50 } 51 52 dirs, err := execChangesetTask(currOyafile.Dir, changesetTask) 53 if err != nil { 54 return nil, err 55 } 56 57 oyafiles := make([]*oyafile.Oyafile, 0, len(dirs)) 58 for _, dir := range dirs { 59 fullPath := filepath.Join(currOyafile.Dir, dir) 60 o, exists, err := oyafile.LoadFromDir(fullPath, currOyafile.RootDir) 61 if !exists { 62 // TODO: Warning that changeset contains paths without Oyafiles? 63 log.Printf("Path %v in changeset does not exist", fullPath) 64 continue 65 } 66 if err != nil { 67 return nil, err 68 } 69 oyafiles = append(oyafiles, o) 70 } 71 return oyafiles, nil 72 } 73 74 func parseChangeset(changeset string) ([]string, error) { 75 dirs := make([]string, 0) 76 77 // TODO: Ignores stderr for the time being. 78 changes := strings.Split(changeset, "\n") 79 for _, change := range changes { 80 if len(change) == 0 { 81 continue 82 } 83 if change[0] != '+' || len(change) < 2 { 84 log.Debugf(" Error: %v", change) 85 return nil, fmt.Errorf("Unexpected changeset entry %q expected \"+path\"", change) 86 } 87 path := change[1:] 88 log.Debugf(" Addition: %v", path) 89 // TODO: Check if path is valid. 90 dirs = append(dirs, path) 91 } 92 93 return dirs, nil 94 95 } 96 97 func normalizePath(oyafileDir, path string) string { 98 if filepath.IsAbs(path) { 99 return filepath.Clean(path) 100 } 101 return filepath.Clean(filepath.Join(oyafileDir, path)) 102 } 103 104 func unique(oyafiles []*oyafile.Oyafile) []*oyafile.Oyafile { 105 result := make([]*oyafile.Oyafile, 0, len(oyafiles)) 106 unique := make(map[string]struct{}) 107 for _, o := range oyafiles { 108 _, ok := unique[o.Dir] 109 if ok { 110 continue 111 } 112 unique[o.Dir] = struct{}{} 113 result = append(result, o) 114 } 115 116 return result 117 }