From 3b8d98be0d43fce884d544ee0d4c6b6ee833d900 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Thu, 7 Dec 2017 11:46:34 +0100 Subject: [PATCH] WIP force explicit init using `init` for local env (#51) * force explicit init using `init` for local env * remove try catch, other small fixes --- Project.toml | 9 -------- src/API.jl | 4 ++++ src/Operations.jl | 19 +++++++++++++++- src/Pkg3.jl | 2 +- src/REPLMode.jl | 24 +++++++++++++++++---- src/Types.jl | 54 +++++++++++++++++++++++++++++++++------------- test/operations.jl | 25 ++++++++++++++++++--- 7 files changed, 104 insertions(+), 33 deletions(-) delete mode 100644 Project.toml diff --git a/Project.toml b/Project.toml deleted file mode 100644 index 1ea925ac2c7e7..0000000000000 --- a/Project.toml +++ /dev/null @@ -1,9 +0,0 @@ -authors = "Stefan Karpinski " -desc = "The next-generation Julia package manager." -keywords = ["package", "management"] -license = "MIT" -name = "Pkg3" -repo = "https://github.com/StefanKarpinski/Pkg3.jl.git" - -[deps] -SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce" diff --git a/src/API.jl b/src/API.jl index 2d0bb9679152b..08011f087d05e 100644 --- a/src/API.jl +++ b/src/API.jl @@ -224,5 +224,9 @@ function gc(env::EnvCache=EnvCache(); period = Week(6), preview=env.preview[]) info("Deleted $(length(paths_to_delete)) package installations", byte_save_str) end +function init(path = pwd()) + Pkg3.Operations.init(path) +end + end # module diff --git a/src/Operations.jl b/src/Operations.jl index 17fe445a2a5d6..2290dd68fddf3 100644 --- a/src/Operations.jl +++ b/src/Operations.jl @@ -5,6 +5,7 @@ using Base: LibGit2 using Pkg3.TerminalMenus using Pkg3.Types import Pkg3: Pkg2, depots, BinaryProvider, USE_LIBGIT2_FOR_ALL_DOWNLOADS, NUM_CONCURRENT_DOWNLOADS +import Pkg3: depots, BinaryProvider, USE_LIBGIT2_FOR_ALL_DOWNLOADS, NUM_CONCURRENT_DOWNLOADS const SlugInt = UInt32 # max p = 4 const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" @@ -399,7 +400,8 @@ function apply_versions(env::EnvCache, pkgs::Vector{PackageSpec})::Vector{UUID} end textwidth = VERSION < v"0.7.0-DEV.1930" ? Base.strwidth : Base.textwidth - max_name = maximum(textwidth(names[pkg.uuid]) for pkg in pkgs) + widths = [textwidth(names[pkg.uuid]) for pkg in pkgs] + max_name = length(widths) == 0 ? 0 : maximum(widths) for _ in 1:length(pkgs) r = take!(results) @@ -666,5 +668,20 @@ function test(env::EnvCache, pkgs::Vector{PackageSpec}; coverage=false) " errored during testing") end end + +function init(path::String) + gitpath = nothing + try + gitpath = git_discover(path, ceiling = homedir()) + catch err + err isa LibGit2.GitError && err.code == LibGit2.Error.ENOTFOUND || rethrow(err) + end + path = gitpath == nothing ? path : dirname(dirname(gitpath)) + mkpath(path) + isfile(joinpath(path, "Project.toml")) && cmderror("Environment already initialized at $path") + touch(joinpath(path, "Project.toml")) + info("Initialized environment in $path by creating the file Project.toml") +end + end # module diff --git a/src/Pkg3.jl b/src/Pkg3.jl index 853b3b23606dd..3b652162a8c3b 100644 --- a/src/Pkg3.jl +++ b/src/Pkg3.jl @@ -41,7 +41,7 @@ include("Operations.jl") include("REPLMode.jl") include("API.jl") -import .API: add, rm, up, test, gc +import .API: add, rm, up, test, gc, init const update = up @enum LoadErrorChoice LOAD_ERROR_QUERY LOAD_ERROR_INSTALL LOAD_ERROR_ERROR diff --git a/src/REPLMode.jl b/src/REPLMode.jl index 22e927f384b86..66e82914e2e65 100644 --- a/src/REPLMode.jl +++ b/src/REPLMode.jl @@ -32,6 +32,7 @@ const cmds = Dict( "gc" => :gc, "fsck" => :fsck, "preview" => :preview, + "init" => :init, ) const opts = Dict( @@ -107,9 +108,7 @@ end function do_cmd(repl::Base.REPL.AbstractREPL, input::String) try tokens = tokenize(input) - local env_opt::Union{String,Void} = get(ENV, "JULIA_ENV", nothing) - env = EnvCache(env_opt) - do_cmd!(env, tokens, repl) + do_cmd!(tokens, repl) catch err if err isa CommandError Base.display_error(repl.t.err_stream, ErrorException(err.msg), Ptr{Void}[]) @@ -119,7 +118,7 @@ function do_cmd(repl::Base.REPL.AbstractREPL, input::String) end end -function do_cmd!(env, tokens, repl) +function do_cmd!(tokens, repl) local cmd::Symbol while !isempty(tokens) token = shift!(tokens) @@ -138,6 +137,9 @@ function do_cmd!(env, tokens, repl) cmderror("misplaced token: ", token) end end + cmd == :init && return do_init!(tokens) + local env_opt::Union{String,Void} = get(ENV, "JULIA_ENV", nothing) + env = EnvCache(env_opt) cmd == :help ? do_help!(env, tokens, repl) : cmd == :preview ? do_preview!(env, tokens, repl) : cmd == :rm ? do_rm!(env, tokens) : @@ -191,6 +193,8 @@ const help = Base.Markdown.parse(""" `test`: run tests for packages `gc`: garbage collect packages not used for a significant time + + `init` initializes an environment in the current, or git base, directory """) const helps = Dict( @@ -279,6 +283,11 @@ const helps = Dict( """, :gc => md""" Deletes packages that are not reached from any environment used within the last 6 weeks. + """, :init => md""" + init + + Creates an environment in the current directory, or the git base directory if the current directory + is in a git repository. """ ) @@ -445,6 +454,13 @@ function do_gc!(env::EnvCache, tokens::Vector{Tuple{Symbol,Vararg{Any}}}) Pkg3.API.gc(env) end +function do_init!(tokens::Vector{Tuple{Symbol,Vararg{Any}}}) + if !isempty(tokens) + cmderror("`init` does currently not take any arguments") + end + Pkg3.API.init(pwd()) +end + function create_mode(repl, main) pkg_mode = LineEdit.Prompt("pkg> "; diff --git a/src/Types.jl b/src/Types.jl index fdb9b62d0b40d..094a8bcd8aa01 100644 --- a/src/Types.jl +++ b/src/Types.jl @@ -11,7 +11,7 @@ export SHA1, VersionRange, VersionSpec, PackageSpec, UpgradeLevel, EnvCache, CommandError, cmderror, has_name, has_uuid, write_env, parse_toml, find_registered!, project_resolve!, manifest_resolve!, registry_resolve!, ensure_resolved, manifest_info, registered_uuids, registered_paths, registered_uuid, registered_name, - git_file_stream, read_project, read_manifest, pathrepr, registries + git_file_stream, git_discover, read_project, read_manifest, pathrepr, registries ## ordering of UUIDs ## @@ -390,15 +390,22 @@ function git_file_stream(repo::LibGit2.GitRepo, spec::String; fakeit::Bool=false return IOBuffer(LibGit2.rawcontent(blob)) end -function find_local_env(start_path::String = pwd()) - path = git_discover(start_path, ceiling = homedir()) - repo = LibGit2.GitRepo(path) - work = LibGit2.workdir(repo) +function find_local_env(start_path::String) + work = nothing + repo = nothing + try + gitpath = git_discover(start_path, ceiling = homedir()) + repo = LibGit2.GitRepo(gitpath) + work = LibGit2.workdir(repo) + catch err + err isa LibGit2.GitError && err.code == LibGit2.Error.ENOTFOUND || rethrow(err) + end + work = (work != nothing) ? work : start_path for name in project_names path = abspath(work, name) isfile(path) && return path, repo end - return abspath(work, project_names[end]), repo + return nothing, repo end function find_named_env() @@ -417,19 +424,24 @@ function find_project(env::String) elseif env == "/" return find_named_env() elseif env == "." - return find_local_env() + path, gitrepo = find_local_env(pwd()) + path == nothing && return init_if_interactive(pwd()), gitrepo + return path, gitrepo elseif startswith(env, "/") || startswith(env, "./") # path to project file or project directory if splitext(env)[2] == ".toml" path = abspath(env) - return path, find_git_repo(path) + if isfile(env) + return path, find_git_repo(path) + else + return init_if_interactive(path), find_git_repo(path) + end end for name in project_names path = abspath(env, name) isfile(path) && return path, find_git_repo(path) end - path = abspath(env, project_names[end]) - return path, find_git_repo(path) + return init_if_interactive(env), find_git_repo(path) else # named environment for depot in depots() path = abspath(depot, "environments", env, project_names[end]) @@ -440,12 +452,24 @@ function find_project(env::String) end end -function find_project(::Void) - try return find_local_env() - catch err - err isa LibGit2.GitError && err.code == LibGit2.Error.ENOTFOUND || rethrow(err) +function init_if_interactive(path::String) + if isinteractive() + choice = TerminalMenus.request("Could not find local environment in $(path), do you want to create it?", + TerminalMenus.RadioMenu(["yes", "no"])) + if choice == 1 + Pkg3.Operations.init(pwd()) + path, gitrepo = find_project(path) + return path + end end - return find_named_env() + cmderror("did not find a local environment at $(path), run `init` to create one") +end + +function find_project(::Void) + path, gitrepo = find_local_env(pwd()) + path != nothing && return path, gitrepo + path, gitrepo = find_named_env() + return path, gitrepo end ## resolving packages from name or uuid ## diff --git a/test/operations.jl b/test/operations.jl index f508b93032f41..a13045e2d816c 100644 --- a/test/operations.jl +++ b/test/operations.jl @@ -17,27 +17,28 @@ function temp_pkg_dir(fn::Function) end end +isinstalled(pkg) = Pkg3._find_package(pkg) != nothing + # Tests for Example.jl fail on master, # so let's use another small package # in the meantime const TEST_PKG = "Crayons" temp_pkg_dir() do project_path + Pkg3.init(project_path) Pkg3.add(TEST_PKG; preview = true) @test_warn "not in project" Pkg3.API.rm("Example") Pkg3.add(TEST_PKG) @eval import $(Symbol(TEST_PKG)) Pkg3.up() Pkg3.rm(TEST_PKG; preview = true) - + @test isinstalled(TEST_PKG) # TODO: Check coverage kwargs # TODO: Check that preview = true doesn't actually execute the test # by creating a package with a test file that fails. Pkg3.test(TEST_PKG) Pkg3.test(TEST_PKG; preview = true) - Pkg3.rm(TEST_PKG) - try Pkg3.add([PackageSpec(TEST_PKG, VersionSpec(v"55"))]) catch e @@ -51,6 +52,24 @@ temp_pkg_dir() do project_path @test_throws CommandError Pkg3.add(nonexisting_pkg) @test_throws CommandError Pkg3.up(nonexisting_pkg) @test_warn "not in project" Pkg3.rm(nonexisting_pkg) + + mktempdir() do tmp + LibGit2.init(tmp) + mkdir(joinpath(tmp, "subfolder")) + cd(joinpath(tmp, "subfolder")) do + # Haven't initialized here so using the default env + @test isinstalled(TEST_PKG) + withenv("JULIA_ENV" => nothing) do + Pkg3.init() + @test !isinstalled(TEST_PKG) + @test isfile(joinpath(tmp, "Project.toml")) + end + end + end + + Pkg3.rm(TEST_PKG) + @test !isinstalled(TEST_PKG) + end end # module