@@ -1052,7 +1052,7 @@ function rm(ctx::Context, pkgs::Vector{PackageSpec}; mode::PackageMode)
10521052 prune_manifest (ctx. env)
10531053 # update project & manifest
10541054 write_env (ctx. env)
1055- show_update (ctx. env; io= ctx. io)
1055+ show_update (ctx. env, ctx . registries ; io= ctx. io)
10561056end
10571057
10581058update_package_add (ctx:: Context , pkg:: PackageSpec , :: Nothing , is_dep:: Bool ) = pkg
@@ -1196,7 +1196,7 @@ function add(ctx::Context, pkgs::Vector{PackageSpec}, new_git=Set{UUID}();
11961196 download_artifacts (ctx. env, platform= platform, julia_version= ctx. julia_version, io= ctx. io)
11971197
11981198 write_env (ctx. env) # write env before building
1199- show_update (ctx. env; io= ctx. io)
1199+ show_update (ctx. env, ctx . registries ; io= ctx. io)
12001200 build_versions (ctx, union (new_apply, new_git))
12011201end
12021202
@@ -1214,7 +1214,7 @@ function develop(ctx::Context, pkgs::Vector{PackageSpec}, new_git::Set{UUID};
12141214 new_apply = download_source (ctx)
12151215 download_artifacts (ctx. env; platform= platform, julia_version= ctx. julia_version, io= ctx. io)
12161216 write_env (ctx. env) # write env before building
1217- show_update (ctx. env; io= ctx. io)
1217+ show_update (ctx. env, ctx . registries ; io= ctx. io)
12181218 build_versions (ctx, union (new_apply, new_git))
12191219end
12201220
@@ -1280,7 +1280,7 @@ function up(ctx::Context, pkgs::Vector{PackageSpec}, level::UpgradeLevel;
12801280 new_apply = download_source (ctx)
12811281 download_artifacts (ctx. env, julia_version= ctx. julia_version, io= ctx. io)
12821282 write_env (ctx. env; skip_writing_project) # write env before building
1283- show_update (ctx. env; io= ctx. io)
1283+ show_update (ctx. env, ctx . registries ; io= ctx. io)
12841284 build_versions (ctx, union (new_apply, new_git))
12851285end
12861286
@@ -1322,7 +1322,7 @@ function pin(ctx::Context, pkgs::Vector{PackageSpec})
13221322 new = download_source (ctx)
13231323 download_artifacts (ctx. env; julia_version= ctx. julia_version, io= ctx. io)
13241324 write_env (ctx. env) # write env before building
1325- show_update (ctx. env; io= ctx. io)
1325+ show_update (ctx. env, ctx . registries ; io= ctx. io)
13261326 build_versions (ctx, new)
13271327end
13281328
@@ -1360,12 +1360,12 @@ function free(ctx::Context, pkgs::Vector{PackageSpec})
13601360 new = download_source (ctx)
13611361 download_artifacts (ctx. env, io= ctx. io)
13621362 write_env (ctx. env) # write env before building
1363- show_update (ctx. env; io= ctx. io)
1363+ show_update (ctx. env, ctx . registries ; io= ctx. io)
13641364 build_versions (ctx, new)
13651365 else
13661366 foreach (pkg -> manifest_info (ctx. env. manifest, pkg. uuid). pinned = false , pkgs)
13671367 write_env (ctx. env)
1368- show_update (ctx. env; io= ctx. io)
1368+ show_update (ctx. env, ctx . registries ; io= ctx. io)
13691369 end
13701370end
13711371
@@ -1636,7 +1636,7 @@ function test(ctx::Context, pkgs::Vector{PackageSpec};
16361636 sandbox (ctx, pkg, source_path, testdir (source_path), test_project_override; force_latest_compatible_version, allow_earlier_backwards_compatible_versions, allow_reresolve) do
16371637 test_fn != = nothing && test_fn ()
16381638 sandbox_ctx = Context (;io= ctx. io)
1639- status (sandbox_ctx. env; mode= PKGMODE_COMBINED, io= sandbox_ctx. io)
1639+ status (sandbox_ctx. env, sandbox_ctx . registries ; mode= PKGMODE_COMBINED, io= sandbox_ctx. io)
16401640 Pkg. _auto_precompile (sandbox_ctx)
16411641 printpkgstyle (ctx. io, :Testing , " Running tests..." )
16421642 flush (stdout )
@@ -1731,6 +1731,79 @@ function print_diff(io::IO, old::Union{Nothing,PackageSpec}, new::Union{Nothing,
17311731 end
17321732end
17331733
1734+ function status_compat_info (pkg:: PackageSpec , env:: EnvCache , regs:: Vector{Registry.RegistryInstance} )
1735+ manifest, project = env. manifest, env. project
1736+ packages_holding_back = String[]
1737+ max_version, max_version_in_compat = v " 0" , v " 0"
1738+ for reg in regs
1739+ reg_pkg = get (reg, pkg. uuid, nothing )
1740+ reg_pkg === nothing && continue
1741+ info = Registry. registry_info (reg_pkg)
1742+ reg_compat_info = Registry. compat_info (info)
1743+ max_version_reg = maximum (keys (reg_compat_info); init= v " 0" )
1744+ max_version = max (max_version, max_version_reg)
1745+ compat_spec = get_compat (env. project, pkg. name)
1746+ versions_in_compat = filter (in (compat_spec), keys (reg_compat_info))
1747+ max_version_in_compat = max (max_version_in_compat, maximum (versions_in_compat; init= v " 0" ))
1748+ end
1749+ max_version == v " 0" && return nothing
1750+ pkg. version == max_version && return nothing
1751+
1752+ # Check compat of project
1753+ if pkg. version == max_version_in_compat && max_version_in_compat != max_version
1754+ return [" compat" ], max_version, max_version_in_compat
1755+ end
1756+
1757+ manifest_info = get (manifest, pkg. uuid, nothing )
1758+ manifest_info === nothing && return nothing
1759+
1760+ # Check compat of dependees
1761+ for (uuid, dep_pkg) in manifest
1762+ is_stdlib (uuid) && continue
1763+ if ! (pkg. uuid in values (dep_pkg. deps))
1764+ continue
1765+ end
1766+ dep_info = get (manifest, uuid, nothing )
1767+ dep_info === nothing && continue
1768+ for reg in regs
1769+ reg_pkg = get (reg, uuid, nothing )
1770+ reg_pkg === nothing && continue
1771+ info = Registry. registry_info (reg_pkg)
1772+ reg_compat_info = Registry. compat_info (info)
1773+ compat_info_v = get (reg_compat_info, dep_info. version, nothing )
1774+ compat_info_v === nothing && continue
1775+ compat_info_v_uuid = compat_info_v[pkg. uuid]
1776+ if ! (max_version in compat_info_v_uuid)
1777+ push! (packages_holding_back, dep_pkg. name)
1778+ end
1779+ end
1780+ end
1781+
1782+ # Check compat with Julia itself
1783+ julia_compatible_versions = Set {VersionNumber} ()
1784+ for reg in regs
1785+ reg_pkg = get (reg, pkg. uuid, nothing )
1786+ reg_pkg === nothing && continue
1787+ info = Registry. registry_info (reg_pkg)
1788+ reg_compat_info = Registry. compat_info (info)
1789+ compat_info_v = get (reg_compat_info, pkg. version, nothing )
1790+ versions = keys (reg_compat_info)
1791+ for v in versions
1792+ compat_info_v = get (reg_compat_info, v, nothing )
1793+ compat_info_v === nothing && continue
1794+ compat_info_v_uuid = compat_info_v[JULIA_UUID]
1795+ if VERSION in compat_info_v_uuid
1796+ push! (julia_compatible_versions, v)
1797+ end
1798+ end
1799+ end
1800+ if ! (max_version in julia_compatible_versions)
1801+ push! (packages_holding_back, " julia" )
1802+ end
1803+
1804+ return sort! (unique! (packages_holding_back)), max_version, max_version_in_compat
1805+ end
1806+
17341807function diff_array (old_env:: Union{EnvCache,Nothing} , new_env:: EnvCache ; manifest= true )
17351808 function index_pkgs (pkgs, uuid)
17361809 idx = findfirst (pkg -> pkg. uuid == uuid, pkgs)
@@ -1757,9 +1830,18 @@ function is_package_downloaded(project_file::String, pkg::PackageSpec)
17571830 return true
17581831end
17591832
1760- function print_status (env:: EnvCache , old_env:: Union{Nothing,EnvCache} , header:: Symbol ,
1761- uuids:: Vector , names:: Vector ; manifest= true , diff= false , ignore_indent= false , io)
1833+ struct PackageStatusData
1834+ uuid:: UUID
1835+ old:: Union{Nothing, PackageSpec}
1836+ new:: Union{Nothing, PackageSpec}
1837+ downloaded:: Bool
1838+ compat_data:: Union{Nothing, Tuple{Vector{String}, VersionNumber, VersionNumber}}
1839+ end
1840+
1841+ function print_status (env:: EnvCache , old_env:: Union{Nothing,EnvCache} , registries:: Vector{Registry.RegistryInstance} , header:: Symbol ,
1842+ uuids:: Vector , names:: Vector ; manifest= true , diff= false , ignore_indent:: Bool , outdated:: Bool , io:: IO )
17621843 not_installed_indicator = sprint ((io, args) -> printstyled (io, args... ; color= :red ), " →" , context= io)
1844+ not_latest_version_indicator = sprint ((io, args) -> printstyled (io, args... ; color= :yellow ), " ↓" , context= io)
17631845 filter = ! isempty (uuids) || ! isempty (names)
17641846 # setup
17651847 xs = diff_array (old_env, env; manifest= manifest)
@@ -1785,20 +1867,62 @@ function print_status(env::EnvCache, old_env::Union{Nothing,EnvCache}, header::S
17851867 # Sort stdlibs and _jlls towards the end in status output
17861868 xs = sort! (xs, by = (x -> (is_stdlib (x[1 ]), endswith (something (x[3 ], x[2 ]). name, " _jll" ), something (x[3 ], x[2 ]). name, x[1 ])))
17871869 all_packages_downloaded = true
1870+
1871+ package_statuses = PackageStatusData[]
17881872 for (uuid, old, new) in xs
17891873 if Types. is_project_uuid (env, uuid)
17901874 continue
17911875 end
1876+
1877+ latest_version = true
1878+ # Compat info
1879+ cinfo = nothing
1880+ if outdated
1881+ if diff == false && ! is_stdlib (new. uuid)
1882+ @assert old == nothing
1883+ cinfo = status_compat_info (new, env, registries)
1884+ if cinfo != = nothing
1885+ latest_version = false
1886+ end
1887+ end
1888+ end
1889+ # if we are running with compat, only show packages that are upper bounded
1890+ if outdated && latest_version
1891+ continue
1892+ end
1893+
17921894 pkg_downloaded = ! is_instantiated (new) || is_package_downloaded (env. project_file, new)
1895+
17931896 all_packages_downloaded &= pkg_downloaded
1794- print (io, pkg_downloaded ? " " : not_installed_indicator)
1795- printstyled (io, " [" , string (uuid)[1 : 8 ], " ] " ; color = :light_black )
1796- diff ? print_diff (io, old, new) : print_single (io, new)
1897+ push! (package_statuses, PackageStatusData (uuid, old, new, pkg_downloaded, cinfo))
1898+ end
1899+
1900+ for pkg in package_statuses
1901+ latest_version = pkg. compat_data === nothing
1902+ print (io, pkg. downloaded ? (all_packages_downloaded ? " " : " " ) : not_installed_indicator)
1903+ printstyled (io, " [" , string (pkg. uuid)[1 : 8 ], " ] " ; color = :light_black )
1904+ diff ? print_diff (io, pkg. old, pkg. new) : print_single (io, pkg. new)
1905+ if outdated && ! diff && pkg. compat_data != = nothing
1906+ packages_holding_back, max_version, max_version_compat = pkg. compat_data
1907+ if pkg. new. version != = max_version_compat && max_version_compat != max_version
1908+ printstyled (io, " [<v" , max_version_compat, " ]" , color= :light_magenta )
1909+ printstyled (io, " ," )
1910+ end
1911+ printstyled (io, " (<v" , max_version, " )" ; color= Base. warn_color ())
1912+ if packages_holding_back == [" compat" ]
1913+ printstyled (io, " [compat]" ; color= :light_magenta )
1914+ else
1915+ pkg_str = isempty (packages_holding_back) ? " " : string (" : " , join (packages_holding_back, " , " ))
1916+ printstyled (io, pkg_str; color= Base. warn_color ())
1917+ end
1918+ end
17971919 println (io)
17981920 end
1921+
17991922 if ! all_packages_downloaded
18001923 printpkgstyle (io, :Info , " packages marked with $not_installed_indicator not downloaded, use `instantiate` to download" , ignore_indent)
18011924 end
1925+
18021926 return nothing
18031927end
18041928
@@ -1819,20 +1943,20 @@ function git_head_env(env, project_dir)
18191943 end
18201944end
18211945
1822- function show_update (env:: EnvCache ; ignore_indent = false , io:: IO )
1946+ function show_update (env:: EnvCache , registries :: Vector{Registry.RegistryInstance} ; io:: IO )
18231947 old_env = EnvCache ()
18241948 old_env. project = env. original_project
18251949 old_env. manifest = env. original_manifest
1826- status (env; header= :Updating , mode= PKGMODE_COMBINED, env_diff= old_env, ignore_indent= ignore_indent , io= io)
1950+ status (env, registries ; header= :Updating , mode= PKGMODE_COMBINED, env_diff= old_env, ignore_indent= false , io= io)
18271951 return nothing
18281952end
18291953
1830- function status (env:: EnvCache , pkgs:: Vector{PackageSpec} = PackageSpec[];
1831- header= nothing , mode:: PackageMode = PKGMODE_PROJECT, git_diff:: Bool = false , env_diff= nothing , ignore_indent= false , io:: IO )
1954+ function status (env:: EnvCache , registries :: Vector{Registry.RegistryInstance} , pkgs:: Vector{PackageSpec} = PackageSpec[];
1955+ header= nothing , mode:: PackageMode = PKGMODE_PROJECT, git_diff:: Bool = false , env_diff= nothing , ignore_indent= true , io:: IO , outdated :: Bool = false )
18321956 io == Base. devnull && return
18331957 # if a package, print header
18341958 if header === nothing && env. pkg != = nothing
1835- printpkgstyle (io, :Project , string (env. pkg. name, " v" , env. pkg. version); color= Base. info_color ())
1959+ printpkgstyle (io, :Project , string (env. pkg. name, " v" , env. pkg. version), true ; color= Base. info_color ())
18361960 end
18371961 # load old env
18381962 old_env = nothing
@@ -1855,10 +1979,10 @@ function status(env::EnvCache, pkgs::Vector{PackageSpec}=PackageSpec[];
18551979 diff = old_env != = nothing
18561980 header = something (header, diff ? :Diff : :Status )
18571981 if mode == PKGMODE_PROJECT || mode == PKGMODE_COMBINED
1858- print_status (env, old_env, header, filter_uuids, filter_names; manifest= false , diff= diff , ignore_indent= ignore_indent , io= io )
1982+ print_status (env, old_env, registries, header, filter_uuids, filter_names; manifest= false , diff, ignore_indent, io, outdated )
18591983 end
18601984 if mode == PKGMODE_MANIFEST || mode == PKGMODE_COMBINED
1861- print_status (env, old_env, header, filter_uuids, filter_names; diff= diff , ignore_indent= ignore_indent , io= io )
1985+ print_status (env, old_env, registries, header, filter_uuids, filter_names; diff, ignore_indent, io, outdated )
18621986 end
18631987end
18641988
0 commit comments