github.com/tooploox/oya@v0.0.21-0.20230524103240-1cda1861aad6/pkg/project/changeset.go (about) 1 package project 2 3 import ( 4 "fmt" 5 "io" 6 "path/filepath" 7 "strings" 8 9 "github.com/tooploox/oya/pkg/changeset" 10 "github.com/tooploox/oya/pkg/oyafile" 11 "github.com/tooploox/oya/pkg/task" 12 ) 13 14 // Changeset returns the list of Oyafiles for the changed directories, based on the 15 // Changeset: directives. 16 // 17 // The algorithm: 18 // 19 // - Add default Changeset task to root Oyafile if there isn’t one 20 // - For each project Oyafile: 21 // - If Changeset task defined: 22 // - Contribute to changeset 23 // - Deduplicate changeset 24 // - Exclude changes outside work directory 25 func (p *Project) Changeset(workDir string) ([]*oyafile.Oyafile, error) { 26 oyafiles, err := p.Oyafiles() 27 if err != nil { 28 return nil, err 29 } 30 if len(oyafiles) == 0 { 31 return nil, ErrNoOyafiles{Path: workDir} 32 } 33 34 rootOyafile := oyafiles[0] 35 36 if rel, err := filepath.Rel(rootOyafile.Dir, p.RootDir); err != nil || rel != "." { 37 panic("Internal error: expecting root Oyafile to be the first item in array returned from project.Project#Oyafiles method") 38 } 39 40 _, ok := rootOyafile.Tasks.LookupTask("Changeset") 41 if !ok { 42 rootOyafile.Tasks.AddTask("Changeset", defaultRootChangesetTask(oyafiles)) 43 } 44 45 // return changeset.Calculate(p.Root, oyafiles) 46 changeset, err := changeset.Calculate(oyafiles) 47 if err != nil { 48 return nil, err 49 } 50 return restrictToDir(workDir, changeset) 51 } 52 53 func restrictToDir(dir string, changeset []*oyafile.Oyafile) ([]*oyafile.Oyafile, error) { 54 restricted := make([]*oyafile.Oyafile, 0, len(changeset)) 55 for _, o := range changeset { 56 if isInside(dir, o) { 57 restricted = append(restricted, o) 58 } 59 } 60 return restricted, nil 61 } 62 63 func isInside(dir string, o *oyafile.Oyafile) bool { 64 d := filepath.Clean(dir) 65 r, err := filepath.Rel(d, o.Dir) 66 return err == nil && !strings.Contains(r, "..") 67 } 68 69 func defaultRootChangesetTask(oyafiles []*oyafile.Oyafile) task.Task { 70 return task.Builtin{ 71 OnExec: func(stdout, stderr io.Writer) error { 72 for _, o := range oyafiles { 73 relPath := filepath.Dir(o.RelPath()) 74 _, err := stdout.Write([]byte(fmt.Sprintf("+%v\n", relPath))) 75 if err != nil { 76 return err 77 } 78 } 79 80 return nil 81 }, 82 } 83 }