kcl-lang.io/kpm@v0.8.7-0.20240520061008-9fc4c5efc8c7/pkg/mvs/mvs.go (about) 1 package mvs 2 3 import ( 4 "fmt" 5 6 "github.com/dominikbraun/graph" 7 "github.com/hashicorp/go-version" 8 "golang.org/x/mod/module" 9 "kcl-lang.io/kpm/pkg/3rdparty/mvs" 10 "kcl-lang.io/kpm/pkg/client" 11 errInt "kcl-lang.io/kpm/pkg/errors" 12 pkg "kcl-lang.io/kpm/pkg/package" 13 "kcl-lang.io/kpm/pkg/reporter" 14 "kcl-lang.io/kpm/pkg/semver" 15 ) 16 17 type ReqsGraph struct { 18 graph.Graph[module.Version, module.Version] 19 KpmClient *client.KpmClient 20 KpmPkg *pkg.KclPkg 21 } 22 23 func (r ReqsGraph) Max(path, v1, v2 string) string { 24 if v1 == "none" || v2 == "" { 25 return v2 26 } 27 if v2 == "none" || v1 == "" { 28 return v1 29 } 30 version1, err := version.NewVersion(v1) 31 if err != nil { 32 reporter.Fatal(reporter.FailedParseVersion, err, fmt.Sprintf("failed to parse version %s for module %s", v1, path)) 33 return "" 34 } 35 version2, err := version.NewVersion(v2) 36 if err != nil { 37 reporter.Fatal(reporter.FailedParseVersion, err, fmt.Sprintf("failed to parse version %s for module %s", v2, path)) 38 return "" 39 } 40 if version1.GreaterThan(version2) { 41 return v1 42 } 43 return v2 44 } 45 46 func (r ReqsGraph) Upgrade(m module.Version) (module.Version, error) { 47 _, properties, err := r.VertexWithProperties(m) 48 if err != nil { 49 return module.Version{}, err 50 } 51 52 // there must be only one property depending on the download source type 53 if len(properties.Attributes) != 1 { 54 return module.Version{}, errInt.MultipleSources 55 } 56 57 var releases []string 58 for sourceType, uri := range properties.Attributes { 59 releases, err = client.GetReleasesFromSource(sourceType, uri) 60 if err != nil { 61 return module.Version{}, err 62 } 63 } 64 65 if releases == nil { 66 return m, nil 67 } 68 69 m.Version, err = semver.LatestCompatibleVersion(releases, m.Version) 70 if err != nil { 71 return module.Version{}, err 72 } 73 _, err = r.Vertex(m) 74 if err == graph.ErrVertexNotFound { 75 d := pkg.Dependency{ 76 Name: m.Path, 77 Version: m.Version, 78 } 79 d.FullName = d.GenDepFullName() 80 for sourceType, uri := range properties.Attributes { 81 d.Source, err = pkg.GenSource(sourceType, uri, m.Version) 82 if err != nil { 83 return module.Version{}, err 84 } 85 } 86 deps := pkg.Dependencies{ 87 Deps: map[string]pkg.Dependency{ 88 m.Path: d, 89 }, 90 } 91 lockDeps := pkg.Dependencies{ 92 Deps: make(map[string]pkg.Dependency), 93 } 94 _, err = r.KpmClient.DownloadDeps(&deps, &lockDeps, r.Graph, r.KpmPkg.HomePath, module.Version{}) 95 if err != nil { 96 return module.Version{}, err 97 } 98 } 99 return m, nil 100 } 101 102 func (r ReqsGraph) Previous(m module.Version) (module.Version, error) { 103 _, properties, err := r.VertexWithProperties(m) 104 if err != nil { 105 return module.Version{}, err 106 } 107 108 // there must be only one property depending on the download source type 109 if len(properties.Attributes) != 1 { 110 return module.Version{}, errInt.MultipleSources 111 } 112 113 var releases []string 114 for sourceType, uri := range properties.Attributes { 115 releases, err = client.GetReleasesFromSource(sourceType, uri) 116 if err != nil { 117 return module.Version{}, err 118 } 119 } 120 121 if releases == nil { 122 return m, nil 123 } 124 125 // copy the version to compare it later 126 v := m.Version 127 128 m.Version, err = semver.LeastOldCompatibleVersion(releases, m.Version) 129 if err != nil && err != errInt.InvalidVersionFormat { 130 return module.Version{}, err 131 } 132 133 if v == m.Version { 134 return module.Version{Path: m.Path, Version: "none"}, nil 135 } 136 137 _, err = r.Vertex(m) 138 if err == graph.ErrVertexNotFound { 139 d := pkg.Dependency{ 140 Name: m.Path, 141 Version: m.Version, 142 } 143 d.FullName = d.GenDepFullName() 144 for sourceType, uri := range properties.Attributes { 145 d.Source, err = pkg.GenSource(sourceType, uri, m.Version) 146 if err != nil { 147 return module.Version{}, err 148 } 149 } 150 deps := pkg.Dependencies{ 151 Deps: map[string]pkg.Dependency{ 152 m.Path: d, 153 }, 154 } 155 lockDeps := pkg.Dependencies{ 156 Deps: make(map[string]pkg.Dependency), 157 } 158 _, err = r.KpmClient.DownloadDeps(&deps, &lockDeps, r.Graph, r.KpmPkg.HomePath, module.Version{}) 159 if err != nil { 160 return module.Version{}, err 161 } 162 } 163 return m, nil 164 } 165 166 func (r ReqsGraph) Required(m module.Version) ([]module.Version, error) { 167 adjMap, err := r.AdjacencyMap() 168 if err != nil { 169 return nil, err 170 } 171 var reqs []module.Version 172 for v := range adjMap[m] { 173 reqs = append(reqs, v) 174 } 175 return reqs, nil 176 } 177 178 // UpdateBuildList decides whether to upgrade or downgrade based on modulesToUpgrade and modulesToDowngrade. 179 // if modulesToUpgrade is empty, upgrade all dependencies. if modulesToUpgrade is not empty, upgrade the dependencies. 180 // if modulesToDowngrade is not empty, downgrade the dependencies. 181 // if modulesToUpgrade and modulesToDowngrade are both empty, first apply upgrade operation and 182 // then downgrade the build list returned from previous operation. 183 func UpdateBuildList(target module.Version, modulesToUpgrade []module.Version, modulesToDowngrade []module.Version, reqs *ReqsGraph) ([]module.Version, error) { 184 var ( 185 UpdBuildLists []module.Version 186 err error 187 ) 188 189 if len(modulesToUpgrade) == 0 { 190 UpdBuildLists, err = mvs.UpgradeAll(target, reqs) 191 } else { 192 UpdBuildLists, err = mvs.Upgrade(target, reqs, modulesToUpgrade...) 193 } 194 if err != nil { 195 return []module.Version{}, err 196 } 197 198 if len(modulesToDowngrade) != 0 { 199 UpdBuildLists, err = mvs.Downgrade(target, reqs, modulesToDowngrade...) 200 } 201 if err != nil { 202 return []module.Version{}, err 203 } 204 205 return UpdBuildLists, nil 206 }