Is there any way to get the list of package changes in response to changing to a new version that would occur without actually changing them? (i.e. a “dry-run” option?)
For instance, if I have a large project and do:
(@TCB) pkg> add TaylorSeries@0.18.2
Resolving package versions...
Installed Glib_jll ────────────────── v2.82.2+1
Installed TimerOutputs ────────────── v0.5.26
Installed SymbolicIndexingInterface ─ v0.3.36
Installed BlockArrays ─────────────── v1.3.0
Installed BandedMatrices ──────────── v1.8.0
Installed ITensorNetworks ─────────── v0.11.24
Updating `~/.julia/environments/TCB/Project.toml`
⌃ [db073c08] ↓ GeoMakie v0.7.9 ⇒ v0.7.7
⌃ [3251bfac] ↓ GeometryOps v0.1.13 ⇒ v0.1.5
[2919e153] ↑ ITensorNetworks v0.11.23 ⇒ v0.11.24
⌅ [f27b6e38] ↓ Polynomials v4.0.12 ⇒ v3.2.4
[6aa5eb33] ↑ TaylorSeries v0.13.2 ⇒ v0.18.2
Updating `~/.julia/environments/TCB/Manifest.toml`
[aae01518] ↑ BandedMatrices v1.7.6 ⇒ v1.8.0
[8e7c35d0] ↑ BlockArrays v1.2.0 ⇒ v1.3.0
[d3bc4f2e] - BranchAndPrune v0.2.1
[96374032] + CRlibm v1.0.1
⌃ [608a59af] ↓ ChaosTools v3.3.0 ⇒ v3.2.1
[90fa49ef] + ErrorfreeArithmetic v0.5.2
⌃ [429591f6] ↓ ExactPredicates v2.2.8 ⇒ v2.2.5
[fa42c844] + FastRounding v0.3.1
⌃ [db073c08] ↓ GeoMakie v0.7.9 ⇒ v0.7.7
⌃ [3251bfac] ↓ GeometryOps v0.1.13 ⇒ v0.1.5
[2919e153] ↑ ITensorNetworks v0.11.23 ⇒ v0.11.24
⌅ [d1acc4aa] ↓ IntervalArithmetic v0.22.19 ⇒ v0.20.9
⌅ [d2bf35a9] ↓ IntervalRootFinding v0.6.0 ⇒ v0.5.11
⌅ [f27b6e38] ↓ Polynomials v4.0.12 ⇒ v3.2.4
[3cc68bcd] + SetRounding v0.2.1
[2efcf032] ↑ SymbolicIndexingInterface v0.3.35 ⇒ v0.3.36
[6aa5eb33] ↑ TaylorSeries v0.13.2 ⇒ v0.18.2
[a759f4b9] ↑ TimerOutputs v0.5.25 ⇒ v0.5.26
[7746bdde] ↑ Glib_jll v2.82.2+0 ⇒ v2.82.2+1
But in fact, I’d rather not do that I as want to keep Polynomials.jl
as the latest version. So I’d really love a way to see this without actually doing it.
By piecing together code from Pkg.jl, I thought something like this would report the changes.
using Pkg, TOML, UUIDs
Pkg.activate("TCB", shared=true) # this is my large package...
function _find_package_versions(pkgdir)
versions = TOML.parsefile(joinpath(pkgdir,"Versions.toml"))
return [parse(VersionNumber, v) for v in keys(versions)]
end
function _find_latest_package_version(pkgdir)
versions = _find_package_versions(pkgdir)
return maximum(versions)
end
function _get_all_packages(registry_path = joinpath(homedir(),".julia","registries","General"))
packages_dict = TOML.parsefile(joinpath(registry_path,"Registry.toml"))["packages"]
packages_dict = Dict( UUID(key) => value for (key, value) in packages_dict)
# find the latest version of each package
for pkg in keys(packages_dict)
packages_dict[pkg]["versions"] = _find_package_versions(joinpath(registry_path, packages_dict[pkg]["path"]))
packages_dict[pkg]["latest_version"] = maximum(packages_dict[pkg]["versions"])
end
names = Dict{UUID, String}(uuid => name for (uuid, (name, version)) in Pkg.Types.stdlibs())
for (uuid, info) in packages_dict
names[UUID(uuid)] = info["name"]
end
return packages_dict, names
end
allpkgs, names = _get_all_packages()
## The goal is see what happens if we try and resolve with the latest version of each package
function pkgspec(pkgname; version=nothing, allpkgs=allpkgs)
pkguuid = findfirst(x->x["name"] == pkgname, pairs(allpkgs))
@assert( pkguuid !== nothing )
pkg = allpkgs[pkguuid]
if version === nothing
version = pkg["latest_version"]
end
pkgs = PackageSpec(pkg["name"], UUID(pkguuid), version)
return pkgs
end
function compute_diff(manifest, vers; pkgnames = names)
manifestpkgs = manifest.deps
for (pkg, newversion) in vers
if pkg in keys(manifestpkgs)
#println("Package $(pkgnames[pkg.uuid]) is already installed")
if newversion != manifestpkgs[pkg].version && Pkg.Types.is_stdlib(pkg) == false
#@show pkgnames[pkg], pkg, newversion, manifestpkgs[pkg].version
if newversion > manifestpkgs[pkg].version
@info "↑ $(pkgnames[pkg]): $(manifestpkgs[pkg].version) -> $newversion [latest: $(allpkgs[pkg]["latest_version"])]"
else
@warn "↓ $(pkgnames[pkg]): $(manifestpkgs[pkg].version) -> $newversion [latest: $(allpkgs[pkg]["latest_version"])]"
end
end
else
@info "+ $(pkgnames[pkg]): -> $newversion [latest: $(allpkgs[pkg]["latest_version"])]"
end
end
end
function test_resolve(pkg::PackageSpec, pkgnames = names)
ctx = Pkg.Types.Context()
env = ctx.env
registries = ctx.registries
julia_version = ctx.julia_version
fixed = Dict{UUID,Pkg.Resolve.Fixed}()
installed_only = false
pkgs = [pkg]
round = 1
oldvers = Dict{UUID,VersionNumber}()
while true
reqs = Pkg.Resolve.Requires(pkg.uuid => Pkg.Types.VersionSpec(pkg.version) for pkg in pkgs)
graph, compat_map = Pkg.Operations.deps_graph(env, registries, pkgnames, reqs, fixed, julia_version, installed_only)
Pkg.Resolve.simplify_graph!(graph)
vers = Pkg.Resolve.resolve(graph)
#println("After round $round: length(vers) = $(length(vers))")
# push these new packages onto the reqs...
for pkguuid in keys(vers)
pkgname = pkgnames[pkguuid]
pkgversion = vers[pkguuid]
push!(pkgs, PackageSpec(pkgname, pkguuid, pkgversion))
end
if length(vers) == length(oldvers)
compute_diff(ctx.env.manifest, vers)
break
end
oldvers = vers
round += 1
end
end
test_resolve(pkgspec("TaylorSeries"; version=v"0.18.2"))
That just shows:
Updating package: TaylorSeries: 0.13.2 -> 0.18.2
[ Info: ↑ TaylorSeries: 0.13.2 -> 0.18.2 [latest: 0.18.2]
(these were done in the same original environment… so I was hoping to see the same changes.)
So I’m clearly missing something important in how the resolution in Pkg.jl actually works. Any hints / suggestions would be greatly appreciated. (The algorithm always ends after round == 2, that was another test to see if there was something iterative I was missing…)
Note that my code to report package changes does sometimes show packages being downgraded, so I hope there isn’t some embarrassing typo in that code that I overlooked.