diff --git a/CHANGELOG.md b/CHANGELOG.md index f247ef9395..ae8a61dfd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,3 +2,4 @@ Pkg v1.7 Release Notes ====================== - Adding packages by folder name in the REPL mode now requires a prepending a `./` to the folder name package folder is in the current folder, e.g. `add ./Package` is required instead of `add Pacakge`. This is to avoid confusion between the package name `Package` and the local directory `Package`. +- `rm`, `pin`, and `free` now support the `--all` option, and the api variants gain the `all_pkgs::Bool` kwarg, to perform the operation on all packages within the project or manifest, depending on the mode of the operation. diff --git a/src/API.jl b/src/API.jl index 12bea14aa1..3cb268d966 100644 --- a/src/API.jl +++ b/src/API.jl @@ -271,7 +271,11 @@ function add(ctx::Context, pkgs::Vector{PackageSpec}; preserve::PreserveLevel=PR return end -function rm(ctx::Context, pkgs::Vector{PackageSpec}; mode=PKGMODE_PROJECT, kwargs...) +function rm(ctx::Context, pkgs::Vector{PackageSpec}; mode=PKGMODE_PROJECT, all_pkgs::Bool=false, kwargs...) + if all_pkgs + !isempty(pkgs) && pkgerror("cannot specify packages when operating on all packages") + append_all_pkgs!(pkgs, ctx, mode) + end require_not_empty(pkgs, :rm) pkgs = deepcopy(pkgs) # deepcopy for avoid mutating PackageSpec members foreach(pkg -> pkg.mode = mode, pkgs) @@ -297,6 +301,20 @@ function rm(ctx::Context, pkgs::Vector{PackageSpec}; mode=PKGMODE_PROJECT, kwarg return end +function append_all_pkgs!(pkgs, ctx, mode) + if mode == PKGMODE_PROJECT || mode == PKGMODE_COMBINED + for (name::String, uuid::UUID) in ctx.env.project.deps + push!(pkgs, PackageSpec(name=name, uuid=uuid)) + end + end + if mode == PKGMODE_MANIFEST || mode == PKGMODE_COMBINED + for (uuid, entry) in ctx.env.manifest + push!(pkgs, PackageSpec(name=entry.name, uuid=uuid)) + end + end + return +end + function up(ctx::Context, pkgs::Vector{PackageSpec}; level::UpgradeLevel=UPLEVEL_MAJOR, mode::PackageMode=PKGMODE_PROJECT, update_registry::Bool=true, kwargs...) @@ -311,15 +329,7 @@ function up(ctx::Context, pkgs::Vector{PackageSpec}; end Operations.prune_manifest(ctx.env) if isempty(pkgs) - if mode == PKGMODE_PROJECT - for (name::String, uuid::UUID) in ctx.env.project.deps - push!(pkgs, PackageSpec(name=name, uuid=uuid)) - end - elseif mode == PKGMODE_MANIFEST - for (uuid, entry) in ctx.env.manifest - push!(pkgs, PackageSpec(name=entry.name, uuid=uuid)) - end - end + append_all_pkgs!(pkgs, ctx, mode) else project_deps_resolve!(ctx.env, pkgs) manifest_resolve!(ctx.env.manifest, pkgs) @@ -335,7 +345,11 @@ function resolve(ctx::Context; kwargs...) return nothing end -function pin(ctx::Context, pkgs::Vector{PackageSpec}; kwargs...) +function pin(ctx::Context, pkgs::Vector{PackageSpec}; all_pkgs::Bool=false, kwargs...) + if all_pkgs + !isempty(pkgs) && pkgerror("cannot specify packages when operating on all packages") + append_all_pkgs!(pkgs, ctx, PKGMODE_PROJECT) + end require_not_empty(pkgs, :pin) pkgs = deepcopy(pkgs) # deepcopy for avoid mutating PackageSpec members Context!(ctx; kwargs...) @@ -364,7 +378,11 @@ function pin(ctx::Context, pkgs::Vector{PackageSpec}; kwargs...) return end -function free(ctx::Context, pkgs::Vector{PackageSpec}; kwargs...) +function free(ctx::Context, pkgs::Vector{PackageSpec}; all_pkgs::Bool=false, kwargs...) + if all_pkgs + !isempty(pkgs) && pkgerror("cannot specify packages when operating on all packages") + append_all_pkgs!(pkgs, ctx, PKGMODE_PROJECT) + end require_not_empty(pkgs, :free) pkgs = deepcopy(pkgs) # deepcopy for avoid mutating PackageSpec members Context!(ctx; kwargs...) diff --git a/src/REPLMode/command_declarations.jl b/src/REPLMode/command_declarations.jl index 46e44d0149..8fcc965b0d 100644 --- a/src/REPLMode/command_declarations.jl +++ b/src/REPLMode/command_declarations.jl @@ -60,16 +60,18 @@ PSA[:name => "remove", :short_name => "rm", :api => API.rm, :should_splat => false, - :arg_count => 1 => Inf, + :arg_count => 0 => Inf, :arg_parser => parse_package, :option_spec => [ PSA[:name => "project", :short_name => "p", :api => :mode => PKGMODE_PROJECT], PSA[:name => "manifest", :short_name => "m", :api => :mode => PKGMODE_MANIFEST], + PSA[:name => "all", :api => :all_pkgs => true], ], :completions => complete_installed_packages, :description => "remove packages from project or manifest", :help => md""" [rm|remove] [-p|--project] pkg[=uuid] ... + [rm|remove] [-p|--project] [--all] Remove package `pkg` from the project file. Since the name `pkg` can only refer to one package in a project this is unambiguous, but you can specify @@ -78,14 +80,16 @@ and UUID do not match. When a package is removed from the project file, it may still remain in the manifest if it is required by some other package in the project. Project mode operation is the default, so passing `-p` or `--project` is optional unless it is preceded by the `-m` or `--manifest` -options at some earlier point. +options at some earlier point. All packages can be removed by passing `--all`. [rm|remove] [-m|--manifest] pkg[=uuid] ... + [rm|remove] [-m|--manifest] [--all] Remove package `pkg` from the manifest file. If the name `pkg` refers to multiple packages in the manifest, `uuid` disambiguates it. Removing a package from the manifest forces the removal of all packages that depend on it, as well as any no-longer-necessary manifest packages due to project package removals. +All packages can be removed by passing `--all`. """, ], PSA[:name => "add", @@ -176,26 +180,34 @@ pkg> develop --local Example PSA[:name => "free", :api => API.free, :should_splat => false, - :arg_count => 1 => Inf, + :arg_count => 0 => Inf, + :option_spec => [ + PSA[:name => "all", :api => :all_pkgs => true], + ], :arg_parser => parse_package, :completions => complete_installed_packages, :description => "undoes a `pin`, `develop`, or stops tracking a repo", :help => md""" free pkg[=uuid] ... + free [--all] -Free a pinned package `pkg`, which allows it to be upgraded or downgraded again. If the package is checked out (see `help develop`) then this command +Free pinned packages, which allows it to be upgraded or downgraded again. If the package is checked out (see `help develop`) then this command makes the package no longer being checked out. """, ], PSA[:name => "pin", :api => API.pin, :should_splat => false, - :arg_count => 1 => Inf, + :arg_count => 0 => Inf, + :option_spec => [ + PSA[:name => "all", :api => :all_pkgs => true], + ], :arg_parser => parse_package, :completions => complete_installed_packages, :description => "pins the version of packages", :help => md""" pin pkg[=uuid] ... + pin [--all] Pin packages to given versions, or the current version if no version is specified. A pinned package has its version fixed and will not be upgraded or downgraded. A pinned package has the symbol `⚲` next to its version in the status list. @@ -205,6 +217,7 @@ A pinned package has the symbol `⚲` next to its version in the status list. pkg> pin Example pkg> pin Example@0.5.0 pkg> pin Example=7876af07-990d-54b4-ab0e-23690620f79a@0.5.0 +pkg> pin --all ``` """, ], diff --git a/test/new.jl b/test/new.jl index 56cef77a87..841c1c0559 100644 --- a/test/new.jl +++ b/test/new.jl @@ -1760,6 +1760,41 @@ end end end +# +# # `all` operations +# +@testset "all" begin + # pin all, free all, rm all packages + isolate(loaded_depot=true) do + Pkg.add("Example") + Pkg.pin(all_pkgs = true) + Pkg.free(all_pkgs = true) + Pkg.dependencies(exuuid) do pkg + @test pkg.name == "Example" + @test !pkg.is_pinned + end + Pkg.rm(all_pkgs = true) + @test !haskey(Pkg.dependencies(), exuuid) + end + isolate() do + Pkg.REPLMode.TEST_MODE[] = true + api, args, opts = first(Pkg.pkg"pin --all") + @test api == Pkg.pin + @test isempty(args) + @test opts == Dict(:all_pkgs => true) + + api, args, opts = first(Pkg.pkg"free --all") + @test api == Pkg.free + @test isempty(args) + @test opts == Dict(:all_pkgs => true) + + api, args, opts = first(Pkg.pkg"rm --all") + @test api == Pkg.rm + @test isempty(args) + @test opts == Dict(:all_pkgs => true) + end +end + # # # build #