From a0c774c1d87a7442b533891e620d1966099c1054 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Sun, 19 Oct 2025 10:42:55 +0200 Subject: [PATCH 1/5] allow for a `deprecated` table in a `Package.toml` in a registry these packages will not tab complete to and will show up as deprecated in pkg status Fixes https://github.com/JuliaLang/Pkg.jl/issues/2194 --- ext/REPLExt/completions.jl | 1 + src/Operations.jl | 17 +++++++ src/Registry/registry_instance.jl | 10 ++++- test/registry.jl | 73 ++++++++++++++++++++++++++++++- 4 files changed, 98 insertions(+), 3 deletions(-) diff --git a/ext/REPLExt/completions.jl b/ext/REPLExt/completions.jl index da75efc19e..8a494cd2ff 100644 --- a/ext/REPLExt/completions.jl +++ b/ext/REPLExt/completions.jl @@ -79,6 +79,7 @@ function complete_remote_package!(comps, partial; hint::Bool) name in cmp && continue if startswith(regpkg.name, partial) pkg = Registry.registry_info(regpkg) + Registry.isdeprecated(pkg) && continue compat_info = Registry.compat_info(pkg) # Filter versions for (v, uncompressed_compat) in compat_info diff --git a/src/Operations.jl b/src/Operations.jl index 591e0305e4..a179f9fadf 100644 --- a/src/Operations.jl +++ b/src/Operations.jl @@ -50,6 +50,18 @@ function is_pkgversion_yanked(entry::PackageEntry, registries::Vector{Registry.R return is_pkgversion_yanked(entry.uuid, entry.version, registries) end +function is_pkg_deprecated(pkg::Union{PackageSpec, PackageEntry}, registries::Vector{Registry.RegistryInstance} = Registry.reachable_registries()) + pkg.uuid === nothing && return false + for reg in registries + reg_pkg = get(reg, pkg.uuid, nothing) + if reg_pkg !== nothing + info = Registry.registry_info(reg_pkg) + Registry.isdeprecated(info) && return true + end + end + return false +end + function default_preserve() return if Base.get_bool_env("JULIA_PKG_PRESERVE_TIERED_INSTALLED", false) PRESERVE_TIERED_INSTALLED @@ -3054,6 +3066,11 @@ function print_status( printstyled(io, " [yanked]"; color = :yellow) end + # show if package is deprecated + if is_pkg_deprecated(pkg_spec, registries) + printstyled(io, " [deprecated]"; color = :yellow) + end + if outdated && !diff && pkg.compat_data !== nothing packages_holding_back, max_version, max_version_compat = pkg.compat_data if pkg.new.version !== max_version_compat && max_version_compat != max_version diff --git a/src/Registry/registry_instance.jl b/src/Registry/registry_instance.jl index 38e3cd7077..253a6ca1e5 100644 --- a/src/Registry/registry_instance.jl +++ b/src/Registry/registry_instance.jl @@ -48,6 +48,9 @@ struct PkgInfo repo::Union{String, Nothing} subdir::Union{String, Nothing} + # Package.toml [deprecated]: + deprecated::Union{Dict{String, Any}, Nothing} + # Versions.toml: version_info::Dict{VersionNumber, VersionInfo} @@ -68,6 +71,7 @@ end isyanked(pkg::PkgInfo, v::VersionNumber) = pkg.version_info[v].yanked treehash(pkg::PkgInfo, v::VersionNumber) = pkg.version_info[v].git_tree_sha1 +isdeprecated(pkg::PkgInfo) = pkg.deprecated !== nothing function uncompress(compressed::Dict{VersionRange, Dict{String, T}}, vsorted::Vector{VersionNumber}) where {T} @assert issorted(vsorted) @@ -201,6 +205,10 @@ function init_package_info!(pkg::PkgEntry) repo = get(d_p, "repo", nothing)::Union{Nothing, String} subdir = get(d_p, "subdir", nothing)::Union{Nothing, String} + # The presence of a [deprecated] table indicates the package is deprecated + # We store the raw table to allow other tools to use the metadata + deprecated = get(d_p, "deprecated", nothing)::Union{Nothing, Dict{String, Any}} + # Versions.toml d_v = custom_isfile(pkg.in_memory_registry, pkg.registry_path, joinpath(pkg.path, "Versions.toml")) ? parsefile(pkg.in_memory_registry, pkg.registry_path, joinpath(pkg.path, "Versions.toml")) : Dict{String, Any}() @@ -256,7 +264,7 @@ function init_package_info!(pkg::PkgEntry) end @assert !isdefined(pkg, :info) - pkg.info = PkgInfo(repo, subdir, version_info, compat, deps, weak_compat, weak_deps, pkg.info_lock) + pkg.info = PkgInfo(repo, subdir, deprecated, version_info, compat, deps, weak_compat, weak_deps, pkg.info_lock) return pkg.info end diff --git a/test/registry.jl b/test/registry.jl index ad30823bd9..0af4188634 100644 --- a/test/registry.jl +++ b/test/registry.jl @@ -41,8 +41,6 @@ function setup_test_registries(dir = pwd()) ) write( joinpath(regpath, "Example", "Deps.toml"), """ - ["0.5"] - julia = "0.6-1.0" """ ) write( @@ -343,6 +341,77 @@ end end end + @testset "deprecated package" begin + temp_pkg_dir() do depot + # Set up test registries with an extra deprecated package + regdir = mktempdir() + setup_test_registries(regdir) + + # Add a deprecated package to the first registry + regpath = joinpath(regdir, "RegistryFoo1") + mkpath(joinpath(regpath, "DeprecatedExample")) + + # Add the deprecated package to Registry.toml + registry_toml = read(joinpath(regpath, "Registry.toml"), String) + registry_toml = replace( + registry_toml, + "[packages]" => + "[packages]\n11111111-1111-1111-1111-111111111111 = { name = \"DeprecatedExample\", path = \"DeprecatedExample\" }" + ) + write(joinpath(regpath, "Registry.toml"), registry_toml) + + # Create deprecated package with [deprecated] table + write( + joinpath(regpath, "DeprecatedExample", "Package.toml"), """ + name = "DeprecatedExample" + uuid = "11111111-1111-1111-1111-111111111111" + repo = "https://github.com/test/DeprecatedExample.jl.git" + + [deprecated] + reason = "This package is no longer maintained" + alternative = "Example" + """ + ) + + write( + joinpath(regpath, "DeprecatedExample", "Versions.toml"), """ + ["1.0.0"] + git-tree-sha1 = "1234567890abcdef1234567890abcdef12345678" + """ + ) + + git_init_and_commit(regpath) + + # Add the test registry + Pkg.Registry.add(url = regpath) + + # Test that the package is marked as deprecated + registries = Pkg.Registry.reachable_registries() + reg_idx = findfirst(r -> r.name == "RegistryFoo", registries) + @test reg_idx !== nothing + + reg = registries[reg_idx] + pkg_uuid = UUID("11111111-1111-1111-1111-111111111111") + @test haskey(reg, pkg_uuid) + + pkg_entry = reg[pkg_uuid] + pkg_info = Pkg.Registry.registry_info(pkg_entry) + + # Test that deprecated info is loaded correctly + @test Pkg.Registry.isdeprecated(pkg_info) + @test pkg_info.deprecated !== nothing + @test pkg_info.deprecated["reason"] == "This package is no longer maintained" + @test pkg_info.deprecated["alternative"] == "Example" + + # Test that non-deprecated package is not marked as deprecated + example1_uuid = UUID("c5f1542f-b8aa-45da-ab42-05303d706c66") + example1_entry = reg[example1_uuid] + example1_info = Pkg.Registry.registry_info(example1_entry) + @test !Pkg.Registry.isdeprecated(example1_info) + @test example1_info.deprecated === nothing + end + end + @testset "yanking" begin uuid = Base.UUID("7876af07-990d-54b4-ab0e-23690620f79a") # Example # Tests that Example@0.5.1 does not get installed From e3ec23811825fca1ad380d24850152da9c534886 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Wed, 22 Oct 2025 11:18:52 +0200 Subject: [PATCH 2/5] store deprecated table under a tags table --- src/Registry/registry_instance.jl | 7 ++++--- test/registry.jl | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Registry/registry_instance.jl b/src/Registry/registry_instance.jl index 253a6ca1e5..dd8670404e 100644 --- a/src/Registry/registry_instance.jl +++ b/src/Registry/registry_instance.jl @@ -48,7 +48,7 @@ struct PkgInfo repo::Union{String, Nothing} subdir::Union{String, Nothing} - # Package.toml [deprecated]: + # Package.toml [tags.deprecated]: deprecated::Union{Dict{String, Any}, Nothing} # Versions.toml: @@ -205,9 +205,10 @@ function init_package_info!(pkg::PkgEntry) repo = get(d_p, "repo", nothing)::Union{Nothing, String} subdir = get(d_p, "subdir", nothing)::Union{Nothing, String} - # The presence of a [deprecated] table indicates the package is deprecated + # The presence of a [tags.deprecated] table indicates the package is deprecated # We store the raw table to allow other tools to use the metadata - deprecated = get(d_p, "deprecated", nothing)::Union{Nothing, Dict{String, Any}} + tags = get(d_p, "tags", nothing)::Union{Nothing, Dict{String, Any}} + deprecated = tags !== nothing ? get(tags, "deprecated", nothing)::Union{Nothing, Dict{String, Any}} : nothing # Versions.toml d_v = custom_isfile(pkg.in_memory_registry, pkg.registry_path, joinpath(pkg.path, "Versions.toml")) ? diff --git a/test/registry.jl b/test/registry.jl index 0af4188634..dbb7e0b6dd 100644 --- a/test/registry.jl +++ b/test/registry.jl @@ -360,14 +360,14 @@ end ) write(joinpath(regpath, "Registry.toml"), registry_toml) - # Create deprecated package with [deprecated] table + # Create deprecated package with [tags.deprecated] table write( joinpath(regpath, "DeprecatedExample", "Package.toml"), """ name = "DeprecatedExample" uuid = "11111111-1111-1111-1111-111111111111" repo = "https://github.com/test/DeprecatedExample.jl.git" - [deprecated] + [tags.deprecated] reason = "This package is no longer maintained" alternative = "Example" """ From 52943f87fd2c7fb757ee27ddcf553f309190b903 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Wed, 22 Oct 2025 11:20:52 +0200 Subject: [PATCH 3/5] docs --- docs/src/registries.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/src/registries.md b/docs/src/registries.md index cada0bdadf..129d17162f 100644 --- a/docs/src/registries.md +++ b/docs/src/registries.md @@ -99,6 +99,35 @@ are the following files: `Compat.toml`, `Deps.toml`, `Package.toml`, and `Versions.toml`. The formats of these files are described below. +### Registry Package.toml + +The `Package.toml` file contains basic metadata about the package, such as its name, UUID, repository URL, and optional tags. + +#### Package tags + +The `[tags]` table in `Package.toml` provides a location for metadata about the package that doesn't fit into the other registry files. This is an extensible framework for adding package-level metadata. + +#### Deprecated packages + +One use of the `[tags]` table is to mark packages as deprecated using `[tags.deprecated]`. Deprecated packages will: +- Show as `[deprecated]` in package status output +- Be excluded from tab-completion suggestions +- Still be installable and usable + +The `[tags.deprecated]` table can contain arbitrary metadata fields. Common fields include: + +```toml +name = "MyPackage" +uuid = "..." +repo = "..." + +[tags.deprecated] +reason = "This package is no longer maintained" +alternative = "ReplacementPackage" +``` + +The specific fields within `[tags.deprecated]` are not currently used by Pkg itself, but are stored to allow other tools and registries to utilize this metadata. + ### Registry Compat.toml The `Compat.toml` file has a series of blocks specifying version From 595ffeeae5992fcc0691798c08c5d9434b88bce4 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Wed, 22 Oct 2025 21:28:38 +0200 Subject: [PATCH 4/5] tags -> metadata --- docs/src/registries.md | 14 +++++++------- src/Registry/registry_instance.jl | 8 ++++---- test/registry.jl | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/src/registries.md b/docs/src/registries.md index 129d17162f..e18f503f98 100644 --- a/docs/src/registries.md +++ b/docs/src/registries.md @@ -101,32 +101,32 @@ The formats of these files are described below. ### Registry Package.toml -The `Package.toml` file contains basic metadata about the package, such as its name, UUID, repository URL, and optional tags. +The `Package.toml` file contains basic metadata about the package, such as its name, UUID, repository URL, and optional metadata. -#### Package tags +#### Package metadata -The `[tags]` table in `Package.toml` provides a location for metadata about the package that doesn't fit into the other registry files. This is an extensible framework for adding package-level metadata. +The `[metadata]` table in `Package.toml` provides a location for metadata about the package that doesn't fit into the other registry files. This is an extensible framework for adding package-level metadata. #### Deprecated packages -One use of the `[tags]` table is to mark packages as deprecated using `[tags.deprecated]`. Deprecated packages will: +One use of the `[metadata]` table is to mark packages as deprecated using `[metadata.deprecated]`. Deprecated packages will: - Show as `[deprecated]` in package status output - Be excluded from tab-completion suggestions - Still be installable and usable -The `[tags.deprecated]` table can contain arbitrary metadata fields. Common fields include: +The `[metadata.deprecated]` table can contain arbitrary metadata fields. Common fields include: ```toml name = "MyPackage" uuid = "..." repo = "..." -[tags.deprecated] +[metadata.deprecated] reason = "This package is no longer maintained" alternative = "ReplacementPackage" ``` -The specific fields within `[tags.deprecated]` are not currently used by Pkg itself, but are stored to allow other tools and registries to utilize this metadata. +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. ### Registry Compat.toml diff --git a/src/Registry/registry_instance.jl b/src/Registry/registry_instance.jl index dd8670404e..447815dae8 100644 --- a/src/Registry/registry_instance.jl +++ b/src/Registry/registry_instance.jl @@ -48,7 +48,7 @@ struct PkgInfo repo::Union{String, Nothing} subdir::Union{String, Nothing} - # Package.toml [tags.deprecated]: + # Package.toml [metadata.deprecated]: deprecated::Union{Dict{String, Any}, Nothing} # Versions.toml: @@ -205,10 +205,10 @@ function init_package_info!(pkg::PkgEntry) repo = get(d_p, "repo", nothing)::Union{Nothing, String} subdir = get(d_p, "subdir", nothing)::Union{Nothing, String} - # The presence of a [tags.deprecated] table indicates the package is deprecated + # The presence of a [metadata.deprecated] table indicates the package is deprecated # We store the raw table to allow other tools to use the metadata - tags = get(d_p, "tags", nothing)::Union{Nothing, Dict{String, Any}} - deprecated = tags !== nothing ? get(tags, "deprecated", nothing)::Union{Nothing, Dict{String, Any}} : nothing + metadata = get(d_p, "metadata", nothing)::Union{Nothing, Dict{String, Any}} + deprecated = metadata !== nothing ? get(metadata, "deprecated", nothing)::Union{Nothing, Dict{String, Any}} : nothing # Versions.toml d_v = custom_isfile(pkg.in_memory_registry, pkg.registry_path, joinpath(pkg.path, "Versions.toml")) ? diff --git a/test/registry.jl b/test/registry.jl index dbb7e0b6dd..32bcc17f73 100644 --- a/test/registry.jl +++ b/test/registry.jl @@ -360,14 +360,14 @@ end ) write(joinpath(regpath, "Registry.toml"), registry_toml) - # Create deprecated package with [tags.deprecated] table + # Create deprecated package with [metadata.deprecated] table write( joinpath(regpath, "DeprecatedExample", "Package.toml"), """ name = "DeprecatedExample" uuid = "11111111-1111-1111-1111-111111111111" repo = "https://github.com/test/DeprecatedExample.jl.git" - [tags.deprecated] + [metadata.deprecated] reason = "This package is no longer maintained" alternative = "Example" """ From d7327f2f4961b063d6f93856c7fd3e5a44639789 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Wed, 22 Oct 2025 21:47:21 +0200 Subject: [PATCH 5/5] show more deprecated info in status --- docs/src/registries.md | 8 +++- src/API.jl | 5 ++- src/Operations.jl | 59 +++++++++++++++++++++++----- src/REPLMode/command_declarations.jl | 12 ++++-- test/registry.jl | 14 +++++++ 5 files changed, 80 insertions(+), 18 deletions(-) diff --git a/docs/src/registries.md b/docs/src/registries.md index e18f503f98..d5e3657f19 100644 --- a/docs/src/registries.md +++ b/docs/src/registries.md @@ -114,7 +114,11 @@ One use of the `[metadata]` table is to mark packages as deprecated using `[meta - Be excluded from tab-completion suggestions - Still be installable and usable -The `[metadata.deprecated]` table can contain arbitrary metadata fields. Common fields include: +The `[metadata.deprecated]` table can contain arbitrary metadata fields. Two special fields are recognized by Pkg and displayed when using `pkg> status --deprecated`: +- `reason`: A string explaining why the package is deprecated +- `alternative`: A string suggesting a replacement package + +Example: ```toml name = "MyPackage" @@ -126,7 +130,7 @@ reason = "This package is no longer maintained" alternative = "ReplacementPackage" ``` -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. +Other fields can be added to `[metadata.deprecated]` for use by registries or other tools. ### Registry Compat.toml diff --git a/src/API.jl b/src/API.jl index ca965f0d2e..d7d3410ead 100644 --- a/src/API.jl +++ b/src/API.jl @@ -1314,14 +1314,15 @@ end @deprecate status(mode::PackageMode) status(mode = mode) -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()) +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()) if compat diff && pkgerror("Compat status has no `diff` mode") outdated && pkgerror("Compat status has no `outdated` mode") + deprecated && pkgerror("Compat status has no `deprecated` mode") extensions && pkgerror("Compat status has no `extensions` mode") Operations.print_compat(ctx, pkgs; io) else - Operations.status(ctx.env, ctx.registries, pkgs; mode, git_diff = diff, io, outdated, extensions, workspace) + Operations.status(ctx.env, ctx.registries, pkgs; mode, git_diff = diff, io, outdated, deprecated, extensions, workspace) end return nothing end diff --git a/src/Operations.jl b/src/Operations.jl index a179f9fadf..1dea0e182c 100644 --- a/src/Operations.jl +++ b/src/Operations.jl @@ -50,16 +50,18 @@ function is_pkgversion_yanked(entry::PackageEntry, registries::Vector{Registry.R return is_pkgversion_yanked(entry.uuid, entry.version, registries) end -function is_pkg_deprecated(pkg::Union{PackageSpec, PackageEntry}, registries::Vector{Registry.RegistryInstance} = Registry.reachable_registries()) - pkg.uuid === nothing && return false +function get_pkg_deprecation_info(pkg::Union{PackageSpec, PackageEntry}, registries::Vector{Registry.RegistryInstance} = Registry.reachable_registries()) + pkg.uuid === nothing && return nothing for reg in registries reg_pkg = get(reg, pkg.uuid, nothing) if reg_pkg !== nothing info = Registry.registry_info(reg_pkg) - Registry.isdeprecated(info) && return true + if Registry.isdeprecated(info) + return info.deprecated + end end end - return false + return nothing end function default_preserve() @@ -2927,11 +2929,12 @@ struct PackageStatusData compat_data::Union{Nothing, Tuple{Vector{String}, VersionNumber, VersionNumber}} changed::Bool extinfo::Union{Nothing, Vector{ExtInfo}} + deprecation_info::Union{Nothing, Dict{String, Any}} end function print_status( env::EnvCache, old_env::Union{Nothing, EnvCache}, registries::Vector{Registry.RegistryInstance}, header::Symbol, - uuids::Vector, names::Vector; manifest = true, diff = false, ignore_indent::Bool, workspace::Bool, outdated::Bool, extensions::Bool, io::IO, + uuids::Vector, names::Vector; manifest = true, diff = false, ignore_indent::Bool, workspace::Bool, outdated::Bool, deprecated::Bool, extensions::Bool, io::IO, mode::PackageMode, hidden_upgrades_info::Bool, show_usagetips::Bool = true ) not_installed_indicator = sprint((io, args) -> printstyled(io, args...; color = Base.error_color()), "→", context = io) @@ -3015,6 +3018,19 @@ function print_status( continue end + # Deprecated info + deprecation_info = nothing + pkg_deprecated = false + if !isnothing(new) + pkg_spec = something(new, old) + deprecation_info = get_pkg_deprecation_info(pkg_spec, registries) + pkg_deprecated = deprecation_info !== nothing + end + + # if we are running with deprecated, only show packages that are deprecated + if deprecated && !pkg_deprecated + continue + end # TODO: Show extension deps for project as well? @@ -3033,7 +3049,7 @@ function print_status( no_visible_packages_heldback &= (!changed || !pkg_heldback) no_packages_heldback &= !pkg_heldback - push!(package_statuses, PackageStatusData(uuid, old, new, pkg_downloaded, pkg_upgradable, pkg_heldback, cinfo, changed, ext_info)) + push!(package_statuses, PackageStatusData(uuid, old, new, pkg_downloaded, pkg_upgradable, pkg_heldback, cinfo, changed, ext_info, deprecation_info)) end for pkg in package_statuses @@ -3067,10 +3083,22 @@ function print_status( end # show if package is deprecated - if is_pkg_deprecated(pkg_spec, registries) + if pkg.deprecation_info !== nothing printstyled(io, " [deprecated]"; color = :yellow) end + # show deprecation details when using --deprecated flag + if deprecated && !diff && pkg.deprecation_info !== nothing + reason = get(pkg.deprecation_info, "reason", nothing) + alternative = get(pkg.deprecation_info, "alternative", nothing) + if reason !== nothing + printstyled(io, " (reason: ", reason, ")"; color = :yellow) + end + if alternative !== nothing + printstyled(io, " (alternative: ", alternative, ")"; color = :yellow) + end + end + if outdated && !diff && pkg.compat_data !== nothing packages_holding_back, max_version, max_version_compat = pkg.compat_data if pkg.new.version !== max_version_compat && max_version_compat != max_version @@ -3161,6 +3189,17 @@ function print_status( It is recommended to update them to resolve a valid version.""", color = Base.warn_color(), ignore_indent) end + # Check if any packages are deprecated for info message + any_deprecated_packages = any(pkg -> pkg.deprecation_info !== nothing, package_statuses) + + # Add info for deprecated packages (only if not already in deprecated mode) + if !deprecated && any_deprecated_packages + deprecated_str = sprint((io, args) -> printstyled(io, args...; color = :yellow), "[deprecated]", context = io) + tipend = manifest ? " -m" : "" + tip = show_usagetips ? " Use `status --deprecated$tipend` to see more information." : "" + printpkgstyle(io, :Info, """Packages marked with $deprecated_str are no longer maintained.$tip""", color = Base.info_color(), ignore_indent) + end + return nothing end @@ -3192,7 +3231,7 @@ end function status( env::EnvCache, registries::Vector{Registry.RegistryInstance}, pkgs::Vector{PackageSpec} = PackageSpec[]; header = nothing, mode::PackageMode = PKGMODE_PROJECT, git_diff::Bool = false, env_diff = nothing, ignore_indent = true, - io::IO, workspace::Bool = false, outdated::Bool = false, extensions::Bool = false, hidden_upgrades_info::Bool = false, show_usagetips::Bool = true + io::IO, workspace::Bool = false, outdated::Bool = false, deprecated::Bool = false, extensions::Bool = false, hidden_upgrades_info::Bool = false, show_usagetips::Bool = true ) io == Base.devnull && return # if a package, print header @@ -3223,10 +3262,10 @@ function status( diff = old_env !== nothing header = something(header, diff ? :Diff : :Status) if mode == PKGMODE_PROJECT || mode == PKGMODE_COMBINED - 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) + 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) end if mode == PKGMODE_MANIFEST || mode == PKGMODE_COMBINED - print_status(env, old_env, registries, header, filter_uuids, filter_names; diff, ignore_indent, io, workspace, outdated, extensions, mode, hidden_upgrades_info, show_usagetips) + 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) end return if is_manifest_current(env) === false tip = if show_usagetips diff --git a/src/REPLMode/command_declarations.jl b/src/REPLMode/command_declarations.jl index c6bf19db3a..b818f7344a 100644 --- a/src/REPLMode/command_declarations.jl +++ b/src/REPLMode/command_declarations.jl @@ -435,6 +435,7 @@ compound_declarations = [ PSA[:name => "manifest", :short_name => "m", :api => :mode => PKGMODE_MANIFEST], PSA[:name => "diff", :short_name => "d", :api => :diff => true], PSA[:name => "outdated", :short_name => "o", :api => :outdated => true], + PSA[:name => "deprecated", :api => :deprecated => true], PSA[:name => "compat", :short_name => "c", :api => :compat => true], PSA[:name => "extensions", :short_name => "e", :api => :extensions => true], PSA[:name => "workspace", :api => :workspace => true], @@ -442,9 +443,9 @@ compound_declarations = [ :completions => :complete_installed_packages, :description => "summarize contents of and changes to environment", :help => md""" - [st|status] [-d|--diff] [--workspace] [-o|--outdated] [pkgs...] - [st|status] [-d|--diff] [--workspace] [-o|--outdated] [-p|--project] [pkgs...] - [st|status] [-d|--diff] [--workspace] [-o|--outdated] [-m|--manifest] [pkgs...] + [st|status] [-d|--diff] [--workspace] [-o|--outdated] [--deprecated] [pkgs...] + [st|status] [-d|--diff] [--workspace] [-o|--outdated] [--deprecated] [-p|--project] [pkgs...] + [st|status] [-d|--diff] [--workspace] [-o|--outdated] [--deprecated] [-m|--manifest] [pkgs...] [st|status] [-d|--diff] [--workspace] [-e|--extensions] [-p|--project] [pkgs...] [st|status] [-d|--diff] [--workspace] [-e|--extensions] [-m|--manifest] [pkgs...] [st|status] [-c|--compat] [pkgs...] @@ -455,7 +456,10 @@ compound_declarations = [ constraints. To see why use `pkg> status --outdated` which shows any packages that are not at their latest version and if any packages are holding them back. Packages marked with `[yanked]` have been yanked from the registry and should be - updated or removed. + updated or removed. Packages marked with `[deprecated]` are no longer maintained. + + Use `pkg> status --deprecated` to show only deprecated packages along with deprecation + information such as the reason and alternative packages (if provided by the registry). Use `pkg> status --extensions` to show dependencies with extensions and what extension dependencies of those that are currently loaded. diff --git a/test/registry.jl b/test/registry.jl index 32bcc17f73..1948016ffc 100644 --- a/test/registry.jl +++ b/test/registry.jl @@ -5,6 +5,8 @@ using Pkg, UUIDs, LibGit2, Test using Pkg: depots1 using Pkg.REPLMode: pkgstr using Pkg.Types: PkgError, manifest_info, PackageSpec, EnvCache +using Pkg.Operations: get_pkg_deprecation_info + using Dates: Second using ..Utils @@ -409,6 +411,18 @@ end example1_info = Pkg.Registry.registry_info(example1_entry) @test !Pkg.Registry.isdeprecated(example1_info) @test example1_info.deprecated === nothing + + # Test get_pkg_deprecation_info function + deprecated_pkg_spec = Pkg.Types.PackageSpec(name = "DeprecatedExample", uuid = pkg_uuid) + normal_pkg_spec = Pkg.Types.PackageSpec(name = "Example1", uuid = example1_uuid) + + dep_info = get_pkg_deprecation_info(deprecated_pkg_spec, registries) + @test dep_info !== nothing + @test dep_info["reason"] == "This package is no longer maintained" + @test dep_info["alternative"] == "Example" + + normal_info = get_pkg_deprecation_info(normal_pkg_spec, registries) + @test normal_info === nothing end end