github.com/tooploox/oya@v0.0.21-0.20230524103240-1cda1861aad6/pkg/raw/requires.go (about) 1 package raw 2 3 import ( 4 "fmt" 5 "regexp" 6 "strings" 7 8 "github.com/tooploox/oya/pkg/semver" 9 "github.com/tooploox/oya/pkg/types" 10 ) 11 12 type Pack interface { 13 ImportPath() types.ImportPath 14 Version() semver.Version 15 } 16 17 type ErrNotRootOyafile struct { 18 Path string 19 } 20 21 func (e ErrNotRootOyafile) Error() string { 22 return fmt.Sprintf("missing Project: directive in %v; not root Oyafile?", e.Path) 23 } 24 25 var requireKeyRegxp = regexp.MustCompile("^Require:") 26 var requireEntryRegexp = regexp.MustCompile("^(\\s*)([^:]+)\\:\\s*([^ #]+)") 27 var topLevelKeyRegexp = regexp.MustCompile("^[\\s]+:") 28 29 var defaultIndent = 2 30 31 // AddRequire adds a Require: entry for the pack. 32 func (raw *Oyafile) AddRequire(pack Pack) error { 33 if err := raw.addRequire(pack); err != nil { 34 return err 35 } 36 return raw.write() 37 } 38 39 // addRequire adds a Require: entry for a pack using the following algorithm: 40 // 1. Look for and update an existing entry for the path. 41 // 2. Look for ANY pack under Require:; if found, insert the new entry beneath it. 42 // 3. Look for Require: key (we know it's empty), insert the new entry inside it. 43 // 4. Look for Project: key, insert the new entry beneath it (under Require:). 44 // 5. Fail because Oyafile has no Project: so we shouldn't be trying to add a require to it. 45 // The method stops if any of the steps succeeds. 46 // NOTE: It does not modify the Oyafile on disk. 47 func (raw *Oyafile) addRequire(pack Pack) error { 48 if found, err := raw.updateExistingEntry(pack); err != nil || found { 49 return err // nil if found 50 } 51 if found, err := raw.insertBeforeExistingEntry(pack); err != nil || found { 52 return err // nil if found 53 } 54 if found, err := raw.insertAfter(requireKeyRegxp, formatRequire(defaultIndent, pack)); err != nil || found { 55 return err // nil if found 56 } 57 58 found, err := raw.insertAfter(projectRegexp, "Require:", formatRequire(defaultIndent, pack)) 59 if err != nil { 60 return err 61 } 62 63 if !found { 64 return ErrNotRootOyafile{Path: raw.Path} 65 } 66 return nil 67 } 68 69 func (raw *Oyafile) updateExistingEntry(pack Pack) (bool, error) { 70 return raw.replaceAllWhen( 71 func(line string) bool { 72 if matches := requireEntryRegexp.FindStringSubmatch(line); len(matches) == 4 { 73 return types.ImportPath(matches[2]) == pack.ImportPath() 74 } 75 return false 76 77 }, []string{formatRequire(0, pack)}...) 78 } 79 80 func (raw *Oyafile) insertBeforeExistingEntry(pack Pack) (bool, error) { 81 return raw.insertBeforeWithin("Require", requireEntryRegexp, formatRequire(0, pack)) 82 } 83 84 func formatRequire(indent int, pack Pack) string { 85 return fmt.Sprintf("%v%v: %v", 86 strings.Repeat(" ", indent), 87 pack.ImportPath(), 88 pack.Version()) 89 }