github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/gnovm/pkg/gnomod/preprocess.go (about) 1 package gnomod 2 3 import ( 4 "golang.org/x/mod/modfile" 5 "golang.org/x/mod/module" 6 "golang.org/x/mod/semver" 7 ) 8 9 func removeDups(syntax *modfile.FileSyntax, require *[]*modfile.Require, replace *[]*modfile.Replace) { 10 if require != nil { 11 purged := removeRequireDups(require) 12 cleanSyntaxTree(syntax, purged) 13 } 14 if replace != nil { 15 purged := removeReplaceDups(replace) 16 cleanSyntaxTree(syntax, purged) 17 } 18 } 19 20 // removeRequireDups removes duplicate requirements. 21 // Requirements with higher version takes priority. 22 func removeRequireDups(require *[]*modfile.Require) map[*modfile.Line]bool { 23 purge := make(map[*modfile.Line]bool) 24 25 keepRequire := make(map[string]string) 26 for _, r := range *require { 27 if v, ok := keepRequire[r.Mod.Path]; ok { 28 if semver.Compare(r.Mod.Version, v) == 1 { 29 keepRequire[r.Mod.Path] = r.Mod.Version 30 } 31 continue 32 } 33 keepRequire[r.Mod.Path] = r.Mod.Version 34 } 35 var req []*modfile.Require 36 added := make(map[string]bool) 37 for _, r := range *require { 38 if v, ok := keepRequire[r.Mod.Path]; ok && !added[r.Mod.Path] && v == r.Mod.Version { 39 req = append(req, r) 40 added[r.Mod.Path] = true 41 continue 42 } 43 purge[r.Syntax] = true 44 } 45 *require = req 46 47 return purge 48 } 49 50 // removeReplaceDups removes duplicate replacements. 51 // Later replacements take priority over earlier ones. 52 func removeReplaceDups(replace *[]*modfile.Replace) map[*modfile.Line]bool { 53 purge := make(map[*modfile.Line]bool) 54 55 haveReplace := make(map[module.Version]bool) 56 for i := len(*replace) - 1; i >= 0; i-- { 57 x := (*replace)[i] 58 if haveReplace[x.Old] { // duplicate detected 59 purge[x.Syntax] = true 60 continue 61 } 62 haveReplace[x.Old] = true 63 } 64 var repl []*modfile.Replace 65 for _, r := range *replace { 66 if !purge[r.Syntax] { 67 repl = append(repl, r) 68 } 69 } 70 *replace = repl 71 72 return purge 73 } 74 75 // cleanSyntaxTree removes purged statements from the syntax tree. 76 func cleanSyntaxTree(syntax *modfile.FileSyntax, purge map[*modfile.Line]bool) { 77 stmts := make([]modfile.Expr, 0, len(syntax.Stmt)) 78 for _, stmt := range syntax.Stmt { 79 switch stmt := stmt.(type) { 80 case *modfile.Line: 81 if purge[stmt] { 82 continue 83 } 84 case *modfile.LineBlock: 85 var lines []*modfile.Line 86 for _, line := range stmt.Line { 87 if !purge[line] { 88 lines = append(lines, line) 89 } 90 } 91 stmt.Line = lines 92 if len(lines) == 0 { 93 continue 94 } 95 } 96 stmts = append(stmts, stmt) 97 } 98 syntax.Stmt = stmts 99 }