From a6dee3c5e8d13e22b5dba1576c4cb41e614bbbdb Mon Sep 17 00:00:00 2001 From: Ian Date: Tue, 29 Dec 2020 16:22:09 -0500 Subject: [PATCH] add REPL hook to prompt to install missing packages, if available in registry --- src/Pkg.jl | 2 ++ src/REPLMode/REPLMode.jl | 41 ++++++++++++++++++++++++++++++++++++++++ test/repl.jl | 5 +++++ 3 files changed, 48 insertions(+) diff --git a/src/Pkg.jl b/src/Pkg.jl index c37d42dfa4..462d2b7d38 100644 --- a/src/Pkg.jl +++ b/src/Pkg.jl @@ -561,6 +561,7 @@ function __init__() end end end + push!(empty!(REPL.install_packages_hooks), REPLMode.try_prompt_pkg_add) OFFLINE_MODE[] = get(ENV, "JULIA_PKG_OFFLINE", nothing) == "true" return nothing end @@ -671,6 +672,7 @@ const precompile_script = """ Pkg.add("TestPkg") Pkg.develop(Pkg.PackageSpec(path="TestPkg.jl")) Pkg.add(Pkg.PackageSpec(path="TestPkg.jl/")) + Pkg.REPLMode.try_prompt_pkg_add(Symbol[:notapackage]) ] add Te\t\t$CTRL_C ] st $CTRL_C diff --git a/src/REPLMode/REPLMode.jl b/src/REPLMode/REPLMode.jl index cc031bf75c..94ab979863 100644 --- a/src/REPLMode/REPLMode.jl +++ b/src/REPLMode/REPLMode.jl @@ -650,4 +650,45 @@ end const help = gen_help() +function try_prompt_pkg_add(pkgs::Vector{Symbol}) + ctx = Context() + available_uuids = [Types.registered_uuids(ctx.registries, String(pkg)) for pkg in pkgs] # vector of vectors + available_pkgs = pkgs[isempty.(available_uuids) .== false] + isempty(available_pkgs) && return false + resp = try + plural1 = length(pkgs) == 1 ? "" : "s" + plural2 = length(available_pkgs) == 1 ? "a package" : "packages" + plural3 = length(available_pkgs) == 1 ? "is" : "are" + plural4 = length(available_pkgs) == 1 ? "" : "s" + missing_pkg_list = length(pkgs) == 1 ? String(pkgs[1]) : "[$(join(pkgs, ", "))]" + available_pkg_list = length(available_pkgs) == 1 ? String(available_pkgs[1]) : "[$(join(available_pkgs, ", "))]" + printstyled(ctx.io, " │ "; color=:green) + println(ctx.io, "Package$(plural1) $(missing_pkg_list) not found,", + " but $(plural2) named $(available_pkg_list) $(plural3) available from a registry.") + printstyled(ctx.io, " │ "; color=:green) + println(ctx.io, "Install package$(plural4)?") + printstyled(ctx.io, " │ "; color=:green) + print(ctx.io, " ") + printstyled(ctx.io, REPLMode.promptf(); color=:blue) + println(ctx.io, "add ", join(available_pkgs, ' ')) + printstyled(ctx.io, " └ "; color=:green) + Base.prompt(stdin, ctx.io, "(y/n)", default = "n") + catch err + if err isa InterruptException + println(ctx.io) + return false + end + rethrow() + end + if lowercase(resp) in ["y", "yes"] + Pkg.add(string.(available_pkgs)) + if length(available_pkgs) < length(pkgs) + return false # declare that some pkgs couldn't be installed + else + return true + end + end + return false +end + end #module diff --git a/test/repl.jl b/test/repl.jl index d29f2d3183..30cb541845 100644 --- a/test/repl.jl +++ b/test/repl.jl @@ -667,4 +667,9 @@ end @inferred Pkg.REPLMode.CompoundSpecs(Pair{String,Vector{Pkg.REPLMode.CommandDeclaration}}[]) end +@testset "REPL missing package install hook" begin + @test Pkg.REPLMode.try_prompt_pkg_add(Symbol[:notapackage]) == false + # cannot test installation of findable packages given requires user input to stdin on the prompt +end + end # module