| 156 | } |
| 157 | |
| 158 | func (d *Devbox) mergeResolvedPackageToLockfile( |
| 159 | pkg *devpkg.Package, |
| 160 | resolved *lock.Package, |
| 161 | lockfile *lock.File, |
| 162 | ) error { |
| 163 | existing := lockfile.Packages[pkg.Raw] |
| 164 | if existing == nil { |
| 165 | ux.Finfof(d.stderr, "Resolved %s to %[1]s %[2]s\n", pkg, resolved.Resolved) |
| 166 | lockfile.Packages[pkg.Raw] = resolved |
| 167 | return nil |
| 168 | } |
| 169 | |
| 170 | // Flake refs have no Version, so the Version-based comparison below would |
| 171 | // always report "Already up-to-date" even when the locked rev changed. |
| 172 | // Handle them via their Resolved field (which embeds the locked rev) and |
| 173 | // LastModified. |
| 174 | if pkgtype.IsFlake(pkg.Raw) { |
| 175 | return d.mergeResolvedFlakeToLockfile(pkg, resolved, existing, lockfile) |
| 176 | } |
| 177 | |
| 178 | if existing.Version != resolved.Version { |
| 179 | if existing.LastModified > resolved.LastModified { |
| 180 | ux.Fwarningf( |
| 181 | d.stderr, |
| 182 | "Resolved version for %s has older last_modified time. Not updating\n", |
| 183 | pkg, |
| 184 | ) |
| 185 | return nil |
| 186 | } |
| 187 | ux.Finfof(d.stderr, "Updating %s %s -> %s\n", pkg, existing.Version, resolved.Version) |
| 188 | useResolvedPackageInLockfile(lockfile, pkg, resolved, existing) |
| 189 | return nil |
| 190 | } |
| 191 | |
| 192 | // Add any missing system infos for packages whose versions did not change. |
| 193 | if lockfile.Packages[pkg.Raw].Systems == nil { |
| 194 | lockfile.Packages[pkg.Raw].Systems = map[string]*lock.SystemInfo{} |
| 195 | } |
| 196 | |
| 197 | userSystem := nix.System() |
| 198 | updated := false |
| 199 | for sysName, newSysInfo := range resolved.Systems { |
| 200 | // Check whether we are actually updating any system info. |
| 201 | if sysName == userSystem { |
| 202 | // The resolved pkg has a system info for the user's system, so add/overwrite it. |
| 203 | if !newSysInfo.Equals(existing.Systems[userSystem]) { |
| 204 | // We only guard this so that the ux messaging is accurate. We could overwrite every time. |
| 205 | updated = true |
| 206 | } |
| 207 | } else { |
| 208 | // Add other system infos if they don't exist, or if we have a different StorePath. This may |
| 209 | // overwrite an existing StorePath, but to ensure correctness we should ensure that all StorePaths |
| 210 | // come from the same package version. |
| 211 | existingSysInfo, exists := existing.Systems[sysName] |
| 212 | if !exists || !existingSysInfo.Equals(newSysInfo) { |
| 213 | updated = true |
| 214 | } |
| 215 | } |