Showing list of package changes?

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.

1 Like

Oh I would also like dry-run so much! Apparently, it was present in Pkg some time ago, but then was removed…

1 Like

I realized I was overcomplicating things.

This code shows the right update.


function compute_diff(manifest, newpkgs::Vector{Pkg.Types.PackageSpec}; pkgnames = names)
  manifestpkgs = manifest.deps 
  for pkg in newpkgs
    newversion = pkg.version
    pkguuid = pkg.uuid
    if pkguuid in keys(manifestpkgs)
      #println("Package $(pkgnames[pkg.uuid]) is already installed")
      if newversion != manifestpkgs[pkguuid].version && Pkg.Types.is_stdlib(pkguuid) == false 
        #@show pkgnames[pkg], pkg, newversion, manifestpkgs[pkg].version
        if newversion > manifestpkgs[pkguuid].version
          @info "↑ $(pkgnames[pkguuid]): $(manifestpkgs[pkguuid].version) -> $newversion [latest: $(allpkgs[pkguuid]["latest_version"])]"  
        else
          @warn "↓ $(pkgnames[pkguuid]): $(manifestpkgs[pkguuid].version) -> $newversion [latest: $(allpkgs[pkguuid]["latest_version"])]"    
        end
      end
    else
      @info "+ $(pkgnames[pkguuid]): -> $newversion [latest: $(allpkgs[pkguuid]["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

  try 
    pkgs, deps_map = Pkg.Operations.tiered_resolve(env, registries, [pkg], julia_version, false)
    compute_diff(env.manifest, pkgs) # this will show the changes. 
    return pkgs, deps_map
  catch e
    println("Failed to resolve package: $(pkgnames[pkg.uuid]) to version $(pkg.version)")
    return e
  end
end 

In which case, I see:

Updating package: TaylorSeries: 0.13.2 -> 0.18.2
[ Info: ↑ TaylorSeries: 0.13.2 -> 0.18.2 [latest: 0.18.2]
┌ Warning: ↓ Polynomials: 4.0.12 -> 3.2.4 [latest: 4.0.12]
└ @ Main ~/Dropbox/dev/TechnicalComputeBundleCompile/test_adding_packages_2.jl:56
┌ Warning: ↓ GeoMakie: 0.7.9 -> 0.7.7 [latest: 0.7.9]
└ @ Main ~/Dropbox/dev/TechnicalComputeBundleCompile/test_adding_packages_2.jl:56
┌ Warning: ↓ GeometryOps: 0.1.13 -> 0.1.5 [latest: 0.1.13]
└ @ Main ~/Dropbox/dev/TechnicalComputeBundleCompile/test_adding_packages_2.jl:56
[ Info: + SetRounding: -> 0.2.1 [latest: 0.2.1]
┌ Warning: ↓ IntervalArithmetic: 0.22.19 -> 0.20.9 [latest: 0.22.19]
└ @ Main ~/Dropbox/dev/TechnicalComputeBundleCompile/test_adding_packages_2.jl:56
┌ Warning: ↓ ChaosTools: 3.3.0 -> 3.2.1 [latest: 3.3.0]
└ @ Main ~/Dropbox/dev/TechnicalComputeBundleCompile/test_adding_packages_2.jl:56
[ Info: + FastRounding: -> 0.3.1 [latest: 0.3.1]
┌ Warning: ↓ ExactPredicates: 2.2.8 -> 2.2.5 [latest: 2.2.8]
└ @ Main ~/Dropbox/dev/TechnicalComputeBundleCompile/test_adding_packages_2.jl:56
┌ Warning: ↓ IntervalRootFinding: 0.6.0 -> 0.5.11 [latest: 0.6.0]
└ @ Main ~/Dropbox/dev/TechnicalComputeBundleCompile/test_adding_packages_2.jl:56
[ Info: + CRlibm: -> 1.0.1 [latest: 1.0.1]
[ Info: + ErrorfreeArithmetic: -> 0.5.2 [latest: 0.5.2]