Skip to content

Commit c1efc3f

Browse files
committed
show more deprecated info in status
1 parent 595ffee commit c1efc3f

File tree

5 files changed

+104
-14
lines changed

5 files changed

+104
-14
lines changed

docs/src/registries.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,11 @@ One use of the `[metadata]` table is to mark packages as deprecated using `[meta
114114
- Be excluded from tab-completion suggestions
115115
- Still be installable and usable
116116

117-
The `[metadata.deprecated]` table can contain arbitrary metadata fields. Common fields include:
117+
The `[metadata.deprecated]` table can contain arbitrary metadata fields. Two special fields are recognized by Pkg and displayed when using `pkg> status --deprecated`:
118+
- `reason`: A string explaining why the package is deprecated
119+
- `alternative`: A string suggesting a replacement package
120+
121+
Example:
118122

119123
```toml
120124
name = "MyPackage"
@@ -126,7 +130,7 @@ reason = "This package is no longer maintained"
126130
alternative = "ReplacementPackage"
127131
```
128132

129-
The specific fields within `[metadata.deprecated]` are not currently used by Pkg itself, but are stored to allow other tools and registries to utilize this metadata.
133+
Other fields can be added to `[metadata.deprecated]` for use by registries or other tools.
130134

131135
### Registry Compat.toml
132136

src/API.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,14 +1314,15 @@ end
13141314

13151315
@deprecate status(mode::PackageMode) status(mode = mode)
13161316

1317-
function status(ctx::Context, pkgs::Vector{PackageSpec}; diff::Bool = false, mode = PKGMODE_PROJECT, workspace::Bool = false, outdated::Bool = false, compat::Bool = false, extensions::Bool = false, io::IO = stdout_f())
1317+
function status(ctx::Context, pkgs::Vector{PackageSpec}; diff::Bool = false, mode = PKGMODE_PROJECT, workspace::Bool = false, outdated::Bool = false, deprecated::Bool = false, compat::Bool = false, extensions::Bool = false, io::IO = stdout_f())
13181318
if compat
13191319
diff && pkgerror("Compat status has no `diff` mode")
13201320
outdated && pkgerror("Compat status has no `outdated` mode")
1321+
deprecated && pkgerror("Compat status has no `deprecated` mode")
13211322
extensions && pkgerror("Compat status has no `extensions` mode")
13221323
Operations.print_compat(ctx, pkgs; io)
13231324
else
1324-
Operations.status(ctx.env, ctx.registries, pkgs; mode, git_diff = diff, io, outdated, extensions, workspace)
1325+
Operations.status(ctx.env, ctx.registries, pkgs; mode, git_diff = diff, io, outdated, deprecated, extensions, workspace)
13251326
end
13261327
return nothing
13271328
end

src/Operations.jl

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,20 @@ function is_pkg_deprecated(pkg::Union{PackageSpec, PackageEntry}, registries::Ve
6262
return false
6363
end
6464

65+
function get_pkg_deprecation_info(pkg::Union{PackageSpec, PackageEntry}, registries::Vector{Registry.RegistryInstance} = Registry.reachable_registries())
66+
pkg.uuid === nothing && return nothing
67+
for reg in registries
68+
reg_pkg = get(reg, pkg.uuid, nothing)
69+
if reg_pkg !== nothing
70+
info = Registry.registry_info(reg_pkg)
71+
if Registry.isdeprecated(info)
72+
return info.deprecated
73+
end
74+
end
75+
end
76+
return nothing
77+
end
78+
6579
function default_preserve()
6680
return if Base.get_bool_env("JULIA_PKG_PRESERVE_TIERED_INSTALLED", false)
6781
PRESERVE_TIERED_INSTALLED
@@ -2927,11 +2941,12 @@ struct PackageStatusData
29272941
compat_data::Union{Nothing, Tuple{Vector{String}, VersionNumber, VersionNumber}}
29282942
changed::Bool
29292943
extinfo::Union{Nothing, Vector{ExtInfo}}
2944+
deprecation_info::Union{Nothing, Dict{String, Any}}
29302945
end
29312946

29322947
function print_status(
29332948
env::EnvCache, old_env::Union{Nothing, EnvCache}, registries::Vector{Registry.RegistryInstance}, header::Symbol,
2934-
uuids::Vector, names::Vector; manifest = true, diff = false, ignore_indent::Bool, workspace::Bool, outdated::Bool, extensions::Bool, io::IO,
2949+
uuids::Vector, names::Vector; manifest = true, diff = false, ignore_indent::Bool, workspace::Bool, outdated::Bool, deprecated::Bool, extensions::Bool, io::IO,
29352950
mode::PackageMode, hidden_upgrades_info::Bool, show_usagetips::Bool = true
29362951
)
29372952
not_installed_indicator = sprint((io, args) -> printstyled(io, args...; color = Base.error_color()), "", context = io)
@@ -3015,6 +3030,19 @@ function print_status(
30153030
continue
30163031
end
30173032

3033+
# Deprecated info
3034+
deprecation_info = nothing
3035+
pkg_deprecated = false
3036+
if !isnothing(new)
3037+
pkg_spec = something(new, old)
3038+
deprecation_info = get_pkg_deprecation_info(pkg_spec, registries)
3039+
pkg_deprecated = deprecation_info !== nothing
3040+
end
3041+
3042+
# if we are running with deprecated, only show packages that are deprecated
3043+
if deprecated && !pkg_deprecated
3044+
continue
3045+
end
30183046

30193047
# TODO: Show extension deps for project as well?
30203048

@@ -3033,7 +3061,7 @@ function print_status(
30333061
no_visible_packages_heldback &= (!changed || !pkg_heldback)
30343062
no_packages_heldback &= !pkg_heldback
30353063

3036-
push!(package_statuses, PackageStatusData(uuid, old, new, pkg_downloaded, pkg_upgradable, pkg_heldback, cinfo, changed, ext_info))
3064+
push!(package_statuses, PackageStatusData(uuid, old, new, pkg_downloaded, pkg_upgradable, pkg_heldback, cinfo, changed, ext_info, deprecation_info))
30373065
end
30383066

30393067
for pkg in package_statuses
@@ -3067,10 +3095,22 @@ function print_status(
30673095
end
30683096

30693097
# show if package is deprecated
3070-
if is_pkg_deprecated(pkg_spec, registries)
3098+
if pkg.deprecation_info !== nothing
30713099
printstyled(io, " [deprecated]"; color = :yellow)
30723100
end
30733101

3102+
# show deprecation details when using --deprecated flag
3103+
if deprecated && !diff && pkg.deprecation_info !== nothing
3104+
reason = get(pkg.deprecation_info, "reason", nothing)
3105+
alternative = get(pkg.deprecation_info, "alternative", nothing)
3106+
if reason !== nothing
3107+
printstyled(io, " (reason: ", reason, ")"; color = :yellow)
3108+
end
3109+
if alternative !== nothing
3110+
printstyled(io, " (alternative: ", alternative, ")"; color = :yellow)
3111+
end
3112+
end
3113+
30743114
if outdated && !diff && pkg.compat_data !== nothing
30753115
packages_holding_back, max_version, max_version_compat = pkg.compat_data
30763116
if pkg.new.version !== max_version_compat && max_version_compat != max_version
@@ -3161,6 +3201,17 @@ function print_status(
31613201
It is recommended to update them to resolve a valid version.""", color = Base.warn_color(), ignore_indent)
31623202
end
31633203

3204+
# Check if any packages are deprecated for info message
3205+
any_deprecated_packages = any(pkg -> pkg.deprecation_info !== nothing, package_statuses)
3206+
3207+
# Add info for deprecated packages (only if not already in deprecated mode)
3208+
if !deprecated && any_deprecated_packages
3209+
deprecated_str = sprint((io, args) -> printstyled(io, args...; color = :yellow), "[deprecated]", context = io)
3210+
tipend = manifest ? " -m" : ""
3211+
tip = show_usagetips ? " Use `status --deprecated$tipend` to see more information." : ""
3212+
printpkgstyle(io, :Info, """Packages marked with $deprecated_str are no longer maintained.$tip""", color = Base.info_color(), ignore_indent)
3213+
end
3214+
31643215
return nothing
31653216
end
31663217

@@ -3192,7 +3243,7 @@ end
31923243
function status(
31933244
env::EnvCache, registries::Vector{Registry.RegistryInstance}, pkgs::Vector{PackageSpec} = PackageSpec[];
31943245
header = nothing, mode::PackageMode = PKGMODE_PROJECT, git_diff::Bool = false, env_diff = nothing, ignore_indent = true,
3195-
io::IO, workspace::Bool = false, outdated::Bool = false, extensions::Bool = false, hidden_upgrades_info::Bool = false, show_usagetips::Bool = true
3246+
io::IO, workspace::Bool = false, outdated::Bool = false, deprecated::Bool = false, extensions::Bool = false, hidden_upgrades_info::Bool = false, show_usagetips::Bool = true
31963247
)
31973248
io == Base.devnull && return
31983249
# if a package, print header
@@ -3223,10 +3274,10 @@ function status(
32233274
diff = old_env !== nothing
32243275
header = something(header, diff ? :Diff : :Status)
32253276
if mode == PKGMODE_PROJECT || mode == PKGMODE_COMBINED
3226-
print_status(env, old_env, registries, header, filter_uuids, filter_names; manifest = false, diff, ignore_indent, io, workspace, outdated, extensions, mode, hidden_upgrades_info, show_usagetips)
3277+
print_status(env, old_env, registries, header, filter_uuids, filter_names; manifest = false, diff, ignore_indent, io, workspace, outdated, deprecated, extensions, mode, hidden_upgrades_info, show_usagetips)
32273278
end
32283279
if mode == PKGMODE_MANIFEST || mode == PKGMODE_COMBINED
3229-
print_status(env, old_env, registries, header, filter_uuids, filter_names; diff, ignore_indent, io, workspace, outdated, extensions, mode, hidden_upgrades_info, show_usagetips)
3280+
print_status(env, old_env, registries, header, filter_uuids, filter_names; diff, ignore_indent, io, workspace, outdated, deprecated, extensions, mode, hidden_upgrades_info, show_usagetips)
32303281
end
32313282
return if is_manifest_current(env) === false
32323283
tip = if show_usagetips

src/REPLMode/command_declarations.jl

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -435,16 +435,17 @@ compound_declarations = [
435435
PSA[:name => "manifest", :short_name => "m", :api => :mode => PKGMODE_MANIFEST],
436436
PSA[:name => "diff", :short_name => "d", :api => :diff => true],
437437
PSA[:name => "outdated", :short_name => "o", :api => :outdated => true],
438+
PSA[:name => "deprecated", :api => :deprecated => true],
438439
PSA[:name => "compat", :short_name => "c", :api => :compat => true],
439440
PSA[:name => "extensions", :short_name => "e", :api => :extensions => true],
440441
PSA[:name => "workspace", :api => :workspace => true],
441442
],
442443
:completions => :complete_installed_packages,
443444
:description => "summarize contents of and changes to environment",
444445
:help => md"""
445-
[st|status] [-d|--diff] [--workspace] [-o|--outdated] [pkgs...]
446-
[st|status] [-d|--diff] [--workspace] [-o|--outdated] [-p|--project] [pkgs...]
447-
[st|status] [-d|--diff] [--workspace] [-o|--outdated] [-m|--manifest] [pkgs...]
446+
[st|status] [-d|--diff] [--workspace] [-o|--outdated] [--deprecated] [pkgs...]
447+
[st|status] [-d|--diff] [--workspace] [-o|--outdated] [--deprecated] [-p|--project] [pkgs...]
448+
[st|status] [-d|--diff] [--workspace] [-o|--outdated] [--deprecated] [-m|--manifest] [pkgs...]
448449
[st|status] [-d|--diff] [--workspace] [-e|--extensions] [-p|--project] [pkgs...]
449450
[st|status] [-d|--diff] [--workspace] [-e|--extensions] [-m|--manifest] [pkgs...]
450451
[st|status] [-c|--compat] [pkgs...]
@@ -455,7 +456,10 @@ compound_declarations = [
455456
constraints. To see why use `pkg> status --outdated` which shows any packages
456457
that are not at their latest version and if any packages are holding them back.
457458
Packages marked with `[yanked]` have been yanked from the registry and should be
458-
updated or removed.
459+
updated or removed. Packages marked with `[deprecated]` are no longer maintained.
460+
461+
Use `pkg> status --deprecated` to show only deprecated packages along with deprecation
462+
information such as the reason and alternative packages (if provided by the registry).
459463
460464
Use `pkg> status --extensions` to show dependencies with extensions and what extension dependencies
461465
of those that are currently loaded.

test/registry.jl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,36 @@ end
409409
example1_info = Pkg.Registry.registry_info(example1_entry)
410410
@test !Pkg.Registry.isdeprecated(example1_info)
411411
@test example1_info.deprecated === nothing
412+
413+
# Test status output with deprecated package
414+
io = IOBuffer()
415+
Pkg.activate(; temp = true, io = devnull)
416+
Pkg.add(name = "DeprecatedExample", uuid = pkg_uuid, io = devnull)
417+
Pkg.add(name = "Example", uuid = example1_uuid, io = devnull)
418+
419+
# Test regular status shows [deprecated] tag
420+
Pkg.status(io = io)
421+
status_output = String(take!(io))
422+
@test occursin("[deprecated]", status_output)
423+
@test occursin("DeprecatedExample", status_output)
424+
# Should suggest using status --deprecated
425+
@test occursin("status --deprecated", status_output)
426+
427+
# Test status --deprecated shows only deprecated packages with details
428+
Pkg.status(deprecated = true, io = io)
429+
deprecated_output = String(take!(io))
430+
@test occursin("[deprecated]", deprecated_output)
431+
@test occursin("DeprecatedExample", deprecated_output)
432+
@test occursin("reason: This package is no longer maintained", deprecated_output)
433+
@test occursin("alternative: Example", deprecated_output)
434+
# Non-deprecated package should not appear
435+
@test !occursin("Example v", deprecated_output)
436+
437+
# Test that status --deprecated with manifest mode works
438+
Pkg.status(deprecated = true, mode = Pkg.PKGMODE_MANIFEST, io = io)
439+
deprecated_manifest_output = String(take!(io))
440+
@test occursin("[deprecated]", deprecated_manifest_output)
441+
@test occursin("DeprecatedExample", deprecated_manifest_output)
412442
end
413443
end
414444

0 commit comments

Comments
 (0)