From ddce02d3428549b52ebbea91c71d7af92c5fe10f Mon Sep 17 00:00:00 2001 From: Valentin Churavy Date: Thu, 2 Aug 2018 18:08:23 -0700 Subject: [PATCH 01/36] add OPENBLAS_NO_AVX512 build option (#28414) (cherry picked from commit b70d21490b9572170da402bc19d15236b9605b3d) --- deps/blas.mk | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/deps/blas.mk b/deps/blas.mk index 6035954cb4faa..26e985be75869 100644 --- a/deps/blas.mk +++ b/deps/blas.mk @@ -73,9 +73,11 @@ endif # Allow disabling AVX for older binutils ifeq ($(OPENBLAS_NO_AVX), 1) -OPENBLAS_BUILD_OPTS += NO_AVX=1 NO_AVX2=1 +OPENBLAS_BUILD_OPTS += NO_AVX=1 NO_AVX2=1 NO_AVX512=1 else ifeq ($(OPENBLAS_NO_AVX2), 1) -OPENBLAS_BUILD_OPTS += NO_AVX2=1 +OPENBLAS_BUILD_OPTS += NO_AVX2=1 NO_AVX512=1 +else ifeq ($(OPENBLAS_NO_AVX512), 1) +OPENBLAS_BUILD_OPTS += NO_AVX512=1 endif # Do not overwrite the "-j" flag From 5da9fe75c45616dd547629d31ce68e3f7a1fa141 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Fri, 3 Aug 2018 10:56:26 +0200 Subject: [PATCH 02/36] emit precompile statements to separate file (#28419) if the filename to trace--compile is stdout, print to the stdout stream (cherry picked from commit cfc747599d665c7ffef6b76fc3ac4b74dbb3ded3) --- base/options.jl | 2 +- contrib/generate_precompile.jl | 98 +++++++++++++++++----------------- contrib/precompile_explicit.jl | 2 +- src/gf.c | 25 +++++++-- src/jloptions.c | 16 ++---- src/julia.h | 2 +- src/options.h | 1 - 7 files changed, 76 insertions(+), 70 deletions(-) diff --git a/base/options.jl b/base/options.jl index 0abf2d55fd866..0706b1c07d72f 100644 --- a/base/options.jl +++ b/base/options.jl @@ -26,7 +26,7 @@ struct JLOptions warn_overwrite::Int8 can_inline::Int8 polly::Int8 - trace_compile::Int8 + trace_compile::Ptr{UInt8} fast_math::Int8 worker::Int8 cookie::Ptr{UInt8} diff --git a/contrib/generate_precompile.jl b/contrib/generate_precompile.jl index e109d5c77056f..30aaa085d568c 100644 --- a/contrib/generate_precompile.jl +++ b/contrib/generate_precompile.jl @@ -82,65 +82,63 @@ function generate_precompile_statements() print("Generating precompile statements...") sysimg = isempty(ARGS) ? joinpath(dirname(Sys.BINDIR), "lib", "julia", "sys.ji") : ARGS[1] - # Run a repl process and replay our script - stdout_accumulator, stderr_accumulator = IOBuffer(), IOBuffer() - with_fake_pty() do slave, master - with_fake_pty() do slave_err, master_err - done = false - withenv("JULIA_HISTORY" => tempname(), "JULIA_PROJECT" => nothing, - "TERM" => "") do - p = run(`$(julia_cmd()) -O0 --trace-compile=yes --sysimage $sysimg - --startup-file=no --color=yes`, - slave, slave, slave_err; wait=false) - readuntil(master, "julia>", keep=true) - for (tty, accumulator) in (master => stdout_accumulator, - master_err => stderr_accumulator) - @async begin - while true - done && break - write(accumulator, readavailable(tty)) + mktemp() do precompile_file, _ + # Run a repl process and replay our script + stdout_accumulator, stderr_accumulator = IOBuffer(), IOBuffer() + with_fake_pty() do slave, master + with_fake_pty() do slave_err, master_err + done = false + withenv("JULIA_HISTORY" => tempname(), "JULIA_PROJECT" => nothing, + "TERM" => "") do + p = run(`$(julia_cmd()) -O0 --trace-compile=$precompile_file --sysimage $sysimg + --startup-file=no --color=yes`, + slave, slave, slave_err; wait=false) + readuntil(master, "julia>", keep=true) + for (tty, accumulator) in (master => stdout_accumulator, + master_err => stderr_accumulator) + @async begin + while true + done && break + write(accumulator, readavailable(tty)) + end end end - end - if have_repl - for l in split(precompile_script, '\n'; keepempty=false) - write(master, l, '\n') + if have_repl + for l in split(precompile_script, '\n'; keepempty=false) + write(master, l, '\n') + end end + write(master, "exit()\n") + wait(p) + done = true end - write(master, "exit()\n") - wait(p) - done = true end end - end - stderr_output = String(take!(stderr_accumulator)) - # println(stderr_output) - # stdout_output = String(take!(stdout_accumulator)) - # println(stdout_output) - - # Extract the precompile statements from stderr - statements = Set{String}() - for statement in split(stderr_output, '\n') - m = match(r"(precompile\(Tuple{.*)", statement) - m === nothing && continue - statement = m.captures[1] - occursin(r"Main.", statement) && continue - push!(statements, statement) - end + # Check what the REPL displayed + # stdout_output = String(take!(stdout_accumulator)) + # println(stdout_output) - # Load the precompile statements - statements_ordered = join(sort(collect(statements)), '\n') - # println(statements_ordered) - if have_repl - # Seems like a reasonable number right now, adjust as needed - @assert length(statements) > 700 - end + # Extract the precompile statements from stderr + statements = Set{String}() + for statement in split(read(precompile_file, String), '\n') + occursin("Main.", statement) && continue + push!(statements, statement) + end + + # Load the precompile statements + statements_ordered = join(sort(collect(statements)), '\n') + # println(statements_ordered) + if have_repl + # Seems like a reasonable number right now, adjust as needed + @assert length(statements) > 700 + end - Base.include_string(PrecompileStagingArea, statements_ordered) - print(" $(length(statements)) generated in ") - Base.time_print((time() - start_time) * 10^9) - println() + Base.include_string(PrecompileStagingArea, statements_ordered) + print(" $(length(statements)) generated in ") + Base.time_print((time() - start_time) * 10^9) + println() + end end # Fall back to explicit list on Windows, might as well include them diff --git a/contrib/precompile_explicit.jl b/contrib/precompile_explicit.jl index b8adb344f2c16..f0d83e491b7eb 100644 --- a/contrib/precompile_explicit.jl +++ b/contrib/precompile_explicit.jl @@ -3,7 +3,7 @@ # Steps to regenerate this file: # 1. Remove all `precompile` calls # 2. Rebuild system image -# 3. Start julia with `--trace-compile=yes and do some stuff +# 3. Start julia with `--trace-compile=precompiles.txt and do some stuff # 5. Run `grep -v '#[0-9]' precompiles.txt >> contrib/precompile_explicit.jl` # (filters out closures, which might have different generated names in different environments) # This list is only used on Windows, otherwise precompile statements are generated dynamically. diff --git a/src/gf.c b/src/gf.c index bb96cd3a721f0..c179563422013 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1071,6 +1071,10 @@ static jl_method_instance_t *cache_method( static jl_method_instance_t *jl_mt_assoc_by_type(jl_methtable_t *mt, jl_datatype_t *tt, int mt_cache, int allow_exec, size_t world) { + // TODO: Merge with jl_dump_compiles? + static ios_t f_precompile; + static JL_STREAM* s_precompile = NULL; + // caller must hold the mt->writelock jl_typemap_entry_t *entry = NULL; entry = jl_typemap_assoc_by_type(mt->cache, (jl_value_t*)tt, NULL, /*subtype*/1, jl_cachearg_offset(mt), world, /*max_world_mask*/0); @@ -1088,11 +1092,24 @@ static jl_method_instance_t *jl_mt_assoc_by_type(jl_methtable_t *mt, jl_datatype if (entry != NULL) { jl_method_t *m = entry->func.method; if (!jl_has_call_ambiguities((jl_value_t*)tt, m)) { - if (jl_options.trace_compile) { + if (jl_options.trace_compile != NULL) { + if (s_precompile == NULL) { + const char* t = jl_options.trace_compile; + if (!strncmp(t, "stderr", 6)) + s_precompile = JL_STDERR; + else { + if (ios_file(&f_precompile, t, 1, 1, 1, 1) == NULL) + jl_errorf("cannot open precompile statement file \"%s\" for writing", t); + s_precompile = (JL_STREAM*) &f_precompile; + } + } if (!jl_has_free_typevars((jl_value_t*)tt)) { - jl_printf(JL_STDERR, "precompile("); - jl_static_show(JL_STDERR, (jl_value_t*)tt); - jl_printf(JL_STDERR, ")\n"); + jl_printf(s_precompile, "precompile("); + jl_static_show(s_precompile, (jl_value_t*)tt); + jl_printf(s_precompile, ")\n"); + + if (s_precompile != JL_STDERR) + ios_flush(&f_precompile); } } if (!mt_cache) { diff --git a/src/jloptions.c b/src/jloptions.c index 9d2a30e2d0fa7..aeefc20c24892 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -55,11 +55,7 @@ jl_options_t jl_options = { 0, // quiet 0, // method overwrite warning 1, // can_inline JL_OPTIONS_POLLY_ON, // polly -#ifdef TRACE_COMPILE - 1, // trace_compile -#else - 0, // trace_compile -#endif + NULL, // trace_compile JL_OPTIONS_FAST_MATH_DEFAULT, 0, // worker NULL, // cookie @@ -575,13 +571,9 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) } break; case opt_trace_compile: - if (!strcmp(optarg,"yes")) - jl_options.trace_compile = 1; - else if (!strcmp(optarg,"no")) - jl_options.trace_compile = 0; - else { - jl_errorf("julia: invalid argument to --trace-compile (%s)", optarg); - } + jl_options.trace_compile = strdup(optarg); + if (!jl_options.trace_compile) + jl_errorf("fatal error: failed to allocate memory: %s", strerror(errno)); break; case opt_math_mode: if (!strcmp(optarg,"ieee")) diff --git a/src/julia.h b/src/julia.h index a49bd51db1853..bcf1d1050dc21 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1799,7 +1799,7 @@ typedef struct { int8_t warn_overwrite; int8_t can_inline; int8_t polly; - int8_t trace_compile; + const char *trace_compile; int8_t fast_math; int8_t worker; const char *cookie; diff --git a/src/options.h b/src/options.h index a669ade52ce43..b860edecce3dc 100644 --- a/src/options.h +++ b/src/options.h @@ -89,7 +89,6 @@ // print all signatures type inference is invoked on //#define TRACE_INFERENCE -//#define TRACE_COMPILE // print all generic method dispatches (excludes inlined and specialized call // sites). this generally prints too much output to be useful. From 156fc0437650c4058249c3f4caf11f47c09ea928 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Thu, 2 Aug 2018 23:10:44 -0400 Subject: [PATCH 03/36] Try to fix deadlock in code loading (#28416) If a precompiled package's init function tries to itself require that package (e.g. by importing a symbol from a submodule of that package), we would run into a deadlock. Fix that by delaying the running of initializers until after we've had a chance to register any root module. Fixes #26028 (cherry picked from commit 0e32871bfcee426fc4bf8c5d70af3f472b069868) --- base/loading.jl | 4 +++- src/dump.c | 6 +++--- test/precompile.jl | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/base/loading.jl b/base/loading.jl index ae913e58a73cb..10f1f555033f2 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -611,7 +611,8 @@ end # or an Exception that describes why it couldn't be loaded # and it reconnects the Base.Docs.META function _include_from_serialized(path::String, depmods::Vector{Any}) - restored = ccall(:jl_restore_incremental, Any, (Cstring, Any), path, depmods) + sv = ccall(:jl_restore_incremental, Any, (Cstring, Any), path, depmods) + restored = sv[1] if !isa(restored, Exception) for M in restored::Vector{Any} M = M::Module @@ -623,6 +624,7 @@ function _include_from_serialized(path::String, depmods::Vector{Any}) end end end + isassigned(sv, 2) && ccall(:jl_init_restored_modules, Cvoid, (Any,), sv[2]) return restored end diff --git a/src/dump.c b/src/dump.c index bd82b0237bfad..d1eddab89eb0f 100644 --- a/src/dump.c +++ b/src/dump.c @@ -2402,7 +2402,7 @@ static jl_array_t *jl_finalize_deserializer(jl_serializer_state *s, arraylist_t return init_order; } -static void jl_init_restored_modules(jl_array_t *init_order) +JL_DLLEXPORT void jl_init_restored_modules(jl_array_t *init_order) { if (!init_order) return; @@ -3118,10 +3118,10 @@ static jl_value_t *_jl_restore_incremental(ios_t *f, jl_array_t *mod_array) arraylist_free(tracee_list); free(tracee_list); } - jl_init_restored_modules(init_order); + jl_value_t *ret = (jl_value_t*)jl_svec(2, restored, init_order); JL_GC_POP(); - return (jl_value_t*)restored; + return (jl_value_t*)ret; } JL_DLLEXPORT jl_value_t *jl_restore_incremental_from_buf(const char *buf, size_t sz, jl_array_t *mod_array) diff --git a/test/precompile.jl b/test/precompile.jl index b88651e9afd38..fa44c465960aa 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -700,4 +700,41 @@ let end end +let + load_path = mktempdir() + load_cache_path = mktempdir() + try + write(joinpath(load_path, "Foo26028.jl"), + """ + module Foo26028 + + module Bar26028 + x = 0 + end + + function __init__() + include(joinpath(@__DIR__, "Baz26028.jl")) + end + + end + """) + write(joinpath(load_path, "Baz26028.jl"), + """ + module Baz26028 + import Foo26028.Bar26028.x + end + """) + + pushfirst!(LOAD_PATH, load_path) + pushfirst!(DEPOT_PATH, load_cache_path) + + Base.compilecache(Base.PkgId("Foo26028")) + @test_nowarn @eval using Foo26028 + finally + rm(load_path, recursive=true) + rm(load_cache_path, recursive=true) + end +end + + end # !withenv From ed88ef404ccb1d235b850067cdca9ce8d109eb6f Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 3 Aug 2018 16:24:52 -0400 Subject: [PATCH 04/36] disable FileWatching tests that fail on mac (#26725) (#28411) (cherry picked from commit 785b82de85058f0a696d04ab3156b6b5977447e9) --- stdlib/FileWatching/test/runtests.jl | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/stdlib/FileWatching/test/runtests.jl b/stdlib/FileWatching/test/runtests.jl index 9673162335936..4696e5ed43d12 100644 --- a/stdlib/FileWatching/test/runtests.jl +++ b/stdlib/FileWatching/test/runtests.jl @@ -398,11 +398,17 @@ let changes = [] @test pop!(changes) == ("" => FileWatching.FileEvent()) if F_GETPATH Sys.iswindows() && @test pop!(changes) == (F_PATH => FileWatching.FileEvent(FileWatching.UV_CHANGE)) - @test pop!(changes) == (F_PATH => FileWatching.FileEvent(FileWatching.UV_RENAME)) + p = pop!(changes) + if !Sys.isapple() + @test p == (F_PATH => FileWatching.FileEvent(FileWatching.UV_RENAME)) + end while changes[end][1] == F_PATH @test pop!(changes)[2] == FileWatching.FileEvent(FileWatching.UV_RENAME) end - @test pop!(changes) == (F_PATH * "~" => FileWatching.FileEvent(FileWatching.UV_RENAME)) + p = pop!(changes) + if !Sys.isapple() + @test p == (F_PATH * "~" => FileWatching.FileEvent(FileWatching.UV_RENAME)) + end while changes[end][1] == F_PATH * "~" @test pop!(changes)[2] == FileWatching.FileEvent(FileWatching.UV_RENAME) end @@ -414,7 +420,10 @@ let changes = [] while changes[end - 1][1] == "$F_PATH$i" @test let x = pop!(changes)[2]; x.changed ⊻ x.renamed; end end - @test pop!(changes) == ("$F_PATH$i" => FileWatching.FileEvent(FileWatching.UV_RENAME)) + p = pop!(changes) + if !Sys.isapple() + @test p == ("$F_PATH$i" => FileWatching.FileEvent(FileWatching.UV_RENAME)) + end end end end From f0d07835c6f10813800900470b5dc9291f25cb1b Mon Sep 17 00:00:00 2001 From: Christian Kurz Date: Fri, 3 Aug 2018 23:16:22 +0200 Subject: [PATCH 05/36] fix pkg3 docs typo (#28422) * Update index.md (cherry picked from commit a4518015f9367d6d5f6697caead0d5bb41a7077b) --- stdlib/Pkg/docs/src/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/Pkg/docs/src/index.md b/stdlib/Pkg/docs/src/index.md index 571f4f157a81a..d49966113830a 100644 --- a/stdlib/Pkg/docs/src/index.md +++ b/stdlib/Pkg/docs/src/index.md @@ -695,7 +695,7 @@ Testing... Sometimes one might want to use some packages only at testing time but not enforce a dependency on them when the package is used. This is possible by -adding `[extra]` dependencies and adding a a "test target" to the Project file. +adding dependencies to `[extras]` and a `test` target in `[targets]` to the Project file. Here we add the `Test` standard library as a test-only dependency by adding the following to the Project file: From e5ae99ee0f0e349c85aba37228554e20084e214a Mon Sep 17 00:00:00 2001 From: Curtis Vogt Date: Sat, 4 Aug 2018 02:20:02 -0500 Subject: [PATCH 06/36] Cache credentials on Pkg up (#28437) Avoids asking the user for their credentials multiple times for the same domain. (cherry picked from commit 1dfc4d1fb05e0a1dcc41d782998c1055bb7b050a) --- stdlib/Pkg/src/Operations.jl | 53 +++++++++++++++++++----------------- stdlib/Pkg/src/Types.jl | 8 ++++-- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/stdlib/Pkg/src/Operations.jl b/stdlib/Pkg/src/Operations.jl index 547cebdc75842..63cf3ad6f273a 100644 --- a/stdlib/Pkg/src/Operations.jl +++ b/stdlib/Pkg/src/Operations.jl @@ -1162,33 +1162,36 @@ end function up(ctx::Context, pkgs::Vector{PackageSpec}) # resolve upgrade levels to version specs new_git = UUID[] - for pkg in pkgs - if pkg.uuid in keys(ctx.stdlibs) - pkg.version = VersionSpec() - continue - end - pkg.version isa UpgradeLevel || continue - level = pkg.version - info = manifest_info(ctx.env, pkg.uuid) - if info !== nothing && haskey(info, "repo-url") - pkg.repo = Types.GitRepo(info["repo-url"], info["repo-rev"]) - new = handle_repos_add!(ctx, [pkg]; upgrade_or_add = (level == UPLEVEL_MAJOR)) - append!(new_git, new) - else - if info !== nothing - pkg.uuid in keys(ctx.stdlibs) && continue - ver = VersionNumber(info["version"]) - if level == UPLEVEL_FIXED - pkg.version = VersionNumber(info["version"]) + Base.shred!(LibGit2.CachedCredentials()) do creds + for pkg in pkgs + if pkg.uuid in keys(ctx.stdlibs) + pkg.version = VersionSpec() + continue + end + pkg.version isa UpgradeLevel || continue + level = pkg.version + info = manifest_info(ctx.env, pkg.uuid) + if info !== nothing && haskey(info, "repo-url") + pkg.repo = Types.GitRepo(info["repo-url"], info["repo-rev"]) + new = handle_repos_add!(ctx, [pkg]; credentials=creds, + upgrade_or_add = (level == UPLEVEL_MAJOR)) + append!(new_git, new) + else + if info !== nothing + pkg.uuid in keys(ctx.stdlibs) && continue + ver = VersionNumber(info["version"]) + if level == UPLEVEL_FIXED + pkg.version = VersionNumber(info["version"]) + else + r = level == UPLEVEL_PATCH ? VersionRange(ver.major, ver.minor) : + level == UPLEVEL_MINOR ? VersionRange(ver.major) : + level == UPLEVEL_MAJOR ? VersionRange() : + error("unexpected upgrade level: $level") + pkg.version = VersionSpec(r) + end else - r = level == UPLEVEL_PATCH ? VersionRange(ver.major, ver.minor) : - level == UPLEVEL_MINOR ? VersionRange(ver.major) : - level == UPLEVEL_MAJOR ? VersionRange() : - error("unexpected upgrade level: $level") - pkg.version = VersionSpec(r) + pkg.version = VersionSpec() end - else - pkg.version = VersionSpec() end end end diff --git a/stdlib/Pkg/src/Types.jl b/stdlib/Pkg/src/Types.jl index 0a247849650d7..d1e6f5b025269 100644 --- a/stdlib/Pkg/src/Types.jl +++ b/stdlib/Pkg/src/Types.jl @@ -577,10 +577,12 @@ function handle_repos_develop!(ctx::Context, pkgs::AbstractVector{PackageSpec}, end end -function handle_repos_add!(ctx::Context, pkgs::AbstractVector{PackageSpec}; upgrade_or_add::Bool=true) +function handle_repos_add!(ctx::Context, pkgs::AbstractVector{PackageSpec}; + upgrade_or_add::Bool=true, credentials=nothing) # Always update the registry when adding UPDATED_REGISTRY_THIS_SESSION[] || Pkg.API.update_registry(ctx) - Base.shred!(LibGit2.CachedCredentials()) do creds + creds = credentials !== nothing ? credentials : LibGit2.CachedCredentials() + try env = ctx.env new_uuids = UUID[] for pkg in pkgs @@ -670,6 +672,8 @@ function handle_repos_add!(ctx::Context, pkgs::AbstractVector{PackageSpec}; upgr @assert pkg.version isa VersionNumber end return new_uuids + finally + creds !== credentials && Base.shred!(creds) end end From fd4b4f3aff6176214c3e7fda13a6e845ebb60e42 Mon Sep 17 00:00:00 2001 From: Curtis Vogt Date: Sat, 4 Aug 2018 10:27:31 -0500 Subject: [PATCH 07/36] Shred overwritten cached credentials (#28436) (cherry picked from commit dd248bf06c6d136ebc214c10f52730be362d290a) --- stdlib/LibGit2/src/types.jl | 4 ++++ stdlib/LibGit2/test/libgit2.jl | 22 ++++++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/stdlib/LibGit2/src/types.jl b/stdlib/LibGit2/src/types.jl index 3348206ffa477..acda07af84f19 100644 --- a/stdlib/LibGit2/src/types.jl +++ b/stdlib/LibGit2/src/types.jl @@ -1303,6 +1303,9 @@ end function approve(cache::CachedCredentials, cred::AbstractCredential, url::AbstractString) cred_id = credential_identifier(url) + if haskey(cache.cred, cred_id) && cred !== cache.cred[cred_id] + Base.shred!(cache.cred[cred_id]) + end cache.cred[cred_id] = cred nothing end @@ -1310,6 +1313,7 @@ end function reject(cache::CachedCredentials, cred::AbstractCredential, url::AbstractString) cred_id = credential_identifier(url) if haskey(cache.cred, cred_id) + Base.shred!(cache.cred[cred_id]) delete!(cache.cred, cred_id) end nothing diff --git a/stdlib/LibGit2/test/libgit2.jl b/stdlib/LibGit2/test/libgit2.jl index 78251599e264c..806ad65cf5433 100644 --- a/stdlib/LibGit2/test/libgit2.jl +++ b/stdlib/LibGit2/test/libgit2.jl @@ -1734,14 +1734,28 @@ mktempdir() do dir @test haskey(cache, cred_id) @test cache[cred_id] === cred - # Reject an approved should cause it to be removed + # Approve the same credential again which does not overwrite + LibGit2.approve(cache, cred, url) + @test haskey(cache, cred_id) + @test cache[cred_id] === cred + + # Overwrite an already cached credential + dup_cred = deepcopy(cred) + LibGit2.approve(cache, dup_cred, url) # Shreds `cred` + @test haskey(cache, cred_id) + @test cache[cred_id] === dup_cred + @test dup_cred.pass == password + @test cred.pass != password + + cred = dup_cred + + # Reject an approved should cause it to be removed and shredded LibGit2.reject(cache, cred, url) @test !haskey(cache, cred_id) - @test cred.user == "julia" - @test cred.pass == password + @test cred.user != "julia" + @test cred.pass != password Base.shred!(cache) - Base.shred!(cred) Base.shred!(password) end From 773cd2131d5ff90899be294548aeb833fb760f75 Mon Sep 17 00:00:00 2001 From: Curtis Vogt Date: Sun, 5 Aug 2018 05:50:37 -0500 Subject: [PATCH 08/36] Avoid possible shredding of passed cred on reject (#28448) (cherry picked from commit 696700fee56a65f1e11a736cde7a4beb14080963) --- stdlib/LibGit2/src/types.jl | 12 +++++++++--- stdlib/LibGit2/test/libgit2.jl | 23 +++++++++++++++++++---- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/stdlib/LibGit2/src/types.jl b/stdlib/LibGit2/src/types.jl index acda07af84f19..e6bee7a03be41 100644 --- a/stdlib/LibGit2/src/types.jl +++ b/stdlib/LibGit2/src/types.jl @@ -1303,8 +1303,9 @@ end function approve(cache::CachedCredentials, cred::AbstractCredential, url::AbstractString) cred_id = credential_identifier(url) - if haskey(cache.cred, cred_id) && cred !== cache.cred[cred_id] - Base.shred!(cache.cred[cred_id]) + if haskey(cache.cred, cred_id) + # Shred the cached credential we'll be overwriting if it isn't identical + cred !== cache.cred[cred_id] && Base.shred!(cache.cred[cred_id]) end cache.cred[cred_id] = cred nothing @@ -1313,7 +1314,8 @@ end function reject(cache::CachedCredentials, cred::AbstractCredential, url::AbstractString) cred_id = credential_identifier(url) if haskey(cache.cred, cred_id) - Base.shred!(cache.cred[cred_id]) + # Shred the cached credential if it isn't the `cred` passed in + cred !== cache.cred[cred_id] && Base.shred!(cache.cred[cred_id]) delete!(cache.cred, cred_id) end nothing @@ -1413,6 +1415,8 @@ function approve(p::CredentialPayload; shred::Bool=true) cred = p.credential cred === nothing && return # No credential was used + # Each `approve` call needs to avoid shredding the passed in credential as we need + # the credential information intact for subsequent approve calls. if p.cache !== nothing approve(p.cache, cred, p.url) shred = false # Avoid wiping `cred` as this would also wipe the cached copy @@ -1441,6 +1445,8 @@ function reject(p::CredentialPayload; shred::Bool=true) cred = p.credential cred === nothing && return # No credential was used + # Note: each `reject` call needs to avoid shredding the passed in credential as we need + # the credential information intact for subsequent reject calls. if p.cache !== nothing reject(p.cache, cred, p.url) end diff --git a/stdlib/LibGit2/test/libgit2.jl b/stdlib/LibGit2/test/libgit2.jl index 806ad65cf5433..b3a243289e0e8 100644 --- a/stdlib/LibGit2/test/libgit2.jl +++ b/stdlib/LibGit2/test/libgit2.jl @@ -1741,20 +1741,35 @@ mktempdir() do dir # Overwrite an already cached credential dup_cred = deepcopy(cred) - LibGit2.approve(cache, dup_cred, url) # Shreds `cred` + LibGit2.approve(cache, dup_cred, url) # Shreds overwritten `cred` @test haskey(cache, cred_id) @test cache[cred_id] === dup_cred - @test dup_cred.pass == password + @test cred.user != "julia" @test cred.pass != password + @test dup_cred.user == "julia" + @test dup_cred.pass == password cred = dup_cred - # Reject an approved should cause it to be removed and shredded - LibGit2.reject(cache, cred, url) + # Reject an approved credential + @test cache[cred_id] === cred + LibGit2.reject(cache, cred, url) # Avoids shredding the credential passed in + @test !haskey(cache, cred_id) + @test cred.user == "julia" + @test cred.pass == password + + # Reject and shred an approved credential + dup_cred = deepcopy(cred) + LibGit2.approve(cache, cred, url) + + LibGit2.reject(cache, dup_cred, url) # Shred `cred` but not passed in `dup_cred` @test !haskey(cache, cred_id) @test cred.user != "julia" @test cred.pass != password + @test dup_cred.user == "julia" + @test dup_cred.pass == password + Base.shred!(dup_cred) Base.shred!(cache) Base.shred!(password) end From 023290b6b0d09e259756ac749ce563b0ff079a2a Mon Sep 17 00:00:00 2001 From: Mohamed Tarek Date: Sun, 5 Aug 2018 08:32:18 +0200 Subject: [PATCH 09/36] Define `size` for SVD (#28439) * Define `size` for SVD Closes https://github.com/JuliaLang/julia/issues/28438. And first PR! * add test to 3-arg `ldiv!` on `SVD` which calls `size` * github pampering (cherry picked from commit e0876d2d0088bee769b8e9c84893fd07cd97af45) --- stdlib/LinearAlgebra/src/svd.jl | 3 +++ stdlib/LinearAlgebra/test/svd.jl | 2 ++ 2 files changed, 5 insertions(+) diff --git a/stdlib/LinearAlgebra/src/svd.jl b/stdlib/LinearAlgebra/src/svd.jl index b41c2ab9e4aee..b463d71989273 100644 --- a/stdlib/LinearAlgebra/src/svd.jl +++ b/stdlib/LinearAlgebra/src/svd.jl @@ -224,6 +224,9 @@ function ldiv!(A::SVD{T}, B::StridedVecOrMat) where T view(A.Vt,1:k,:)' * (view(A.S,1:k) .\ (view(A.U,:,1:k)' * B)) end +size(A::SVD, dim::Integer) = dim == 1 ? size(A.U, dim) : size(A.Vt, dim) +size(A::SVD) = (size(A, 1), size(A, 2)) + # Generalized svd struct GeneralizedSVD{T,S} <: Factorization{T} U::S diff --git a/stdlib/LinearAlgebra/test/svd.jl b/stdlib/LinearAlgebra/test/svd.jl index e253f6eb2b8d7..59830c46b0d3a 100644 --- a/stdlib/LinearAlgebra/test/svd.jl +++ b/stdlib/LinearAlgebra/test/svd.jl @@ -29,6 +29,8 @@ using LinearAlgebra: BlasComplex, BlasFloat, BlasReal, QRPivoted # matrices from the factorization as expected. @test sf1.U*Diagonal(sf1.S)*sf1.Vt' ≊ m1 @test sf2.U*Diagonal(sf2.S)*sf2.Vt' ≊ m2 + + @test ldiv!([0., 0.], svd(Matrix(I, 2, 2)), [1., 1.]) ≊ [1., 1.] end n = 10 From eddbc5b46146d19e9e9d487e7d440b50d5b9fad9 Mon Sep 17 00:00:00 2001 From: David Varela Date: Tue, 31 Jul 2018 02:02:18 -0700 Subject: [PATCH 10/36] [RFC] Make command spec more declarative (Pkg PR 509) * Refactor `REPLMode.parse_quotes` (cherry picked from commit 3e88964271da95740291c3cf604bcd89ccf4f80f, Julia PR #28443) --- stdlib/Pkg/src/API.jl | 17 +- stdlib/Pkg/src/REPLMode.jl | 1587 ++++++++++++++++++++---------------- stdlib/Pkg/test/repl.jl | 331 +++++++- 3 files changed, 1217 insertions(+), 718 deletions(-) diff --git a/stdlib/Pkg/src/API.jl b/stdlib/Pkg/src/API.jl index 8d6d85fb284f0..dc659e3959408 100644 --- a/stdlib/Pkg/src/API.jl +++ b/stdlib/Pkg/src/API.jl @@ -28,9 +28,11 @@ add_or_develop(pkg::Union{String, PackageSpec}; kwargs...) = add_or_develop([pkg add_or_develop(pkgs::Vector{String}; kwargs...) = add_or_develop([check_package_name(pkg) for pkg in pkgs]; kwargs...) add_or_develop(pkgs::Vector{PackageSpec}; kwargs...) = add_or_develop(Context(), pkgs; kwargs...) -function add_or_develop(ctx::Context, pkgs::Vector{PackageSpec}; mode::Symbol, devdir::Union{String,Nothing}=nothing, kwargs...) +function add_or_develop(ctx::Context, pkgs::Vector{PackageSpec}; mode::Symbol, devdir::Bool=false, kwargs...) Context!(ctx; kwargs...) + devdir = devdir ? joinpath(dirname(ctx.env.project_file), "dev") : nothing + # All developed packages should go through handle_repos_develop so just give them an empty repo for pkg in pkgs mode == :develop && pkg.repo == nothing && (pkg.repo = Types.GitRepo()) @@ -67,7 +69,12 @@ rm(pkg::Union{String, PackageSpec}; kwargs...) = rm([pkg]; kwargs...) rm(pkgs::Vector{String}; kwargs...) = rm([PackageSpec(pkg) for pkg in pkgs]; kwargs...) rm(pkgs::Vector{PackageSpec}; kwargs...) = rm(Context(), pkgs; kwargs...) -function rm(ctx::Context, pkgs::Vector{PackageSpec}; kwargs...) +function rm(ctx::Context, pkgs::Vector{PackageSpec}; mode=PKGMODE_PROJECT, kwargs...) + for pkg in pkgs + #TODO only overwrite pkg.mode is default value ? + pkg.mode = mode + end + Context!(ctx; kwargs...) ctx.preview && preview_info() project_deps_resolve!(ctx.env, pkgs) @@ -144,6 +151,12 @@ up(pkgs::Vector{PackageSpec}; kwargs...) = up(Context(), pkgs; kwargs...) function up(ctx::Context, pkgs::Vector{PackageSpec}; level::UpgradeLevel=UPLEVEL_MAJOR, mode::PackageMode=PKGMODE_PROJECT, do_update_registry=true, kwargs...) + for pkg in pkgs + # TODO only override if they are not already set + pkg.mode = mode + pkg.version = level + end + Context!(ctx; kwargs...) ctx.preview && preview_info() do_update_registry && update_registry(ctx) diff --git a/stdlib/Pkg/src/REPLMode.jl b/stdlib/Pkg/src/REPLMode.jl index a7df17f52b8a0..c38749b968b14 100644 --- a/stdlib/Pkg/src/REPLMode.jl +++ b/stdlib/Pkg/src/REPLMode.jl @@ -1,5 +1,3 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - module REPLMode using Markdown @@ -11,45 +9,6 @@ import REPL: LineEdit, REPLCompletions import ..devdir, ..Types.casesensitive_isdir, ..TOML using ..Types, ..Display, ..Operations, ..API -############ -# Commands # -############ -@enum(CommandKind, CMD_HELP, CMD_STATUS, CMD_SEARCH, CMD_ADD, CMD_RM, CMD_UP, - CMD_TEST, CMD_GC, CMD_PREVIEW, CMD_INIT, CMD_BUILD, CMD_FREE, - CMD_PIN, CMD_CHECKOUT, CMD_DEVELOP, CMD_GENERATE, CMD_PRECOMPILE, - CMD_INSTANTIATE, CMD_RESOLVE, CMD_ACTIVATE, CMD_DEACTIVATE) - -struct Command - kind::CommandKind - val::String -end -Base.show(io::IO, cmd::Command) = print(io, cmd.val) - -const cmds = Dict( - "help" => CMD_HELP, - "?" => CMD_HELP, - "status" => CMD_STATUS, - "st" => CMD_STATUS, - "add" => CMD_ADD, - "rm" => CMD_RM, - "remove" => CMD_RM, - "up" => CMD_UP, - "update" => CMD_UP, - "test" => CMD_TEST, - "gc" => CMD_GC, - "preview" => CMD_PREVIEW, - "build" => CMD_BUILD, - "pin" => CMD_PIN, - "free" => CMD_FREE, - "develop" => CMD_DEVELOP, - "dev" => CMD_DEVELOP, - "generate" => CMD_GENERATE, - "precompile" => CMD_PRECOMPILE, - "instantiate" => CMD_INSTANTIATE, - "resolve" => CMD_RESOLVE, - "activate" => CMD_ACTIVATE, -) - ################# # Git revisions # ################# @@ -60,64 +19,133 @@ end ########### # Options # ########### -@enum(OptionKind, OPT_ENV, OPT_PROJECT, OPT_MANIFEST, OPT_MAJOR, OPT_MINOR, - OPT_PATCH, OPT_FIXED, OPT_COVERAGE, OPT_NAME, - OPT_LOCAL, OPT_SHARED) - -function Types.PackageMode(opt::OptionKind) - opt == OPT_MANIFEST && return PKGMODE_MANIFEST - opt == OPT_PROJECT && return PKGMODE_PROJECT - throw(ArgumentError("invalid option $opt")) +#TODO should this opt be removed: ("name", :cmd, :temp => false) +struct OptionSpec + name::String + short_name::Union{Nothing,String} + api::Pair{Symbol, Any} + is_switch::Bool end -function Types.UpgradeLevel(opt::OptionKind) - opt == OPT_MAJOR && return UPLEVEL_MAJOR - opt == OPT_MINOR && return UPLEVEL_MINOR - opt == OPT_PATCH && return UPLEVEL_PATCH - opt == OPT_FIXED && return UPLEVEL_FIXED - throw(ArgumentError("invalid option $opt")) +@enum(OptionClass, OPT_ARG, OPT_SWITCH) +const OptionDeclaration = Tuple{Union{String,Vector{String}}, # name + short_name? + OptionClass, # arg or switch + Pair{Symbol, Any} # api keywords + } + +function OptionSpec(x::OptionDeclaration)::OptionSpec + get_names(name::String) = (name, nothing) + function get_names(names::Vector{String}) + @assert length(names) == 2 + return (names[1], names[2]) + end + + is_switch = x[2] == OPT_SWITCH + api = x[3] + (name, short_name) = get_names(x[1]) + #TODO assert matching lex regex + if !is_switch + @assert api.second === nothing || hasmethod(api.second, Tuple{String}) + end + return OptionSpec(name, short_name, api, is_switch) end -struct Option - kind::OptionKind - val::String - argument::Union{String, Nothing} - Option(kind::OptionKind, val::String) = new(kind, val, nothing) - function Option(kind::OptionKind, val::String, argument::Union{String, Nothing}) - if kind in (OPT_PROJECT, OPT_MANIFEST, OPT_MAJOR, - OPT_MINOR, OPT_PATCH, OPT_FIXED) && - argument !== nothing - cmderror("the `$val` option does not take an argument") - elseif kind in (OPT_ENV,) && argument == nothing - cmderror("the `$val` option requires an argument") +function OptionSpecs(decs::Vector{OptionDeclaration})::Dict{String, OptionSpec} + specs = Dict() + for x in decs + opt_spec = OptionSpec(x) + @assert get(specs, opt_spec.name, nothing) === nothing # don't overwrite + specs[opt_spec.name] = opt_spec + if opt_spec.short_name !== nothing + @assert get(specs, opt_spec.short_name, nothing) === nothing # don't overwrite + specs[opt_spec.short_name] = opt_spec end - new(kind, val, argument) end + return specs end -Base.show(io::IO, opt::Option) = print(io, "--$(opt.val)", opt.argument == nothing ? "" : "=$(opt.argument)") -const opts = Dict( - "env" => OPT_ENV, - "project" => OPT_PROJECT, - "p" => OPT_PROJECT, - "manifest" => OPT_MANIFEST, - "m" => OPT_MANIFEST, - "major" => OPT_MAJOR, - "minor" => OPT_MINOR, - "patch" => OPT_PATCH, - "fixed" => OPT_FIXED, - "coverage" => OPT_COVERAGE, - "name" => OPT_NAME, - "local" => OPT_LOCAL, - "shared" => OPT_SHARED, -) +struct Option + val::String + argument::Union{Nothing,String} + Option(val::AbstractString) = new(val, nothing) + Option(val::AbstractString, arg::Union{Nothing,String}) = new(val, arg) +end +Base.show(io::IO, opt::Option) = print(io, "--$(opt.val)", opt.argument == nothing ? "" : "=$(opt.argument)") function parse_option(word::AbstractString)::Option m = match(r"^(?: -([a-z]) | --([a-z]{2,})(?:\s*=\s*(\S*))? )$"ix, word) - m == nothing && cmderror("invalid option: ", repr(word)) - k = m.captures[1] != nothing ? m.captures[1] : m.captures[2] - haskey(opts, k) || cmderror("invalid option: ", repr(word)) - return Option(opts[k], String(k), m.captures[3] == nothing ? nothing : String(m.captures[3])) + m == nothing && cmderror("malformed option: ", repr(word)) + option_name = (m.captures[1] != nothing ? m.captures[1] : m.captures[2]) + option_arg = (m.captures[3] == nothing ? nothing : String(m.captures[3])) + return Option(option_name, option_arg) +end + +meta_option_declarations = OptionDeclaration[ + ("env", OPT_ARG, :env => arg->EnvCache(Base.parse_env(arg))) +] +meta_option_specs = OptionSpecs(meta_option_declarations) + +################ +# Command Spec # +################ +@enum(CommandKind, CMD_HELP, CMD_RM, CMD_ADD, CMD_DEVELOP, CMD_UP, + CMD_STATUS, CMD_TEST, CMD_GC, CMD_BUILD, CMD_PIN, + CMD_FREE, CMD_GENERATE, CMD_RESOLVE, CMD_PRECOMPILE, + CMD_INSTANTIATE, CMD_ACTIVATE, CMD_PREVIEW, + CMD_REGISTRY_ADD, + ) +@enum(ArgClass, ARG_RAW, ARG_PKG, ARG_VERSION, ARG_REV, ARG_ALL) +struct ArgSpec + class::ArgClass + count::Vector{Int} +end +const CommandDeclaration = Tuple{CommandKind, + Vector{String}, # names + Function, # handler + Tuple{ArgClass, Vector{Int}}, # argument count + Vector{OptionDeclaration}, # options + Union{Nothing, Markdown.MD}, #help + } +struct CommandSpec + kind::CommandKind + names::Vector{String} + handler::Function + argument_spec::ArgSpec # note: just use range operator for max/min + option_specs::Dict{String, OptionSpec} + help::Union{Nothing, Markdown.MD} +end +command_specs = Dict{String,CommandSpec}() # TODO remove this ? + +function SuperSpecs(foo)::Dict{String,Dict{String,CommandSpec}} + super_specs = Dict() + for x in foo + sub_specs = CommandSpecs(x.second) + for name in x.first + @assert get(super_specs, name, nothing) === nothing + super_specs[name] = sub_specs + end + end + return super_specs +end + +# populate a dictionary: command_name -> command_spec +function CommandSpecs(declarations::Vector{CommandDeclaration})::Dict{String,CommandSpec} + specs = Dict() + for dec in declarations + names = dec[2] + spec = CommandSpec(dec[1], + names, + dec[3], + ArgSpec(dec[4]...), + OptionSpecs(dec[5]), + dec[end]) + for name in names + # TODO regex check name + @assert get(specs, name, nothing) === nothing + specs[name] = spec + end + end + return specs end ################### @@ -154,44 +182,97 @@ end ################ # REPL parsing # ################ -const lex_re = r"^[\?\./\+\-](?!\-) | ((git|ssh|http(s)?)|(git@[\w\-\.]+))(:(//)?)([\w\.@\:/\-~]+)(\.git)(/)? | [^@\#\s;]+\s*=\s*[^@\#\s;]+ | \#\s*[^@\#\s;]* | @\s*[^@\#\s;]* | [^@\#\s;]+|;"x +mutable struct Statement + command::Union{Nothing,CommandSpec} + options::Vector{String} + arguments::Vector{String} + meta_options::Vector{String} + Statement() = new(nothing, [], [], []) +end -const Token = Union{Command, Option, VersionRange, String, Rev} - -function tokenize(cmd::String)::Vector{Vector{Token}} - # phase 1: tokenize accoring to whitespace / quotes - chunks = parse_quotes(cmd) - # phase 2: tokenzie unquoted tokens according to pkg REPL syntax - words::Vector{String} = [] - for chunk in chunks - is_quoted = chunk[1] - word = chunk[2] - if is_quoted - push!(words, word) - else # break unquoted chunks further according to lexer - # note: space before `$word` is necessary to keep using current `lex_re` - # v - append!(words, map(m->m.match, eachmatch(lex_re, " $word"))) - end +struct QuotedWord + word::String + isquoted::Bool +end + +function parse(cmd::String)::Vector{Statement} + # replace new lines with ; to support multiline commands + cmd = replace(replace(cmd, "\r\n" => "; "), "\n" => "; ") + # tokenize accoring to whitespace / quotes + qwords = parse_quotes(cmd) + # tokenzie unquoted tokens according to pkg REPL syntax + words::Vector{String} = collect(Iterators.flatten(map(qword2word, qwords))) + # break up words according to ";"(doing this early makes subsequent processing easier) + word_groups = group_words(words) + # create statements + statements = map(Statement, word_groups) + return statements +end + +# vector of words -> structured statement +# minimal checking is done in this phase +function Statement(words) + is_option(word) = first(word) == '-' + statement = Statement() + + word = popfirst!(words) + # meta options + while is_option(word) + push!(statement.meta_options, word) + isempty(words) && cmderror("no command specified") + word = popfirst!(words) end + # command + if word in keys(super_specs) + super = super_specs[word] + word = popfirst!(words) + else + super = super_specs["package"] + end + command = get(super, word, nothing) + command !== nothing || cmderror("expected command. instead got [$word]") + statement.command = command + # command arguments + for word in words + push!((is_option(word) ? statement.options : statement.arguments), word) + end + return statement +end - commands = Vector{Token}[] - while !isempty(words) - push!(commands, tokenize!(words)) +# break up words according to `;`(doing this early makes subsequent processing easier) +# the final group does not require a trailing `;` +function group_words(words)::Vector{Vector{String}} + statements = Vector{String}[] + x = String[] + for word in words + if word == ";" + isempty(x) ? cmderror("empty statement") : push!(statements, x) + x = String[] + else + push!(x, word) + end end - return commands + isempty(x) || push!(statements, x) + return statements +end + +const lex_re = r"^[\?\./\+\-](?!\-) | ((git|ssh|http(s)?)|(git@[\w\-\.]+))(:(//)?)([\w\.@\:/\-~]+)(\.git)(/)? | [^@\#\s;]+\s*=\s*[^@\#\s;]+ | \#\s*[^@\#\s;]* | @\s*[^@\#\s;]* | [^@\#\s;]+|;"x + +function qword2word(qword::QuotedWord) + return qword.isquoted ? [qword.word] : map(m->m.match, eachmatch(lex_re, " $(qword.word)")) + # ^ + # note: space before `$word` is necessary to keep using current `lex_re` end -function parse_quotes(cmd::String) +function parse_quotes(cmd::String)::Vector{QuotedWord} in_doublequote = false in_singlequote = false - all_tokens::Array = [] - token_in_progress::Array{Char} = [] + qwords = QuotedWord[] + token_in_progress = Char[] push_token!(is_quoted) = begin - complete_token = String(token_in_progress) + push!(qwords, QuotedWord(String(token_in_progress), is_quoted)) empty!(token_in_progress) - push!(all_tokens, (is_quoted, complete_token)) end for c in cmd @@ -216,644 +297,364 @@ function parse_quotes(cmd::String) end end if (in_doublequote || in_singlequote) - ArgumentError("unterminated quote") + cmderror("unterminated quote") else push_token!(false) end # to avoid complexity in the main loop, empty tokens are allowed above and # filtered out before returning - isnotempty(x) = !isempty(x[2]) - filter!(isnotempty, all_tokens) - return all_tokens + return filter(x->!isempty(x.word), qwords) end -function tokenize!(words::Vector{<:AbstractString})::Vector{Token} - tokens = Token[] - help_mode = false - preview_mode = false - # First parse a Command or a modifier (help / preview) + Command - while !isempty(words) - word = popfirst!(words) - if word[1] == '-' && length(word) > 1 - push!(tokens, parse_option(word)) - else - haskey(cmds, word) || cmderror("invalid command: ", repr(word)) - cmdkind = cmds[word] - push!(tokens, Command(cmdkind, word)) - # If help / preview and not in help mode we want to eat another cmd - if !help_mode - cmdkind == CMD_HELP && (help_mode = true; continue) - cmdkind == CMD_PREVIEW && (preview_mode = true; continue) - end - break - end - end - if isempty(tokens) || !(tokens[end] isa Command) - cmderror("no package command given") - end - # Now parse the arguments / options to the command - while !isempty(words) - word = popfirst!(words) - if word == ";" - return tokens - elseif first(word) == '-' - push!(tokens, parse_option(word)) - elseif first(word) == '@' - push!(tokens, VersionRange(strip(word[2:end]))) - elseif first(word) == '#' - push!(tokens, Rev(word[2:end])) - else - push!(tokens, String(word)) - end - end - return tokens +############## +# PkgCommand # +############## +const Token = Union{String, VersionRange, Rev} +const PkgArguments = Union{Vector{String}, Vector{PackageSpec}} +#TODO embed spec in PkgCommand? +struct PkgCommand + meta_options::Vector{Option} + spec::CommandSpec + options::Vector{Option} + arguments::PkgArguments + PkgCommand() = new([], "", [], []) + PkgCommand(meta_opts, cmd_name, opts, args) = new(meta_opts, cmd_name, opts, args) end +const APIOption = Pair{Symbol, Any} +APIOptions(command::PkgCommand)::Vector{APIOption} = + APIOptions(command.options, command.spec.option_specs) + +function APIOptions(options::Vector{Option}, + specs::Dict{String, OptionSpec}, + )::Vector{APIOption} + return map(options) do opt + spec = specs[opt.val] + # opt is switch + spec.is_switch && return spec.api + # no opt wrapper -> just use raw argument + spec.api.second === nothing && return spec.api.first => opt.argument + # given opt wrapper + return spec.api.first => spec.api.second(opt.argument) + end +end -############# -# Execution # -############# - -function do_cmd(repl::REPL.AbstractREPL, input::String; do_rethrow=false) - try - commands = tokenize(input) - for command in commands - do_cmd!(command, repl) - end - catch err - if do_rethrow - rethrow(err) - end - if err isa CommandError || err isa ResolverError - Base.display_error(repl.t.err_stream, ErrorException(sprint(showerror, err)), Ptr{Nothing}[]) - else - Base.display_error(repl.t.err_stream, err, Base.catch_backtrace()) - end +function key_api(key::Symbol, api_opts::Vector{APIOption}) + index = findfirst(x->x.first == key, api_opts) + if index !== nothing + return api_opts[index].second end end -function enforce_argument_order(tokens::Vector{Token}) - prev_token = nothing - function check_prev_token(valid_type::DataType, error_message::AbstractString) - prev_token isa valid_type || cmderror(error_message) +set_default!(opt, api_opts::Vector{APIOption}) = + key_api(opt.first, api_opts) === nothing && push!(api_opts, opt) + +function enforce_argument_order(args::Vector{Token}) + prev_arg = nothing + function check_prev_arg(valid_type::DataType, error_message::AbstractString) + prev_arg isa valid_type || cmderror(error_message) end - for token in tokens - if token isa VersionRange - check_prev_token(String, "package name/uuid must precede version spec `@$token`") - elseif token isa Rev - check_prev_token(String, "package name/uuid must precede rev spec `#$(token.rev)`") + for arg in args + if arg isa VersionRange + check_prev_arg(String, "package name/uuid must precede version spec `@$arg`") + elseif arg isa Rev + check_prev_arg(String, "package name/uuid must precede rev spec `#$(arg.rev)`") end - prev_token = token + prev_arg = arg end end -function do_cmd!(tokens::Vector{Token}, repl) - cmd = env_opt = nothing - while !isempty(tokens) - token = popfirst!(tokens) - if token isa Command - cmd = token - break - elseif token isa Option - # Only OPT_ENV is allowed before a command - if token.kind == OPT_ENV - env_opt = Base.parse_env(token.argument) - else - cmderror("unrecognized command option: `$token`") - end - else - cmderror("misplaced token: ", token) - end +function word2token(word::AbstractString)::Token + if first(word) == '@' + return VersionRange(word[2:end]) + elseif first(word) == '#' + return Rev(word[2:end]) + else + return String(word) end +end - if cmd.kind == CMD_ACTIVATE - return Base.invokelatest(do_activate!, Base.active_project() === nothing ? - nothing : EnvCache(env_opt), tokens) +function enforce_arg_spec(raw_args::Vector{String}, class::ArgClass) + # TODO is there a more idiomatic way to do this? + function has_types(arguments::Vector{Token}, types::Vector{DataType}) + return !isempty(filter(x->typeof(x) in types, arguments)) end - ctx = Context(env = EnvCache(env_opt)) - if cmd.kind == CMD_PREVIEW - ctx.preview = true - isempty(tokens) && cmderror("expected a command to preview") - cmd = popfirst!(tokens) - end + class == ARG_RAW && return raw_args + args::Vector{Token} = map(word2token, raw_args) + class == ARG_ALL && return args - enforce_argument_order(tokens) - - # Using invokelatest to hide the functions from inference. - # Otherwise it would try to infer everything here. - cmd.kind == CMD_INIT ? Base.invokelatest( do_init!, ctx, tokens) : - cmd.kind == CMD_HELP ? Base.invokelatest( do_help!, ctx, tokens, repl) : - cmd.kind == CMD_RM ? Base.invokelatest( do_rm!, ctx, tokens) : - cmd.kind == CMD_ADD ? Base.invokelatest(do_add_or_develop!, ctx, tokens, CMD_ADD) : - cmd.kind == CMD_CHECKOUT ? Base.invokelatest(do_add_or_develop!, ctx, tokens, CMD_DEVELOP) : - cmd.kind == CMD_DEVELOP ? Base.invokelatest(do_add_or_develop!, ctx, tokens, CMD_DEVELOP) : - cmd.kind == CMD_UP ? Base.invokelatest( do_up!, ctx, tokens) : - cmd.kind == CMD_STATUS ? Base.invokelatest( do_status!, ctx, tokens) : - cmd.kind == CMD_TEST ? Base.invokelatest( do_test!, ctx, tokens) : - cmd.kind == CMD_GC ? Base.invokelatest( do_gc!, ctx, tokens) : - cmd.kind == CMD_BUILD ? Base.invokelatest( do_build!, ctx, tokens) : - cmd.kind == CMD_PIN ? Base.invokelatest( do_pin!, ctx, tokens) : - cmd.kind == CMD_FREE ? Base.invokelatest( do_free!, ctx, tokens) : - cmd.kind == CMD_GENERATE ? Base.invokelatest( do_generate!, ctx, tokens) : - cmd.kind == CMD_RESOLVE ? Base.invokelatest( do_resolve!, ctx, tokens) : - cmd.kind == CMD_PRECOMPILE ? Base.invokelatest( do_precompile!, ctx, tokens) : - cmd.kind == CMD_INSTANTIATE ? Base.invokelatest( do_instantiate!, ctx, tokens) : - cmderror("`$cmd` command not yet implemented") - return + if class == ARG_PKG && has_types(args, [VersionRange, Rev]) + cmderror("no versioned packages allowed") + elseif class == ARG_REV && has_types(args, [VersionRange]) + cmderror("no versioned packages allowed") + elseif class == ARG_VERSION && has_types(args, [Rev]) + cmderror("no reved packages allowed") + end + return args end -const help = md""" - -**Welcome to the Pkg REPL-mode**. To return to the `julia>` prompt, either press -backspace when the input line is empty or press Ctrl+C. - - -**Synopsis** - - pkg> [--env=...] cmd [opts] [args] - -Multiple commands can be given on the same line by interleaving a `;` between the commands. - -**Environment** - -The `--env` meta option determines which project environment to manipulate. By -default, this looks for a git repo in the parents directories of the current -working directory, and if it finds one, it uses that as an environment. Otherwise, -it uses a named environment (typically found in `~/.julia/environments`) looking -for environments named `v$(VERSION.major).$(VERSION.minor).$(VERSION.patch)`, -`v$(VERSION.major).$(VERSION.minor)`, `v$(VERSION.major)` or `default` in order. - -**Commands** - -What action you want the package manager to take: - -`help`: show this message - -`status`: summarize contents of and changes to environment - -`add`: add packages to project - -`develop`: clone the full package repo locally for development - -`rm`: remove packages from project or manifest - -`up`: update packages in manifest - -`test`: run tests for packages - -`build`: run the build script for packages - -`pin`: pins the version of packages - -`free`: undoes a `pin`, `develop`, or stops tracking a repo. - -`instantiate`: downloads all the dependencies for the project - -`resolve`: resolves to update the manifest from changes in dependencies of -developed packages - -`generate`: generate files for a new project - -`preview`: previews a subsequent command without affecting the current state - -`precompile`: precompile all the project dependencies - -`gc`: garbage collect packages not used for a significant time - -`activate`: set the primary environment the package manager manipulates -""" - -const helps = Dict( - CMD_HELP => md""" - - help - - Display this message. - - help cmd ... - - Display usage information for commands listed. - - Available commands: `help`, `status`, `add`, `rm`, `up`, `preview`, `gc`, `test`, `build`, `free`, `pin`, `develop`. - """, CMD_STATUS => md""" - - status - status [-p|--project] - status [-m|--manifest] - - Show the status of the current environment. By default, the full contents of - the project file is summarized, showing what version each package is on and - how it has changed since the last git commit (if in a git repo), as well as - any changes to manifest packages not already listed. In `--project` mode, the - status of the project file is summarized. In `--manifest` mode the output also - includes the dependencies of explicitly added packages. - """, CMD_GENERATE => md""" - - generate pkgname - - Create a project called `pkgname` in the current folder. - """, - CMD_ADD => md""" - - add pkg[=uuid] [@version] [#rev] ... - - Add package `pkg` to the current project file. If `pkg` could refer to - multiple different packages, specifying `uuid` allows you to disambiguate. - `@version` optionally allows specifying which versions of packages. Versions - may be specified by `@1`, `@1.2`, `@1.2.3`, allowing any version with a prefix - that matches, or ranges thereof, such as `@1.2-3.4.5`. A git-revision can be - specified by `#branch` or `#commit`. - - If a local path is used as an argument to `add`, the path needs to be a git repository. - The project will then track that git repository just like if it is was tracking a remote repository online. - - **Examples** - ``` - pkg> add Example - pkg> add Example@0.5 - pkg> add Example#master - pkg> add Example#c37b675 - pkg> add https://github.com/JuliaLang/Example.jl#master - pkg> add git@github.com:JuliaLang/Example.jl.git - pkg> add Example=7876af07-990d-54b4-ab0e-23690620f79a - ``` - """, CMD_RM => md""" - - rm [-p|--project] pkg[=uuid] ... - - 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 - a `uuid` anyway, and the command is ignored, with a warning if package name - and UUID do not mactch. 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. - - rm [-m|--manifest] pkg[=uuid] ... - - 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. - """, CMD_UP => md""" - - up [-p|project] [opts] pkg[=uuid] [@version] ... - up [-m|manifest] [opts] pkg[=uuid] [@version] ... - - opts: --major | --minor | --patch | --fixed - - Update the indicated package within the constraints of the indicated version - specifications. Versions may be specified by `@1`, `@1.2`, `@1.2.3`, allowing - any version with a prefix that matches, or ranges thereof, such as `@1.2-3.4.5`. - In `--project` mode, package specifications only match project packages, while - in `manifest` mode they match any manifest package. Bound level options force - the following packages to be upgraded only within the current major, minor, - patch version; if the `--fixed` upgrade level is given, then the following - packages will not be upgraded at all. - """, CMD_PREVIEW => md""" - - preview cmd - - Runs the command `cmd` in preview mode. This is defined such that no side effects - will take place i.e. no packages are downloaded and neither the project nor manifest - is modified. - """, CMD_TEST => md""" - - test [opts] pkg[=uuid] ... - - opts: --coverage - - Run the tests for package `pkg`. This is done by running the file `test/runtests.jl` - in the package directory. The option `--coverage` can be used to run the tests with - coverage enabled. - """, CMD_GC => md""" - - Deletes packages that cannot be reached from any existing environment. - """, CMD_BUILD =>md""" - - build pkg[=uuid] ... - - Run the build script in deps/build.jl for each package in `pkg`` and all of their dependencies in depth-first recursive order. - If no packages are given, runs the build scripts for all packages in the manifest. - """, CMD_PIN => md""" - - pin pkg[=uuid] ... - - 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. - """, CMD_FREE => md""" - free pkg[=uuid] ... - - 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 - makes the package no longer being checked out. - """, CMD_DEVELOP => md""" - develop [--shared|--local] pkg[=uuid] [#rev] ... - - Make a package available for development. If `pkg` is an existing local path that path will be recorded in - the manifest and used. Otherwise, a full git clone of `pkg` at rev `rev` is made. The location of the clone is - controlled by the `--shared` (default) and `--local` arguments. The `--shared` location defaults to - `~/.julia/dev`, but can be controlled with the `JULIA_PKG_DEVDIR` environment variable. When `--local` is given, - the clone is placed in a `dev` folder in the current project. - This operation is undone by `free`. - - *Example* - ```jl - pkg> develop Example - pkg> develop Example#master - pkg> develop Example#c37b675 - pkg> develop https://github.com/JuliaLang/Example.jl#master - pkg> develop --local Example - ``` - """, CMD_PRECOMPILE => md""" - precompile - - Precompile all the dependencies of the project by running `import` on all of them in a new process. - """, CMD_INSTANTIATE => md""" - instantiate - instantiate [-m|--manifest] - instantiate [-p|--project] - - Download all the dependencies for the current project at the version given by the project's manifest. - If no manifest exists or the `--project` option is given, resolve and download the dependencies compatible with the project. - """, CMD_RESOLVE => md""" - resolve - - Resolve the project i.e. run package resolution and update the Manifest. This is useful in case the dependencies of developed - packages have changed causing the current Manifest to_indices be out of sync. - """ -) - -function do_help!( - ctk::Context, - tokens::Vector{Token}, - repl::REPL.AbstractREPL, -) - disp = REPL.REPLDisplay(repl) - if isempty(tokens) - Base.display(disp, help) - return - end - help_md = md"" - for token in tokens - if token isa Command - if haskey(helps, token.kind) - isempty(help_md.content) || - push!(help_md.content, md"---") - push!(help_md.content, helps[token.kind].content) +function package_args(args::Vector{Token}, spec::CommandSpec)::Vector{PackageSpec} + pkgs = PackageSpec[] + for arg in args + if arg isa String + is_add_or_develop = spec.kind in (CMD_ADD, CMD_DEVELOP) + push!(pkgs, parse_package(arg; add_or_develop=is_add_or_develop)) + elseif arg isa VersionRange + pkgs[end].version = arg + elseif arg isa Rev + pkg = pkgs[end] + if pkg.repo == nothing + pkg.repo = Types.GitRepo("", arg.rev) else - cmderror("Sorry, I don't have any help for the `$(token.val)` command.") + pkgs[end].repo.rev = arg.rev end else - error("invalid usage of help command") + assert(false) end end - Base.display(disp, help_md) + return pkgs end -function do_rm!(ctx::Context, tokens::Vector{Token}) - # tokens: package names and/or uuids - mode = PKGMODE_PROJECT - pkgs = PackageSpec[] - while !isempty(tokens) - token = popfirst!(tokens) - if token isa String - push!(pkgs, parse_package(token)) - pkgs[end].mode = mode - elseif token isa VersionRange - cmderror("`rm` does not take version specs") - elseif token isa Option - if token.kind in (OPT_PROJECT, OPT_MANIFEST) - mode = PackageMode(token.kind) - else - cmderror("invalid option for `rm`: $token") - end - end - end - isempty(pkgs) && - cmderror("`rm` – list packages to remove") - API.rm(ctx, pkgs) +function enforce_arg_count(count::Vector{Int}, args::PkgArguments) + isempty(count) && return + length(args) in count || + cmderror("Wrong number of arguments") end -function do_add_or_develop!(ctx::Context, tokens::Vector{Token}, cmd::CommandKind) - @assert cmd in (CMD_ADD, CMD_DEVELOP) - mode = cmd == CMD_ADD ? :add : :develop - # tokens: package names and/or uuids, optionally followed by version specs - isempty(tokens) && - cmderror("`$mode` – list packages to $mode") - pkgs = PackageSpec[] - dev_mode = OPT_SHARED # TODO: Make this default configurable - while !isempty(tokens) - token = popfirst!(tokens) - if token isa String - push!(pkgs, parse_package(token; add_or_develop=true)) - elseif token isa VersionRange - pkgs[end].version = VersionSpec(token) - elseif token isa Rev - # WE did not get the repo from the - pkg = pkgs[end] - if pkg.repo == nothing - pkg.repo = Types.GitRepo("", token.rev) - else - pkgs[end].repo.rev = token.rev - end - elseif token isa Option - if mode === :develop && token.kind in (OPT_LOCAL, OPT_SHARED) - dev_mode = token.kind - else - cmderror("`$mode` doesn't take options: $token") - end - end +function enforce_args(raw_args::Vector{String}, spec::ArgSpec, cmd_spec::CommandSpec)::PkgArguments + if spec.class == ARG_RAW + enforce_arg_count(spec.count, raw_args) + return raw_args end - dev_dir = mode === :add ? nothing : dev_mode == OPT_LOCAL ? - joinpath(dirname(ctx.env.project_file), "dev") : nothing - return API.add_or_develop(ctx, pkgs, mode=mode, devdir=dev_dir) + + args = enforce_arg_spec(raw_args, spec.class) + enforce_argument_order(args) + pkgs = package_args(args, cmd_spec) + enforce_arg_count(spec.count, pkgs) + return pkgs end -function do_up!(ctx::Context, tokens::Vector{Token}) - # tokens: - # - upgrade levels as options: --[fixed|patch|minor|major] - # - package names and/or uuids, optionally followed by version specs - pkgs = PackageSpec[] - mode = PKGMODE_PROJECT - level = UPLEVEL_MAJOR - while !isempty(tokens) - token = popfirst!(tokens) - if token isa String - push!(pkgs, parse_package(token)) - pkgs[end].version = level - pkgs[end].mode = mode - elseif token isa VersionRange - pkgs[end].version = VersionSpec(token) - elseif token isa Option - if token.kind in (OPT_PROJECT, OPT_MANIFEST) - mode = PackageMode(token.kind) - elseif token.kind in (OPT_MAJOR, OPT_MINOR, OPT_PATCH, OPT_FIXED) - level = UpgradeLevel(token.kind) - else - cmderror("invalid option for `up`: $(token)") - end - end +function enforce_option(option::String, specs::Dict{String,OptionSpec})::Option + opt = parse_option(option) + spec = get(specs, opt.val, nothing) + spec !== nothing || + cmderror("option '$(opt.val)' is not a valid option") + if spec.is_switch + opt.argument === nothing || + cmderror("option '$(opt.val)' does not take an argument, but '$(opt.argument)' given") + else # option takes an argument + opt.argument !== nothing || + cmderror("option '$(opt.val)' expects an argument, but no argument given") end - API.up(ctx, pkgs; level=level, mode=mode) + return opt end -function do_pin!(ctx::Context, tokens::Vector{Token}) - pkgs = PackageSpec[] - while !isempty(tokens) - token = popfirst!(tokens) - if token isa String - push!(pkgs, parse_package(token)) - elseif token isa VersionRange - if token.lower != token.upper - cmderror("pinning a package requires a single version, not a versionrange") - end - pkgs[end].version = VersionSpec(token) - else - cmderror("free only takes a list of packages ") - end +function enforce_meta_options(options::Vector{String}, specs::Dict{String,OptionSpec})::Vector{Option} + meta_opt_names = keys(specs) + return map(options) do opt + tok = enforce_option(opt, specs) + tok.val in meta_opt_names || + cmderror("option '$opt' is not a valid meta option.") + #TODO hint that maybe they intended to use it as a command option + return tok end - API.pin(ctx, pkgs) end -function do_free!(ctx::Context, tokens::Vector{Token}) - pkgs = PackageSpec[] - while !isempty(tokens) - token = popfirst!(tokens) - if token isa String - push!(pkgs, parse_package(token)) +function enforce_opts(options::Vector{String}, specs::Dict{String,OptionSpec})::Vector{Option} + unique_keys = Symbol[] + get_key(opt::Option) = specs[opt.val].api.first + + # final parsing + toks = map(x->enforce_option(x,specs),options) + # checking + for opt in toks + # valid option + opt.val in keys(specs) || + cmderror("option '$(opt.val)' is not supported") + # conflicting options + key = get_key(opt) + if key in unique_keys + conflicting = filter(opt->get_key(opt) == key, toks) + cmderror("Conflicting options: $conflicting") else - cmderror("free only takes a list of packages") + push!(unique_keys, key) end end - API.free(ctx, pkgs) + return toks end -function do_status!(ctx::Context, tokens::Vector{Token}) - mode = PKGMODE_COMBINED - while !isempty(tokens) - token = popfirst!(tokens) - if token isa Option - if token.kind in (OPT_PROJECT, OPT_MANIFEST) - mode = PackageMode(token.kind) - else - cmderror("invalid option for `status`: $(token)") - end - else - cmderror("`status` does not take arguments") - end - end - Display.status(ctx, mode) +# this the entry point for the majority of input checks +function PkgCommand(statement::Statement)::PkgCommand + meta_opts = enforce_meta_options(statement.meta_options, + meta_option_specs) + args = enforce_args(statement.arguments, + statement.command.argument_spec, + statement.command) + opts = enforce_opts(statement.options, statement.command.option_specs) + return PkgCommand(meta_opts, statement.command, opts, args) end -# TODO , test recursive dependencies as on option. -function do_test!(ctx::Context, tokens::Vector{Token}) - pkgs = PackageSpec[] - coverage = false - while !isempty(tokens) - token = popfirst!(tokens) - if token isa String - pkg = parse_package(token) - pkg.mode = PKGMODE_MANIFEST - push!(pkgs, pkg) - elseif token isa Option - if token.kind == OPT_COVERAGE - coverage = true - else - cmderror("invalid option for `test`: $token") - end +############# +# Execution # +############# +function do_cmd(repl::REPL.AbstractREPL, input::String; do_rethrow=false) + try + statements = parse(input) + commands = map(PkgCommand, statements) + for cmd in commands + do_cmd!(cmd, repl) + end + catch err + if do_rethrow + rethrow(err) + end + if err isa CommandError || err isa ResolverError + Base.display_error(repl.t.err_stream, ErrorException(sprint(showerror, err)), Ptr{Nothing}[]) else - # TODO: Better error message - cmderror("invalid usage for `test`") + Base.display_error(repl.t.err_stream, err, Base.catch_backtrace()) end end - API.test(ctx, pkgs; coverage = coverage) end -function do_gc!(ctx::Context, tokens::Vector{Token}) - !isempty(tokens) && cmderror("`gc` does not take any arguments") - API.gc(ctx) +function do_cmd!(command::PkgCommand, repl) + meta_opts = APIOptions(command.meta_options, meta_option_specs) + ctx = Context(meta_opts...) + spec = command.spec + + # REPL specific commands + if spec.kind == CMD_HELP + return Base.invokelatest(do_help!, ctx, command, repl) + elseif spec.kind == CMD_PREVIEW + ctx.preview = true + cmd = command.arguments[1] + cmd_spec = get(command_specs, cmd, nothing) + cmd_spec === nothing && + cmderror("'$cmd' is not a valid command") + spec = cmd_spec + command = PkgCommand([], cmd, [], PackageSpec[]) + end + + # API commands + # TODO is invokelatest still needed? + Base.invokelatest(spec.handler, ctx, command.arguments, APIOptions(command)) end -function do_build!(ctx::Context, tokens::Vector{Token}) - pkgs = PackageSpec[] - while !isempty(tokens) - token = popfirst!(tokens) - if token isa String - push!(pkgs, parse_package(token)) - else - cmderror("`build` only takes a list of packages") - end +function do_help!(ctk::Context, command::PkgCommand, repl::REPL.AbstractREPL) + disp = REPL.REPLDisplay(repl) + if isempty(command.arguments) + Base.display(disp, help) + return end - API.build(ctx, pkgs) + help_md = md"" + for arg in command.arguments + spec = get(command_specs, arg, nothing) + spec === nothing && + cmderror("'$arg' does not name a command") + spec.help === nothing && + cmderror("Sorry, I don't have any help for the `$arg` command.") + isempty(help_md.content) || + push!(help_md.content, md"---") + push!(help_md.content, spec.help) + end + Base.display(disp, help_md) end -function do_generate!(ctx::Context, tokens::Vector{Token}) - isempty(tokens) && cmderror("`generate` requires a project name as an argument") - token = popfirst!(tokens) - token isa String || cmderror("`generate` takes a name of the project to create") - isempty(tokens) || cmderror("`generate` takes a single project name as an argument") - API.generate(ctx, token) +# TODO set default Display.status keyword: mode = PKGMODE_COMBINED +function do_status!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) + set_default!(:mode => PKGMODE_COMBINED, api_opts) + Display.status(ctx, key_api(:mode, api_opts)) end -function do_precompile!(ctx::Context, tokens::Vector{Token}) - if !isempty(tokens) - cmderror("`precompile` does not take any arguments") - end - API.precompile(ctx) +# TODO remove the need to specify a handler function (not needed for REPL commands) +do_preview!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = nothing + +# TODO , test recursive dependencies as on option. +function do_test!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) + foreach(arg -> arg.mode = PKGMODE_MANIFEST, args) + API.test(ctx, args; api_opts...) end -function do_instantiate!(ctx::Context, tokens::Vector{Token}) - manifest = nothing - for token in tokens - if token isa Option - if token.kind == OPT_MANIFEST - manifest = true - elseif token.kind == OPT_PROJECT - manifest = false - else - cmderror("invalid option for `instantiate`: $(token)") - end - else - cmderror("invalid argument for `instantiate` :$(token)") - end +function do_registry_add!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) + println("This is a dummy function for now") + println("My args are:") + for arg in args + println("- $arg") end - API.instantiate(ctx; manifest=manifest) end -function do_resolve!(ctx::Context, tokens::Vector{Token}) - !isempty(tokens) && cmderror("`resolve` does not take any arguments") +do_precompile!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = + API.precompile(ctx) + +do_resolve!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = API.resolve(ctx) -end -function do_activate!(env::Union{EnvCache,Nothing}, tokens::Vector{Token}) - if isempty(tokens) +do_gc!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = + API.gc(ctx; api_opts...) + +do_instantiate!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = + API.instantiate(ctx; api_opts...) + +do_generate!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = + API.generate(ctx, args[1]) + +do_build!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = + API.build(ctx, args; api_opts...) + +do_rm!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = + API.rm(ctx, args; api_opts...) + +do_free!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = + API.free(ctx, args; api_opts...) + +do_up!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = + API.up(ctx, args; api_opts...) + +function do_activate!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) + if isempty(args) return API.activate() + end + + path = args[1] + env = Base.active_project() === nothing ? nothing : ctx.env + devpath = nothing + if env !== nothing && haskey(env.project["deps"], path) + uuid = UUID(env.project["deps"][path]) + info = manifest_info(env, uuid) + devpath = haskey(info, "path") ? joinpath(dirname(env.project_file), info["path"]) : nothing + end + # `pkg> activate path` does the following + # 1. if path exists, activate that + # 2. if path exists in deps, and the dep is deved, activate that path (`devpath`) above + # 3. activate the non-existing directory (e.g. as in `pkg> activate . for initing a new dev`) + if Types.isdir_windows_workaround(path) + API.activate(abspath(path)) + elseif devpath !== nothing + API.activate(abspath(devpath)) else - path = popfirst!(tokens) - if !isempty(tokens) || !(path isa String) - cmderror("`activate` takes an optional path to the env to activate") - end - devpath = nothing - if env !== nothing && haskey(env.project["deps"], path) - uuid = UUID(env.project["deps"][path]) - info = manifest_info(env, uuid) - devpath = haskey(info, "path") ? joinpath(dirname(env.project_file), info["path"]) : nothing - end - # `pkg> activate path` does the following - # 1. if path exists, activate that - # 2. if path exists in deps, and the dep is deved, activate that path (`devpath` above) - # 3. activate the non-existing directory (e.g. as in `pkg> activate .` for initing a new env) - if Types.isdir_windows_workaround(path) - API.activate(abspath(path)) - elseif devpath !== nothing - API.activate(abspath(devpath)) - else - API.activate(abspath(path)) + API.activate(abspath(path)) + end +end + +function do_pin!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) + for arg in args + # TODO not sure this is correct + if arg.version.ranges[1].lower != arg.version.ranges[1].upper + cmderror("pinning a package requires a single version, not a versionrange") end end + API.pin(ctx, args; api_opts...) +end + +function do_add!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) + push!(api_opts, :mode => :add) + API.add_or_develop(ctx, args; api_opts...) +end + +function do_develop!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) + push!(api_opts, :mode => :develop) + API.add_or_develop(ctx, args; api_opts...) end ###################### @@ -872,10 +673,11 @@ function MiniREPL() end REPL.REPLDisplay(repl::MiniREPL) = repl.display -__init__() = minirepl[] = MiniREPL() const minirepl = Ref{MiniREPL}() +#= __init__() = =# minirepl[] = MiniREPL() + macro pkg_str(str::String) :($(do_cmd)(minirepl[], $str; do_rethrow=true)) end @@ -883,9 +685,25 @@ end pkgstr(str::String) = do_cmd(minirepl[], str; do_rethrow=true) # handle completions -all_commands_sorted = sort!(collect(keys(cmds))) +all_commands_sorted = [] +long_commands = [] +all_options_sorted = [] +long_options = [] + +all_commands_sorted = sort(collect(String,keys(command_specs))) long_commands = filter(c -> length(c) > 2, all_commands_sorted) -all_options_sorted = [length(opt) > 1 ? "--$opt" : "-$opt" for opt in sort!(collect(keys(opts)))] +function all_options() + all_opts = [] + for command in values(command_specs) + for opt_spec in command.option_specs + push!(all_opts, opt_spec.name) + opt_spec.short_name !== nothing && push!(all_opts, opt_spec.short_name) + end + end + unique!(all_opts) + return all_opts +end +all_options_sorted = [length(opt) > 1 ? "--$opt" : "-$opt" for opt in sort!(all_options())] long_options = filter(c -> length(c) > 2, all_options_sorted) struct PkgCompletionProvider <: LineEdit.CompletionProvider end @@ -912,7 +730,7 @@ function complete_option(s, i1, i2) end function complete_package(s, i1, i2, lastcommand, project_opt) - if lastcommand in [CMD_STATUS, CMD_RM, CMD_UP, CMD_TEST, CMD_BUILD, CMD_FREE, CMD_PIN, CMD_CHECKOUT] + if lastcommand in [CMD_STATUS, CMD_RM, CMD_UP, CMD_TEST, CMD_BUILD, CMD_FREE, CMD_PIN] return complete_installed_package(s, i1, i2, project_opt) elseif lastcommand in [CMD_ADD, CMD_DEVELOP] return complete_remote_package(s, i1, i2) @@ -971,25 +789,17 @@ function completions(full, index) end # tokenize input, don't offer any completions for invalid commands - tokens = try - tokenize(join(pre_words[1:end-1], ' '))[end] + statement = try + parse(join(pre_words[1:end-1], ' '))[end] catch return String[], 0:-1, false end - tokens = reverse!(tokens) - - lastcommand = nothing + lastcommand = statement.command.kind project_opt = true - for t in tokens - if t isa Command - lastcommand = t.kind - break - end - end - for t in tokens - if t isa Option && t.kind in [OPT_PROJECT, OPT_MANIFEST] - project_opt = t.kind == OPT_PROJECT + for opt in statement.options + if opt in ["--manifest", "--project", "-m", "-p"] + project_opt = opt in ["--project", "-p"] break end end @@ -1011,7 +821,7 @@ prev_prefix = "" function promptf() global prev_project_timestamp, prev_prefix, prev_project_file project_file = try - project_file = Base.active_project() + Types.find_project_file() catch nothing end @@ -1121,4 +931,385 @@ function repl_init(repl) return end +######## +# SPEC # +######## +command_declarations = [ +["registry"] => CommandDeclaration[ +( + CMD_REGISTRY_ADD, + ["add"], + do_registry_add!, + (ARG_PKG, []), + [], + nothing, +), +], #registry + +["package"] => CommandDeclaration[ +( CMD_TEST, + ["test"], + do_test!, + (ARG_PKG, []), + [ + ("coverage", OPT_SWITCH, :coverage => true), + ], + md""" + + test [opts] pkg[=uuid] ... + + opts: --coverage + +Run the tests for package `pkg`. This is done by running the file `test/runtests.jl` +in the package directory. The option `--coverage` can be used to run the tests with +coverage enabled. The `startup.jl` file is disabled during testing unless +julia is started with `--startup-file=yes`. + """, +),( CMD_HELP, + ["help", "?"], + do_help!, + (ARG_RAW, []), + [], + md""" + + help + +Display this message. + + help cmd ... + +Display usage information for commands listed. + +Available commands: `help`, `status`, `add`, `rm`, `up`, `preview`, `gc`, `test`, `build`, `free`, `pin`, `develop`. + """, +),( CMD_INSTANTIATE, + ["instantiate"], + do_instantiate!, + (ARG_RAW, [0]), + [ + (["project", "p"], OPT_SWITCH, :manifest => false), + (["manifest", "m"], OPT_SWITCH, :manifest => true), + ], + md""" + instantiate + instantiate [-m|--manifest] + instantiate [-p|--project] + +Download all the dependencies for the current project at the version given by the project's manifest. +If no manifest exists or the `--project` option is given, resolve and download the dependencies compatible with the project. + """, +),( CMD_RM, + ["remove", "rm"], + do_rm!, + (ARG_PKG, []), + [ + (["project", "p"], OPT_SWITCH, :mode => PKGMODE_PROJECT), + (["manifest", "m"], OPT_SWITCH, :mode => PKGMODE_MANIFEST), + ], + md""" + + rm [-p|--project] pkg[=uuid] ... + +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 +a `uuid` anyway, and the command is ignored, with a warning if package name +and UUID do not mactch. 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. + + rm [-m|--manifest] pkg[=uuid] ... + +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. + """, +),( CMD_ADD, + ["add"], + do_add!, + (ARG_ALL, []), + [], + md""" + + add pkg[=uuid] [@version] [#rev] ... + +Add package `pkg` to the current project file. If `pkg` could refer to +multiple different packages, specifying `uuid` allows you to disambiguate. +`@version` optionally allows specifying which versions of packages. Versions +may be specified by `@1`, `@1.2`, `@1.2.3`, allowing any version with a prefix +that matches, or ranges thereof, such as `@1.2-3.4.5`. A git-revision can be +specified by `#branch` or `#commit`. + +If a local path is used as an argument to `add`, the path needs to be a git repository. +The project will then track that git repository just like if it is was tracking a remote repository online. + +**Examples** +``` +pkg> add Example +pkg> add Example@0.5 +pkg> add Example#master +pkg> add Example#c37b675 +pkg> add https://github.com/JuliaLang/Example.jl#master +pkg> add git@github.com:JuliaLang/Example.jl.git +pkg> add Example=7876af07-990d-54b4-ab0e-23690620f79a +``` + """, +),( CMD_DEVELOP, + ["develop", "dev"], + do_develop!, + (ARG_ALL, []), + [ + ("local", OPT_SWITCH, :devdir => true), + ("shared", OPT_SWITCH, :devdir => false), + ], + md""" + develop [--shared|--local] pkg[=uuid] [#rev] ... + +Make a package available for development. If `pkg` is an existing local path that path will be recorded in +the manifest and used. Otherwise, a full git clone of `pkg` at rev `rev` is made. The location of the clone is +controlled by the `--shared` (default) and `--local` arguments. The `--shared` location defaults to +`~/.julia/dev`, but can be controlled with the `JULIA_PKG_DEVDIR` environment variable. When `--local` is given, +the clone is placed in a `dev` folder in the current project. +This operation is undone by `free`. + +*Example* +```jl +pkg> develop Example +pkg> develop Example#master +pkg> develop Example#c37b675 +pkg> develop https://github.com/JuliaLang/Example.jl#master +pkg> develop --local Example +``` + """, +),( CMD_FREE, + ["free"], + do_free!, + (ARG_PKG, []), + [], + md""" + free pkg[=uuid] ... + +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 +makes the package no longer being checked out. + """, +),( CMD_PIN, + ["pin"], + do_pin!, + (ARG_VERSION, []), + [], + md""" + + pin pkg[=uuid] ... + +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. + """, +),( CMD_BUILD, + ["build"], + do_build!, + (ARG_PKG, []), + [], + md""" + + build pkg[=uuid] ... + +Run the build script in `deps/build.jl` for each package in `pkg` and all of their dependencies in depth-first recursive order. +If no packages are given, runs the build scripts for all packages in the manifest. +The `startup.jl` file is disabled during building unless julia is started with `--startup-file=yes`. + """, +),( CMD_RESOLVE, + ["resolve"], + do_resolve!, + (ARG_RAW, [0]), + [], + md""" + resolve + +Resolve the project i.e. run package resolution and update the Manifest. This is useful in case the dependencies of developed +packages have changed causing the current Manifest to_indices be out of sync. + """, +),( CMD_ACTIVATE, + ["activate"], + do_activate!, + (ARG_RAW, [0,1]), + [], + nothing, +),( CMD_UP, + ["update", "up"], + do_up!, + (ARG_VERSION, []), + [ + (["project", "p"], OPT_SWITCH, :mode => PKGMODE_PROJECT), + (["manifest", "m"], OPT_SWITCH, :mode => PKGMODE_MANIFEST), + ("major", OPT_SWITCH, :level => UPLEVEL_MAJOR), + ("minor", OPT_SWITCH, :level => UPLEVEL_MINOR), + ("patch", OPT_SWITCH, :level => UPLEVEL_PATCH), + ("fixed", OPT_SWITCH, :level => UPLEVEL_FIXED), + ], + md""" + + up [-p|project] [opts] pkg[=uuid] [@version] ... + up [-m|manifest] [opts] pkg[=uuid] [@version] ... + + opts: --major | --minor | --patch | --fixed + +Update the indicated package within the constraints of the indicated version +specifications. Versions may be specified by `@1`, `@1.2`, `@1.2.3`, allowing +any version with a prefix that matches, or ranges thereof, such as `@1.2-3.4.5`. +In `--project` mode, package specifications only match project packages, while +in `manifest` mode they match any manifest package. Bound level options force +the following packages to be upgraded only within the current major, minor, +patch version; if the `--fixed` upgrade level is given, then the following +packages will not be upgraded at all. + """, +),( CMD_GENERATE, + ["generate"], + do_generate!, + (ARG_RAW, [1]), + [], + md""" + + generate pkgname + +Create a project called `pkgname` in the current folder. + """, +),( CMD_PRECOMPILE, + ["precompile"], + do_precompile!, + (ARG_RAW, [0]), + [], + md""" + precompile + +Precompile all the dependencies of the project by running `import` on all of them in a new process. +The `startup.jl` file is disabled during precompilation unless julia is started with `--startup-file=yes`. + """, +),( CMD_STATUS, + ["status", "st"], + do_status!, + (ARG_RAW, [0]), + [ + (["project", "p"], OPT_SWITCH, :mode => PKGMODE_PROJECT), + (["manifest", "m"], OPT_SWITCH, :mode => PKGMODE_MANIFEST), + ], + md""" + + status + status [-p|--project] + status [-m|--manifest] + +Show the status of the current environment. By default, the full contents of +the project file is summarized, showing what version each package is on and +how it has changed since the last git commit (if in a git repo), as well as +any changes to manifest packages not already listed. In `--project` mode, the +status of the project file is summarized. In `--manifest` mode the output also +includes the dependencies of explicitly added packages. + """, +),( CMD_GC, + ["gc"], + do_gc!, + (ARG_RAW, [0]), + [], + md""" + +Deletes packages that cannot be reached from any existing environment. + """, +),( CMD_PREVIEW, + ["preview"], + do_preview!, + (ARG_RAW, [1]), + [], + md""" + + preview cmd + +Runs the command `cmd` in preview mode. This is defined such that no side effects +will take place i.e. no packages are downloaded and neither the project nor manifest +is modified. + """, +), +], #package +] #command_declarations + +super_specs = SuperSpecs(command_declarations) # TODO should this go here ? +command_specs = super_specs["package"] +all_commands_sorted = sort(collect(String,keys(command_specs))) +long_commands = filter(c -> length(c) > 2, all_commands_sorted) +function all_options() + all_opts = [] + for command in values(command_specs) + for opt_spec in values(command.option_specs) + push!(all_opts, opt_spec.name) + opt_spec.short_name !== nothing && push!(all_opts, opt_spec.short_name) + end + end + unique!(all_opts) + return all_opts end +all_options_sorted = [length(opt) > 1 ? "--$opt" : "-$opt" for opt in sort!(all_options())] +long_options = filter(c -> length(c) > 2, all_options_sorted) + +const help = md""" + +**Welcome to the Pkg REPL-mode**. To return to the `julia>` prompt, either press +backspace when the input line is empty or press Ctrl+C. + + +**Synopsis** + + pkg> [--env=...] cmd [opts] [args] + +Multiple commands can be given on the same line by interleaving a `;` between the commands. + +**Environment** + +The `--env` meta option determines which project environment to manipulate. By +default, this looks for a git repo in the parents directories of the current +working directory, and if it finds one, it uses that as an environment. Otherwise, +it uses a named environment (typically found in `~/.julia/environments`) looking +for environments named `v$(VERSION.major).$(VERSION.minor).$(VERSION.patch)`, +`v$(VERSION.major).$(VERSION.minor)`, `v$(VERSION.major)` or `default` in order. + +**Commands** + +What action you want the package manager to take: + +`help`: show this message + +`status`: summarize contents of and changes to environment + +`add`: add packages to project + +`develop`: clone the full package repo locally for development + +`rm`: remove packages from project or manifest + +`up`: update packages in manifest + +`test`: run tests for packages + +`build`: run the build script for packages + +`pin`: pins the version of packages + +`free`: undoes a `pin`, `develop`, or stops tracking a repo. + +`instantiate`: downloads all the dependencies for the project + +`resolve`: resolves to update the manifest from changes in dependencies of +developed packages + +`generate`: generate files for a new project + +`preview`: previews a subsequent command without affecting the current state + +`precompile`: precompile all the project dependencies + +`gc`: garbage collect packages not used for a significant time + +`activate`: set the primary environment the package manager manipulates +""" + +end #module diff --git a/stdlib/Pkg/test/repl.jl b/stdlib/Pkg/test/repl.jl index 2530a4ed5709a..34e7ad9f75918 100644 --- a/stdlib/Pkg/test/repl.jl +++ b/stdlib/Pkg/test/repl.jl @@ -72,23 +72,27 @@ temp_pkg_dir() do project_path end @testset "tokens" begin - tokens = Pkg.REPLMode.tokenize("add git@github.com:JuliaLang/Example.jl.git") - @test tokens[1][2] == "git@github.com:JuliaLang/Example.jl.git" - tokens = Pkg.REPLMode.tokenize("add git@github.com:JuliaLang/Example.jl.git#master") - @test tokens[1][2] == "git@github.com:JuliaLang/Example.jl.git" - @test tokens[1][3].rev == "master" - tokens = Pkg.REPLMode.tokenize("add git@github.com:JuliaLang/Example.jl.git#c37b675") - @test tokens[1][2] == "git@github.com:JuliaLang/Example.jl.git" - @test tokens[1][3].rev == "c37b675" - tokens = Pkg.REPLMode.tokenize("add git@github.com:JuliaLang/Example.jl.git@v0.5.0") - @test tokens[1][2] == "git@github.com:JuliaLang/Example.jl.git" - @test repr(tokens[1][3]) == "VersionRange(\"0.5.0\")" - tokens = Pkg.REPLMode.tokenize("add git@github.com:JuliaLang/Example.jl.git@0.5.0") - @test tokens[1][2] == "git@github.com:JuliaLang/Example.jl.git" - @test repr(tokens[1][3]) == "VersionRange(\"0.5.0\")" - tokens = Pkg.REPLMode.tokenize("add git@gitlab-fsl.jsc.näsan.guvv:drats/URGA2010.jl.git@0.5.0") - @test tokens[1][2] == "git@gitlab-fsl.jsc.näsan.guvv:drats/URGA2010.jl.git" - @test repr(tokens[1][3]) == "VersionRange(\"0.5.0\")" + statement = Pkg.REPLMode.parse("add git@github.com:JuliaLang/Example.jl.git")[1] + @test "add" in statement.command.names + @test statement.arguments[1] == "git@github.com:JuliaLang/Example.jl.git" + statement = Pkg.REPLMode.parse("add git@github.com:JuliaLang/Example.jl.git#master")[1] + @test "add" in statement.command.names + @test length(statement.arguments) == 2 + @test statement.arguments[1] == "git@github.com:JuliaLang/Example.jl.git" + @test statement.arguments[2] == "#master" + statement = Pkg.REPLMode.parse("add git@github.com:JuliaLang/Example.jl.git#c37b675")[1] + @test "add" in statement.command.names + @test length(statement.arguments) == 2 + @test statement.arguments[1] == "git@github.com:JuliaLang/Example.jl.git" + @test statement.arguments[2] == "#c37b675" + statement = Pkg.REPLMode.parse("add git@github.com:JuliaLang/Example.jl.git@v0.5.0")[1] + @test statement.arguments[1] == "git@github.com:JuliaLang/Example.jl.git" + @test statement.arguments[2] == "@v0.5.0" + statement = Pkg.REPLMode.parse("add git@gitlab-fsl.jsc.näsan.guvv:drats/URGA2010.jl.git@0.5.0")[1] + @test "add" in statement.command.names + @test length(statement.arguments) == 2 + @test statement.arguments[1] == "git@gitlab-fsl.jsc.näsan.guvv:drats/URGA2010.jl.git" + @test statement.arguments[2] == "@0.5.0" end temp_pkg_dir() do project_path; cd(project_path) do; mktempdir() do tmp_pkg_path @@ -566,10 +570,301 @@ end @testset "`do_generate!` error paths" begin with_temp_env() do - @test_throws CommandError Pkg.REPLMode.pkgstr("generate @0.0.0") @test_throws CommandError Pkg.REPLMode.pkgstr("generate Example Example2") @test_throws CommandError Pkg.REPLMode.pkgstr("generate") end end +@testset "`parse_option` unit tests" begin + opt = Pkg.REPLMode.parse_option("-x") + @test opt.val == "x" + @test opt.argument === nothing + opt = Pkg.REPLMode.parse_option("--hello") + @test opt.val == "hello" + @test opt.argument === nothing + opt = Pkg.REPLMode.parse_option("--env=some") + @test opt.val == "env" + @test opt.argument == "some" +end + +@testset "`parse` integration tests" begin + @test isempty(Pkg.REPLMode.parse("")) + + statement = Pkg.REPLMode.parse("up")[1] + @test statement.command.kind == Pkg.REPLMode.CMD_UP + @test isempty(statement.meta_options) + @test isempty(statement.options) + @test isempty(statement.arguments) + + statement = Pkg.REPLMode.parse("dev Example")[1] + @test statement.command.kind == Pkg.REPLMode.CMD_DEVELOP + @test isempty(statement.meta_options) + @test isempty(statement.options) + @test statement.arguments == ["Example"] + + statement = Pkg.REPLMode.parse("dev Example#foo #bar")[1] + @test statement.command.kind == Pkg.REPLMode.CMD_DEVELOP + @test isempty(statement.meta_options) + @test isempty(statement.options) + @test statement.arguments == ["Example", "#foo", "#bar"] + + statement = Pkg.REPLMode.parse("dev Example#foo Example@v0.0.1")[1] + @test statement.command.kind == Pkg.REPLMode.CMD_DEVELOP + @test isempty(statement.meta_options) + @test isempty(statement.options) + @test statement.arguments == ["Example", "#foo", "Example", "@v0.0.1"] + + statement = Pkg.REPLMode.parse("--one -t add --first --second arg1")[1] + @test statement.command.kind == Pkg.REPLMode.CMD_ADD + @test statement.meta_options == ["--one", "-t"] + @test statement.options == ["--first", "--second"] + @test statement.arguments == ["arg1"] + + statements = Pkg.REPLMode.parse("--one -t add --first -o arg1; --meta pin -x -a arg0 Example") + @test statements[1].command.kind == Pkg.REPLMode.CMD_ADD + @test statements[1].meta_options == ["--one", "-t"] + @test statements[1].options == ["--first", "-o"] + @test statements[1].arguments == ["arg1"] + @test statements[2].command.kind == Pkg.REPLMode.CMD_PIN + @test statements[2].meta_options == ["--meta"] + @test statements[2].options == ["-x", "-a"] + @test statements[2].arguments == ["arg0", "Example"] + + statements = Pkg.REPLMode.parse("up; --meta -x pin --first; dev") + @test statements[1].command.kind == Pkg.REPLMode.CMD_UP + @test isempty(statements[1].meta_options) + @test isempty(statements[1].options) + @test isempty(statements[1].arguments) + @test statements[2].command.kind == Pkg.REPLMode.CMD_PIN + @test statements[2].meta_options == ["--meta", "-x"] + @test statements[2].options == ["--first"] + @test isempty(statements[2].arguments) + @test statements[3].command.kind == Pkg.REPLMode.CMD_DEVELOP + @test isempty(statements[3].meta_options) + @test isempty(statements[3].options) + @test isempty(statements[3].arguments) +end + +@testset "argument count errors" begin + temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; + @test_throws CommandError Pkg.REPLMode.pkgstr("activate one two") + @test_throws CommandError Pkg.REPLMode.pkgstr("activate one two three") + @test_throws CommandError Pkg.REPLMode.pkgstr("precompile Example") + end + end + end +end + +@testset "invalid options" begin + temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; + @test_throws CommandError Pkg.REPLMode.pkgstr("rm --minor Example") + @test_throws CommandError Pkg.REPLMode.pkgstr("pin --project Example") + end + end + end +end + +@testset "Argument order" begin + temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; + @test_throws CommandError Pkg.REPLMode.pkgstr("add FooBar Example#foobar#foobar") + @test_throws CommandError Pkg.REPLMode.pkgstr("up Example#foobar@0.0.0") + @test_throws CommandError Pkg.REPLMode.pkgstr("pin Example@0.0.0@0.0.1") + @test_throws CommandError Pkg.REPLMode.pkgstr("up #foobar") + @test_throws CommandError Pkg.REPLMode.pkgstr("add @0.0.1") + end + end + end +end + +@testset "conflicting options" begin + temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; + @test_throws CommandError Pkg.REPLMode.pkgstr("up --major --minor") + @test_throws CommandError Pkg.REPLMode.pkgstr("rm --project --manifest") + end + end + end +end + +@testset "gc" begin + temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; + @test_throws CommandError Pkg.REPLMode.pkgstr("gc --project") + @test_throws CommandError Pkg.REPLMode.pkgstr("gc --minor") + @test_throws CommandError Pkg.REPLMode.pkgstr("gc Example") + Pkg.REPLMode.pkgstr("gc") + end + end + end +end + +@testset "precompile" begin + temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; + @test_throws CommandError Pkg.REPLMode.pkgstr("precompile --project") + @test_throws CommandError Pkg.REPLMode.pkgstr("precompile Example") + Pkg.REPLMode.pkgstr("precompile") + end + end + end +end + +@testset "generate" begin + temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; + @test_throws CommandError Pkg.REPLMode.pkgstr("generate --major Example") + @test_throws CommandError Pkg.REPLMode.pkgstr("generate --foobar Example") + @test_throws CommandError Pkg.REPLMode.pkgstr("generate Example1 Example2") + Pkg.REPLMode.pkgstr("generate Example") + end + end + end +end + +@testset "test" begin + temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; + Pkg.add("Example") + @test_throws CommandError Pkg.REPLMode.pkgstr("test --project Example") + Pkg.REPLMode.pkgstr("test --coverage Example") + Pkg.REPLMode.pkgstr("test Example") + end + end + end +end + +@testset "build" begin + temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; + @test_throws CommandError Pkg.REPLMode.pkgstr("build --project") + @test_throws CommandError Pkg.REPLMode.pkgstr("build --minor") + end + end + end +end + +@testset "free" begin + temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; + @test_throws CommandError Pkg.REPLMode.pkgstr("free --project") + @test_throws CommandError Pkg.REPLMode.pkgstr("free --major") + end + end + end +end + +@testset "unit tests for `group_words`" begin + # simple + groups = Pkg.REPLMode.group_words(["add", "Example"]) + @test length(groups) == 1 + @test groups[1][1] == "add" + @test groups[1][2] == "Example" + # statement break + groups = Pkg.REPLMode.group_words(["a", "b", "c", ";", "a", "b"]) + @test length(groups) == 2 + groups = Pkg.REPLMode.group_words(["a", "b", "c", ";", "a", "b", ";", "d"]) + @test length(groups) == 3 + # trailing statement break + groups = Pkg.REPLMode.group_words(["a", "b", "c", ";", "a", "b", ";"]) + @test length(groups) == 2 + # errors + @test_throws CommandError Pkg.REPLMode.group_words(["a", "b", ";", ";", "a", "b"]) + @test_throws CommandError Pkg.REPLMode.group_words([";", "add", "Example"]) +end + +@testset "tests for api opts" begin + specs = Pkg.REPLMode.OptionSpecs(Pkg.REPLMode.OptionDeclaration[ + (["project", "p"], Pkg.REPLMode.OPT_SWITCH, :mode => Pkg.Types.PKGMODE_PROJECT), + (["manifest", "m"], Pkg.REPLMode.OPT_SWITCH, :mode => Pkg.Types.PKGMODE_MANIFEST), + ("major", Pkg.REPLMode.OPT_SWITCH, :level => Pkg.Types.UPLEVEL_MAJOR), + ("minor", Pkg.REPLMode.OPT_SWITCH, :level => Pkg.Types.UPLEVEL_MINOR), + ("patch", Pkg.REPLMode.OPT_SWITCH, :level => Pkg.Types.UPLEVEL_PATCH), + ("fixed", Pkg.REPLMode.OPT_SWITCH, :level => Pkg.Types.UPLEVEL_FIXED), + ("rawnum", Pkg.REPLMode.OPT_ARG, :num => nothing), + ("plus", Pkg.REPLMode.OPT_ARG, :num => x->parse(Int,x)+1), + ]) + + api_opts = Pkg.REPLMode.APIOptions([ + Pkg.REPLMode.Option("manifest"), + Pkg.REPLMode.Option("patch"), + Pkg.REPLMode.Option("rawnum", "5"), + ], specs) + + @test Pkg.REPLMode.key_api(:foo, api_opts) === nothing + @test Pkg.REPLMode.key_api(:mode, api_opts) == Pkg.Types.PKGMODE_MANIFEST + @test Pkg.REPLMode.key_api(:level, api_opts) == Pkg.Types.UPLEVEL_PATCH + @test Pkg.REPLMode.key_api(:num, api_opts) == "5" + + api_opts = Pkg.REPLMode.APIOptions([ + Pkg.REPLMode.Option("project"), + Pkg.REPLMode.Option("patch"), + Pkg.REPLMode.Option("plus", "5"), + ], specs) + + @test Pkg.REPLMode.key_api(:mode, api_opts) == Pkg.Types.PKGMODE_PROJECT + @test Pkg.REPLMode.key_api(:level, api_opts) == Pkg.Types.UPLEVEL_PATCH + @test Pkg.REPLMode.key_api(:num, api_opts) == 6 + + @test Pkg.REPLMode.key_api(:foo, api_opts) === nothing + Pkg.REPLMode.set_default!(:foo => "bar", api_opts) + @test Pkg.REPLMode.key_api(:foo, api_opts) == "bar" + Pkg.REPLMode.set_default!(:level => "bar", api_opts) + @test Pkg.REPLMode.key_api(:level, api_opts) == Pkg.Types.UPLEVEL_PATCH +end + +@testset "meta option errors" begin + temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; + # unregistered meta options + @test_throws CommandError Pkg.REPLMode.pkgstr("--foo=foo add Example") + @test_throws CommandError Pkg.REPLMode.pkgstr("--bar add Example") + @test_throws CommandError Pkg.REPLMode.pkgstr("-x add Example") + # malformed, but registered meta option + @test_throws CommandError Pkg.REPLMode.pkgstr("--env Example") + end + end + end +end + +@testset "activate" begin + temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; + mkdir("Foo") + pkg"activate" + default = Base.active_project() + pkg"activate Foo" + @test Base.active_project() == joinpath(pwd(), "Foo", "Project.toml") + pkg"activate" + @test Base.active_project() == default + end + end + end +end + +@testset "subcommands" begin + temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do + Pkg.REPLMode.pkg"package add Example" + @test isinstalled(TEST_PKG) + Pkg.REPLMode.pkg"package rm Example" + @test !isinstalled(TEST_PKG) + end + end + end +end + +@testset "`parse_quotes` unit tests" begin + qwords = Pkg.REPLMode.parse_quotes("\"Don't\" forget to '\"test\"'") + @test qwords[1].isquoted + @test qwords[1].word == "Don't" + @test !qwords[2].isquoted + @test qwords[2].word == "forget" + @test !qwords[3].isquoted + @test qwords[3].word == "to" + @test qwords[4].isquoted + @test qwords[4].word == "\"test\"" + @test_throws CommandError Pkg.REPLMode.parse_quotes("Don't") + @test_throws CommandError Pkg.REPLMode.parse_quotes("Unterminated \"quot") +end + +@testset "argument kinds" begin + temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; + @test_throws CommandError pkg"pin Example#foo" + @test_throws CommandError pkg"test Example#foo" + @test_throws CommandError pkg"test Example@v0.0.1" + end + end + end +end + end # module From 82e9078dbefb5074fa1a7d409cdf699ea37c878c Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Wed, 1 Aug 2018 00:31:21 +0200 Subject: [PATCH 11/36] Make `Pkg.activate(path)` behave like `pkg> activate path`. (Pkg PR 543) (cherry picked from commit e9e320b3fb59868425388ecbb51e9a42a5afff77, Julia PR #28443) --- stdlib/Pkg/src/API.jl | 21 ++++++++++++++++++++ stdlib/Pkg/src/REPLMode.jl | 23 +++------------------- stdlib/Pkg/test/api.jl | 39 ++++++++++++++++++++++++++++++++++++++ stdlib/Pkg/test/pkg.jl | 1 + stdlib/Pkg/test/repl.jl | 2 ++ 5 files changed, 66 insertions(+), 20 deletions(-) create mode 100644 stdlib/Pkg/test/api.jl diff --git a/stdlib/Pkg/src/API.jl b/stdlib/Pkg/src/API.jl index dc659e3959408..010d9047dec17 100644 --- a/stdlib/Pkg/src/API.jl +++ b/stdlib/Pkg/src/API.jl @@ -548,7 +548,28 @@ function status(ctx::Context, mode=PKGMODE_PROJECT) end function activate(path::Union{String,Nothing}=nothing) + if path !== nothing + devpath = nothing + env = Base.active_project() === nothing ? nothing : EnvCache() + if env !== nothing && haskey(env.project["deps"], path) + uuid = UUID(env.project["deps"][path]) + info = manifest_info(env, uuid) + devpath = haskey(info, "path") ? joinpath(dirname(env.project_file), info["path"]) : nothing + end + # `pkg> activate path`/`Pkg.activate(path)` does the following + # 1. if path exists, activate that + # 2. if path exists in deps, and the dep is deved, activate that path (`devpath` above) + # 3. activate the non-existing directory (e.g. as in `pkg> activate .` for initing a new env) + if Types.isdir_windows_workaround(path) + path = abspath(path) + elseif devpath !== nothing + path = abspath(devpath) + else + path = abspath(path) + end + end Base.ACTIVE_PROJECT[] = Base.load_path_expand(path) + return end """ diff --git a/stdlib/Pkg/src/REPLMode.jl b/stdlib/Pkg/src/REPLMode.jl index c38749b968b14..13a173ffe774b 100644 --- a/stdlib/Pkg/src/REPLMode.jl +++ b/stdlib/Pkg/src/REPLMode.jl @@ -612,28 +612,11 @@ do_up!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = API.up(ctx, args; api_opts...) function do_activate!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) + # TODO: Remove the ctx argument to this function. if isempty(args) - return API.activate() - end - - path = args[1] - env = Base.active_project() === nothing ? nothing : ctx.env - devpath = nothing - if env !== nothing && haskey(env.project["deps"], path) - uuid = UUID(env.project["deps"][path]) - info = manifest_info(env, uuid) - devpath = haskey(info, "path") ? joinpath(dirname(env.project_file), info["path"]) : nothing - end - # `pkg> activate path` does the following - # 1. if path exists, activate that - # 2. if path exists in deps, and the dep is deved, activate that path (`devpath`) above - # 3. activate the non-existing directory (e.g. as in `pkg> activate . for initing a new dev`) - if Types.isdir_windows_workaround(path) - API.activate(abspath(path)) - elseif devpath !== nothing - API.activate(abspath(devpath)) + return API.activate(nothing) else - API.activate(abspath(path)) + return API.activate(args[1]) end end diff --git a/stdlib/Pkg/test/api.jl b/stdlib/Pkg/test/api.jl new file mode 100644 index 0000000000000..edbc15f186754 --- /dev/null +++ b/stdlib/Pkg/test/api.jl @@ -0,0 +1,39 @@ +module APITests + +using Pkg, Test + +@testset "Pkg.activate" begin + cd(mktempdir()) do + path = pwd() + Pkg.activate(".") + mkdir("Foo") + cd(mkdir("modules")) do + Pkg.generate("Foo") + end + Pkg.develop(Pkg.Types.PackageSpec(url="modules/Foo")) # to avoid issue #542 + Pkg.activate("Foo") # activate path Foo over deps Foo + @test Base.active_project() == joinpath(path, "Foo", "Project.toml") + Pkg.activate(".") + rm("Foo"; force=true, recursive=true) + Pkg.activate("Foo") # activate path from developed Foo + @test Base.active_project() == joinpath(path, "modules", "Foo", "Project.toml") + Pkg.activate(".") + Pkg.activate("./Foo") # activate empty directory Foo (sidestep the developed Foo) + @test Base.active_project() == joinpath(path, "Foo", "Project.toml") + Pkg.activate(".") + Pkg.activate("Bar") # activate empty directory Bar + @test Base.active_project() == joinpath(path, "Bar", "Project.toml") + Pkg.activate(".") + Pkg.add("Example") # non-deved deps should not be activated + Pkg.activate("Example") + @test Base.active_project() == joinpath(path, "Example", "Project.toml") + Pkg.activate(".") + cd(mkdir("tests")) + Pkg.activate("Foo") # activate developed Foo from another directory + @test Base.active_project() == joinpath(path, "modules", "Foo", "Project.toml") + Pkg.activate() # activate home project + @test Base.ACTIVE_PROJECT[] === nothing + end +end + +end # module APITests diff --git a/stdlib/Pkg/test/pkg.jl b/stdlib/Pkg/test/pkg.jl index ae9a706aefbd3..6538a4bba0d88 100644 --- a/stdlib/Pkg/test/pkg.jl +++ b/stdlib/Pkg/test/pkg.jl @@ -436,5 +436,6 @@ temp_pkg_dir() do project_path end include("repl.jl") +include("api.jl") end # module diff --git a/stdlib/Pkg/test/repl.jl b/stdlib/Pkg/test/repl.jl index 34e7ad9f75918..5714dc7a9fd17 100644 --- a/stdlib/Pkg/test/repl.jl +++ b/stdlib/Pkg/test/repl.jl @@ -282,6 +282,8 @@ temp_pkg_dir() do project_path cd(mkdir("tests")) pkg"activate Foo" # activate developed Foo from another directory @test Base.active_project() == joinpath(path, "modules", "Foo", "Project.toml") + pkg"activate" # activate home project + @test Base.ACTIVE_PROJECT[] === nothing end end From a15865284a6d916185b22bdff25025f7736e06b6 Mon Sep 17 00:00:00 2001 From: David Varela Date: Wed, 1 Aug 2018 01:15:32 -0700 Subject: [PATCH 12/36] Refactor some REPL issues (Pkg PR 552) * Refactor: APIOptions should be a dictionary * Fix `do_activate!` interface * Update tests: APIOptions is a dictionary * Allow more flexibility for REPL `do_<>` functions (cherry picked from commit 5b6fbb0d898a99c62b9df9285f977f2bae3383dc, Julia PR #28443) --- stdlib/Pkg/src/REPLMode.jl | 117 +++++++++++++++++-------------------- stdlib/Pkg/src/Types.jl | 8 +++ stdlib/Pkg/test/repl.jl | 20 +++---- 3 files changed, 68 insertions(+), 77 deletions(-) diff --git a/stdlib/Pkg/src/REPLMode.jl b/stdlib/Pkg/src/REPLMode.jl index 13a173ffe774b..443f7f2a3017b 100644 --- a/stdlib/Pkg/src/REPLMode.jl +++ b/stdlib/Pkg/src/REPLMode.jl @@ -19,7 +19,6 @@ end ########### # Options # ########### -#TODO should this opt be removed: ("name", :cmd, :temp => false) struct OptionSpec name::String short_name::Union{Nothing,String} @@ -101,7 +100,7 @@ struct ArgSpec end const CommandDeclaration = Tuple{CommandKind, Vector{String}, # names - Function, # handler + Union{Nothing,Function}, # handler Tuple{ArgClass, Vector{Int}}, # argument count Vector{OptionDeclaration}, # options Union{Nothing, Markdown.MD}, #help @@ -109,7 +108,7 @@ const CommandDeclaration = Tuple{CommandKind, struct CommandSpec kind::CommandKind names::Vector{String} - handler::Function + handler::Union{Nothing,Function} argument_spec::ArgSpec # note: just use range operator for max/min option_specs::Dict{String, OptionSpec} help::Union{Nothing, Markdown.MD} @@ -311,7 +310,6 @@ end ############## const Token = Union{String, VersionRange, Rev} const PkgArguments = Union{Vector{String}, Vector{PackageSpec}} -#TODO embed spec in PkgCommand? struct PkgCommand meta_options::Vector{Option} spec::CommandSpec @@ -321,14 +319,14 @@ struct PkgCommand PkgCommand(meta_opts, cmd_name, opts, args) = new(meta_opts, cmd_name, opts, args) end -const APIOption = Pair{Symbol, Any} -APIOptions(command::PkgCommand)::Vector{APIOption} = +const APIOptions = Dict{Symbol, Any} +APIOptions(command::PkgCommand)::Dict{Symbol, Any} = APIOptions(command.options, command.spec.option_specs) function APIOptions(options::Vector{Option}, specs::Dict{String, OptionSpec}, - )::Vector{APIOption} - return map(options) do opt + )::Dict{Symbol, Any} + keyword_vec = map(options) do opt spec = specs[opt.val] # opt is switch spec.is_switch && return spec.api @@ -337,18 +335,9 @@ function APIOptions(options::Vector{Option}, # given opt wrapper return spec.api.first => spec.api.second(opt.argument) end + return Dict(keyword_vec) end -function key_api(key::Symbol, api_opts::Vector{APIOption}) - index = findfirst(x->x.first == key, api_opts) - if index !== nothing - return api_opts[index].second - end -end - -set_default!(opt, api_opts::Vector{APIOption}) = - key_api(opt.first, api_opts) === nothing && push!(api_opts, opt) - function enforce_argument_order(args::Vector{Token}) prev_arg = nothing function check_prev_arg(valid_type::DataType, error_message::AbstractString) @@ -496,6 +485,8 @@ function PkgCommand(statement::Statement)::PkgCommand return PkgCommand(meta_opts, statement.command, opts, args) end +Context!(ctx::APIOptions)::Context = Types.Context!(collect(ctx)) + ############# # Execution # ############# @@ -519,15 +510,14 @@ function do_cmd(repl::REPL.AbstractREPL, input::String; do_rethrow=false) end function do_cmd!(command::PkgCommand, repl) - meta_opts = APIOptions(command.meta_options, meta_option_specs) - ctx = Context(meta_opts...) + context = APIOptions(command.meta_options, meta_option_specs) spec = command.spec # REPL specific commands if spec.kind == CMD_HELP - return Base.invokelatest(do_help!, ctx, command, repl) + return Base.invokelatest(do_help!, command, repl) elseif spec.kind == CMD_PREVIEW - ctx.preview = true + context[:preview] = true cmd = command.arguments[1] cmd_spec = get(command_specs, cmd, nothing) cmd_spec === nothing && @@ -538,10 +528,15 @@ function do_cmd!(command::PkgCommand, repl) # API commands # TODO is invokelatest still needed? - Base.invokelatest(spec.handler, ctx, command.arguments, APIOptions(command)) + api_opts = APIOptions(command) + if applicable(spec.handler, context, command.arguments, api_opts) + Base.invokelatest(spec.handler, context, command.arguments, api_opts) + else + Base.invokelatest(spec.handler, command.arguments, api_opts) + end end -function do_help!(ctk::Context, command::PkgCommand, repl::REPL.AbstractREPL) +function do_help!(command::PkgCommand, repl::REPL.AbstractREPL) disp = REPL.REPLDisplay(repl) if isempty(command.arguments) Base.display(disp, help) @@ -562,21 +557,16 @@ function do_help!(ctk::Context, command::PkgCommand, repl::REPL.AbstractREPL) end # TODO set default Display.status keyword: mode = PKGMODE_COMBINED -function do_status!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) - set_default!(:mode => PKGMODE_COMBINED, api_opts) - Display.status(ctx, key_api(:mode, api_opts)) -end - -# TODO remove the need to specify a handler function (not needed for REPL commands) -do_preview!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = nothing +do_status!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = + Display.status(Context!(ctx), get(api_opts, :mode, PKGMODE_COMBINED)) # TODO , test recursive dependencies as on option. -function do_test!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) +function do_test!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) foreach(arg -> arg.mode = PKGMODE_MANIFEST, args) - API.test(ctx, args; api_opts...) + API.test(Context!(ctx), args; collect(api_opts)...) end -function do_registry_add!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) +function do_registry_add!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) println("This is a dummy function for now") println("My args are:") for arg in args @@ -584,35 +574,34 @@ function do_registry_add!(ctx::Context, args::PkgArguments, api_opts::Vector{API end end -do_precompile!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = - API.precompile(ctx) +do_precompile!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = + API.precompile(Context!(ctx)) -do_resolve!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = - API.resolve(ctx) +do_resolve!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = + API.resolve(Context!(ctx)) -do_gc!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = - API.gc(ctx; api_opts...) +do_gc!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = + API.gc(Context!(ctx); collect(api_opts)...) -do_instantiate!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = - API.instantiate(ctx; api_opts...) +do_instantiate!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = + API.instantiate(Context!(ctx); collect(api_opts)...) -do_generate!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = - API.generate(ctx, args[1]) +do_generate!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = + API.generate(Context!(ctx), args[1]) -do_build!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = - API.build(ctx, args; api_opts...) +do_build!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = + API.build(Context!(ctx), args; collect(api_opts)...) -do_rm!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = - API.rm(ctx, args; api_opts...) +do_rm!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = + API.rm(Context!(ctx), args; collect(api_opts)...) -do_free!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = - API.free(ctx, args; api_opts...) +do_free!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = + API.free(Context!(ctx), args; collect(api_opts)...) -do_up!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) = - API.up(ctx, args; api_opts...) +do_up!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = + API.up(Context!(ctx), args; collect(api_opts)...) -function do_activate!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) - # TODO: Remove the ctx argument to this function. +function do_activate!(args::PkgArguments, api_opts::APIOptions) if isempty(args) return API.activate(nothing) else @@ -620,24 +609,24 @@ function do_activate!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOpti end end -function do_pin!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) +function do_pin!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) for arg in args # TODO not sure this is correct if arg.version.ranges[1].lower != arg.version.ranges[1].upper cmderror("pinning a package requires a single version, not a versionrange") end end - API.pin(ctx, args; api_opts...) + API.pin(Context!(ctx), args; collect(api_opts)...) end -function do_add!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) - push!(api_opts, :mode => :add) - API.add_or_develop(ctx, args; api_opts...) +function do_add!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) + api_opts[:mode] = :add + API.add_or_develop(Context!(ctx), args; collect(api_opts)...) end -function do_develop!(ctx::Context, args::PkgArguments, api_opts::Vector{APIOption}) - push!(api_opts, :mode => :develop) - API.add_or_develop(ctx, args; api_opts...) +function do_develop!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) + api_opts[:mode] = :develop + API.add_or_develop(Context!(ctx), args; collect(api_opts)...) end ###################### @@ -950,7 +939,7 @@ julia is started with `--startup-file=yes`. """, ),( CMD_HELP, ["help", "?"], - do_help!, + nothing, (ARG_RAW, []), [], md""" @@ -1201,7 +1190,7 @@ Deletes packages that cannot be reached from any existing environment. """, ),( CMD_PREVIEW, ["preview"], - do_preview!, + nothing, (ARG_RAW, [1]), [], md""" diff --git a/stdlib/Pkg/src/Types.jl b/stdlib/Pkg/src/Types.jl index d1e6f5b025269..60db6699f1ccf 100644 --- a/stdlib/Pkg/src/Types.jl +++ b/stdlib/Pkg/src/Types.jl @@ -358,6 +358,14 @@ Base.@kwdef mutable struct Context old_pkg2_clone_name::String = "" end +function Context!(kw_context::Vector{Pair{Symbol,Any}})::Context + ctx = Context() + for (k, v) in kw_context + setfield!(ctx, k, v) + end + return ctx +end + function Context!(ctx::Context; kwargs...) for (k, v) in kwargs setfield!(ctx, k, v) diff --git a/stdlib/Pkg/test/repl.jl b/stdlib/Pkg/test/repl.jl index 5714dc7a9fd17..9486804e9f97c 100644 --- a/stdlib/Pkg/test/repl.jl +++ b/stdlib/Pkg/test/repl.jl @@ -785,10 +785,10 @@ end Pkg.REPLMode.Option("rawnum", "5"), ], specs) - @test Pkg.REPLMode.key_api(:foo, api_opts) === nothing - @test Pkg.REPLMode.key_api(:mode, api_opts) == Pkg.Types.PKGMODE_MANIFEST - @test Pkg.REPLMode.key_api(:level, api_opts) == Pkg.Types.UPLEVEL_PATCH - @test Pkg.REPLMode.key_api(:num, api_opts) == "5" + @test get(api_opts,:foo,nothing) === nothing + @test get(api_opts,:mode,nothing) == Pkg.Types.PKGMODE_MANIFEST + @test get(api_opts,:level,nothing) == Pkg.Types.UPLEVEL_PATCH + @test get(api_opts,:num,nothing) == "5" api_opts = Pkg.REPLMode.APIOptions([ Pkg.REPLMode.Option("project"), @@ -796,15 +796,9 @@ end Pkg.REPLMode.Option("plus", "5"), ], specs) - @test Pkg.REPLMode.key_api(:mode, api_opts) == Pkg.Types.PKGMODE_PROJECT - @test Pkg.REPLMode.key_api(:level, api_opts) == Pkg.Types.UPLEVEL_PATCH - @test Pkg.REPLMode.key_api(:num, api_opts) == 6 - - @test Pkg.REPLMode.key_api(:foo, api_opts) === nothing - Pkg.REPLMode.set_default!(:foo => "bar", api_opts) - @test Pkg.REPLMode.key_api(:foo, api_opts) == "bar" - Pkg.REPLMode.set_default!(:level => "bar", api_opts) - @test Pkg.REPLMode.key_api(:level, api_opts) == Pkg.Types.UPLEVEL_PATCH + @test get(api_opts,:mode,nothing) == Pkg.Types.PKGMODE_PROJECT + @test get(api_opts,:level,nothing) == Pkg.Types.UPLEVEL_PATCH + @test get(api_opts,:num,nothing) == 6 end @testset "meta option errors" begin From 455589aaabd0d77da2af2452e48738a03d7a5636 Mon Sep 17 00:00:00 2001 From: David Varela Date: Wed, 1 Aug 2018 23:47:16 -0700 Subject: [PATCH 13/36] Fix `instantiate` error message (Pkg PR 560) (cherry picked from commit 85d2a7e3b5b3e74be4af4cb580bb9928a7348e7e, Julia PR #28443) --- stdlib/Pkg/src/API.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/Pkg/src/API.jl b/stdlib/Pkg/src/API.jl index 010d9047dec17..e2cd8fb3f60ba 100644 --- a/stdlib/Pkg/src/API.jl +++ b/stdlib/Pkg/src/API.jl @@ -505,7 +505,7 @@ function instantiate(ctx::Context; manifest::Union{Bool, Nothing}=nothing, kwarg return end if !isfile(ctx.env.manifest_file) && manifest == true - cmderror("manifest at $(ctx.env.manifest) does not exist") + cmderror("manifest at $(ctx.env.manifest_file) does not exist") end update_registry(ctx) urls = Dict{} From 1b788480e3429c29681f711274504723960a76d9 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Thu, 2 Aug 2018 10:08:13 +0200 Subject: [PATCH 14/36] Replace depots()[1] with depots1() where depots1 throws (Pkg PR 563) a more descriptive error, instead of a BoundsError, in the case where DEPOT_PATH is empty. (cherry picked from commit 0ecaf2d7ad203ab2cfed5ffc657f0404a9dcd021, Julia PR #28443) --- stdlib/Pkg/src/Operations.jl | 6 +++--- stdlib/Pkg/src/Pkg.jl | 10 ++++++++-- stdlib/Pkg/src/Types.jl | 8 ++++---- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/stdlib/Pkg/src/Operations.jl b/stdlib/Pkg/src/Operations.jl index 63cf3ad6f273a..77cc24148304d 100644 --- a/stdlib/Pkg/src/Operations.jl +++ b/stdlib/Pkg/src/Operations.jl @@ -9,7 +9,7 @@ import LibGit2 import REPL using REPL.TerminalMenus using ..Types, ..GraphType, ..Resolve, ..Pkg2, ..BinaryProvider, ..GitTools, ..Display -import ..depots, ..devdir, ..Types.uuid_julia +import ..depots, ..depots1, ..devdir, ..Types.uuid_julia function find_installed(name::String, uuid::UUID, sha1::SHA1) slug_default = Base.version_slug(uuid, sha1) @@ -20,7 +20,7 @@ function find_installed(name::String, uuid::UUID, sha1::SHA1) ispath(path) && return path end end - return abspath(depots()[1], "packages", name, slug_default) + return abspath(depots1(), "packages", name, slug_default) end function load_versions(path::String) @@ -480,7 +480,7 @@ function install_git( tree = nothing try repo, git_hash = Base.shred!(LibGit2.CachedCredentials()) do creds - clones_dir = joinpath(depots()[1], "clones") + clones_dir = joinpath(depots1(), "clones") ispath(clones_dir) || mkpath(clones_dir) repo_path = joinpath(clones_dir, string(uuid)) repo = ispath(repo_path) ? LibGit2.GitRepo(repo_path) : begin diff --git a/stdlib/Pkg/src/Pkg.jl b/stdlib/Pkg/src/Pkg.jl index 3efe4bc1b4619..fabbcf54698a0 100644 --- a/stdlib/Pkg/src/Pkg.jl +++ b/stdlib/Pkg/src/Pkg.jl @@ -12,8 +12,14 @@ export PackageMode, PKGMODE_MANIFEST, PKGMODE_PROJECT export UpgradeLevel, UPLEVEL_MAJOR, UPLEVEL_MAJOR, UPLEVEL_MINOR, UPLEVEL_PATCH depots() = Base.DEPOT_PATH -logdir() = joinpath(depots()[1], "logs") -devdir() = get(ENV, "JULIA_PKG_DEVDIR", joinpath(depots()[1], "dev")) +function depots1() + d = depots() + isempty(d) && cmderror("no depots found in DEPOT_PATH") + return d[1] +end + +logdir() = joinpath(depots1(), "logs") +devdir() = get(ENV, "JULIA_PKG_DEVDIR", joinpath(depots1(), "dev")) const UPDATED_REGISTRY_THIS_SESSION = Ref(false) # load snapshotted dependencies diff --git a/stdlib/Pkg/src/Types.jl b/stdlib/Pkg/src/Types.jl index 60db6699f1ccf..74566582e7e8f 100644 --- a/stdlib/Pkg/src/Types.jl +++ b/stdlib/Pkg/src/Types.jl @@ -11,7 +11,7 @@ using REPL.TerminalMenus using ..TOML import ..Pkg, ..UPDATED_REGISTRY_THIS_SESSION -import Pkg: GitTools, depots, logdir +import Pkg: GitTools, depots, depots1, logdir import Base: SHA1 using SHA @@ -519,7 +519,7 @@ function handle_repos_develop!(ctx::Context, pkgs::AbstractVector{PackageSpec}, # We save the repo in case another environement wants to # develop from the same repo, this avoids having to reclone it # from scratch. - clone_path = joinpath(depots()[1], "clones") + clone_path = joinpath(depots1(), "clones") mkpath(clone_path) repo_path = joinpath(clone_path, string(hash(pkg.repo.url), "_full")) repo = nothing @@ -597,7 +597,7 @@ function handle_repos_add!(ctx::Context, pkgs::AbstractVector{PackageSpec}; pkg.repo == nothing && continue pkg.special_action = PKGSPEC_REPO_ADDED isempty(pkg.repo.url) && set_repo_for_pkg!(env, pkg) - clones_dir = joinpath(depots()[1], "clones") + clones_dir = joinpath(depots1(), "clones") mkpath(clones_dir) repo_path = joinpath(clones_dir, string(hash(pkg.repo.url))) repo = nothing @@ -899,7 +899,7 @@ end # Return paths of all registries in all depots function registries(; clone_default=true)::Vector{String} isempty(depots()) && return String[] - user_regs = abspath(depots()[1], "registries") + user_regs = abspath(depots1(), "registries") # TODO: delete the following let block in Julia 1.0 let uncurated = joinpath(user_regs, "Uncurated"), general = joinpath(user_regs, "General") From 24e9ed07742cfaa5d0f0a259273eccd3b5d18dc5 Mon Sep 17 00:00:00 2001 From: David Varela Date: Thu, 2 Aug 2018 02:34:44 -0700 Subject: [PATCH 15/36] Refactor `activate` to avoid complexity in the main method (Pkg PR 559) (cherry picked from commit fcb1e4f1111a9031eb019add6b1c12ec271d70a9, Julia PR #28443) --- stdlib/Pkg/src/API.jl | 40 ++++++++++++++++++-------------------- stdlib/Pkg/src/REPLMode.jl | 2 +- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/stdlib/Pkg/src/API.jl b/stdlib/Pkg/src/API.jl index e2cd8fb3f60ba..89f1002134e34 100644 --- a/stdlib/Pkg/src/API.jl +++ b/stdlib/Pkg/src/API.jl @@ -547,29 +547,27 @@ function status(ctx::Context, mode=PKGMODE_PROJECT) return end -function activate(path::Union{String,Nothing}=nothing) - if path !== nothing - devpath = nothing - env = Base.active_project() === nothing ? nothing : EnvCache() - if env !== nothing && haskey(env.project["deps"], path) - uuid = UUID(env.project["deps"][path]) - info = manifest_info(env, uuid) - devpath = haskey(info, "path") ? joinpath(dirname(env.project_file), info["path"]) : nothing - end - # `pkg> activate path`/`Pkg.activate(path)` does the following - # 1. if path exists, activate that - # 2. if path exists in deps, and the dep is deved, activate that path (`devpath` above) - # 3. activate the non-existing directory (e.g. as in `pkg> activate .` for initing a new env) - if Types.isdir_windows_workaround(path) - path = abspath(path) - elseif devpath !== nothing - path = abspath(devpath) - else - path = abspath(path) - end +activate() = (Base.ACTIVE_PROJECT[] = Base.load_path_expand(nothing)) +function activate(path::String) + devpath = nothing + env = Base.active_project() === nothing ? nothing : EnvCache() + if env !== nothing && haskey(env.project["deps"], path) + uuid = UUID(env.project["deps"][path]) + info = manifest_info(env, uuid) + devpath = haskey(info, "path") ? joinpath(dirname(env.project_file), info["path"]) : nothing + end + # `pkg> activate path`/`Pkg.activate(path)` does the following + # 1. if path exists, activate that + # 2. if path exists in deps, and the dep is deved, activate that path (`devpath` above) + # 3. activate the non-existing directory (e.g. as in `pkg> activate .` for initing a new env) + if Types.isdir_windows_workaround(path) + path = abspath(path) + elseif devpath !== nothing + path = abspath(devpath) + else + path = abspath(path) end Base.ACTIVE_PROJECT[] = Base.load_path_expand(path) - return end """ diff --git a/stdlib/Pkg/src/REPLMode.jl b/stdlib/Pkg/src/REPLMode.jl index 443f7f2a3017b..6510d4bf66f95 100644 --- a/stdlib/Pkg/src/REPLMode.jl +++ b/stdlib/Pkg/src/REPLMode.jl @@ -603,7 +603,7 @@ do_up!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = function do_activate!(args::PkgArguments, api_opts::APIOptions) if isempty(args) - return API.activate(nothing) + return API.activate() else return API.activate(args[1]) end From 0db0773eb9ea0aa6d040f5d1195f4a7b0a2d9c31 Mon Sep 17 00:00:00 2001 From: Christof Stocker Date: Thu, 2 Aug 2018 11:48:26 +0200 Subject: [PATCH 16/36] rename Uncurated to General (Pkg PR 564) (cherry picked from commit 484deaf85a8f43fc69d6c12e6dd095a9f1c7af2d, Julia PR #28443) --- stdlib/Pkg/bin/generate.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/Pkg/bin/generate.jl b/stdlib/Pkg/bin/generate.jl index cbbe0a1e447cc..3481698eaf884 100644 --- a/stdlib/Pkg/bin/generate.jl +++ b/stdlib/Pkg/bin/generate.jl @@ -11,7 +11,7 @@ write_toml(prefix, "Registry") do io println(io, "repo = ", repr(repo)) println(io, "\ndescription = \"\"\"") print(io, """ - Official uncurated Julia package registry where people can + Official general Julia package registry where people can register any package they want without too much debate about naming and without enforced standards on documentation or testing. We nevertheless encourage documentation, testing and From 8dedc4cf2a6691e61bc3b54c9149ae4d7158d89a Mon Sep 17 00:00:00 2001 From: David Varela Date: Thu, 2 Aug 2018 02:50:36 -0700 Subject: [PATCH 17/36] Fix parser (lexer) (Pkg PR 553) * Fix parser * Add test for REPL `?` help syntax (cherry picked from commit f4d04110c0ca93619cade4b043a4e9b62103eb53, Julia PR #28443) --- stdlib/Pkg/src/REPLMode.jl | 24 ++++++++++++++---------- stdlib/Pkg/test/repl.jl | 12 +++++++----- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/stdlib/Pkg/src/REPLMode.jl b/stdlib/Pkg/src/REPLMode.jl index 6510d4bf66f95..358e10038b4fe 100644 --- a/stdlib/Pkg/src/REPLMode.jl +++ b/stdlib/Pkg/src/REPLMode.jl @@ -200,7 +200,7 @@ function parse(cmd::String)::Vector{Statement} # tokenize accoring to whitespace / quotes qwords = parse_quotes(cmd) # tokenzie unquoted tokens according to pkg REPL syntax - words::Vector{String} = collect(Iterators.flatten(map(qword2word, qwords))) + words = lex(qwords) # break up words according to ";"(doing this early makes subsequent processing easier) word_groups = group_words(words) # create statements @@ -210,7 +210,7 @@ end # vector of words -> structured statement # minimal checking is done in this phase -function Statement(words) +function Statement(words)::Statement is_option(word) = first(word) == '-' statement = Statement() @@ -257,10 +257,16 @@ end const lex_re = r"^[\?\./\+\-](?!\-) | ((git|ssh|http(s)?)|(git@[\w\-\.]+))(:(//)?)([\w\.@\:/\-~]+)(\.git)(/)? | [^@\#\s;]+\s*=\s*[^@\#\s;]+ | \#\s*[^@\#\s;]* | @\s*[^@\#\s;]* | [^@\#\s;]+|;"x -function qword2word(qword::QuotedWord) - return qword.isquoted ? [qword.word] : map(m->m.match, eachmatch(lex_re, " $(qword.word)")) - # ^ - # note: space before `$word` is necessary to keep using current `lex_re` +function lex(qwords::Vector{QuotedWord})::Vector{String} + words = String[] + for qword in qwords + if qword.isquoted + push!(words, qword.word) + else + append!(words, map(m->m.match, eachmatch(lex_re, qword.word))) + end + end + return words end function parse_quotes(cmd::String)::Vector{QuotedWord} @@ -279,18 +285,16 @@ function parse_quotes(cmd::String)::Vector{QuotedWord} if in_singlequote # raw char push!(token_in_progress, c) else # delimiter + in_doublequote ? push_token!(true) : push_token!(false) in_doublequote = !in_doublequote - push_token!(true) end elseif c == '\'' if in_doublequote # raw char push!(token_in_progress, c) else # delimiter + in_singlequote ? push_token!(true) : push_token!(false) in_singlequote = !in_singlequote - push_token!(true) end - elseif c == ' ' && !(in_doublequote || in_singlequote) - push_token!(false) else push!(token_in_progress, c) end diff --git a/stdlib/Pkg/test/repl.jl b/stdlib/Pkg/test/repl.jl index 9486804e9f97c..6dc3e00fe7058 100644 --- a/stdlib/Pkg/test/repl.jl +++ b/stdlib/Pkg/test/repl.jl @@ -72,6 +72,10 @@ temp_pkg_dir() do project_path end @testset "tokens" begin + statement = Pkg.REPLMode.parse("?dev")[1] + @test statement.command.kind == Pkg.REPLMode.CMD_HELP + @test length(statement.arguments) == 1 + @test statement.arguments[1] == "dev" statement = Pkg.REPLMode.parse("add git@github.com:JuliaLang/Example.jl.git")[1] @test "add" in statement.command.names @test statement.arguments[1] == "git@github.com:JuliaLang/Example.jl.git" @@ -844,11 +848,9 @@ end @test qwords[1].isquoted @test qwords[1].word == "Don't" @test !qwords[2].isquoted - @test qwords[2].word == "forget" - @test !qwords[3].isquoted - @test qwords[3].word == "to" - @test qwords[4].isquoted - @test qwords[4].word == "\"test\"" + @test qwords[2].word == " forget to " + @test qwords[3].isquoted + @test qwords[3].word == "\"test\"" @test_throws CommandError Pkg.REPLMode.parse_quotes("Don't") @test_throws CommandError Pkg.REPLMode.parse_quotes("Unterminated \"quot") end From 4ca16b2b23d7fb60d35d8059bb9aafa930f7dd87 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Thu, 2 Aug 2018 13:55:38 +0200 Subject: [PATCH 18/36] Change devdir kwarg to shared in REPL mode, add the kwarg to the API Pkg PR 565 (cherry picked from commit 94eec9bde0ca3270d66b74eec8249bcd5390dd97, Julia PR #28443) --- stdlib/Pkg/src/API.jl | 9 ++++----- stdlib/Pkg/src/REPLMode.jl | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/stdlib/Pkg/src/API.jl b/stdlib/Pkg/src/API.jl index 89f1002134e34..9fa5450dc3e3d 100644 --- a/stdlib/Pkg/src/API.jl +++ b/stdlib/Pkg/src/API.jl @@ -28,11 +28,9 @@ add_or_develop(pkg::Union{String, PackageSpec}; kwargs...) = add_or_develop([pkg add_or_develop(pkgs::Vector{String}; kwargs...) = add_or_develop([check_package_name(pkg) for pkg in pkgs]; kwargs...) add_or_develop(pkgs::Vector{PackageSpec}; kwargs...) = add_or_develop(Context(), pkgs; kwargs...) -function add_or_develop(ctx::Context, pkgs::Vector{PackageSpec}; mode::Symbol, devdir::Bool=false, kwargs...) +function add_or_develop(ctx::Context, pkgs::Vector{PackageSpec}; mode::Symbol, shared::Bool=true, kwargs...) Context!(ctx; kwargs...) - devdir = devdir ? joinpath(dirname(ctx.env.project_file), "dev") : nothing - # All developed packages should go through handle_repos_develop so just give them an empty repo for pkg in pkgs mode == :develop && pkg.repo == nothing && (pkg.repo = Types.GitRepo()) @@ -45,7 +43,8 @@ function add_or_develop(ctx::Context, pkgs::Vector{PackageSpec}; mode::Symbol, d ctx.preview && preview_info() if mode == :develop - new_git = handle_repos_develop!(ctx, pkgs, something(devdir, Pkg.devdir())) + devdir = shared ? Pkg.devdir() : joinpath(dirname(ctx.env.project_file), "dev") + new_git = handle_repos_develop!(ctx, pkgs, devdir) else new_git = handle_repos_add!(ctx, pkgs; upgrade_or_add=true) end @@ -63,7 +62,7 @@ function add_or_develop(ctx::Context, pkgs::Vector{PackageSpec}; mode::Symbol, d end add(args...; kwargs...) = add_or_develop(args...; mode = :add, kwargs...) -develop(args...; kwargs...) = add_or_develop(args...; mode = :develop, kwargs...) +develop(args...; shared=true, kwargs...) = add_or_develop(args...; mode = :develop, shared = shared, kwargs...) rm(pkg::Union{String, PackageSpec}; kwargs...) = rm([pkg]; kwargs...) rm(pkgs::Vector{String}; kwargs...) = rm([PackageSpec(pkg) for pkg in pkgs]; kwargs...) diff --git a/stdlib/Pkg/src/REPLMode.jl b/stdlib/Pkg/src/REPLMode.jl index 358e10038b4fe..75aaee666c48d 100644 --- a/stdlib/Pkg/src/REPLMode.jl +++ b/stdlib/Pkg/src/REPLMode.jl @@ -1037,8 +1037,8 @@ pkg> add Example=7876af07-990d-54b4-ab0e-23690620f79a do_develop!, (ARG_ALL, []), [ - ("local", OPT_SWITCH, :devdir => true), - ("shared", OPT_SWITCH, :devdir => false), + ("local", OPT_SWITCH, :shared => false), + ("shared", OPT_SWITCH, :shared => true), ], md""" develop [--shared|--local] pkg[=uuid] [#rev] ... From ee62aefbad78dd49b87b25ae676ee236f99637e5 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Fri, 3 Aug 2018 17:27:03 +0200 Subject: [PATCH 19/36] use full path for local paths when determining package name Pkg PR 571 (cherry picked from commit e5da1831b2f4260625efc22a1fa48a25d71df2e9, Julia PR #28443) --- stdlib/Pkg/src/Types.jl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/stdlib/Pkg/src/Types.jl b/stdlib/Pkg/src/Types.jl index 74566582e7e8f..6b7eb16bc66d9 100644 --- a/stdlib/Pkg/src/Types.jl +++ b/stdlib/Pkg/src/Types.jl @@ -704,8 +704,12 @@ function parse_package!(ctx, pkg, project_path) pkg.name = ctx.old_pkg2_clone_name else # This is an old style package, get the name from src/PackageName - m = match(reg_pkg, pkg.repo.url) - m === nothing && cmderror("cannot determine package name from URL: $(pkg.repo.url)") + if isdir_windows_workaround(pkg.repo.url) + m = match(reg_pkg, abspath(pkg.repo.url)) + else + m = match(reg_pkg, pkg.repo.url) + end + m === nothing && cmderror("cannot determine package name from URL or path: $(pkg.repo.url)") pkg.name = m.captures[1] end reg_uuids = registered_uuids(env, pkg.name) From 49209ff8389b57eccd5b1630ab05cb0ee217e7e9 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Fri, 3 Aug 2018 17:59:17 +0200 Subject: [PATCH 20/36] stop using PkgError (Pkg PR 577) (cherry picked from commit 4b43e63cd3a0da85c9a9a473ab3fdecbb9cb1095, Julia PR #28443) --- stdlib/Pkg/src/Pkg2/reqs.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stdlib/Pkg/src/Pkg2/reqs.jl b/stdlib/Pkg/src/Pkg2/reqs.jl index 9d6da6cdf2944..59f0690e7ad01 100644 --- a/stdlib/Pkg/src/Pkg2/reqs.jl +++ b/stdlib/Pkg/src/Pkg2/reqs.jl @@ -23,12 +23,12 @@ struct Requirement <: Line while !isempty(fields) && fields[1][1] == '@' push!(system, popfirst!(fields)[2:end]) end - isempty(fields) && throw(PkgError("invalid requires entry: $content")) + isempty(fields) && error("invalid requires entry: $content") package = popfirst!(fields) all(field->occursin(Base.VERSION_REGEX, field), fields) || - throw(PkgError("invalid requires entry for $package: $content")) + error("invalid requires entry for $package: $content") versions = VersionNumber.(fields) - issorted(versions) || throw(PkgError("invalid requires entry for $package: $content")) + issorted(versions) || error("invalid requires entry for $package: $content") new(content, package, VersionSet(versions), system) end end From c50a1ff955709909b339e3ff6121f6d7164e9ba6 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Fri, 3 Aug 2018 22:44:43 +0200 Subject: [PATCH 21/36] ignore julia in test/REQUIRE (Pkg PR 578) (cherry picked from commit 855ea64a083020b49ab389de2d95d1ca2b139c92, Julia PR #28443) --- stdlib/Pkg/src/Operations.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/stdlib/Pkg/src/Operations.jl b/stdlib/Pkg/src/Operations.jl index 77cc24148304d..b99cce4aa5fde 100644 --- a/stdlib/Pkg/src/Operations.jl +++ b/stdlib/Pkg/src/Operations.jl @@ -945,6 +945,7 @@ function pkg2_test_target_compatibility!(ctx, path, pkgs) for r in Pkg2.Reqs.read(test_reqfile) r isa Pkg2.Reqs.Requirement || continue pkg_name, vspec = r.package, VersionSpec(VersionRange[r.versions.intervals...]) + pkg_name == "julia" && continue push!(pkgs, PackageSpec(pkg_name, vspec)) end registry_resolve!(ctx.env, pkgs) From 19c9fabd5b7da173d0690b5c62803e7339b20c7f Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Fri, 3 Aug 2018 22:45:15 +0200 Subject: [PATCH 22/36] Also collect manifest entries from target deps when testing / building. Pkg PR 572 (cherry picked from commit 917b1e714b3dd2c977210712cf4e522002598547, Julia PR #28443) --- stdlib/Pkg/src/Operations.jl | 34 +++++++++++-------- stdlib/Pkg/test/pkg.jl | 12 +++++++ stdlib/Pkg/test/test_packages/x1/Project.toml | 5 +++ stdlib/Pkg/test/test_packages/x1/src/x1.jl | 5 +++ stdlib/Pkg/test/test_packages/x2/Project.toml | 6 ++++ stdlib/Pkg/test/test_packages/x2/src/x2.jl | 5 +++ stdlib/Pkg/test/test_packages/x3/Project.toml | 9 +++++ stdlib/Pkg/test/test_packages/x3/src/x3.jl | 5 +++ .../test/test_packages/x3/test/runtests.jl | 7 ++++ 9 files changed, 74 insertions(+), 14 deletions(-) create mode 100644 stdlib/Pkg/test/test_packages/x1/Project.toml create mode 100644 stdlib/Pkg/test/test_packages/x1/src/x1.jl create mode 100644 stdlib/Pkg/test/test_packages/x2/Project.toml create mode 100644 stdlib/Pkg/test/test_packages/x2/src/x2.jl create mode 100644 stdlib/Pkg/test/test_packages/x3/Project.toml create mode 100644 stdlib/Pkg/test/test_packages/x3/src/x3.jl create mode 100644 stdlib/Pkg/test/test_packages/x3/test/runtests.jl diff --git a/stdlib/Pkg/src/Operations.jl b/stdlib/Pkg/src/Operations.jl index b99cce4aa5fde..71866a0877ba1 100644 --- a/stdlib/Pkg/src/Operations.jl +++ b/stdlib/Pkg/src/Operations.jl @@ -791,6 +791,19 @@ function with_dependencies_loadable_at_toplevel(f, mainctx::Context, pkg::Packag need_to_resolve = false is_project = Types.is_project(localctx.env, pkg) + # Only put `pkg` and its deps + target deps (recursively) in the temp project + collect_deps!(seen, pkg) = begin + pkg.uuid in seen && return + push!(seen, pkg.uuid) + info = manifest_info(localctx.env, pkg.uuid) + info === nothing && return + need_to_resolve |= haskey(info, "path") + localctx.env.project["deps"][pkg.name] = string(pkg.uuid) + for (dpkg, duuid) in get(info, "deps", []) + collect_deps!(seen, PackageSpec(dpkg, UUID(duuid))) + end + end + if is_project # testing the project itself # the project might have changes made to it so need to resolve need_to_resolve = true @@ -807,23 +820,11 @@ function with_dependencies_loadable_at_toplevel(f, mainctx::Context, pkg::Packag )] else # Only put `pkg` and its deps (recursively) in the temp project - collect_deps!(seen, pkg) = begin - pkg.uuid in seen && return - push!(seen, pkg.uuid) - info = manifest_info(localctx.env, pkg.uuid) - need_to_resolve |= haskey(info, "path") - localctx.env.project["deps"][pkg.name] = string(pkg.uuid) - for (dpkg, duuid) in get(info, "deps", []) - collect_deps!(seen, PackageSpec(dpkg, UUID(duuid))) - end - end - # Only put `pkg` and its deps (revursively) in the temp project empty!(localctx.env.project["deps"]) localctx.env.project["deps"][pkg.name] = string(pkg.uuid) - seen_uuids = Set{UUID}() - collect_deps!(seen_uuids, pkg)# Only put `pkg` and its deps (recursively) in the temp project - + # Only put `pkg` and its deps (recursively) in the temp project + collect_deps!(seen_uuids, pkg) end pkgs = PackageSpec[] @@ -833,6 +834,11 @@ function with_dependencies_loadable_at_toplevel(f, mainctx::Context, pkg::Packag end if !isempty(target) collect_target_deps!(localctx, pkgs, pkg, target) + seen_uuids = Set{UUID}() + for dpkg in pkgs + # Also put eventual deps of target deps in new manifest + collect_deps!(seen_uuids, dpkg) + end end mktempdir() do tmpdir diff --git a/stdlib/Pkg/test/pkg.jl b/stdlib/Pkg/test/pkg.jl index 6538a4bba0d88..459672847f9ce 100644 --- a/stdlib/Pkg/test/pkg.jl +++ b/stdlib/Pkg/test/pkg.jl @@ -435,6 +435,18 @@ temp_pkg_dir() do project_path end end +@testset "dependency of test dependency (#567)" begin + mktempdir() do tmpdir + temp_pkg_dir() do project_path; cd(tmpdir) do; with_temp_env() do + for x in ["x1", "x2", "x3"] + cp(joinpath(@__DIR__, "test_packages/$x"), joinpath(tmpdir, "$x")) + Pkg.develop(Pkg.PackageSpec(url = joinpath(tmpdir, x))) + end + Pkg.test("x3") + end end end + end +end + include("repl.jl") include("api.jl") diff --git a/stdlib/Pkg/test/test_packages/x1/Project.toml b/stdlib/Pkg/test/test_packages/x1/Project.toml new file mode 100644 index 0000000000000..1026a589fde5c --- /dev/null +++ b/stdlib/Pkg/test/test_packages/x1/Project.toml @@ -0,0 +1,5 @@ +name = "x1" +uuid = "52033f98-96b1-11e8-17f9-4d5b643961d8" +version = "0.1.0" + +[deps] diff --git a/stdlib/Pkg/test/test_packages/x1/src/x1.jl b/stdlib/Pkg/test/test_packages/x1/src/x1.jl new file mode 100644 index 0000000000000..bd929422af3f4 --- /dev/null +++ b/stdlib/Pkg/test/test_packages/x1/src/x1.jl @@ -0,0 +1,5 @@ +module x1 + +greet() = print("Hello World!") + +end # module diff --git a/stdlib/Pkg/test/test_packages/x2/Project.toml b/stdlib/Pkg/test/test_packages/x2/Project.toml new file mode 100644 index 0000000000000..ada91ef334f7c --- /dev/null +++ b/stdlib/Pkg/test/test_packages/x2/Project.toml @@ -0,0 +1,6 @@ +name = "x2" +uuid = "52baf49e-96b1-11e8-23dd-2d073a3a6758" +version = "0.1.0" + +[deps] +x1 = "52033f98-96b1-11e8-17f9-4d5b643961d8" diff --git a/stdlib/Pkg/test/test_packages/x2/src/x2.jl b/stdlib/Pkg/test/test_packages/x2/src/x2.jl new file mode 100644 index 0000000000000..8afcc2e013477 --- /dev/null +++ b/stdlib/Pkg/test/test_packages/x2/src/x2.jl @@ -0,0 +1,5 @@ +module x2 + +greet() = print("Hello World!") + +end # module diff --git a/stdlib/Pkg/test/test_packages/x3/Project.toml b/stdlib/Pkg/test/test_packages/x3/Project.toml new file mode 100644 index 0000000000000..8cd99a21c7922 --- /dev/null +++ b/stdlib/Pkg/test/test_packages/x3/Project.toml @@ -0,0 +1,9 @@ +name = "x3" +uuid = "53501efc-96b1-11e8-0d90-e1a45c33f0f8" +version = "0.1.0" + +[extras] +x2 = "52baf49e-96b1-11e8-23dd-2d073a3a6758" + +[targets] +test = ["x2"] diff --git a/stdlib/Pkg/test/test_packages/x3/src/x3.jl b/stdlib/Pkg/test/test_packages/x3/src/x3.jl new file mode 100644 index 0000000000000..a9b26ef703c75 --- /dev/null +++ b/stdlib/Pkg/test/test_packages/x3/src/x3.jl @@ -0,0 +1,5 @@ +module x3 + +greet() = print("Hello World!") + +end # module diff --git a/stdlib/Pkg/test/test_packages/x3/test/runtests.jl b/stdlib/Pkg/test/test_packages/x3/test/runtests.jl new file mode 100644 index 0000000000000..85b0336d373e1 --- /dev/null +++ b/stdlib/Pkg/test/test_packages/x3/test/runtests.jl @@ -0,0 +1,7 @@ +module X3Tests + +using x2 + +println("hello") + +end # module From 05138f50277d9d7d053c63412081e40f481a8ab9 Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Fri, 3 Aug 2018 17:03:45 -0400 Subject: [PATCH 23/36] Propagate track-allocation option to test process. (Pkg PR 579) (cherry picked from commit ff586edf41645e59f00289c1dd90628f66b311be, Julia PR #28443) --- stdlib/Pkg/src/Operations.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stdlib/Pkg/src/Operations.jl b/stdlib/Pkg/src/Operations.jl index 71866a0877ba1..48bdb67967092 100644 --- a/stdlib/Pkg/src/Operations.jl +++ b/stdlib/Pkg/src/Operations.jl @@ -1294,7 +1294,8 @@ function test(ctx::Context, pkgs::Vector{PackageSpec}; coverage=false) --color=$(Base.have_color ? "yes" : "no") --compiled-modules=$(Bool(Base.JLOptions().use_compiled_modules) ? "yes" : "no") --check-bounds=yes - --startup-file=$(Base.JLOptions().startupfile != 2 ? "yes" : "no") + --startup-file=$(Base.JLOptions().startupfile == 1 ? "yes" : "no") + --track-allocation=$(("none", "user", "all")[Base.JLOptions().malloc_log + 1]) --eval $code ``` run_test = () -> begin From 202b5236e7ba48ef0da01b1a212c601b075f2b88 Mon Sep 17 00:00:00 2001 From: Christof Stocker Date: Fri, 3 Aug 2018 23:14:20 +0200 Subject: [PATCH 24/36] add --shared option for activate (Pkg PR 558) (cherry picked from commit f647d704719c96307a797d9b1fde02b3f247e4a7, Julia PR #28443) --- stdlib/Pkg/src/API.jl | 58 +++++++++++++++++++++++++------------- stdlib/Pkg/src/Pkg.jl | 13 +++++---- stdlib/Pkg/src/REPLMode.jl | 17 +++++++++-- stdlib/Pkg/test/repl.jl | 23 +++++++++++++-- 4 files changed, 81 insertions(+), 30 deletions(-) diff --git a/stdlib/Pkg/src/API.jl b/stdlib/Pkg/src/API.jl index 9fa5450dc3e3d..a57b39edd35a8 100644 --- a/stdlib/Pkg/src/API.jl +++ b/stdlib/Pkg/src/API.jl @@ -546,27 +546,47 @@ function status(ctx::Context, mode=PKGMODE_PROJECT) return end -activate() = (Base.ACTIVE_PROJECT[] = Base.load_path_expand(nothing)) -function activate(path::String) - devpath = nothing - env = Base.active_project() === nothing ? nothing : EnvCache() - if env !== nothing && haskey(env.project["deps"], path) - uuid = UUID(env.project["deps"][path]) - info = manifest_info(env, uuid) - devpath = haskey(info, "path") ? joinpath(dirname(env.project_file), info["path"]) : nothing - end - # `pkg> activate path`/`Pkg.activate(path)` does the following - # 1. if path exists, activate that - # 2. if path exists in deps, and the dep is deved, activate that path (`devpath` above) - # 3. activate the non-existing directory (e.g. as in `pkg> activate .` for initing a new env) - if Types.isdir_windows_workaround(path) - path = abspath(path) - elseif devpath !== nothing - path = abspath(devpath) +activate() = (Base.ACTIVE_PROJECT[] = nothing) +function activate(path::String; shared::Bool=false) + if !shared + devpath = nothing + env = Base.active_project() === nothing ? nothing : EnvCache() + if env !== nothing && haskey(env.project["deps"], path) + uuid = UUID(env.project["deps"][path]) + info = manifest_info(env, uuid) + devpath = haskey(info, "path") ? joinpath(dirname(env.project_file), info["path"]) : nothing + end + # `pkg> activate path`/`Pkg.activate(path)` does the following + # 1. if path exists, activate that + # 2. if path exists in deps, and the dep is deved, activate that path (`devpath` above) + # 3. activate the non-existing directory (e.g. as in `pkg> activate .` for initing a new env) + if Types.isdir_windows_workaround(path) + fullpath = abspath(path) + elseif devpath !== nothing + fullpath = abspath(devpath) + else + fullpath = abspath(path) + isdir(fullpath) || @info("new environment will be placed at $fullpath") + end else - path = abspath(path) + # initialize `fullpath` in case of empty `Pkg.depots()` + fullpath = "" + # loop over all depots to check if the shared environment already exists + for depot in Pkg.depots() + fullpath = joinpath(Pkg.envdir(depot), path) + isdir(fullpath) && break + end + # this disallows names such as "Foo/bar", ".", "..", etc + if basename(abspath(fullpath)) != path + cmderror("not a valid name for a shared environment: $(path)") + end + # unless the shared environment already exists, place it in the first depots + if !isdir(fullpath) + fullpath = joinpath(Pkg.envdir(Pkg.depots1()), path) + @info("new shared environment \"$path\" will be placed at $fullpath") + end end - Base.ACTIVE_PROJECT[] = Base.load_path_expand(path) + Base.ACTIVE_PROJECT[] = Base.load_path_expand(fullpath) end """ diff --git a/stdlib/Pkg/src/Pkg.jl b/stdlib/Pkg/src/Pkg.jl index fabbcf54698a0..5c341e745925d 100644 --- a/stdlib/Pkg/src/Pkg.jl +++ b/stdlib/Pkg/src/Pkg.jl @@ -20,6 +20,7 @@ end logdir() = joinpath(depots1(), "logs") devdir() = get(ENV, "JULIA_PKG_DEVDIR", joinpath(depots1(), "dev")) +envdir(depot = depots1()) = joinpath(depot, "environments") const UPDATED_REGISTRY_THIS_SESSION = Ref(false) # load snapshotted dependencies @@ -261,18 +262,20 @@ const status = API.status """ - Pkg.activate([s::String]) + Pkg.activate([s::String]; shared::Bool=false) Activate the environment at `s`. The active environment is the environment that is modified by executing package commands. The logic for what path is activated is as follows: - * If `s` is a path that exist, that environment will be activcated. - * If `s` is a package name in the current projec activate that is tracking a path, -activate the environment at that path. + * If `shared` is `true`, the first existing environment named `s` from the depots + in the depot stack will be activated. If no such environment exists yet, + activate it in the first depot. + * If `s` is a path that exist, that environment will be activated. + * If `s` is a package name in the current project activate that is tracking a path, + activate the environment at that path. * If `s` is a non-existing path, activate that path. - If no argument is given to `activate`, activate the home project, which is the one specified by either `--project` command line when starting julia, or `JULIA_PROJECT` environment variable. diff --git a/stdlib/Pkg/src/REPLMode.jl b/stdlib/Pkg/src/REPLMode.jl index 75aaee666c48d..740e8d96096eb 100644 --- a/stdlib/Pkg/src/REPLMode.jl +++ b/stdlib/Pkg/src/REPLMode.jl @@ -609,7 +609,7 @@ function do_activate!(args::PkgArguments, api_opts::APIOptions) if isempty(args) return API.activate() else - return API.activate(args[1]) + return API.activate(args[1]; collect(api_opts)...) end end @@ -1110,8 +1110,19 @@ packages have changed causing the current Manifest to_indices be out of sync. ["activate"], do_activate!, (ARG_RAW, [0,1]), - [], - nothing, + [ + ("shared", OPT_SWITCH, :shared => true), + ], + md""" + activate + activate [--shared] path + +Activate the environment at the given `path`, or the home project environment if no `path` is specified. +The active environment is the environment that is modified by executing package commands. +When the option `--shared` is given, `path` will be assumed to be a directory name and searched for in the +`environments` folders of the depots in the depot stack. In case no such environment exists in any of the depots, +it will be placed in the first depot of the stack. + """ , ),( CMD_UP, ["update", "up"], do_up!, diff --git a/stdlib/Pkg/test/repl.jl b/stdlib/Pkg/test/repl.jl index 6dc3e00fe7058..374815d0044fb 100644 --- a/stdlib/Pkg/test/repl.jl +++ b/stdlib/Pkg/test/repl.jl @@ -261,6 +261,14 @@ temp_pkg_dir() do project_path cd(mktempdir()) do path = pwd() pkg"activate ." + @test Base.active_project() == joinpath(path, "Project.toml") + # tests illegal names for shared environments + @test_throws Pkg.Types.CommandError pkg"activate --shared ." + @test_throws Pkg.Types.CommandError pkg"activate --shared ./Foo" + @test_throws Pkg.Types.CommandError pkg"activate --shared Foo/Bar" + @test_throws Pkg.Types.CommandError pkg"activate --shared ../Bar" + # check that those didn't change te enviroment + @test Base.active_project() == joinpath(path, "Project.toml") mkdir("Foo") cd(mkdir("modules")) do pkg"generate Foo" @@ -269,23 +277,32 @@ temp_pkg_dir() do project_path pkg"activate Foo" # activate path Foo over deps Foo @test Base.active_project() == joinpath(path, "Foo", "Project.toml") pkg"activate ." + @test_logs (:info, r"new shared environment") pkg"activate --shared Foo" # activate shared Foo + @test Base.active_project() == joinpath(Pkg.envdir(), "Foo", "Project.toml") + pkg"activate ." rm("Foo"; force=true, recursive=true) pkg"activate Foo" # activate path from developed Foo @test Base.active_project() == joinpath(path, "modules", "Foo", "Project.toml") pkg"activate ." - pkg"activate ./Foo" # activate empty directory Foo (sidestep the developed Foo) + @test_logs (:info, r"new environment") pkg"activate ./Foo" # activate empty directory Foo (sidestep the developed Foo) @test Base.active_project() == joinpath(path, "Foo", "Project.toml") pkg"activate ." - pkg"activate Bar" # activate empty directory Bar + @test_logs (:info, r"new environment") pkg"activate Bar" # activate empty directory Bar @test Base.active_project() == joinpath(path, "Bar", "Project.toml") pkg"activate ." pkg"add Example" # non-deved deps should not be activated - pkg"activate Example" + @test_logs (:info, r"new environment") pkg"activate Example" @test Base.active_project() == joinpath(path, "Example", "Project.toml") pkg"activate ." cd(mkdir("tests")) pkg"activate Foo" # activate developed Foo from another directory @test Base.active_project() == joinpath(path, "modules", "Foo", "Project.toml") + tmpdepot = mktempdir() + tmpdir = mkpath(joinpath(tmpdepot, "environments", "Foo")) + push!(Base.DEPOT_PATH, tmpdepot) + pkg"activate --shared Foo" # activate existing shared Foo + @test Base.active_project() == joinpath(tmpdir, "Project.toml") + pop!(Base.DEPOT_PATH) pkg"activate" # activate home project @test Base.ACTIVE_PROJECT[] === nothing end From 1a68c36445d3bfd2ba723bcbfdbd1ffa0e44b6d0 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Sat, 4 Aug 2018 00:18:16 +0200 Subject: [PATCH 25/36] allow using a path kword arg to PackageSpec (Pkg PR 580) (cherry picked from commit e804d11ef9cefe75d08126cc3323fab59672572c, Julia PR #28443) --- stdlib/Pkg/src/Pkg.jl | 10 +++++----- stdlib/Pkg/src/REPLMode.jl | 18 +----------------- stdlib/Pkg/src/Types.jl | 13 +++++++++---- stdlib/Pkg/test/api.jl | 2 +- stdlib/Pkg/test/pkg.jl | 2 +- 5 files changed, 17 insertions(+), 28 deletions(-) diff --git a/stdlib/Pkg/src/Pkg.jl b/stdlib/Pkg/src/Pkg.jl index 5c341e745925d..1f0b83db24a78 100644 --- a/stdlib/Pkg/src/Pkg.jl +++ b/stdlib/Pkg/src/Pkg.jl @@ -292,7 +292,7 @@ const activate = API.activate """ PackageSpec(name::String, [uuid::UUID, version::VersionNumber]) - PackageSpec(; name, url, rev, version, mode, level) + PackageSpec(; name, url, path, rev, version, mode, level) A `PackageSpec` is a representation of a package with various metadata. This includes: @@ -301,8 +301,8 @@ This includes: * The package unique `uuid`. * A `version` (for example when adding a package. When upgrading, can also be an instance of the enum [`UpgradeLevel`](@ref) - * A `url` (which might also be a local path) and an optional git `rev`ision. - `rev` could be a branch name or a git commit SHA. + * A `url` and an optional git `rev`ision. `rev` could be a branch name or a git commit SHA. + * A local path `path`. This is equivalent to using the `url` argument but can be more descriptive. * A `mode`, which is an instance of the enum [`PackageMode`](@ref) which can be either `PKGMODE_PROJECT` or `PKGMODE_MANIFEST`, defaults to `PKGMODE_PROJECT`. Used in e.g. [`Pkg.rm`](@ref). @@ -317,8 +317,8 @@ Below is a comparison between the REPL version and the `PackageSpec` version: | `Package@0.2` | `PackageSpec(name="Package", version="0.2")` | | `Package=a67d...` | `PackageSpec(name="Package", uuid="a67d..."` | | `Package#master` | `PackageSpec(name="Package", rev="master")` | -| `local/path#feature` | `PackageSpec(url="local/path"; rev="feature)` | -| `www.mypkg.com` | `PackageSpec("url=www.mypkg.com")` | +| `local/path#feature` | `PackageSpec(path="local/path"; rev="feature)` | +| `www.mypkg.com` | `PackageSpec(url="www.mypkg.com")` | | `--manifest Package` | `PackageSpec(name="Package", mode=PKGSPEC_MANIFEST)`| | `--major Package` | `PackageSpec(name="Package", version=PKGLEVEL_MAJOR`)| """ diff --git a/stdlib/Pkg/src/REPLMode.jl b/stdlib/Pkg/src/REPLMode.jl index 740e8d96096eb..29dd6a44e774e 100644 --- a/stdlib/Pkg/src/REPLMode.jl +++ b/stdlib/Pkg/src/REPLMode.jl @@ -666,22 +666,6 @@ long_commands = [] all_options_sorted = [] long_options = [] -all_commands_sorted = sort(collect(String,keys(command_specs))) -long_commands = filter(c -> length(c) > 2, all_commands_sorted) -function all_options() - all_opts = [] - for command in values(command_specs) - for opt_spec in command.option_specs - push!(all_opts, opt_spec.name) - opt_spec.short_name !== nothing && push!(all_opts, opt_spec.short_name) - end - end - unique!(all_opts) - return all_opts -end -all_options_sorted = [length(opt) > 1 ? "--$opt" : "-$opt" for opt in sort!(all_options())] -long_options = filter(c -> length(c) > 2, all_options_sorted) - struct PkgCompletionProvider <: LineEdit.CompletionProvider end function LineEdit.complete_line(c::PkgCompletionProvider, s) @@ -1220,7 +1204,7 @@ is modified. ], #package ] #command_declarations -super_specs = SuperSpecs(command_declarations) # TODO should this go here ? +super_specs = SuperSpecs(command_declarations) command_specs = super_specs["package"] all_commands_sorted = sort(collect(String,keys(command_specs))) long_commands = filter(c -> length(c) > 2, all_commands_sorted) diff --git a/stdlib/Pkg/src/Types.jl b/stdlib/Pkg/src/Types.jl index 6b7eb16bc66d9..aa74fb1ccc089 100644 --- a/stdlib/Pkg/src/Types.jl +++ b/stdlib/Pkg/src/Types.jl @@ -169,9 +169,14 @@ function PackageSpec(repo::GitRepo) end # kwarg constructor -function PackageSpec(;name::AbstractString="", uuid::Union{String, UUID}=UUID(0), version::Union{VersionNumber, String} = "*", - url = nothing, rev = nothing, mode::PackageMode = PKGMODE_PROJECT) - if url !== nothing || rev !== nothing +function PackageSpec(;name::AbstractString="", uuid::Union{String, UUID}=UUID(0), + version::Union{VersionNumber, String, VersionSpec} = VersionSpec(), + url = nothing, rev = nothing, path=nothing, mode::PackageMode = PKGMODE_PROJECT) + if url !== nothing || path !== nothing || rev !== nothing + if path !== nothing || url !== nothing + path !== nothing && url !== nothing && cmderror("cannot specify both path and url") + url = url == nothing ? path : url + end repo = GitRepo(url=url, rev=rev) else repo = nothing @@ -190,7 +195,7 @@ function Base.show(io::IO, pkg::PackageSpec) f = ["name" => pkg.name, "uuid" => has_uuid(pkg) ? pkg.uuid : "", "v" => (vstr == "VersionSpec(\"*\")" ? "" : vstr)] if pkg.repo !== nothing if !isempty(pkg.repo.url) - push!(f, "url/path" => pkg.repo.url) + push!(f, "url/path" => string("\"", pkg.repo.url, "\"")) end if !isempty(pkg.repo.rev) push!(f, "rev" => pkg.repo.rev) diff --git a/stdlib/Pkg/test/api.jl b/stdlib/Pkg/test/api.jl index edbc15f186754..452eca69126c5 100644 --- a/stdlib/Pkg/test/api.jl +++ b/stdlib/Pkg/test/api.jl @@ -10,7 +10,7 @@ using Pkg, Test cd(mkdir("modules")) do Pkg.generate("Foo") end - Pkg.develop(Pkg.Types.PackageSpec(url="modules/Foo")) # to avoid issue #542 + Pkg.develop(Pkg.Types.PackageSpec(path="modules/Foo")) # to avoid issue #542 Pkg.activate("Foo") # activate path Foo over deps Foo @test Base.active_project() == joinpath(path, "Foo", "Project.toml") Pkg.activate(".") diff --git a/stdlib/Pkg/test/pkg.jl b/stdlib/Pkg/test/pkg.jl index 459672847f9ce..3fb935e1efd0f 100644 --- a/stdlib/Pkg/test/pkg.jl +++ b/stdlib/Pkg/test/pkg.jl @@ -405,7 +405,7 @@ temp_pkg_dir() do project_path @testset "inconsistent repo state" begin package_path = joinpath(project_path, "Example") LibGit2.with(LibGit2.clone("https://github.com/JuliaLang/Example.jl", package_path)) do repo - Pkg.add(PackageSpec(url=package_path)) + Pkg.add(PackageSpec(path=package_path)) end rm(joinpath(package_path, ".git"); force=true, recursive=true) @test_throws CommandError Pkg.update() From ec810548e03c725ec36aa6efe95275483ff61094 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Sat, 4 Aug 2018 01:15:19 +0200 Subject: [PATCH 26/36] rename CommandError to PkgError (Pkg PR 475) (cherry picked from commit eed9ea7fb6c927432954987ac46d89791f0804b3, Julia PR #28443) --- stdlib/Pkg/src/API.jl | 18 ++--- stdlib/Pkg/src/GitTools.jl | 8 +-- stdlib/Pkg/src/Operations.jl | 22 +++---- stdlib/Pkg/src/Pkg.jl | 2 +- stdlib/Pkg/src/REPLMode.jl | 44 ++++++------- stdlib/Pkg/src/Types.jl | 32 ++++----- stdlib/Pkg/src/generate.jl | 2 +- stdlib/Pkg/test/pkg.jl | 16 ++--- stdlib/Pkg/test/repl.jl | 123 ++++++++++++++++++----------------- stdlib/Pkg/test/resolve.jl | 2 +- 10 files changed, 136 insertions(+), 133 deletions(-) diff --git a/stdlib/Pkg/src/API.jl b/stdlib/Pkg/src/API.jl index a57b39edd35a8..09d807b0e0a74 100644 --- a/stdlib/Pkg/src/API.jl +++ b/stdlib/Pkg/src/API.jl @@ -19,7 +19,7 @@ include("generate.jl") function check_package_name(x::String) if !(occursin(Pkg.REPLMode.name_re, x)) - cmderror("$x is not a valid packagename") + pkgerror("$x is not a valid packagename") end return PackageSpec(x) end @@ -39,7 +39,7 @@ function add_or_develop(ctx::Context, pkgs::Vector{PackageSpec}; mode::Symbol, s # if julia is passed as a package the solver gets tricked; # this catches the error early on any(pkg->(pkg.name == "julia"), pkgs) && - cmderror("Trying to $mode julia as a package") + pkgerror("Trying to $mode julia as a package") ctx.preview && preview_info() if mode == :develop @@ -54,7 +54,7 @@ function add_or_develop(ctx::Context, pkgs::Vector{PackageSpec}; mode::Symbol, s ensure_resolved(ctx.env, pkgs, registry=true) any(pkg -> Types.collides_with_project(ctx.env, pkg), pkgs) && - cmderror("Cannot $mode package with the same name or uuid as the project") + pkgerror("Cannot $mode package with the same name or uuid as the project") Operations.add_or_develop(ctx, pkgs; new_git=new_git) ctx.preview && preview_info() @@ -107,7 +107,7 @@ function update_registry(ctx) try GitTools.fetch(repo; refspecs=["+refs/heads/$branch:refs/remotes/origin/$branch"]) catch e - e isa CommandError || rethrow(e) + e isa PkgError || rethrow(e) push!(errors, (reg, "failed to fetch from repo")) return end @@ -219,7 +219,7 @@ function free(ctx::Context, pkgs::Vector{PackageSpec}; kwargs...) for pkg in pkgs info = manifest_info(ctx.env, pkg.uuid) if !get(info, "pinned", false) && !(pkg.uuid in uuids_in_registry) - cmderror("cannot free an unpinned package that does not exist in a registry") + pkgerror("cannot free an unpinned package that does not exist in a registry") end end Operations.free(ctx, pkgs) @@ -238,7 +238,7 @@ function test(ctx::Context, pkgs::Vector{PackageSpec}; coverage=false, kwargs... ctx.preview && preview_info() if isempty(pkgs) # TODO: Allow this? - ctx.env.pkg == nothing && cmderror("trying to test unnamed project") + ctx.env.pkg == nothing && pkgerror("trying to test unnamed project") push!(pkgs, ctx.env.pkg) end project_resolve!(ctx.env, pkgs) @@ -468,7 +468,7 @@ function precompile(ctx::Context) sourcepath = Base.locate_package(pkg) if sourcepath == nothing # XXX: this isn't supposed to be fatal - cmderror("couldn't find path to $(pkg.name) when trying to precompilie project") + pkgerror("couldn't find path to $(pkg.name) when trying to precompilie project") end stale = true for path_to_try in paths::Vector{String} @@ -504,7 +504,7 @@ function instantiate(ctx::Context; manifest::Union{Bool, Nothing}=nothing, kwarg return end if !isfile(ctx.env.manifest_file) && manifest == true - cmderror("manifest at $(ctx.env.manifest_file) does not exist") + pkgerror("manifest at $(ctx.env.manifest_file) does not exist") end update_registry(ctx) urls = Dict{} @@ -578,7 +578,7 @@ function activate(path::String; shared::Bool=false) end # this disallows names such as "Foo/bar", ".", "..", etc if basename(abspath(fullpath)) != path - cmderror("not a valid name for a shared environment: $(path)") + pkgerror("not a valid name for a shared environment: $(path)") end # unless the shared environment already exists, place it in the first depots if !isdir(fullpath) diff --git a/stdlib/Pkg/src/GitTools.jl b/stdlib/Pkg/src/GitTools.jl index 05d4dc6998318..acd988ead9bd9 100644 --- a/stdlib/Pkg/src/GitTools.jl +++ b/stdlib/Pkg/src/GitTools.jl @@ -97,9 +97,9 @@ function clone(url, source_path; header=nothing, kwargs...) err isa LibGit2.GitError || rethrow(err) if (err.class == LibGit2.Error.Net && err.code == LibGit2.Error.EINVALIDSPEC) || (err.class == LibGit2.Error.Repository && err.code == LibGit2.Error.ENOTFOUND) - Pkg.Types.cmderror("Git repository not found at '$(url)'") + Pkg.Types.pkgerror("Git repository not found at '$(url)'") else - Pkg.Types.cmderror("failed to clone from $(url), error: $err") + Pkg.Types.pkgerror("failed to clone from $(url), error: $err") end finally print(stdout, "\033[2K") # clear line @@ -128,9 +128,9 @@ function fetch(repo::LibGit2.GitRepo, remoteurl=nothing; header=nothing, kwargs. catch err err isa LibGit2.GitError || rethrow(err) if (err.class == LibGit2.Error.Repository && err.code == LibGit2.Error.ERROR) - Pkg.Types.cmderror("Git repository not found at '$(remoteurl)'") + Pkg.Types.pkgerror("Git repository not found at '$(remoteurl)'") else - Pkg.Types.cmderror("failed to fetch from $(remoteurl), error: $err") + Pkg.Types.pkgerror("failed to fetch from $(remoteurl), error: $err") end finally print(stdout, "\033[2K") # clear line diff --git a/stdlib/Pkg/src/Operations.jl b/stdlib/Pkg/src/Operations.jl index 48bdb67967092..f03de979c85dc 100644 --- a/stdlib/Pkg/src/Operations.jl +++ b/stdlib/Pkg/src/Operations.jl @@ -37,7 +37,7 @@ function load_package_data(f::Base.Callable, path::String, versions) vr = VersionRange(v) ver in vr || continue dict = get!(data, ver, Dict{String,Any}()) - haskey(dict, key) && cmderror("$ver/$key is duplicated in $path") + haskey(dict, key) && pkgerror("$ver/$key is duplicated in $path") dict[key] = f(value) end end @@ -53,7 +53,7 @@ function load_package_data_raw(T::Type, path::String) for (v, d) in toml, (key, value) in d vr = VersionRange(v) dict = get!(data, vr, Dict{String,T}()) - haskey(dict, key) && cmderror("$vr/$key is duplicated in $path") + haskey(dict, key) && pkgerror("$vr/$key is duplicated in $path") dict[key] = T(value) end return data @@ -106,7 +106,7 @@ function collect_fixed!(ctx::Context, pkgs::Vector{PackageSpec}, uuid_to_name::D path = project_rel_path(ctx, path) if !isdir(path) - cmderror("path $(path) for package $(pkg.name) no longer exists. Remove the package or `develop` it at a new path") + pkgerror("path $(path) for package $(pkg.name) no longer exists. Remove the package or `develop` it at a new path") end uuid_to_pkg[pkg.uuid] = pkg @@ -328,7 +328,7 @@ function resolve_versions!(ctx::Context, pkgs::Vector{PackageSpec})::Dict{UUID,V proj_compat = Types.project_compatibility(ctx, name) v = intersect(pkg.version, proj_compat) if isempty(v) - cmderror(string("for package $(pkg.name) intersection between project compatibility $(proj_compat) ", + pkgerror(string("for package $(pkg.name) intersection between project compatibility $(proj_compat) ", "and package version $(pkg.version) is empty")) end pkg.version = v @@ -382,7 +382,7 @@ function version_data!(ctx::Context, pkgs::Vector{PackageSpec}) info = parse_toml(path, "Package.toml") if haskey(names, uuid) names[uuid] == info["name"] || - cmderror("$uuid: name mismatch between registries: ", + pkgerror("$uuid: name mismatch between registries: ", "$(names[uuid]) vs. $(info["name"])") else names[uuid] = info["name"] @@ -569,7 +569,7 @@ function apply_versions(ctx::Context, pkgs::Vector{PackageSpec}, hashes::Dict{UU try success = install_archive(urls[pkg.uuid], hashes[pkg.uuid], path) if ctx.use_only_tarballs_for_downloads && !success - cmderror("failed to get tarball from $(urls[pkg.uuid])") + pkgerror("failed to get tarball from $(urls[pkg.uuid])") end put!(results, (pkg, success, path)) catch err @@ -582,7 +582,7 @@ function apply_versions(ctx::Context, pkgs::Vector{PackageSpec}, hashes::Dict{UU missed_packages = Tuple{PackageSpec, String}[] for i in 1:length(pkgs_to_install) pkg, exc_or_success, bt_or_path = take!(results) - exc_or_success isa Exception && cmderror("Error when installing packages:\n", sprint(Base.showerror, exc_or_success, bt_or_path)) + exc_or_success isa Exception && pkgerror("Error when installing packages:\n", sprint(Base.showerror, exc_or_success, bt_or_path)) success, path = exc_or_success, bt_or_path if success vstr = pkg.version != nothing ? "v$(pkg.version)" : "[$h]" @@ -1021,7 +1021,7 @@ function build_versions(ctx::Context, uuids::Vector{UUID}; might_need_to_resolve path = project_rel_path(ctx, info["path"]) hash_or_path = path else - cmderror("Could not find either `git-tree-sha1` or `path` for package $(pkg.name)") + pkgerror("Could not find either `git-tree-sha1` or `path` for package $(pkg.name)") end version = v"0.0" end @@ -1260,7 +1260,7 @@ function test(ctx::Context, pkgs::Vector{PackageSpec}; coverage=false) elseif pkg.uuid in keys(ctx.stdlibs) version_path = Types.stdlib_path(pkg.name) else - cmderror("Could not find either `git-tree-sha1` or `path` for package $(pkg.name)") + pkgerror("Could not find either `git-tree-sha1` or `path` for package $(pkg.name)") end end testfile = joinpath(version_path, "test", "runtests.jl") @@ -1271,7 +1271,7 @@ function test(ctx::Context, pkgs::Vector{PackageSpec}; coverage=false) push!(testfiles, testfile) end if !isempty(missing_runtests) - cmderror(length(missing_runtests) == 1 ? "Package " : "Packages ", + pkgerror(length(missing_runtests) == 1 ? "Package " : "Packages ", join(missing_runtests, ", "), " did not provide a `test/runtests.jl` file") end @@ -1316,7 +1316,7 @@ function test(ctx::Context, pkgs::Vector{PackageSpec}; coverage=false) end if !isempty(pkgs_errored) - cmderror(length(pkgs_errored) == 1 ? "Package " : "Packages ", + pkgerror(length(pkgs_errored) == 1 ? "Package " : "Packages ", join(pkgs_errored, ", "), " errored during testing") end diff --git a/stdlib/Pkg/src/Pkg.jl b/stdlib/Pkg/src/Pkg.jl index 1f0b83db24a78..e1551c0e0369e 100644 --- a/stdlib/Pkg/src/Pkg.jl +++ b/stdlib/Pkg/src/Pkg.jl @@ -14,7 +14,7 @@ export UpgradeLevel, UPLEVEL_MAJOR, UPLEVEL_MAJOR, UPLEVEL_MINOR, UPLEVEL_PATCH depots() = Base.DEPOT_PATH function depots1() d = depots() - isempty(d) && cmderror("no depots found in DEPOT_PATH") + isempty(d) && pkgerror("no depots found in DEPOT_PATH") return d[1] end diff --git a/stdlib/Pkg/src/REPLMode.jl b/stdlib/Pkg/src/REPLMode.jl index 29dd6a44e774e..39366bc5a207c 100644 --- a/stdlib/Pkg/src/REPLMode.jl +++ b/stdlib/Pkg/src/REPLMode.jl @@ -73,7 +73,7 @@ Base.show(io::IO, opt::Option) = print(io, "--$(opt.val)", opt.argument == nothi function parse_option(word::AbstractString)::Option m = match(r"^(?: -([a-z]) | --([a-z]{2,})(?:\s*=\s*(\S*))? )$"ix, word) - m == nothing && cmderror("malformed option: ", repr(word)) + m == nothing && pkgerror("malformed option: ", repr(word)) option_name = (m.captures[1] != nothing ? m.captures[1] : m.captures[2]) option_arg = (m.captures[3] == nothing ? nothing : String(m.captures[3])) return Option(option_name, option_arg) @@ -174,7 +174,7 @@ function parse_package(word::AbstractString; add_or_develop=false)::PackageSpec # Guess it is a url then return PackageSpec(Types.GitRepo(word)) else - cmderror("`$word` cannot be parsed as a package") + pkgerror("`$word` cannot be parsed as a package") end end @@ -218,7 +218,7 @@ function Statement(words)::Statement # meta options while is_option(word) push!(statement.meta_options, word) - isempty(words) && cmderror("no command specified") + isempty(words) && pkgerror("no command specified") word = popfirst!(words) end # command @@ -229,7 +229,7 @@ function Statement(words)::Statement super = super_specs["package"] end command = get(super, word, nothing) - command !== nothing || cmderror("expected command. instead got [$word]") + command !== nothing || pkgerror("expected command. instead got [$word]") statement.command = command # command arguments for word in words @@ -245,7 +245,7 @@ function group_words(words)::Vector{Vector{String}} x = String[] for word in words if word == ";" - isempty(x) ? cmderror("empty statement") : push!(statements, x) + isempty(x) ? pkgerror("empty statement") : push!(statements, x) x = String[] else push!(x, word) @@ -300,7 +300,7 @@ function parse_quotes(cmd::String)::Vector{QuotedWord} end end if (in_doublequote || in_singlequote) - cmderror("unterminated quote") + pkgerror("unterminated quote") else push_token!(false) end @@ -345,7 +345,7 @@ end function enforce_argument_order(args::Vector{Token}) prev_arg = nothing function check_prev_arg(valid_type::DataType, error_message::AbstractString) - prev_arg isa valid_type || cmderror(error_message) + prev_arg isa valid_type || pkgerror(error_message) end for arg in args @@ -379,11 +379,11 @@ function enforce_arg_spec(raw_args::Vector{String}, class::ArgClass) class == ARG_ALL && return args if class == ARG_PKG && has_types(args, [VersionRange, Rev]) - cmderror("no versioned packages allowed") + pkgerror("no versioned packages allowed") elseif class == ARG_REV && has_types(args, [VersionRange]) - cmderror("no versioned packages allowed") + pkgerror("no versioned packages allowed") elseif class == ARG_VERSION && has_types(args, [Rev]) - cmderror("no reved packages allowed") + pkgerror("no reved packages allowed") end return args end @@ -413,7 +413,7 @@ end function enforce_arg_count(count::Vector{Int}, args::PkgArguments) isempty(count) && return length(args) in count || - cmderror("Wrong number of arguments") + pkgerror("Wrong number of arguments") end function enforce_args(raw_args::Vector{String}, spec::ArgSpec, cmd_spec::CommandSpec)::PkgArguments @@ -433,13 +433,13 @@ function enforce_option(option::String, specs::Dict{String,OptionSpec})::Option opt = parse_option(option) spec = get(specs, opt.val, nothing) spec !== nothing || - cmderror("option '$(opt.val)' is not a valid option") + pkgerror("option '$(opt.val)' is not a valid option") if spec.is_switch opt.argument === nothing || - cmderror("option '$(opt.val)' does not take an argument, but '$(opt.argument)' given") + pkgerror("option '$(opt.val)' does not take an argument, but '$(opt.argument)' given") else # option takes an argument opt.argument !== nothing || - cmderror("option '$(opt.val)' expects an argument, but no argument given") + pkgerror("option '$(opt.val)' expects an argument, but no argument given") end return opt end @@ -449,7 +449,7 @@ function enforce_meta_options(options::Vector{String}, specs::Dict{String,Option return map(options) do opt tok = enforce_option(opt, specs) tok.val in meta_opt_names || - cmderror("option '$opt' is not a valid meta option.") + pkgerror("option '$opt' is not a valid meta option.") #TODO hint that maybe they intended to use it as a command option return tok end @@ -465,12 +465,12 @@ function enforce_opts(options::Vector{String}, specs::Dict{String,OptionSpec}):: for opt in toks # valid option opt.val in keys(specs) || - cmderror("option '$(opt.val)' is not supported") + pkgerror("option '$(opt.val)' is not supported") # conflicting options key = get_key(opt) if key in unique_keys conflicting = filter(opt->get_key(opt) == key, toks) - cmderror("Conflicting options: $conflicting") + pkgerror("Conflicting options: $conflicting") else push!(unique_keys, key) end @@ -505,7 +505,7 @@ function do_cmd(repl::REPL.AbstractREPL, input::String; do_rethrow=false) if do_rethrow rethrow(err) end - if err isa CommandError || err isa ResolverError + if err isa PkgError || err isa ResolverError Base.display_error(repl.t.err_stream, ErrorException(sprint(showerror, err)), Ptr{Nothing}[]) else Base.display_error(repl.t.err_stream, err, Base.catch_backtrace()) @@ -525,7 +525,7 @@ function do_cmd!(command::PkgCommand, repl) cmd = command.arguments[1] cmd_spec = get(command_specs, cmd, nothing) cmd_spec === nothing && - cmderror("'$cmd' is not a valid command") + pkgerror("'$cmd' is not a valid command") spec = cmd_spec command = PkgCommand([], cmd, [], PackageSpec[]) end @@ -550,9 +550,9 @@ function do_help!(command::PkgCommand, repl::REPL.AbstractREPL) for arg in command.arguments spec = get(command_specs, arg, nothing) spec === nothing && - cmderror("'$arg' does not name a command") + pkgerror("'$arg' does not name a command") spec.help === nothing && - cmderror("Sorry, I don't have any help for the `$arg` command.") + pkgerror("Sorry, I don't have any help for the `$arg` command.") isempty(help_md.content) || push!(help_md.content, md"---") push!(help_md.content, spec.help) @@ -617,7 +617,7 @@ function do_pin!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) for arg in args # TODO not sure this is correct if arg.version.ranges[1].lower != arg.version.ranges[1].upper - cmderror("pinning a package requires a single version, not a versionrange") + pkgerror("pinning a package requires a single version, not a versionrange") end end API.pin(Context!(ctx), args; collect(api_opts)...) diff --git a/stdlib/Pkg/src/Types.jl b/stdlib/Pkg/src/Types.jl index aa74fb1ccc089..9f5936e541ef5 100644 --- a/stdlib/Pkg/src/Types.jl +++ b/stdlib/Pkg/src/Types.jl @@ -19,7 +19,7 @@ using SHA export UUID, pkgID, SHA1, VersionRange, VersionSpec, empty_versionspec, Requires, Fixed, merge_requires!, satisfies, ResolverError, PackageSpec, EnvCache, Context, Context!, - CommandError, cmderror, has_name, has_uuid, write_env, parse_toml, find_registered!, + PkgError, pkgerror, has_name, has_uuid, write_env, parse_toml, find_registered!, project_resolve!, project_deps_resolve!, manifest_resolve!, registry_resolve!, stdlib_resolve!, handle_repos_develop!, handle_repos_add!, ensure_resolved, manifest_info, registered_uuids, registered_paths, registered_uuid, registered_name, read_project, read_package, read_manifest, pathrepr, registries, @@ -112,13 +112,13 @@ function Base.showerror(io::IO, pkgerr::ResolverError) end ################# -# Command Error # +# Pkg Error # ################# -struct CommandError <: Exception +struct PkgError <: Exception msg::String end -cmderror(msg::String...) = throw(CommandError(join(msg))) -Base.show(io::IO, err::CommandError) = print(io, err.msg) +pkgerror(msg::String...) = throw(PkgError(join(msg))) +Base.show(io::IO, err::PkgError) = print(io, err.msg) ############### @@ -174,7 +174,7 @@ function PackageSpec(;name::AbstractString="", uuid::Union{String, UUID}=UUID(0) url = nothing, rev = nothing, path=nothing, mode::PackageMode = PKGMODE_PROJECT) if url !== nothing || path !== nothing || rev !== nothing if path !== nothing || url !== nothing - path !== nothing && url !== nothing && cmderror("cannot specify both path and url") + path !== nothing && url !== nothing && pkgerror("cannot specify both path and url") url = url == nothing ? path : url end repo = GitRepo(url=url, rev=rev) @@ -398,7 +398,7 @@ function get_deps(project::Dict, target::Union{Nothing,String}=nothing) for name in names haskey(deps, name) && continue haskey(extras, name) || - cmderror("target `$target` has unlisted dependency `$name`") + pkgerror("target `$target` has unlisted dependency `$name`") deps[name] = extras[name] end return deps @@ -441,7 +441,7 @@ function read_project(file::String) isfile(file) ? open(read_project, file) : read_project(devnull) end -_throw_package_err(x, f) = cmderror("expected a `$x` entry in project file at $(abspath(f))") +_throw_package_err(x, f) = pkgerror("expected a `$x` entry in project file at $(abspath(f))") function read_package(f::String) project = read_project(f) haskey(project, "name") || _throw_package_err("name", f) @@ -449,7 +449,7 @@ function read_package(f::String) name = project["name"] entry = joinpath(dirname(f), "src", "$name.jl") if !isfile(entry) - cmderror("expected the file `src/$name.jl` to exist for package $name at $(dirname(f))") + pkgerror("expected the file `src/$name.jl` to exist for package $name at $(dirname(f))") end return project end @@ -571,7 +571,7 @@ function handle_repos_develop!(ctx::Context, pkgs::AbstractVector{PackageSpec}, dev_pkg_path = joinpath(devdir, pkg.name) if isdir(dev_pkg_path) if !isfile(joinpath(dev_pkg_path, "src", pkg.name * ".jl")) - cmderror("Path `$(dev_pkg_path)` exists but it does not contain `src/$(pkg.name).jl") + pkgerror("Path `$(dev_pkg_path)` exists but it does not contain `src/$(pkg.name).jl") else @info "Path `$(dev_pkg_path)` exists and looks like the correct package, using existing path instead of cloning" end @@ -714,7 +714,7 @@ function parse_package!(ctx, pkg, project_path) else m = match(reg_pkg, pkg.repo.url) end - m === nothing && cmderror("cannot determine package name from URL or path: $(pkg.repo.url)") + m === nothing && pkgerror("cannot determine package name from URL or path: $(pkg.repo.url)") pkg.name = m.captures[1] end reg_uuids = registered_uuids(env, pkg.name) @@ -761,7 +761,7 @@ function get_object_branch(repo, rev) gitobject = LibGit2.GitObject(repo, rev) catch err err isa LibGit2.GitError && err.code == LibGit2.Error.ENOTFOUND || rethrow(err) - cmderror("git object $(rev) could not be found") + pkgerror("git object $(rev) could not be found") end end return gitobject, isbranch @@ -787,7 +787,7 @@ function project_deps_resolve!(env::EnvCache, pkgs::AbstractVector{PackageSpec}) uuids = env.project["deps"] names = Dict(uuid => name for (uuid, name) in uuids) length(uuids) < length(names) && # TODO: handle this somehow? - cmderror("duplicate UUID found in project file's [deps] section") + pkgerror("duplicate UUID found in project file's [deps] section") for pkg in pkgs pkg.mode == PKGMODE_PROJECT || continue if has_name(pkg) && !has_uuid(pkg) && pkg.name in keys(uuids) @@ -890,7 +890,7 @@ function ensure_resolved(env::EnvCache, end print(io, "Please specify by known `name=uuid`.") end - cmderror(msg) + pkgerror(msg) end const DEFAULT_REGISTRIES = Dict("General" => "https://github.com/JuliaRegistries/General.git") @@ -1070,7 +1070,7 @@ function registered_name(env::EnvCache, uuid::UUID)::String name = nothing for value in values name == nothing && (name = value[2]) - name != value[2] && cmderror("package `$uuid` has multiple registered name values: $name, $(value[2])") + name != value[2] && pkgerror("package `$uuid` has multiple registered name values: $name, $(value[2])") end return name end @@ -1078,7 +1078,7 @@ end # Return most current package info for a registered UUID function registered_info(env::EnvCache, uuid::UUID, key::String) paths = env.paths[uuid] - isempty(paths) && cmderror("`$uuid` is not registered") + isempty(paths) && pkgerror("`$uuid` is not registered") values = [] for path in paths info = parse_toml(path, "Package.toml") diff --git a/stdlib/Pkg/src/generate.jl b/stdlib/Pkg/src/generate.jl index 04663c7196ae8..bd5d57cc93605 100644 --- a/stdlib/Pkg/src/generate.jl +++ b/stdlib/Pkg/src/generate.jl @@ -5,7 +5,7 @@ function generate(ctx::Context, path::String; kwargs...) Context!(ctx; kwargs...) ctx.preview && preview_info() dir, pkg = dirname(path), basename(path) - isdir(path) && cmderror("$(abspath(path)) already exists") + isdir(path) && pkgerror("$(abspath(path)) already exists") printstyled("Generating"; color=:green, bold=true) print(" project $pkg:\n") project(pkg, dir; preview=ctx.preview) diff --git a/stdlib/Pkg/test/pkg.jl b/stdlib/Pkg/test/pkg.jl index 3fb935e1efd0f..92aac84606b37 100644 --- a/stdlib/Pkg/test/pkg.jl +++ b/stdlib/Pkg/test/pkg.jl @@ -215,7 +215,7 @@ temp_pkg_dir() do project_path end @testset "invalid pkg name" begin - @test_throws CommandError Pkg.add(",sa..,--") + @test_throws PkgError Pkg.add(",sa..,--") end @testset "stdlibs as direct dependency" begin @@ -241,7 +241,7 @@ temp_pkg_dir() do project_path withenv("JULIA_PKG_DEVDIR" => devdir) do try Pkg.setprotocol!("notarealprotocol") - @test_throws CommandError Pkg.develop("Example") + @test_throws PkgError Pkg.develop("Example") Pkg.setprotocol!("https") Pkg.develop("Example") @test isinstalled(TEST_PKG) @@ -259,8 +259,8 @@ temp_pkg_dir() do project_path @testset "adding nonexisting packages" begin nonexisting_pkg = randstring(14) - @test_throws CommandError Pkg.add(nonexisting_pkg) - @test_throws CommandError Pkg.update(nonexisting_pkg) + @test_throws PkgError Pkg.add(nonexisting_pkg) + @test_throws PkgError Pkg.update(nonexisting_pkg) end Pkg.rm(TEST_PKG.name) @@ -281,7 +281,7 @@ temp_pkg_dir() do project_path end @testset "add julia" begin - @test_throws CommandError Pkg.add("julia") + @test_throws PkgError Pkg.add("julia") end end @@ -390,9 +390,9 @@ end temp_pkg_dir() do project_path @testset "invalid repo url" begin cd(project_path) do - @test_throws CommandError Pkg.add("https://github.com") + @test_throws PkgError Pkg.add("https://github.com") Pkg.generate("FooBar") - @test_throws CommandError Pkg.add("./Foobar") + @test_throws PkgError Pkg.add("./Foobar") end end end @@ -408,7 +408,7 @@ temp_pkg_dir() do project_path Pkg.add(PackageSpec(path=package_path)) end rm(joinpath(package_path, ".git"); force=true, recursive=true) - @test_throws CommandError Pkg.update() + @test_throws PkgError Pkg.update() end end end diff --git a/stdlib/Pkg/test/repl.jl b/stdlib/Pkg/test/repl.jl index 374815d0044fb..c29c5ff165a84 100644 --- a/stdlib/Pkg/test/repl.jl +++ b/stdlib/Pkg/test/repl.jl @@ -3,7 +3,7 @@ module REPLTests using Pkg -import Pkg.Types.CommandError +import Pkg.Types.PkgError using UUIDs using Test import LibGit2 @@ -25,7 +25,7 @@ function git_init_package(tmp, path) end @testset "generate args" begin - @test_throws CommandError pkg"generate" + @test_throws PkgError pkg"generate" end temp_pkg_dir() do project_path @@ -56,18 +56,18 @@ temp_pkg_dir() do project_path pkg"generate Foo" pkg"dev Foo" mv(joinpath("Foo", "src", "Foo.jl"), joinpath("Foo", "src", "Foo2.jl")) - @test_throws CommandError pkg"dev Foo" + @test_throws PkgError pkg"dev Foo" mv(joinpath("Foo", "src", "Foo2.jl"), joinpath("Foo", "src", "Foo.jl")) write(joinpath("Foo", "Project.toml"), """ name = "Foo" """ ) - @test_throws CommandError pkg"dev Foo" + @test_throws PkgError pkg"dev Foo" write(joinpath("Foo", "Project.toml"), """ uuid = "b7b78b08-812d-11e8-33cd-11188e330cbe" """ ) - @test_throws CommandError pkg"dev Foo" + @test_throws PkgError pkg"dev Foo" end end @@ -135,7 +135,7 @@ temp_pkg_dir() do project_path; cd(project_path) do; mktempdir() do tmp_pkg_path #@eval import $(Symbol(pkg2)) @test Pkg.installed()[pkg2] == v"0.1.0" Pkg.REPLMode.pkgstr("free $pkg2") - @test_throws CommandError Pkg.REPLMode.pkgstr("free $pkg2") + @test_throws PkgError Pkg.REPLMode.pkgstr("free $pkg2") Pkg.test("UnregisteredWithProject") write(joinpath(p2, "Project.toml"), """ @@ -263,10 +263,10 @@ temp_pkg_dir() do project_path pkg"activate ." @test Base.active_project() == joinpath(path, "Project.toml") # tests illegal names for shared environments - @test_throws Pkg.Types.CommandError pkg"activate --shared ." - @test_throws Pkg.Types.CommandError pkg"activate --shared ./Foo" - @test_throws Pkg.Types.CommandError pkg"activate --shared Foo/Bar" - @test_throws Pkg.Types.CommandError pkg"activate --shared ../Bar" + @test_throws Pkg.Types.PkgError pkg"activate --shared ." + @test_throws Pkg.Types.PkgError pkg"activate --shared ./Foo" + @test_throws Pkg.Types.PkgError pkg"activate --shared Foo/Bar" + @test_throws Pkg.Types.PkgError pkg"activate --shared ../Bar" # check that those didn't change te enviroment @test Base.active_project() == joinpath(path, "Project.toml") mkdir("Foo") @@ -420,11 +420,14 @@ temp_pkg_dir() do project_path; cd(project_path) do pkg"build" @eval using BigProject pkg"build BigProject" - @test_throws CommandError pkg"add BigProject" - pkg"test SubModule" - pkg"test SubModule2" - pkg"test BigProject" - pkg"test" + @test_throws PkgError pkg"add BigProject" + # the command below also tests multiline input + Pkg.REPLMode.pkgstr(""" + test SubModule + test SubModule2 + test BigProject + test + """) current_json = Pkg.API.installed()["JSON"] old_project = read("Project.toml", String) open("Project.toml"; append=true) do io @@ -541,8 +544,8 @@ end pkg = Pkg.REPLMode.parse_package(path; add_or_develop=true) @test (pkg.repo.url == path) # errors - @test_throws CommandError Pkg.REPLMode.parse_package(url) - @test_throws CommandError Pkg.REPLMode.parse_package(path) + @test_throws PkgError Pkg.REPLMode.parse_package(url) + @test_throws PkgError Pkg.REPLMode.parse_package(path) end @testset "unit test for REPLMode.promptf" begin @@ -583,18 +586,18 @@ end @testset "Argument order" begin with_temp_env() do - @test_throws CommandError Pkg.REPLMode.pkgstr("add FooBar Example#foobar#foobar") - @test_throws CommandError Pkg.REPLMode.pkgstr("up Example#foobar@0.0.0") - @test_throws CommandError Pkg.REPLMode.pkgstr("pin Example@0.0.0@0.0.1") - @test_throws CommandError Pkg.REPLMode.pkgstr("up #foobar") - @test_throws CommandError Pkg.REPLMode.pkgstr("add @0.0.1") + @test_throws PkgError Pkg.REPLMode.pkgstr("add FooBar Example#foobar#foobar") + @test_throws PkgError Pkg.REPLMode.pkgstr("up Example#foobar@0.0.0") + @test_throws PkgError Pkg.REPLMode.pkgstr("pin Example@0.0.0@0.0.1") + @test_throws PkgError Pkg.REPLMode.pkgstr("up #foobar") + @test_throws PkgError Pkg.REPLMode.pkgstr("add @0.0.1") end end @testset "`do_generate!` error paths" begin with_temp_env() do - @test_throws CommandError Pkg.REPLMode.pkgstr("generate Example Example2") - @test_throws CommandError Pkg.REPLMode.pkgstr("generate") + @test_throws PkgError Pkg.REPLMode.pkgstr("generate Example Example2") + @test_throws PkgError Pkg.REPLMode.pkgstr("generate") end end @@ -670,9 +673,9 @@ end @testset "argument count errors" begin temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; - @test_throws CommandError Pkg.REPLMode.pkgstr("activate one two") - @test_throws CommandError Pkg.REPLMode.pkgstr("activate one two three") - @test_throws CommandError Pkg.REPLMode.pkgstr("precompile Example") + @test_throws PkgError Pkg.REPLMode.pkgstr("activate one two") + @test_throws PkgError Pkg.REPLMode.pkgstr("activate one two three") + @test_throws PkgError Pkg.REPLMode.pkgstr("precompile Example") end end end @@ -680,8 +683,8 @@ end @testset "invalid options" begin temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; - @test_throws CommandError Pkg.REPLMode.pkgstr("rm --minor Example") - @test_throws CommandError Pkg.REPLMode.pkgstr("pin --project Example") + @test_throws PkgError Pkg.REPLMode.pkgstr("rm --minor Example") + @test_throws PkgError Pkg.REPLMode.pkgstr("pin --project Example") end end end @@ -689,11 +692,11 @@ end @testset "Argument order" begin temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; - @test_throws CommandError Pkg.REPLMode.pkgstr("add FooBar Example#foobar#foobar") - @test_throws CommandError Pkg.REPLMode.pkgstr("up Example#foobar@0.0.0") - @test_throws CommandError Pkg.REPLMode.pkgstr("pin Example@0.0.0@0.0.1") - @test_throws CommandError Pkg.REPLMode.pkgstr("up #foobar") - @test_throws CommandError Pkg.REPLMode.pkgstr("add @0.0.1") + @test_throws PkgError Pkg.REPLMode.pkgstr("add FooBar Example#foobar#foobar") + @test_throws PkgError Pkg.REPLMode.pkgstr("up Example#foobar@0.0.0") + @test_throws PkgError Pkg.REPLMode.pkgstr("pin Example@0.0.0@0.0.1") + @test_throws PkgError Pkg.REPLMode.pkgstr("up #foobar") + @test_throws PkgError Pkg.REPLMode.pkgstr("add @0.0.1") end end end @@ -701,8 +704,8 @@ end @testset "conflicting options" begin temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; - @test_throws CommandError Pkg.REPLMode.pkgstr("up --major --minor") - @test_throws CommandError Pkg.REPLMode.pkgstr("rm --project --manifest") + @test_throws PkgError Pkg.REPLMode.pkgstr("up --major --minor") + @test_throws PkgError Pkg.REPLMode.pkgstr("rm --project --manifest") end end end @@ -710,9 +713,9 @@ end @testset "gc" begin temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; - @test_throws CommandError Pkg.REPLMode.pkgstr("gc --project") - @test_throws CommandError Pkg.REPLMode.pkgstr("gc --minor") - @test_throws CommandError Pkg.REPLMode.pkgstr("gc Example") + @test_throws PkgError Pkg.REPLMode.pkgstr("gc --project") + @test_throws PkgError Pkg.REPLMode.pkgstr("gc --minor") + @test_throws PkgError Pkg.REPLMode.pkgstr("gc Example") Pkg.REPLMode.pkgstr("gc") end end @@ -721,8 +724,8 @@ end @testset "precompile" begin temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; - @test_throws CommandError Pkg.REPLMode.pkgstr("precompile --project") - @test_throws CommandError Pkg.REPLMode.pkgstr("precompile Example") + @test_throws PkgError Pkg.REPLMode.pkgstr("precompile --project") + @test_throws PkgError Pkg.REPLMode.pkgstr("precompile Example") Pkg.REPLMode.pkgstr("precompile") end end @@ -731,9 +734,9 @@ end @testset "generate" begin temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; - @test_throws CommandError Pkg.REPLMode.pkgstr("generate --major Example") - @test_throws CommandError Pkg.REPLMode.pkgstr("generate --foobar Example") - @test_throws CommandError Pkg.REPLMode.pkgstr("generate Example1 Example2") + @test_throws PkgError Pkg.REPLMode.pkgstr("generate --major Example") + @test_throws PkgError Pkg.REPLMode.pkgstr("generate --foobar Example") + @test_throws PkgError Pkg.REPLMode.pkgstr("generate Example1 Example2") Pkg.REPLMode.pkgstr("generate Example") end end @@ -743,7 +746,7 @@ end @testset "test" begin temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; Pkg.add("Example") - @test_throws CommandError Pkg.REPLMode.pkgstr("test --project Example") + @test_throws PkgError Pkg.REPLMode.pkgstr("test --project Example") Pkg.REPLMode.pkgstr("test --coverage Example") Pkg.REPLMode.pkgstr("test Example") end @@ -753,8 +756,8 @@ end @testset "build" begin temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; - @test_throws CommandError Pkg.REPLMode.pkgstr("build --project") - @test_throws CommandError Pkg.REPLMode.pkgstr("build --minor") + @test_throws PkgError Pkg.REPLMode.pkgstr("build --project") + @test_throws PkgError Pkg.REPLMode.pkgstr("build --minor") end end end @@ -762,8 +765,8 @@ end @testset "free" begin temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; - @test_throws CommandError Pkg.REPLMode.pkgstr("free --project") - @test_throws CommandError Pkg.REPLMode.pkgstr("free --major") + @test_throws PkgError Pkg.REPLMode.pkgstr("free --project") + @test_throws PkgError Pkg.REPLMode.pkgstr("free --major") end end end @@ -784,8 +787,8 @@ end groups = Pkg.REPLMode.group_words(["a", "b", "c", ";", "a", "b", ";"]) @test length(groups) == 2 # errors - @test_throws CommandError Pkg.REPLMode.group_words(["a", "b", ";", ";", "a", "b"]) - @test_throws CommandError Pkg.REPLMode.group_words([";", "add", "Example"]) + @test_throws PkgError Pkg.REPLMode.group_words(["a", "b", ";", ";", "a", "b"]) + @test_throws PkgError Pkg.REPLMode.group_words([";", "add", "Example"]) end @testset "tests for api opts" begin @@ -825,11 +828,11 @@ end @testset "meta option errors" begin temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; # unregistered meta options - @test_throws CommandError Pkg.REPLMode.pkgstr("--foo=foo add Example") - @test_throws CommandError Pkg.REPLMode.pkgstr("--bar add Example") - @test_throws CommandError Pkg.REPLMode.pkgstr("-x add Example") + @test_throws PkgError Pkg.REPLMode.pkgstr("--foo=foo add Example") + @test_throws PkgError Pkg.REPLMode.pkgstr("--bar add Example") + @test_throws PkgError Pkg.REPLMode.pkgstr("-x add Example") # malformed, but registered meta option - @test_throws CommandError Pkg.REPLMode.pkgstr("--env Example") + @test_throws PkgError Pkg.REPLMode.pkgstr("--env Example") end end end @@ -868,15 +871,15 @@ end @test qwords[2].word == " forget to " @test qwords[3].isquoted @test qwords[3].word == "\"test\"" - @test_throws CommandError Pkg.REPLMode.parse_quotes("Don't") - @test_throws CommandError Pkg.REPLMode.parse_quotes("Unterminated \"quot") + @test_throws PkgError Pkg.REPLMode.parse_quotes("Don't") + @test_throws PkgError Pkg.REPLMode.parse_quotes("Unterminated \"quot") end @testset "argument kinds" begin temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; - @test_throws CommandError pkg"pin Example#foo" - @test_throws CommandError pkg"test Example#foo" - @test_throws CommandError pkg"test Example@v0.0.1" + @test_throws PkgError pkg"pin Example#foo" + @test_throws PkgError pkg"test Example#foo" + @test_throws PkgError pkg"test Example@v0.0.1" end end end diff --git a/stdlib/Pkg/test/resolve.jl b/stdlib/Pkg/test/resolve.jl index 20c919d8ef62e..8bfd55010b76b 100644 --- a/stdlib/Pkg/test/resolve.jl +++ b/stdlib/Pkg/test/resolve.jl @@ -54,7 +54,7 @@ function load_package_data_raw(T::Type, input::String) for (v, d) in toml, (key, value) in d vr = VersionRange(v) dict = get!(data, vr, Dict{String,T}()) - haskey(dict, key) && cmderror("$ver/$key is duplicated in $path") + haskey(dict, key) && pkgerror("$ver/$key is duplicated in $path") dict[key] = T(value) end return data From 499ccdfb1e4548c3a49275a4510d58d00cb4351e Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Sat, 4 Aug 2018 02:15:30 +0200 Subject: [PATCH 27/36] only look for Project files in installed (Pkg PR 539) (cherry picked from commit d7381349d3204ebc8081d40816ec3f28d5dbbb54, Julia PR #28443) --- stdlib/Pkg/docs/src/index.md | 3 --- stdlib/Pkg/src/API.jl | 3 ++- stdlib/Pkg/src/REPLMode.jl | 2 +- stdlib/Pkg/test/pkg.jl | 32 ++++++++++++++--------------- stdlib/Pkg/test/repl.jl | 40 +++++++++++++++--------------------- 5 files changed, 36 insertions(+), 44 deletions(-) diff --git a/stdlib/Pkg/docs/src/index.md b/stdlib/Pkg/docs/src/index.md index d49966113830a..c9a2ca512f85d 100644 --- a/stdlib/Pkg/docs/src/index.md +++ b/stdlib/Pkg/docs/src/index.md @@ -1,8 +1,5 @@ # Pkg -!!! warning - This documentation is a work in progress and the information in it might be or become outdated. - ## Introduction Pkg is the standard package manager for Julia 1.0 and newer. Unlike traditional diff --git a/stdlib/Pkg/src/API.jl b/stdlib/Pkg/src/API.jl index 09d807b0e0a74..76d067cce29c8 100644 --- a/stdlib/Pkg/src/API.jl +++ b/stdlib/Pkg/src/API.jl @@ -253,7 +253,8 @@ function test(ctx::Context, pkgs::Vector{PackageSpec}; coverage=false, kwargs... end -function installed(mode::PackageMode=PKGMODE_MANIFEST) +installed() = __installed(PKGMODE_PROJECT) +function __installed(mode::PackageMode=PKGMODE_MANIFEST) diffs = Display.status(Context(), mode, #=use_as_api=# true) version_status = Dict{String, Union{VersionNumber,Nothing}}() diffs == nothing && return version_status diff --git a/stdlib/Pkg/src/REPLMode.jl b/stdlib/Pkg/src/REPLMode.jl index 39366bc5a207c..6d18bca325a59 100644 --- a/stdlib/Pkg/src/REPLMode.jl +++ b/stdlib/Pkg/src/REPLMode.jl @@ -699,7 +699,7 @@ function complete_package(s, i1, i2, lastcommand, project_opt) end function complete_installed_package(s, i1, i2, project_opt) - pkgs = project_opt ? API.installed(PKGMODE_PROJECT) : API.installed() + pkgs = project_opt ? API.__installed(PKGMODE_PROJECT) : API.__installed() pkgs = sort!(collect(keys(filter((p) -> p[2] != nothing, pkgs)))) cmp = filter(cmd -> startswith(cmd, s), pkgs) return cmp, i1:i2, !isempty(cmp) diff --git a/stdlib/Pkg/test/pkg.jl b/stdlib/Pkg/test/pkg.jl index 92aac84606b37..00f846619d5f9 100644 --- a/stdlib/Pkg/test/pkg.jl +++ b/stdlib/Pkg/test/pkg.jl @@ -136,18 +136,18 @@ temp_pkg_dir() do project_path @testset "adding and upgrading different versions" begin # VersionNumber Pkg.add(PackageSpec(TEST_PKG.name, v"0.3")) - @test Pkg.installed()[TEST_PKG.name] == v"0.3" + @test Pkg.API.__installed()[TEST_PKG.name] == v"0.3" Pkg.add(PackageSpec(TEST_PKG.name, v"0.3.1")) - @test Pkg.installed()[TEST_PKG.name] == v"0.3.1" + @test Pkg.API.__installed()[TEST_PKG.name] == v"0.3.1" Pkg.rm(TEST_PKG.name) # VersionRange Pkg.add(PackageSpec(TEST_PKG.name, VersionSpec(VersionRange("0.3.0-0.3.2")))) - @test Pkg.installed()[TEST_PKG.name] == v"0.3.2" + @test Pkg.API.__installed()[TEST_PKG.name] == v"0.3.2" Pkg.update(; level = UPLEVEL_PATCH) - @test Pkg.installed()[TEST_PKG.name] == v"0.3.3" + @test Pkg.API.__installed()[TEST_PKG.name] == v"0.3.3" Pkg.update(; level = UPLEVEL_MINOR) - @test Pkg.installed()[TEST_PKG.name].minor != 3 + @test Pkg.API.__installed()[TEST_PKG.name].minor != 3 Pkg.rm(TEST_PKG.name) end @@ -164,26 +164,26 @@ temp_pkg_dir() do project_path @testset "pinning / freeing" begin Pkg.add(TEST_PKG.name) - old_v = Pkg.installed()[TEST_PKG.name] + old_v = Pkg.API.__installed()[TEST_PKG.name] Pkg.pin(PackageSpec(TEST_PKG.name, v"0.2")) - @test Pkg.installed()[TEST_PKG.name].minor == 2 + @test Pkg.API.__installed()[TEST_PKG.name].minor == 2 Pkg.update(TEST_PKG.name) - @test Pkg.installed()[TEST_PKG.name].minor == 2 + @test Pkg.API.__installed()[TEST_PKG.name].minor == 2 Pkg.free(TEST_PKG.name) Pkg.update() - @test Pkg.installed()[TEST_PKG.name] == old_v + @test Pkg.API.__installed()[TEST_PKG.name] == old_v Pkg.rm(TEST_PKG.name) end @testset "develop / freeing" begin Pkg.add(TEST_PKG.name) - old_v = Pkg.installed()[TEST_PKG.name] + old_v = Pkg.API.__installed()[TEST_PKG.name] Pkg.rm(TEST_PKG.name) mktempdir() do devdir withenv("JULIA_PKG_DEVDIR" => devdir) do Pkg.develop(TEST_PKG.name) @test isinstalled(TEST_PKG) - @test Pkg.installed()[TEST_PKG.name] > old_v + @test Pkg.API.__installed()[TEST_PKG.name] > old_v test_pkg_main_file = joinpath(devdir, TEST_PKG.name, "src", TEST_PKG.name * ".jl") @test isfile(test_pkg_main_file) # Pkg #152 @@ -209,7 +209,7 @@ temp_pkg_dir() do project_path @test isfile(joinpath(devdir, TEST_PKG.name, "deps", "deps.jl")) Pkg.test(TEST_PKG.name) Pkg.free(TEST_PKG.name) - @test Pkg.installed()[TEST_PKG.name] == old_v + @test Pkg.API.__installed()[TEST_PKG.name] == old_v end end end @@ -221,7 +221,7 @@ temp_pkg_dir() do project_path @testset "stdlibs as direct dependency" begin uuid_pkg = (name = "CRC32c", uuid = UUID("8bf52ea8-c179-5cab-976a-9e18b702a9bc")) Pkg.add("CRC32c") - @test haskey(Pkg.installed(), uuid_pkg.name) + @test haskey(Pkg.API.__installed(), uuid_pkg.name) Pkg.update() # Disable until fixed in Base # Pkg.test("CRC32c") @@ -298,7 +298,7 @@ temp_pkg_dir() do project_path cd(joinpath(dir, "UnregisteredWithProject")) do with_current_env() do Pkg.update() - @test haskey(Pkg.installed(), "Example") + @test haskey(Pkg.API.__installed(), "Example") end end end @@ -308,12 +308,12 @@ end temp_pkg_dir() do project_path @testset "libgit2 downloads" begin Pkg.add(TEST_PKG.name; use_libgit2_for_all_downloads=true) - @test haskey(Pkg.installed(), TEST_PKG.name) + @test haskey(Pkg.API.__installed(), TEST_PKG.name) Pkg.rm(TEST_PKG.name) end @testset "tarball downloads" begin Pkg.add("JSON"; use_only_tarballs_for_downloads=true) - @test haskey(Pkg.installed(), "JSON") + @test haskey(Pkg.API.__installed(), "JSON") Pkg.rm("JSON") end end diff --git a/stdlib/Pkg/test/repl.jl b/stdlib/Pkg/test/repl.jl index c29c5ff165a84..600e11db3d049 100644 --- a/stdlib/Pkg/test/repl.jl +++ b/stdlib/Pkg/test/repl.jl @@ -103,7 +103,7 @@ temp_pkg_dir() do project_path; cd(project_path) do; mktempdir() do tmp_pkg_path pkg"activate ." pkg"add Example" @test isinstalled(TEST_PKG) - v = Pkg.installed()[TEST_PKG.name] + v = Pkg.API.__installed()[TEST_PKG.name] pkg"rm Example" pkg"add Example#master" @@ -117,12 +117,12 @@ temp_pkg_dir() do project_path; cd(project_path) do; mktempdir() do tmp_pkg_path pkg"test Example" @test isinstalled(TEST_PKG) - @test Pkg.installed()[TEST_PKG.name] > v + @test Pkg.API.__installed()[TEST_PKG.name] > v pkg = "UnregisteredWithoutProject" p = git_init_package(tmp_pkg_path, joinpath(@__DIR__, "test_packages/$pkg")) Pkg.REPLMode.pkgstr("add $p; precompile") @eval import $(Symbol(pkg)) - @test Pkg.installed()[pkg] == v"0.0" + @test Pkg.API.__installed()[pkg] == v"0.0" Pkg.test("UnregisteredWithoutProject") pkg2 = "UnregisteredWithProject" @@ -133,7 +133,7 @@ temp_pkg_dir() do project_path; cd(project_path) do; mktempdir() do tmp_pkg_path # FIXME: why isn't this testing the Pkg after importing, rather than after freeing it #@eval import Example #@eval import $(Symbol(pkg2)) - @test Pkg.installed()[pkg2] == v"0.1.0" + @test Pkg.API.__installed()[pkg2] == v"0.1.0" Pkg.REPLMode.pkgstr("free $pkg2") @test_throws PkgError Pkg.REPLMode.pkgstr("free $pkg2") Pkg.test("UnregisteredWithProject") @@ -148,7 +148,7 @@ temp_pkg_dir() do project_path; cd(project_path) do; mktempdir() do tmp_pkg_path LibGit2.add!(repo, "*") LibGit2.commit(repo, "bump version"; author = TEST_SIG, committer=TEST_SIG) pkg"update" - @test Pkg.installed()[pkg2] == v"0.2.0" + @test Pkg.API.__installed()[pkg2] == v"0.2.0" Pkg.REPLMode.pkgstr("rm $pkg2") c = LibGit2.commit(repo, "empty commit"; author = TEST_SIG, committer=TEST_SIG) @@ -173,7 +173,7 @@ temp_pkg_dir() do project_path; cd(project_path) do; mktempdir() do tmp_pkg_path mktempdir() do depot_dir pushfirst!(DEPOT_PATH, depot_dir) pkg"instantiate" - @test Pkg.installed()[pkg2] == v"0.2.0" + @test Pkg.API.__installed()[pkg2] == v"0.2.0" end finally empty!(DEPOT_PATH) @@ -207,8 +207,8 @@ temp_pkg_dir() do project_path; cd(project_path) do Pkg.REPLMode.pkgstr("build; precompile") @test Base.find_package("UnregisteredWithProject") == joinpath(p1_new_path, "src", "UnregisteredWithProject.jl") @test Base.find_package("UnregisteredWithoutProject") == joinpath(p2_new_path, "src", "UnregisteredWithoutProject.jl") - @test Pkg.installed()["UnregisteredWithProject"] == v"0.1.0" - @test Pkg.installed()["UnregisteredWithoutProject"] == v"0.0.0" + @test Pkg.API.__installed()["UnregisteredWithProject"] == v"0.1.0" + @test Pkg.API.__installed()["UnregisteredWithoutProject"] == v"0.0.0" Pkg.test("UnregisteredWithoutProject") Pkg.test("UnregisteredWithProject") @@ -235,8 +235,8 @@ temp_pkg_dir() do project_path; cd(project_path) do mkdir("tests") cd("tests") pkg"develop ../SubModule2" - @test Pkg.installed()["SubModule1"] == v"0.1.0" - @test Pkg.installed()["SubModule2"] == v"0.1.0" + @test Pkg.API.__installed()["SubModule1"] == v"0.1.0" + @test Pkg.API.__installed()["SubModule2"] == v"0.1.0" # make sure paths to SubModule1 and SubModule2 are relative manifest = Pkg.Types.Context().env.manifest @test manifest["SubModule1"][1]["path"] == "SubModule1" @@ -454,7 +454,9 @@ temp_pkg_dir() do project_path setup_package(parent_dir, pkg_name) = begin mkdir(parent_dir) cd(parent_dir) do - Pkg.generate(pkg_name) + withenv("USER" => "Test User") do + Pkg.generate(pkg_name) + end cd(pkg_name) do LibGit2.with(LibGit2.init(joinpath(project_path, parent_dir, pkg_name))) do repo LibGit2.add!(repo, "*") @@ -833,9 +835,7 @@ end @test_throws PkgError Pkg.REPLMode.pkgstr("-x add Example") # malformed, but registered meta option @test_throws PkgError Pkg.REPLMode.pkgstr("--env Example") - end - end - end + end end end end @testset "activate" begin @@ -847,9 +847,7 @@ end @test Base.active_project() == joinpath(pwd(), "Foo", "Project.toml") pkg"activate" @test Base.active_project() == default - end - end - end + end end end end @testset "subcommands" begin @@ -858,9 +856,7 @@ end @test isinstalled(TEST_PKG) Pkg.REPLMode.pkg"package rm Example" @test !isinstalled(TEST_PKG) - end - end - end + end end end end @testset "`parse_quotes` unit tests" begin @@ -880,9 +876,7 @@ end @test_throws PkgError pkg"pin Example#foo" @test_throws PkgError pkg"test Example#foo" @test_throws PkgError pkg"test Example@v0.0.1" - end - end - end + end end end end end # module From 1dc9b59ec89dee8df8120ed99cc5ac5f38d305f8 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Sat, 4 Aug 2018 11:37:32 +0200 Subject: [PATCH 28/36] remove ability to give a git revision to devved packages Pkg PR 581 * remove ability to give a git revision to devved packages * wip (cherry picked from commit 43a0285191e77b7859b7571743a5d5c045a3ad5a, Julia PR #28443) --- stdlib/Pkg/docs/src/index.md | 6 +++--- stdlib/Pkg/src/API.jl | 7 ++++++- stdlib/Pkg/src/REPLMode.jl | 5 ++++- stdlib/Pkg/src/Types.jl | 11 ++++------- stdlib/Pkg/test/pkg.jl | 1 + stdlib/Pkg/test/repl.jl | 15 +-------------- 6 files changed, 19 insertions(+), 26 deletions(-) diff --git a/stdlib/Pkg/docs/src/index.md b/stdlib/Pkg/docs/src/index.md index c9a2ca512f85d..7e01e44a08584 100644 --- a/stdlib/Pkg/docs/src/index.md +++ b/stdlib/Pkg/docs/src/index.md @@ -347,13 +347,13 @@ If we try to `dev` a package at some branch that already exists at `~/.julia/dev For example: ``` -(v0.7) pkg> dev Example#master +(v0.7) pkg> dev Example Updating git-repo `https://github.com/JuliaLang/Example.jl.git` [ Info: Path `/Users/kristoffer/.julia/dev/Example` exists and looks like the correct package, using existing path instead of cloning ``` -Note the info message saying that it is using the existing path. This means that you cannot use `dev` to e.g. change branches of -an already developed package. +Note the info message saying that it is using the existing path. As a general rule, the package manager will +never touch files that are tracking a path. If `dev` is used on a local path, that path to that package is recorded and used when loading that package. The path will be recorded relative to the project file, unless it is given as an absolute path. diff --git a/stdlib/Pkg/src/API.jl b/stdlib/Pkg/src/API.jl index 76d067cce29c8..a4cc2a363f682 100644 --- a/stdlib/Pkg/src/API.jl +++ b/stdlib/Pkg/src/API.jl @@ -33,7 +33,12 @@ function add_or_develop(ctx::Context, pkgs::Vector{PackageSpec}; mode::Symbol, s # All developed packages should go through handle_repos_develop so just give them an empty repo for pkg in pkgs - mode == :develop && pkg.repo == nothing && (pkg.repo = Types.GitRepo()) + if mode == :develop + pkg.repo == nothing && (pkg.repo = Types.GitRepo()) + if !isempty(pkg.repo.rev) + pkgerror("git revision cannot be given to `develop`") + end + end end # if julia is passed as a package the solver gets tricked; diff --git a/stdlib/Pkg/src/REPLMode.jl b/stdlib/Pkg/src/REPLMode.jl index 6d18bca325a59..e3803371282b9 100644 --- a/stdlib/Pkg/src/REPLMode.jl +++ b/stdlib/Pkg/src/REPLMode.jl @@ -397,6 +397,9 @@ function package_args(args::Vector{Token}, spec::CommandSpec)::Vector{PackageSpe elseif arg isa VersionRange pkgs[end].version = arg elseif arg isa Rev + if spec.kind == CMD_DEVELOP + pkgerror("a git revision cannot be given to `develop`") + end pkg = pkgs[end] if pkg.repo == nothing pkg.repo = Types.GitRepo("", arg.rev) @@ -1025,7 +1028,7 @@ pkg> add Example=7876af07-990d-54b4-ab0e-23690620f79a ("shared", OPT_SWITCH, :shared => true), ], md""" - develop [--shared|--local] pkg[=uuid] [#rev] ... + develop [--shared|--local] pkg[=uuid] ... Make a package available for development. If `pkg` is an existing local path that path will be recorded in the manifest and used. Otherwise, a full git clone of `pkg` at rev `rev` is made. The location of the clone is diff --git a/stdlib/Pkg/src/Types.jl b/stdlib/Pkg/src/Types.jl index 9f5936e541ef5..1cd15177f05f6 100644 --- a/stdlib/Pkg/src/Types.jl +++ b/stdlib/Pkg/src/Types.jl @@ -545,13 +545,10 @@ function handle_repos_develop!(ctx::Context, pkgs::AbstractVector{PackageSpec}, project_path = mktempdir() cp(repo_path, project_path; force=true) LibGit2.with(LibGit2.GitRepo(project_path)) do repo - rev = pkg.repo.rev - if isempty(rev) - if LibGit2.isattached(repo) - rev = LibGit2.branch(repo) - else - rev = string(LibGit2.GitHash(LibGit2.head(repo))) - end + if LibGit2.isattached(repo) + rev = LibGit2.branch(repo) + else + rev = string(LibGit2.GitHash(LibGit2.head(repo))) end gitobject, isbranch = get_object_branch(repo, rev) try diff --git a/stdlib/Pkg/test/pkg.jl b/stdlib/Pkg/test/pkg.jl index 00f846619d5f9..32e1f8d18bb5c 100644 --- a/stdlib/Pkg/test/pkg.jl +++ b/stdlib/Pkg/test/pkg.jl @@ -181,6 +181,7 @@ temp_pkg_dir() do project_path Pkg.rm(TEST_PKG.name) mktempdir() do devdir withenv("JULIA_PKG_DEVDIR" => devdir) do + @test_throws PkgError Pkg.develop(PackageSpec(url="bleh", rev="blurg")) Pkg.develop(TEST_PKG.name) @test isinstalled(TEST_PKG) @test Pkg.API.__installed()[TEST_PKG.name] > old_v diff --git a/stdlib/Pkg/test/repl.jl b/stdlib/Pkg/test/repl.jl index 600e11db3d049..20ebc5395c64c 100644 --- a/stdlib/Pkg/test/repl.jl +++ b/stdlib/Pkg/test/repl.jl @@ -42,16 +42,7 @@ temp_pkg_dir() do project_path Pkg.test("PackageWithBuildSpecificTestDeps") end - pkg"dev Example" - devdir = joinpath(DEPOT_PATH[1], "dev", "Example") - @test isdir(devdir) - rm(devdir; recursive=true) - @test !isdir(devdir) - pkg"dev Example#DO_NOT_REMOVE" - @test isdir(devdir) - LibGit2.with(LibGit2.GitRepo(devdir)) do repo - @test LibGit2.branch(repo) == "DO_NOT_REMOVE" - end + @test_throws PkgError pkg"dev Example#blergh" pkg"generate Foo" pkg"dev Foo" @@ -211,10 +202,6 @@ temp_pkg_dir() do project_path; cd(project_path) do @test Pkg.API.__installed()["UnregisteredWithoutProject"] == v"0.0.0" Pkg.test("UnregisteredWithoutProject") Pkg.test("UnregisteredWithProject") - - pkg"develop Example#c37b675" - @test Base.find_package("Example") == joinpath(tmp, "Example", "src", "Example.jl") - Pkg.test("Example") end finally empty!(DEPOT_PATH) From 0edf36b4cd469afba6901c7f7c840f6eff8a11f5 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Sat, 4 Aug 2018 11:11:09 +0200 Subject: [PATCH 29/36] update precompilation for Pkg (cherry picked from commit afbba1a5537fe5840a47d90008673ac35505accd, Julia PR #28443) --- contrib/generate_precompile.jl | 19 +- stdlib/Pkg/src/Pkg.jl | 29 ++- stdlib/Pkg/src/precompile.jl | 423 ++++++++++++++++++++++++++++++--- 3 files changed, 417 insertions(+), 54 deletions(-) diff --git a/contrib/generate_precompile.jl b/contrib/generate_precompile.jl index 30aaa085d568c..67885582754f8 100644 --- a/contrib/generate_precompile.jl +++ b/contrib/generate_precompile.jl @@ -35,19 +35,12 @@ cd("complet_path\t\t$CTRL_C julia_cmd() = (julia = joinpath(Sys.BINDIR, Base.julia_exename()); `$julia`) have_repl = haskey(Base.loaded_modules, Base.PkgId(Base.UUID("3fa0cd96-eef1-5676-8a61-b3b8758bbffb"), "REPL")) -have_pkg = haskey(Base.loaded_modules, - Base.PkgId(Base.UUID("44cfe95a-1eb2-52ea-b672-e2afdf69b78f"), "Pkg")) - -if have_pkg - precompile_script *= """ - tmp = mktempdir() - cd(tmp) - touch("Project.toml") - ] activate . - st - $CTRL_C - rm(tmp; recursive=true) - """ +Pkg = get(Base.loaded_modules, + Base.PkgId(Base.UUID("44cfe95a-1eb2-52ea-b672-e2afdf69b78f"), "Pkg"), + nothing) + +if Pkg !== nothing + precompile_script *= Pkg.precompile_script end function generate_precompile_statements() diff --git a/stdlib/Pkg/src/Pkg.jl b/stdlib/Pkg/src/Pkg.jl index e1551c0e0369e..f5e34961758e0 100644 --- a/stdlib/Pkg/src/Pkg.jl +++ b/stdlib/Pkg/src/Pkg.jl @@ -14,7 +14,7 @@ export UpgradeLevel, UPLEVEL_MAJOR, UPLEVEL_MAJOR, UPLEVEL_MINOR, UPLEVEL_PATCH depots() = Base.DEPOT_PATH function depots1() d = depots() - isempty(d) && pkgerror("no depots found in DEPOT_PATH") + isempty(d) && Pkg.Types.pkgerror("no depots found in DEPOT_PATH") return d[1] end @@ -42,6 +42,7 @@ import .REPLMode: @pkg_str import .Types: UPLEVEL_MAJOR, UPLEVEL_MINOR, UPLEVEL_PATCH, UPLEVEL_FIXED import .Types: PKGMODE_MANIFEST, PKGMODE_PROJECT + """ PackageMode @@ -347,6 +348,30 @@ function __init__() end end +METADATA_compatible_uuid(pkg::String) = Types.uuid5(Types.uuid_package, pkg) + +################## +# Precompilation # +################## + +const CTRL_C = '\x03' +const precompile_script = """ + import Pkg + tmp = mktempdir() + cd(tmp) + empty!(DEPOT_PATH) + pushfirst!(DEPOT_PATH, tmp) + # Prevent cloning registry + mkdir("registries") + touch("registries/blocker") # prevents default registry from cloning + touch("Project.toml") + ] activate . + $CTRL_C + Pkg.add("Test") # adding an stdlib doesn't require internet access + ] st + $CTRL_C + rm(tmp; recursive=true)""" + module PrecompileArea import ..Pkg using ..Types @@ -357,6 +382,4 @@ module PrecompileArea include("precompile.jl") end -METADATA_compatible_uuid(pkg::String) = Types.uuid5(Types.uuid_package, pkg) - end # module diff --git a/stdlib/Pkg/src/precompile.jl b/stdlib/Pkg/src/precompile.jl index b6f5c152b3d0a..75b1b05e48827 100644 --- a/stdlib/Pkg/src/precompile.jl +++ b/stdlib/Pkg/src/precompile.jl @@ -1,82 +1,429 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - +precompile(Tuple{Type{Base.Dict{K, V} where V where K}, Array{Base.Pair{A, B} where B where A, 1}}) +precompile(Tuple{Type{Base.Dict{Pkg.Types.VersionRange, Base.Dict{String, Base.UUID}}}}) +precompile(Tuple{Type{Base.Dict{Pkg.Types.VersionRange, Base.Dict{String, Pkg.Types.VersionSpec}}}}) +precompile(Tuple{Type{Base.Dict{String, Any}}, Base.Pair{String, String}}) +precompile(Tuple{Type{Base.Dict{String, Base.UUID}}}) +precompile(Tuple{Type{Base.Dict{String, Pkg.Types.VersionSpec}}}) +precompile(Tuple{Type{Base.Generator{I, F} where F where I}, Type{Base.UUID}, Base.ValueIterator{Base.Dict{String, Any}}}) +precompile(Tuple{Type{Base.Generator{I, F} where F where I}, Type{Base.UUID}, Base.ValueIterator{Base.Dict{String, String}}}) +precompile(Tuple{Type{Base.Generator{I, F} where F where I}, typeof(Base.close), Array{LibGit2.GitAnnotated, 1}}) +precompile(Tuple{Type{Base.Generator{I, F} where F where I}, typeof(Pkg.TOML.is_tabular), Base.ValueIterator{Base.Dict{String, Any}}}) precompile(Tuple{Type{Base.Generator{I, F} where F where I}, typeof(Pkg.TOML.table2dict), Array{Any, 1}}) precompile(Tuple{Type{Base.IOContext{IO_t} where IO_t<:IO}, Base.GenericIOBuffer{Array{UInt8, 1}}, Base.TTY}) +precompile(Tuple{Type{Base.Pair{A, B} where B where A}, Base.UUID, Int64}) +precompile(Tuple{Type{Base.Pair{A, B} where B where A}, Base.UUID, Pkg.Types.VersionSpec}) +precompile(Tuple{Type{Base.Pair{A, B} where B where A}, Base.VersionNumber, Base.SHA1}) +precompile(Tuple{Type{Base.Pair{A, B} where B where A}, String, Base.UUID}) precompile(Tuple{Type{Base.SHA1}, Base.SubString{String}}) precompile(Tuple{Type{Base.SHA1}, String}) -precompile(Tuple{Type{NamedTuple{(:env,), Tuple{Pkg.Types.EnvCache}}}, Tuple{Pkg.Types.EnvCache}}) -precompile(Tuple{Type{Pkg.Display.DiffEntry}, Base.UUID, String, Nothing, Pkg.Display.VerInfo}) +precompile(Tuple{Type{Char}, Int32}) +precompile(Tuple{Type{NamedTuple{(:by,), T} where T<:Tuple}, Tuple{typeof(Base.identity)}}) +precompile(Tuple{Type{NamedTuple{(:header, :color), T} where T<:Tuple}, Tuple{String, Symbol}}) +precompile(Tuple{Type{NamedTuple{(:indent, :region_active), T} where T<:Tuple}, Tuple{Int64, Bool}}) +precompile(Tuple{Type{NamedTuple{(:indent, :sorted, :by), T} where T<:Tuple}, Tuple{Int64, Bool, typeof(Base.identity)}}) +precompile(Tuple{Type{NamedTuple{(:init,), T} where T<:Tuple}, Tuple{Int64}}) +precompile(Tuple{Type{NamedTuple{(:mode,), T} where T<:Tuple}, Tuple{Symbol}}) +precompile(Tuple{Type{NamedTuple{(:transfer_progress, :credentials), T} where T<:Tuple}, Tuple{Ptr{Nothing}, Ptr{Nothing}}}) +precompile(Tuple{Type{Pkg.Display.DiffEntry}, Base.UUID, String, Pkg.Display.VerInfo, Pkg.Display.VerInfo}) precompile(Tuple{Type{Pkg.Display.VerInfo}, Base.SHA1, Nothing, Base.VersionNumber, Bool, Nothing}) precompile(Tuple{Type{Pkg.Display.VerInfo}, Base.SHA1, Nothing, Base.VersionNumber, Bool, Pkg.Types.GitRepo}) +precompile(Tuple{Type{Pkg.Display.VerInfo}, Nothing, Nothing, Nothing, Bool, Nothing}) +precompile(Tuple{Type{Pkg.Display.VerInfo}, Nothing, String, Base.VersionNumber, Bool, Nothing}) +precompile(Tuple{Type{Pkg.Types.EnvCache}, Nothing, Nothing, String, String, Nothing, Base.Dict{String, Any}, Base.Dict{String, Any}, Base.Dict{String, Array{Base.UUID, 1}}, Base.Dict{Base.UUID, Array{String, 1}}, Base.Dict{Base.UUID, Array{String, 1}}}) +precompile(Tuple{Type{Pkg.Types.GitRepo}, String, String, Base.SHA1}) precompile(Tuple{Type{Pkg.Types.GitRepo}, String, String}) -precompile(Tuple{getfield(Core, Symbol("#kw#Type")), NamedTuple{(:env,), Tuple{Pkg.Types.EnvCache}}, Type{Pkg.Types.Context}}) +precompile(Tuple{Type{Pkg.Types.PackageSpec}, Base.SubString{String}, Pkg.Types.VersionSpec}) +precompile(Tuple{Type{Pkg.Types.PackageSpec}, Base.SubString{String}}) +precompile(Tuple{Type{Pkg.Types.PackageSpec}, String, Base.UUID, Pkg.Types.VersionSpec}) +precompile(Tuple{Type{Pkg.Types.PackageSpec}, String}) +precompile(Tuple{Type{Pkg.Types.VersionBound}, Base.SubString{String}}) +precompile(Tuple{Type{Pkg.Types.VersionBound}, Int64, Int64}) +precompile(Tuple{Type{Pkg.Types.VersionBound}, Tuple{Int64, Int64, Int64}}) +precompile(Tuple{Type{Pkg.Types.VersionBound}, Tuple{Int64, Int64}}) +precompile(Tuple{Type{Pkg.Types.VersionBound}, Tuple{UInt32, UInt32}}) +precompile(Tuple{Type{Pkg.Types.VersionBound}, UInt32, UInt32}) +precompile(Tuple{Type{Pkg.Types.VersionRange}, Base.VersionNumber}) +precompile(Tuple{Type{Pkg.Types.VersionSpec}, String}) +precompile(Tuple{Type{REPL.LineEdit.PrefixSearchState}, REPL.Terminals.TTYTerminal, REPL.LineEdit.PrefixHistoryPrompt, String, Base.GenericIOBuffer{Array{UInt8, 1}}}) +precompile(Tuple{Type{REPL.LineEdit.PromptState}, REPL.Terminals.TTYTerminal, REPL.LineEdit.Prompt, Base.GenericIOBuffer{Array{UInt8, 1}}, Symbol, Array{Base.GenericIOBuffer{Array{UInt8, 1}}, 1}, Int64, REPL.LineEdit.InputAreaState, Int64, Base.Threads.TatasLock, Float64}) +precompile(Tuple{Type{REPL.LineEdit.SearchState}, REPL.Terminals.TTYTerminal, REPL.LineEdit.HistoryPrompt, Bool, Base.GenericIOBuffer{Array{UInt8, 1}}, Base.GenericIOBuffer{Array{UInt8, 1}}}) +precompile(Tuple{Type{REPL.REPLHistoryProvider}, Array{String, 1}, Nothing, Int64, Int64, Int64, Base.GenericIOBuffer{Array{UInt8, 1}}, Nothing, Base.Dict{Symbol, Any}, Array{UInt8, 1}}) +precompile(Tuple{Type{REPL.REPLHistoryProvider}, Base.Dict{Symbol, Any}}) +precompile(Tuple{getfield(Base, Symbol("#kw##printstyled")), NamedTuple{(:bold, :color), Tuple{Bool, Symbol}}, typeof(Base.printstyled), Base.TTY, String}) +precompile(Tuple{getfield(Base, Symbol("#kw##sort!")), NamedTuple{(:by,), Tuple{typeof(Base.Unicode.lowercase)}}, typeof(Base.sort!), Array{String, 1}}) +precompile(Tuple{getfield(Base, Symbol("#kw##sort!")), NamedTuple{(:by,), Tuple{typeof(Base.identity)}}, typeof(Base.sort!), Array{String, 1}}) +precompile(Tuple{getfield(Base.Cartesian, Symbol("#@nloops")), LineNumberNode, Module, Int64, Symbol, Expr, Expr, Expr}) +precompile(Tuple{getfield(Core, Symbol("#kw#Type")), NamedTuple{(:header, :color), Tuple{String, Symbol}}, Type{Pkg.GitTools.MiniProgressBar}}) +precompile(Tuple{getfield(Core, Symbol("#kw#Type")), NamedTuple{(:payload, :transfer_progress, :credentials), Tuple{Base.Dict{Symbol, Any}, Ptr{Nothing}, Ptr{Nothing}}}, Type{LibGit2.RemoteCallbacks}}) +precompile(Tuple{getfield(Pkg.API, Symbol("#kw##add_or_develop")), NamedTuple{(:mode,), Tuple{Symbol}}, typeof(Pkg.API.add_or_develop), Pkg.Types.Context, Array{Pkg.Types.PackageSpec, 1}}) +precompile(Tuple{getfield(Pkg.TOML, Symbol("#kw##_print")), NamedTuple{(:indent, :sorted, :by), Tuple{Int64, Bool, typeof(Base.identity)}}, typeof(Pkg.TOML._print), Base.IOStream, Base.Dict{String, Any}, Array{String, 1}}) +precompile(Tuple{getfield(Pkg.TOML, Symbol("#kw##print")), NamedTuple{(:sorted,), Tuple{Bool}}, typeof(Pkg.TOML.print), Base.IOStream, Base.Dict{String, Any}}) +precompile(Tuple{getfield(Pkg.TOML, Symbol("#kw##printvalue")), NamedTuple{(:sorted,), Tuple{Bool}}, typeof(Pkg.TOML.printvalue), Base.IOStream, Array{String, 1}}) +precompile(Tuple{getfield(Pkg.TOML, Symbol("#kw##printvalue")), NamedTuple{(:sorted,), Tuple{Bool}}, typeof(Pkg.TOML.printvalue), Base.IOStream, String}) +precompile(Tuple{getfield(REPL.LineEdit, Symbol("#kw##add_nested_key!")), NamedTuple{(:override,), Tuple{Bool}}, typeof(REPL.LineEdit.add_nested_key!), Base.Dict{Char, Any}, String, Nothing}) +precompile(Tuple{getfield(REPL.LineEdit, Symbol("#kw##refresh_multi_line")), NamedTuple{(:indent, :region_active), Tuple{Int64, Bool}}, typeof(REPL.LineEdit.refresh_multi_line), REPL.Terminals.TerminalBuffer, REPL.Terminals.TTYTerminal, Base.GenericIOBuffer{Array{UInt8, 1}}, REPL.LineEdit.InputAreaState, REPL.LineEdit.PromptState}) +precompile(Tuple{typeof(Base.:(!=)), Base.SubString{String}, Nothing}) +precompile(Tuple{typeof(Base.:(!=)), Base.UUID, Base.UUID}) +precompile(Tuple{typeof(Base.:(==)), Base.Dict{String, Any}, Nothing}) precompile(Tuple{typeof(Base.:(==)), Base.SHA1, Nothing}) precompile(Tuple{typeof(Base.:(==)), Base.UUID, Base.UUID}) +precompile(Tuple{typeof(Base.:(==)), Expr, Int64}) precompile(Tuple{typeof(Base.:(==)), Nothing, Base.UUID}) precompile(Tuple{typeof(Base.:(==)), Nothing, Nothing}) -precompile(Tuple{typeof(Base.:(==)), Pkg.REPLMode.CommandKind, Pkg.REPLMode.CommandKind}) precompile(Tuple{typeof(Base.:(==)), String, Nothing}) -precompile(Tuple{typeof(Base.append!), Array{String, 1}, Array{Base.SubString{String}, 1}}) +precompile(Tuple{typeof(Base.:(==)), Symbol, Int64}) +precompile(Tuple{typeof(Base.Cartesian._nloops), Int64, Symbol, Expr, Expr, Expr}) +precompile(Tuple{typeof(Base.Cartesian.exprresolve), LineNumberNode}) +precompile(Tuple{typeof(Base.Cartesian.lreplace!), Int64, Base.Cartesian.LReplace{String}}) +precompile(Tuple{typeof(Base.Filesystem.ispath), String}) +precompile(Tuple{typeof(Base.Filesystem.mtime), String}) +precompile(Tuple{typeof(Base.Iterators.enumerate), Array{Base.VersionNumber, 1}}) +precompile(Tuple{typeof(Base._array_for), Type{Array{Base.BitArray{2}, 1}}, Base.UnitRange{Int64}, Base.HasShape{1}}) +precompile(Tuple{typeof(Base._array_for), Type{Array{Base.VersionNumber, 1}}, Base.UnitRange{Int64}, Base.HasShape{1}}) +precompile(Tuple{typeof(Base._array_for), Type{Base.BitArray{1}}, Base.UnitRange{Int64}, Base.HasShape{1}}) +precompile(Tuple{typeof(Base._array_for), Type{Base.BitArray{2}}, Base.UnitRange{Int64}, Base.HasShape{1}}) +precompile(Tuple{typeof(Base._array_for), Type{Base.Dict{Base.VersionNumber, Int64}}, Base.UnitRange{Int64}, Base.HasShape{1}}) +precompile(Tuple{typeof(Base._array_for), Type{Base.UUID}, Base.ValueIterator{Base.Dict{String, Any}}, Base.HasLength}) +precompile(Tuple{typeof(Base._collect), Array{Pkg.REPLMode.Statement, 1}, Base.Generator{Array{Pkg.REPLMode.Statement, 1}, Type{Pkg.REPLMode.PkgCommand}}, Base.EltypeUnknown, Base.HasShape{1}}) +precompile(Tuple{typeof(Base._compute_eltype), Type{Tuple{Array{String, 1}, LibGit2.CachedCredentials}}}) +precompile(Tuple{typeof(Base._compute_eltype), Type{Tuple{Bool, LibGit2.CachedCredentials}}}) +precompile(Tuple{typeof(Base._compute_eltype), Type{Tuple{Int32, Base.Cstring, Ptr{Nothing}}}}) +precompile(Tuple{typeof(Base._deepcopy_array_t), Array{Base.Dict{String, Any}, 1}, Type{Base.Dict{String, Any}}, Base.IdDict{Any, Any}}) +precompile(Tuple{typeof(Base._getindex), Base.IndexLinear, Base.BitArray{2}, Base.LogicalIndex{Int64, Base.BitArray{1}}, Int64}) +precompile(Tuple{typeof(Base._iterate), Base.Dict{String, Any}, Int64}) +precompile(Tuple{typeof(Base._promote_typejoin), Type{Any}, Type{Ptr{Nothing}}}) +precompile(Tuple{typeof(Base._promote_typejoin), Type{Array{String, 1}}, Type{LibGit2.CachedCredentials}}) +precompile(Tuple{typeof(Base._promote_typejoin), Type{Bool}, Type{LibGit2.CachedCredentials}}) +precompile(Tuple{typeof(Base._promote_typejoin), Type{Int32}, Type{Base.Cstring}}) +precompile(Tuple{typeof(Base._promote_typejoin), Type{Union{}}, Type{Array{String, 1}}}) +precompile(Tuple{typeof(Base._promote_typejoin), Type{Union{}}, Type{Bool}}) +precompile(Tuple{typeof(Base._promote_typejoin), Type{Union{}}, Type{Int32}}) +precompile(Tuple{typeof(Base._shrink), typeof(Base.setdiff!), Array{Base.UUID, 1}, Tuple{Array{Base.UUID, 1}}}) +precompile(Tuple{typeof(Base.add_sum), Int64, Int64}) +precompile(Tuple{typeof(Base.afoldl), typeof(Base.:(+)), Int64, Int64, Int64}) +precompile(Tuple{typeof(Base.all), Base.Generator{Base.ValueIterator{Base.Dict{String, Any}}, typeof(Pkg.TOML.is_tabular)}}) +precompile(Tuple{typeof(Base.close), Base.Channel{Any}}) +precompile(Tuple{typeof(Base.close), LibGit2.GitAnnotated}) +precompile(Tuple{typeof(Base.close), LibGit2.GitConfig}) +precompile(Tuple{typeof(Base.close), LibGit2.GitDiff}) +precompile(Tuple{typeof(Base.close), LibGit2.GitReference}) +precompile(Tuple{typeof(Base.close), LibGit2.GitRemote}) precompile(Tuple{typeof(Base.close), LibGit2.GitRepo}) +precompile(Tuple{typeof(Base.close), LibGit2.GitTree}) +precompile(Tuple{typeof(Base.cmd_gen), Tuple{Tuple{Base.Cmd}}}) precompile(Tuple{typeof(Base.collect), Base.Generator{Array{Any, 1}, typeof(Pkg.TOML.table2dict)}}) +precompile(Tuple{typeof(Base.collect), Base.Generator{Base.ValueIterator{Base.Dict{String, Any}}, Type{Base.UUID}}}) +precompile(Tuple{typeof(Base.collect), Base.Generator{Base.ValueIterator{Base.Dict{String, String}}, Type{Base.UUID}}}) +precompile(Tuple{typeof(Base.collect), Base.KeySet{String, Base.Dict{String, Any}}}) +precompile(Tuple{typeof(Base.collect_similar), Array{LibGit2.GitAnnotated, 1}, Base.Generator{Array{LibGit2.GitAnnotated, 1}, typeof(Base.close)}}) +precompile(Tuple{typeof(Base.collect_to_with_first!), Array{Base.UUID, 1}, Base.UUID, Base.Generator{Base.ValueIterator{Base.Dict{String, Any}}, Type{Base.UUID}}, Int64}) +precompile(Tuple{typeof(Base.collect_to_with_first!), Array{String, 1}, String, Base.Generator{Array{String, 1}, typeof(Pkg.REPLMode.word2token)}, Int64}) +precompile(Tuple{typeof(Base.convert), Type{Array{Array{Base.BitArray{2}, 1}, 1}}, Array{Array{Base.BitArray{2}, 1}, 1}}) +precompile(Tuple{typeof(Base.convert), Type{Array{Array{Base.VersionNumber, 1}, 1}}, Array{Array{Base.VersionNumber, 1}, 1}}) +precompile(Tuple{typeof(Base.convert), Type{Array{Array{Int64, 1}, 1}}, Array{Array{Int64, 1}, 1}}) +precompile(Tuple{typeof(Base.convert), Type{Array{Base.BitArray{1}, 1}}, Array{Base.BitArray{1}, 1}}) +precompile(Tuple{typeof(Base.convert), Type{Array{Base.Dict{Base.VersionNumber, Int64}, 1}}, Array{Base.Dict{Base.VersionNumber, Int64}, 1}}) +precompile(Tuple{typeof(Base.convert), Type{Array{Base.UUID, 1}}, Array{Base.UUID, 1}}) +precompile(Tuple{typeof(Base.convert), Type{Array{Char, 1}}, Array{Char, 1}}) +precompile(Tuple{typeof(Base.convert), Type{Array{Int64, 1}}, Array{Int64, 1}}) +precompile(Tuple{typeof(Base.convert), Type{Array{Symbol, 1}}, Array{UInt8, 1}}) +precompile(Tuple{typeof(Base.convert), Type{Array{Union{Pkg.Types.VersionRange, String, Pkg.REPLMode.Rev}, 1}}, Array{String, 1}}) +precompile(Tuple{typeof(Base.convert), Type{Base.Dict{Base.UUID, Int64}}, Base.Dict{Base.UUID, Int64}}) +precompile(Tuple{typeof(Base.convert), Type{Base.Dict{Base.UUID, Pkg.GraphType.ResolveLogEntry}}, Base.Dict{Base.UUID, Pkg.GraphType.ResolveLogEntry}}) +precompile(Tuple{typeof(Base.convert), Type{Base.Dict{K, V} where V where K}, Base.Dict{Symbol, Any}}) +precompile(Tuple{typeof(Base.convert), Type{Base.Dict{Symbol, Any}}, Base.Dict{Any, Any}}) +precompile(Tuple{typeof(Base.convert), Type{Base.UUID}, Base.UUID}) +precompile(Tuple{typeof(Base.convert), Type{REPL.LineEdit.TextInterface}, REPL.LineEdit.Prompt}) +precompile(Tuple{typeof(Base.convert), Type{REPL.Terminals.AbstractTerminal}, REPL.Terminals.TTYTerminal}) +precompile(Tuple{typeof(Base.convert), Type{REPL.Terminals.TextTerminal}, REPL.Terminals.TTYTerminal}) +precompile(Tuple{typeof(Base.convert), Type{Union{Nothing, IO}}, Base.IOStream}) +precompile(Tuple{typeof(Base.convert), Type{Union{Nothing, IO}}, Nothing}) +precompile(Tuple{typeof(Base.convert), Type{Union{Nothing, REPL.LineEdit.Prompt}}, Nothing}) +precompile(Tuple{typeof(Base.convert), Type{Union{Pkg.Types.UpgradeLevel, Base.VersionNumber, Pkg.Types.VersionSpec}}, Base.VersionNumber}) +precompile(Tuple{typeof(Base.copy_chunks!), Array{UInt64, 1}, Int64, Array{UInt64, 1}, Int64, Int64}) +precompile(Tuple{typeof(Base.count), Base.BitArray{1}}) +precompile(Tuple{typeof(Base.deepcopy), Base.Dict{String, Any}}) precompile(Tuple{typeof(Base.deepcopy_internal), Array{Base.Dict{String, Any}, 1}, Base.IdDict{Any, Any}}) precompile(Tuple{typeof(Base.deepcopy_internal), Base.Dict{Any, Any}, Base.IdDict{Any, Any}}) -precompile(Tuple{typeof(Base.diff_names), Tuple{Symbol, Symbol, Symbol}, Tuple{Symbol, Symbol, Symbol, Symbol, Symbol, Symbol}}) -precompile(Tuple{typeof(Base.diff_names), Tuple{Symbol, Symbol}, Tuple{Symbol, Symbol, Symbol, Symbol, Symbol, Symbol}}) -precompile(Tuple{typeof(Base.diff_names), Tuple{Symbol}, Tuple{Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol}}) -precompile(Tuple{typeof(Base.eachmatch), Base.Regex, String}) -precompile(Tuple{typeof(Base.empty), Array{Union{Nothing, Base.SubString{String}}, 1}, Type{Base.SubString{String}}}) +precompile(Tuple{typeof(Base.deepcopy_internal), Base.Dict{String, Any}, Base.IdDict{Any, Any}}) +precompile(Tuple{typeof(Base.deepcopy_internal), Base.Dict{String, String}, Base.IdDict{Any, Any}}) +precompile(Tuple{typeof(Base.deepcopy_internal), String, Base.IdDict{Any, Any}}) +precompile(Tuple{typeof(Base.delete!), Base.Dict{String, Any}, String}) +precompile(Tuple{typeof(Base.delete!), Base.IdDict{Any, Any}, Symbol}) +precompile(Tuple{typeof(Base.empty), Base.Dict{Any, Any}, Type{Base.UUID}, Type{Int64}}) +precompile(Tuple{typeof(Base.empty), Base.Dict{Any, Any}, Type{String}, Type{Base.UUID}}) +precompile(Tuple{typeof(Base.empty), Base.Dict{Any, Any}, Type{String}, Type{String}}) +precompile(Tuple{typeof(Base.eof), Base.IOStream}) +precompile(Tuple{typeof(Base.get!), Base.Dict{Base.UUID, Array{String, 1}}, Base.UUID, Array{String, 1}}) +precompile(Tuple{typeof(Base.get!), Base.Dict{Pkg.Types.VersionRange, Base.Dict{String, Base.UUID}}, Pkg.Types.VersionRange, Base.Dict{String, Base.UUID}}) +precompile(Tuple{typeof(Base.get!), Base.Dict{Pkg.Types.VersionRange, Base.Dict{String, Pkg.Types.VersionSpec}}, Pkg.Types.VersionRange, Base.Dict{String, Pkg.Types.VersionSpec}}) +precompile(Tuple{typeof(Base.get!), Base.Dict{String, Any}, String, Array{Base.Dict{String, Any}, 1}}) +precompile(Tuple{typeof(Base.get!), Base.Dict{String, Array{Base.UUID, 1}}, String, Array{Base.UUID, 1}}) +precompile(Tuple{typeof(Base.get), Base.Dict{String, Any}, String, Base.Dict{Any, Any}}) +precompile(Tuple{typeof(Base.get), Base.Dict{String, Pkg.REPLMode.CommandSpec}, String, Nothing}) +precompile(Tuple{typeof(Base.getindex), Array{Array{Base.VersionNumber, 1}, 1}, Int64}) +precompile(Tuple{typeof(Base.getindex), Array{Array{Int64, 1}, 1}, Int64}) +precompile(Tuple{typeof(Base.getindex), Array{Array{UInt64, 1}, 1}, Int64}) +precompile(Tuple{typeof(Base.getindex), Array{Base.BitArray{1}, 1}, Int64}) +precompile(Tuple{typeof(Base.getindex), Array{Base.BitArray{2}, 1}, Int64}) +precompile(Tuple{typeof(Base.getindex), Array{Base.Dict{Int64, Int64}, 1}, Int64}) precompile(Tuple{typeof(Base.getindex), Array{Base.Dict{String, Any}, 1}, Int64}) -precompile(Tuple{typeof(Base.getproperty), Pkg.REPLMode.Command, Symbol}) +precompile(Tuple{typeof(Base.getindex), Array{Base.UUID, 1}, Int64}) +precompile(Tuple{typeof(Base.getindex), Array{Base.VersionNumber, 1}, Base.BitArray{1}}) +precompile(Tuple{typeof(Base.getindex), Array{Int64, 1}, Int64}) +precompile(Tuple{typeof(Base.getindex), Base.BitArray{1}, Base.UnitRange{Int64}}) +precompile(Tuple{typeof(Base.getindex), Base.BitArray{2}, Base.BitArray{1}, Base.BitArray{1}}) +precompile(Tuple{typeof(Base.getindex), Base.Dict{Int64, Int64}, Int64}) +precompile(Tuple{typeof(Base.getindex), Base.Dict{String, Base.UUID}, String}) +precompile(Tuple{typeof(Base.getindex), Base.Dict{Symbol, Function}, Symbol}) +precompile(Tuple{typeof(Base.getindex), NamedTuple{(:indent, :region_active), Tuple{Int64, Bool}}, Symbol}) +precompile(Tuple{typeof(Base.getindex), NamedTuple{(:prompt_prefix, :prompt_suffix, :complete, :sticky), Tuple{String, String, Pkg.REPLMode.PkgCompletionProvider, Bool}}, Symbol}) +precompile(Tuple{typeof(Base.getindex), NamedTuple{(:prompt_prefix, :prompt_suffix, :repl, :complete, :on_enter), Tuple{String, typeof(Base.input_color), REPL.LineEditREPL, REPL.REPLCompletionProvider, typeof(REPL.return_callback)}}, Symbol}) +precompile(Tuple{typeof(Base.getindex), Pkg.TOML.Table, String}) +precompile(Tuple{typeof(Base.getindex), Type{Pkg.Types.VersionRange}, Pkg.Pkg2.Pkg2Types.VersionInterval}) precompile(Tuple{typeof(Base.getproperty), Pkg.TOML.Table, Symbol}) +precompile(Tuple{typeof(Base.getproperty), Pkg.Types.PackageSpec, Symbol}) +precompile(Tuple{typeof(Base.getproperty), REPL.Terminals.TerminalBuffer, Symbol}) +precompile(Tuple{typeof(Base.hash), Tuple{String, UInt64}, UInt64}) +precompile(Tuple{typeof(Base.hash), Tuple{String}, UInt64}) precompile(Tuple{typeof(Base.haskey), Base.Dict{Base.UUID, Base.Dict{K, V} where V where K}, Base.UUID}) +precompile(Tuple{typeof(Base.haskey), Base.Dict{String, Base.UUID}, String}) +precompile(Tuple{typeof(Base.haskey), Base.Dict{String, Pkg.Types.VersionSpec}, String}) +precompile(Tuple{typeof(Base.haskey), NamedTuple{(:indent, :region_active), Tuple{Int64, Bool}}, Symbol}) +precompile(Tuple{typeof(Base.haskey), NamedTuple{(:prompt_prefix, :prompt_suffix, :complete, :sticky), Tuple{String, String, Pkg.REPLMode.PkgCompletionProvider, Bool}}, Symbol}) +precompile(Tuple{typeof(Base.haskey), NamedTuple{(:prompt_prefix, :prompt_suffix, :repl, :complete, :on_enter), Tuple{String, typeof(Base.input_color), REPL.LineEditREPL, REPL.REPLCompletionProvider, typeof(REPL.return_callback)}}, Symbol}) precompile(Tuple{typeof(Base.haskey), Pkg.TOML.Table, String}) +precompile(Tuple{typeof(Base.ident_cmp), Tuple{String, UInt64}, Tuple{String, UInt64}}) +precompile(Tuple{typeof(Base.ident_cmp), Tuple{String}, Tuple{String}}) +precompile(Tuple{typeof(Base.ident_cmp), Tuple{}, Tuple{}}) +precompile(Tuple{typeof(Base.identity), Int64}) +precompile(Tuple{typeof(Base.in), Base.UUID, Array{Base.UUID, 1}}) +precompile(Tuple{typeof(Base.in), Base.VersionNumber, Pkg.Types.VersionSpec}) +precompile(Tuple{typeof(Base.in), String, Array{String, 1}}) +precompile(Tuple{typeof(Base.in), String, Base.KeySet{String, Base.Dict{String, Any}}}) +precompile(Tuple{typeof(Base.in), String, Base.KeySet{String, Base.Dict{String, Base.Dict{String, Pkg.REPLMode.CommandSpec}}}}) +precompile(Tuple{typeof(Base.indexed_iterate), Base.Pair{Any, Any}, Int64, Int64}) +precompile(Tuple{typeof(Base.indexed_iterate), Base.Pair{Any, Any}, Int64}) +precompile(Tuple{typeof(Base.indexed_iterate), Base.Pair{String, Any}, Int64, Int64}) +precompile(Tuple{typeof(Base.indexed_iterate), Base.Pair{String, Any}, Int64}) +precompile(Tuple{typeof(Base.indexed_iterate), Tuple{Char, Bool}, Int64, Int64}) +precompile(Tuple{typeof(Base.indexed_iterate), Tuple{Char, Bool}, Int64}) +precompile(Tuple{typeof(Base.indexed_iterate), Tuple{String, Array{String, 1}, Array{String, 1}}, Int64, Int64}) +precompile(Tuple{typeof(Base.indexed_iterate), Tuple{String, Array{String, 1}, Array{String, 1}}, Int64}) +precompile(Tuple{typeof(Base.input_color)}) +precompile(Tuple{typeof(Base.invokelatest), typeof(Pkg.REPLMode.do_status!), Base.Dict{Symbol, Any}, Array{String, 1}, Base.Dict{Symbol, Any}}) precompile(Tuple{typeof(Base.isempty), Array{Base.Dict{String, Any}, 1}}) +precompile(Tuple{typeof(Base.isempty), Array{Base.UUID, 1}}) +precompile(Tuple{typeof(Base.isempty), Base.Dict{String, Any}}) +precompile(Tuple{typeof(Base.isempty), Base.Dict{String, String}}) +precompile(Tuple{typeof(Base.isempty), NamedTuple{(:mode,), Tuple{Symbol}}}) +precompile(Tuple{typeof(Base.isopen), Base.Channel{Any}}) precompile(Tuple{typeof(Base.iterate), Array{Base.Dict{String, Any}, 1}, Int64}) precompile(Tuple{typeof(Base.iterate), Array{Base.Dict{String, Any}, 1}}) +precompile(Tuple{typeof(Base.iterate), Array{Base.UUID, 1}, Int64}) +precompile(Tuple{typeof(Base.iterate), Array{Base.UUID, 1}}) +precompile(Tuple{typeof(Base.iterate), Base.Channel{Any}}) +precompile(Tuple{typeof(Base.iterate), Base.Dict{Any, Any}, Int64}) +precompile(Tuple{typeof(Base.iterate), Base.Dict{Any, Any}}) +precompile(Tuple{typeof(Base.iterate), Base.Dict{String, Any}, Int64}) +precompile(Tuple{typeof(Base.iterate), Base.Dict{String, Any}}) +precompile(Tuple{typeof(Base.iterate), Tuple{Base.BitArray{1}}, Int64}) +precompile(Tuple{typeof(Base.iterate), Tuple{Base.BitArray{1}}}) +precompile(Tuple{typeof(Base.join), Base.GenericIOBuffer{Array{UInt8, 1}}, Tuple{String}, Char}) +precompile(Tuple{typeof(Base.join), Base.GenericIOBuffer{Array{UInt8, 1}}, Tuple{Symbol, Symbol}, String}) +precompile(Tuple{typeof(Base.join), Base.GenericIOBuffer{Array{UInt8, 1}}, Tuple{UInt32, UInt32, UInt32}, Char}) +precompile(Tuple{typeof(Base.join), Base.GenericIOBuffer{Array{UInt8, 1}}, Tuple{UInt32, UInt32}, Char}) +precompile(Tuple{typeof(Base.join), Tuple{Symbol, Symbol}, String}) +precompile(Tuple{typeof(Base.keys), Base.Dict{String, Any}}) +precompile(Tuple{typeof(Base.keys), Base.Dict{String, Base.Dict{String, Pkg.REPLMode.CommandSpec}}}) +precompile(Tuple{typeof(Base.lastindex), Base.BitArray{1}}) +precompile(Tuple{typeof(Base.length), Array{Array{Base.BitArray{2}, 1}, 1}}) +precompile(Tuple{typeof(Base.length), Array{Array{Base.VersionNumber, 1}, 1}}) +precompile(Tuple{typeof(Base.length), Array{Array{Int64, 1}, 1}}) +precompile(Tuple{typeof(Base.length), Array{Base.BitArray{1}, 1}}) +precompile(Tuple{typeof(Base.length), Array{Base.Dict{Base.VersionNumber, Int64}, 1}}) +precompile(Tuple{typeof(Base.length), Array{Base.Dict{Int64, Int64}, 1}}) precompile(Tuple{typeof(Base.length), Array{Base.Dict{String, Any}, 1}}) +precompile(Tuple{typeof(Base.length), Array{Base.UUID, 1}}) +precompile(Tuple{typeof(Base.length), Array{Int64, 1}}) +precompile(Tuple{typeof(Base.length), Base.BitArray{1}}) +precompile(Tuple{typeof(Base.length), Base.Dict{Base.UUID, Int64}}) +precompile(Tuple{typeof(Base.length), Base.Dict{Base.UUID, Pkg.GraphType.ResolveLogEntry}}) +precompile(Tuple{typeof(Base.length), Base.Dict{String, Any}}) +precompile(Tuple{typeof(Base.map), Type{Base.UUID}, Base.ValueIterator{Base.Dict{String, Any}}}) +precompile(Tuple{typeof(Base.map), Type{Base.UUID}, Base.ValueIterator{Base.Dict{String, String}}}) +precompile(Tuple{typeof(Base.map), typeof(Base.close), Array{LibGit2.GitAnnotated, 1}}) +precompile(Tuple{typeof(Base.mapreduce_first), typeof(Base.identity), typeof(Base.add_sum), Int64}) +precompile(Tuple{typeof(Base.match), Base.Regex, String}) +precompile(Tuple{typeof(Base.merge!), Base.Dict{String, Any}, Base.Dict{String, Any}}) precompile(Tuple{typeof(Base.merge), Base.Dict{String, Any}, Base.Dict{String, String}}) +precompile(Tuple{typeof(Base.merge), NamedTuple{(), Tuple{}}, Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}}) +precompile(Tuple{typeof(Base.merge), NamedTuple{(), Tuple{}}, NamedTuple{(:mode,), Tuple{Symbol}}}) +precompile(Tuple{typeof(Base.merge), NamedTuple{(:payload,), Tuple{Base.Dict{Symbol, Any}}}, NamedTuple{(:transfer_progress, :credentials), Tuple{Ptr{Nothing}, Ptr{Nothing}}}}) +precompile(Tuple{typeof(Base.merge_names), Tuple{Symbol, Symbol, Symbol}, Tuple{Symbol}}) +precompile(Tuple{typeof(Base.merge_names), Tuple{Symbol, Symbol}, Tuple{Symbol, Symbol}}) +precompile(Tuple{typeof(Base.merge_names), Tuple{Symbol, Symbol}, Tuple{Symbol}}) +precompile(Tuple{typeof(Base.merge_names), Tuple{Symbol}, Tuple{Symbol, Symbol}}) precompile(Tuple{typeof(Base.merge_names), Tuple{Symbol}, Tuple{Symbol}}) -precompile(Tuple{typeof(Base.merge_types), Tuple{Symbol, Symbol}, Type{NamedTuple{(:callbacks,), Tuple{Base.Dict{Symbol, Tuple{Ptr{Nothing}, Any}}}}}, Type{NamedTuple{(:credentials,), Tuple{LibGit2.CachedCredentials}}}}) -precompile(Tuple{typeof(Base.push!), Array{Base.SubString{String}, 1}, Base.SubString{String}}) -precompile(Tuple{typeof(Base.read), Base.IOStream, Type{String}}) +precompile(Tuple{typeof(Base.merge_names), Tuple{Symbol}, Tuple{}}) +precompile(Tuple{typeof(Base.notify_error), Base.Channel{Any}, Base.InvalidStateException}) +precompile(Tuple{typeof(Base.peek), Base.IOStream}) +precompile(Tuple{typeof(Base.prepend!), Array{Base.Dict{Any, Any}, 1}, Array{Base.Dict{Any, Any}, 1}}) +precompile(Tuple{typeof(Base.print), Base.GenericIOBuffer{Array{UInt8, 1}}, Base.SubString{String}}) +precompile(Tuple{typeof(Base.print), Base.GenericIOBuffer{Array{UInt8, 1}}, Pkg.Types.VersionSpec}) +precompile(Tuple{typeof(Base.print), Base.IOStream, String, String, String, Char}) +precompile(Tuple{typeof(Base.print), Base.TTY, String, String, Char}) +precompile(Tuple{typeof(Base.promote_eltype), Base.KeySet{Base.UUID, Base.Dict{Base.UUID, Pkg.Types.VersionSpec}}}) +precompile(Tuple{typeof(Base.push!), Array{Base.UUID, 1}, Base.UUID}) +precompile(Tuple{typeof(Base.push!), Array{Int64, 1}, Int64}) +precompile(Tuple{typeof(Base.push!), Array{Pkg.Types.VersionRange, 1}, Pkg.Types.VersionRange}) +precompile(Tuple{typeof(Base.push!), Array{Tuple{Base.UUID, String}, 1}, Tuple{Base.UUID, String}}) +precompile(Tuple{typeof(Base.push!), Base.Set{Base.VersionNumber}, Base.VersionNumber}) +precompile(Tuple{typeof(Base.push!), Base.Set{Symbol}, Symbol}) +precompile(Tuple{typeof(Base.push!), Pkg.GraphType.ResolveLogEntry, Tuple{Nothing, String}}) +precompile(Tuple{typeof(Base.push!), Pkg.GraphType.ResolveLogEntry, Tuple{Pkg.GraphType.ResolveLogEntry, String}}) +precompile(Tuple{typeof(Base.put!), Base.Channel{Any}, Tuple{String, Array{String, 1}, Array{String, 1}}}) +precompile(Tuple{typeof(Base.rethrow), Base.InvalidStateException}) +precompile(Tuple{typeof(Base.rstrip), String}) +precompile(Tuple{typeof(Base.seek), Base.IOStream, Int64}) +precompile(Tuple{typeof(Base.setdiff!), Base.Set{Base.UUID}, Array{Base.UUID, 1}}) +precompile(Tuple{typeof(Base.setindex!), Array{Base.BitArray{1}, 1}, Base.BitArray{1}, Int64}) +precompile(Tuple{typeof(Base.setindex!), Base.BitArray{1}, Bool, Int64}) precompile(Tuple{typeof(Base.setindex!), Base.Dict{Base.UUID, Base.Dict{K, V} where V where K}, Base.Dict{String, Any}, Base.UUID}) +precompile(Tuple{typeof(Base.setindex!), Base.Dict{Base.UUID, Int64}, Int64, Base.UUID}) +precompile(Tuple{typeof(Base.setindex!), Base.Dict{Base.UUID, Pkg.Types.VersionSpec}, Pkg.Types.VersionSpec, Base.UUID}) +precompile(Tuple{typeof(Base.setindex!), Base.Dict{Base.UUID, String}, String, Base.UUID}) +precompile(Tuple{typeof(Base.setindex!), Base.Dict{Base.VersionNumber, Base.SHA1}, Base.SHA1, Base.VersionNumber}) +precompile(Tuple{typeof(Base.setindex!), Base.Dict{Int64, Int64}, Int64, Int64}) precompile(Tuple{typeof(Base.setindex!), Base.Dict{String, Any}, Array{Any, 1}, String}) precompile(Tuple{typeof(Base.setindex!), Base.Dict{String, Any}, Array{Base.Dict{String, Any}, 1}, String}) +precompile(Tuple{typeof(Base.setindex!), Base.Dict{String, Any}, Array{String, 1}, String}) precompile(Tuple{typeof(Base.setindex!), Base.Dict{String, Any}, Base.Dict{Any, Any}, String}) -precompile(Tuple{typeof(Base.setindex!), Base.Dict{String, Any}, Pkg.TOML.Table, String}) +precompile(Tuple{typeof(Base.setindex!), Base.Dict{String, Any}, Base.Dict{String, String}, String}) +precompile(Tuple{typeof(Base.setindex!), Base.Dict{String, Any}, Base.UUID, String}) +precompile(Tuple{typeof(Base.setindex!), Base.Dict{String, Base.UUID}, Base.UUID, String}) +precompile(Tuple{typeof(Base.setindex!), Base.Dict{String, Pkg.Types.VersionSpec}, Pkg.Types.VersionSpec, String}) +precompile(Tuple{typeof(Base.setindex!), Base.Dict{Symbol, Any}, LibGit2.CredentialPayload, Symbol}) +precompile(Tuple{typeof(Base.setindex!), Base.Dict{Symbol, Any}, Pkg.GitTools.MiniProgressBar, Symbol}) +precompile(Tuple{typeof(Base.setindex!), Base.EnvDict, String, String}) +precompile(Tuple{typeof(Base.setproperty!), Pkg.GraphType.Graph, Symbol, Array{Array{Base.BitArray{2}, 1}, 1}}) +precompile(Tuple{typeof(Base.setproperty!), Pkg.GraphType.Graph, Symbol, Array{Array{Int64, 1}, 1}}) +precompile(Tuple{typeof(Base.setproperty!), Pkg.GraphType.Graph, Symbol, Array{Base.BitArray{1}, 1}}) +precompile(Tuple{typeof(Base.setproperty!), Pkg.GraphType.Graph, Symbol, Array{Int64, 1}}) +precompile(Tuple{typeof(Base.setproperty!), Pkg.GraphType.GraphData, Symbol, Array{Array{Base.VersionNumber, 1}, 1}}) +precompile(Tuple{typeof(Base.setproperty!), Pkg.GraphType.GraphData, Symbol, Array{Base.Dict{Base.VersionNumber, Int64}, 1}}) +precompile(Tuple{typeof(Base.setproperty!), Pkg.GraphType.GraphData, Symbol, Array{Base.UUID, 1}}) +precompile(Tuple{typeof(Base.setproperty!), Pkg.GraphType.GraphData, Symbol, Array{Int64, 1}}) +precompile(Tuple{typeof(Base.setproperty!), Pkg.GraphType.GraphData, Symbol, Base.Dict{Base.UUID, Int64}}) +precompile(Tuple{typeof(Base.setproperty!), Pkg.GraphType.ResolveLog, Symbol, Base.Dict{Base.UUID, Pkg.GraphType.ResolveLogEntry}}) +precompile(Tuple{typeof(Base.setproperty!), Pkg.REPLMode.Statement, Symbol, Pkg.REPLMode.CommandSpec}) +precompile(Tuple{typeof(Base.setproperty!), Pkg.Types.PackageSpec, Symbol, Base.UUID}) +precompile(Tuple{typeof(Base.setproperty!), Pkg.Types.PackageSpec, Symbol, Base.VersionNumber}) +precompile(Tuple{typeof(Base.setproperty!), Pkg.Types.PackageSpec, Symbol, String}) precompile(Tuple{typeof(Base.similar), Array{Base.Dict{String, Any}, 1}}) -precompile(Tuple{typeof(Base.string), String, Base.UUID}) -precompile(Tuple{typeof(Base.string), String, Module, String, String, String, Int64}) +precompile(Tuple{typeof(Base.skip_deleted_floor!), Base.Dict{String, Any}}) +precompile(Tuple{typeof(Base.string), String, Base.SubString{String}, String, String}) +precompile(Tuple{typeof(Base.string), Symbol, Int64}) +precompile(Tuple{typeof(Base.strip), Base.SubString{String}}) +precompile(Tuple{typeof(Base.structdiff), NamedTuple{(:indent, :region_active), Tuple{Int64, Bool}}, Type{NamedTuple{(:indent, :region_active), T} where T<:Tuple}}) +precompile(Tuple{typeof(Base.structdiff), NamedTuple{(:prompt_prefix, :prompt_suffix, :complete, :sticky), Tuple{String, String, Pkg.REPLMode.PkgCompletionProvider, Bool}}, Type{NamedTuple{(:prompt_prefix, :prompt_suffix, :keymap_dict, :repl, :complete, :on_enter, :on_done, :hist, :sticky), T} where T<:Tuple}}) +precompile(Tuple{typeof(Base.structdiff), NamedTuple{(:prompt_prefix, :prompt_suffix, :repl, :complete, :on_enter), Tuple{String, typeof(Base.input_color), REPL.LineEditREPL, REPL.REPLCompletionProvider, typeof(REPL.return_callback)}}, Type{NamedTuple{(:prompt_prefix, :prompt_suffix, :keymap_dict, :repl, :complete, :on_enter, :on_done, :hist, :sticky), T} where T<:Tuple}}) +precompile(Tuple{typeof(Base.sum), Array{Int64, 1}}) +precompile(Tuple{typeof(Base.sym_in), Symbol, Tuple{Symbol, Symbol}}) precompile(Tuple{typeof(Base.sym_in), Symbol, Tuple{Symbol}}) +precompile(Tuple{typeof(Base.sym_in), Symbol, Tuple{}}) +precompile(Tuple{typeof(Base.to_indices), Base.BitArray{2}, Tuple{Base.OneTo{Int64}}, Tuple{Int64}}) +precompile(Tuple{typeof(Base.trues), Int64}) +precompile(Tuple{typeof(Base.union!), Base.Set{Base.UUID}, Base.KeySet{Base.UUID, Base.Dict{Base.UUID, Pkg.Types.Fixed}}}) +precompile(Tuple{typeof(Base.union!), Base.Set{Base.UUID}, Base.KeySet{Base.UUID, Base.Dict{Base.UUID, Pkg.Types.VersionSpec}}}) +precompile(Tuple{typeof(Base.unique!), Array{Base.UUID, 1}}) +precompile(Tuple{typeof(Base.unique!), Array{String, 1}}) +precompile(Tuple{typeof(Base.values), Base.Dict{String, Any}}) +precompile(Tuple{typeof(Base.values), Base.Dict{String, String}}) +precompile(Tuple{typeof(Base.vcat), Base.BitArray{1}, Base.BitArray{1}}) +precompile(Tuple{typeof(Base.vcat), Base.BitArray{1}}) +precompile(Tuple{typeof(Base.vcat), Base.BitArray{2}, Base.BitArray{2}, Base.BitArray{2}, Base.BitArray{2}}) +precompile(Tuple{typeof(Base.vcat), Base.BitArray{2}, Base.BitArray{2}}) +precompile(Tuple{typeof(Base.vect), Base.Cmd, Base.Cmd}) +precompile(Tuple{typeof(Base.vect), Base.VersionNumber}) +precompile(Tuple{typeof(Base.vect), Nothing}) precompile(Tuple{typeof(Base.write), Base.TTY, Array{UInt8, 1}}) -precompile(Tuple{typeof(Core.Compiler.vect), Tuple{Nothing, Int64}}) -precompile(Tuple{typeof(Core.Compiler.vect), Tuple{Pkg.REPLMode.OptionKind, Int64}}) +precompile(Tuple{typeof(Base.write), REPL.Terminals.TTYTerminal, Array{UInt8, 1}}) +precompile(Tuple{typeof(Core.Compiler.eltype), Type{Array{Base.BitArray{2}, 1}}}) +precompile(Tuple{typeof(Core.Compiler.eltype), Type{Array{Base.KeySet{Base.UUID, Base.Dict{Base.UUID, Pkg.Types.VersionSpec}}, 1}}}) +precompile(Tuple{typeof(Core.Compiler.eltype), Type{Array{Pkg.Pkg2.Pkg2Types.VersionInterval, 1}}}) +precompile(Tuple{typeof(Core.Compiler.eltype), Type{Array{UInt32, 1}}}) +precompile(Tuple{typeof(Core.Compiler.eltype), Type{Array{UInt8, 1}}}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, typeof(Base.invokelatest), Nothing}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, typeof(Base.invokelatest), typeof(Pkg.REPLMode.do_help!)}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, typeof(Base.open), typeof(Pkg.Pkg2.Reqs.read)}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, typeof(Base.open), typeof(Pkg.TOML.parse)}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{Base.IteratorsMD.CartesianIndex{0}}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{Base.Missing, Int64}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{Base.Missing}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{Base.Val{1}, typeof(Base.cat_t), Union}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{Bool, typeof(Pkg.Types.parse_toml)}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{Int64, Tuple{Int64, Tuple{Int64, Tuple{Int64, Tuple{}}}}}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{NamedTuple{(:dims,), Tuple{Base.Val{1}}}, typeof(Base.cat_t), Union}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{Nothing, Int64, typeof(Base.sprint), typeof(Base.showerror)}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{Nothing, Int64, typeof(Base.sprint), typeof(Pkg.GraphType.showlog)}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{Pkg.REPLMode.CommandKind, Int64}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{typeof(Base.:(!))}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{typeof(Base.:(&))}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{typeof(Base.:(+))}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{typeof(Base.:(-))}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{typeof(Base.:(==))}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{typeof(Base.:(>))}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{typeof(Base.:(~))}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{typeof(Base.Unicode.lowercase)}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{typeof(Base.abs)}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{typeof(Base.first)}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{typeof(Base.identity)}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{typeof(Base.maximum)}, Int64}) +precompile(Tuple{typeof(Core.Compiler.getindex), Tuple{typeof(Pkg.BinaryProvider.parse_tar_list)}, Int64}) precompile(Tuple{typeof(Pkg.Display.filter_manifest), Pkg.Display.InProject{Base.Dict{String, Any}}, Base.Dict{String, Any}}) precompile(Tuple{typeof(Pkg.Display.in_project), Base.Dict{String, Any}}) precompile(Tuple{typeof(Pkg.Display.manifest_diff), Pkg.Types.Context, Base.Dict{String, Any}, Base.Dict{String, Any}}) precompile(Tuple{typeof(Pkg.Display.name_ver_info), Base.Dict{String, Any}}) precompile(Tuple{typeof(Pkg.Display.not_in_project), Base.Dict{String, Any}}) precompile(Tuple{typeof(Pkg.Display.print_diff), Base.TTY, Pkg.Types.Context, Array{Pkg.Display.DiffEntry, 1}, Bool}) -precompile(Tuple{typeof(Pkg.GitTools.showprogress), Base.TTY, Pkg.GitTools.MiniProgressBar}) -precompile(Tuple{typeof(Pkg.GitTools.transfer_progress), Ptr{LibGit2.TransferProgress}, Base.Dict{Symbol, Any}}) -precompile(Tuple{typeof(Pkg.REPLMode.do_status!), Pkg.Types.Context, Array{Union{Pkg.Types.VersionRange, String, Pkg.REPLMode.Command, Pkg.REPLMode.Option, Pkg.REPLMode.Rev}, 1}}) +precompile(Tuple{typeof(Pkg.Operations.load_package_data_raw), Type{Base.UUID}, String}) +precompile(Tuple{typeof(Pkg.REPLMode.do_add!), Base.Dict{Symbol, Any}, Array{Pkg.Types.PackageSpec, 1}, Base.Dict{Symbol, Any}}) +precompile(Tuple{typeof(Pkg.REPLMode.do_status!), Base.Dict{Symbol, Any}, Array{String, 1}, Base.Dict{Symbol, Any}}) precompile(Tuple{typeof(Pkg.REPLMode.promptf)}) precompile(Tuple{typeof(Pkg.TOML.SOME), Array{String, 1}}) precompile(Tuple{typeof(Pkg.TOML.SOME), Pkg.TOML.Table}) precompile(Tuple{typeof(Pkg.TOML.insertpair), Pkg.TOML.Parser{Base.IOStream}, Pkg.TOML.Table, String, Array{String, 1}, Int64}) -precompile(Tuple{typeof(Pkg.TOML.insertpair), Pkg.TOML.Parser{Base.IOStream}, Pkg.TOML.Table, String, String, Int64}) +precompile(Tuple{typeof(Pkg.TOML.insertpair), Pkg.TOML.Parser{Base.IOStream}, Pkg.TOML.Table, String, Pkg.TOML.Table, Int64}) +precompile(Tuple{typeof(Pkg.TOML.is_array_of_tables), Array{Base.Dict{String, Any}, 1}}) +precompile(Tuple{typeof(Pkg.TOML.is_array_of_tables), Array{String, 1}}) +precompile(Tuple{typeof(Pkg.TOML.is_array_of_tables), String}) +precompile(Tuple{typeof(Pkg.TOML.is_tabular), Array{Base.Dict{String, Any}, 1}}) +precompile(Tuple{typeof(Pkg.TOML.is_tabular), Array{String, 1}}) +precompile(Tuple{typeof(Pkg.TOML.is_tabular), Base.Dict{String, Any}}) +precompile(Tuple{typeof(Pkg.TOML.is_tabular), String}) +precompile(Tuple{typeof(Pkg.TOML.parsefile), String}) precompile(Tuple{typeof(Pkg.Types.printpkgstyle), Base.TTY, Symbol, String}) -precompile(Tuple{typeof(REPL.LineEdit.complete_line), Pkg.REPLMode.PkgCompletionProvider, REPL.LineEdit.PromptState}) -precompile(Tuple{typeof(REPL.LineEdit.write_prompt), REPL.Terminals.TerminalBuffer, typeof(Pkg.REPLMode.promptf)}) - -@assert precompile(Tuple{typeof(Pkg.REPLMode.do_help!), Pkg.Types.Context, Vector{Pkg.REPLMode.Token}, REPL.LineEditREPL}) -@assert precompile(Tuple{typeof(Pkg.REPLMode.do_status!), Pkg.Types.Context, Vector{Pkg.REPLMode.Token}}) -@assert precompile(Tuple{typeof(Pkg.REPLMode.do_add_or_develop!), Pkg.Types.Context, Vector{Pkg.REPLMode.Token}, Pkg.REPLMode.CommandKind}) -@assert precompile(Tuple{typeof(Pkg.REPLMode.do_rm!), Pkg.Types.Context, Vector{Pkg.REPLMode.Token}}) -@assert precompile(Tuple{typeof(Pkg.REPLMode.do_up!), Pkg.Types.Context, Vector{Pkg.REPLMode.Token}}) -@assert precompile(Tuple{typeof(Pkg.REPLMode.do_pin!), Pkg.Types.Context, Vector{Pkg.REPLMode.Token}}) -@assert precompile(Tuple{typeof(Pkg.REPLMode.do_free!), Pkg.Types.Context, Vector{Pkg.REPLMode.Token}}) -@assert precompile(Tuple{typeof(Pkg.REPLMode.do_test!), Pkg.Types.Context, Vector{Pkg.REPLMode.Token}}) -@assert precompile(Tuple{typeof(Pkg.REPLMode.do_build!), Pkg.Types.Context, Vector{Pkg.REPLMode.Token}}) - +precompile(Tuple{typeof(Pkg.Types.semver_interval), Base.RegexMatch}) +precompile(Tuple{typeof(Pkg.Types.write_env_usage), String}) +precompile(Tuple{typeof(REPL.LineEdit._clear_input_area), REPL.Terminals.TerminalBuffer, REPL.LineEdit.InputAreaState}) +precompile(Tuple{typeof(REPL.LineEdit.add_history), REPL.REPLHistoryProvider, REPL.LineEdit.PromptState}) +precompile(Tuple{typeof(REPL.LineEdit.clear_input_area), REPL.Terminals.TerminalBuffer, REPL.LineEdit.PromptState}) +precompile(Tuple{typeof(REPL.LineEdit.edit_abort), REPL.LineEdit.MIState, Bool}) +precompile(Tuple{typeof(REPL.LineEdit.edit_insert), REPL.LineEdit.MIState, String}) +precompile(Tuple{typeof(REPL.LineEdit.edit_insert), REPL.LineEdit.PromptState, String}) +precompile(Tuple{typeof(REPL.LineEdit.fixup_keymaps!), Base.Dict{Char, Any}, Int64, Char, Nothing}) +precompile(Tuple{typeof(REPL.LineEdit.init_state), REPL.Terminals.TTYTerminal, REPL.LineEdit.Prompt}) +precompile(Tuple{typeof(REPL.LineEdit.move_input_end), REPL.LineEdit.MIState}) +precompile(Tuple{typeof(REPL.LineEdit.normalize_key), Int64}) +precompile(Tuple{typeof(REPL.LineEdit.normalize_key), String}) +precompile(Tuple{typeof(REPL.LineEdit.on_enter), REPL.LineEdit.MIState}) +precompile(Tuple{typeof(REPL.LineEdit.postprocess!), Base.Dict{Char, Any}}) +precompile(Tuple{typeof(REPL.LineEdit.prompt_string), String}) +precompile(Tuple{typeof(REPL.LineEdit.push_undo), REPL.LineEdit.PromptState, Bool}) +precompile(Tuple{typeof(REPL.LineEdit.refresh_line), REPL.LineEdit.PromptState, REPL.Terminals.TTYTerminal}) +precompile(Tuple{typeof(REPL.LineEdit.refresh_multi_line), REPL.Terminals.TerminalBuffer, REPL.LineEdit.PromptState}) +precompile(Tuple{typeof(REPL.LineEdit.state), REPL.LineEdit.MIState, REPL.LineEdit.Prompt}) +precompile(Tuple{typeof(REPL.LineEdit.update_key_repeats), REPL.LineEdit.MIState, Array{Char, 1}}) +precompile(Tuple{typeof(REPL.LineEdit.write_prompt), REPL.Terminals.TerminalBuffer, REPL.LineEdit.Prompt}) +precompile(Tuple{typeof(REPL.LineEdit.write_prompt), REPL.Terminals.TerminalBuffer, String}) From 931786b2e3e4630ecb9757bf355966f0e1985d1c Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Sat, 4 Aug 2018 11:54:34 +0200 Subject: [PATCH 30/36] add licenses to files (cherry picked from commit d5890e6f0eafd43102402f18e0d8229092e03c1b, Julia PR #28443) --- stdlib/Pkg/src/REPLMode.jl | 2 ++ stdlib/Pkg/src/precompile.jl | 2 ++ stdlib/Pkg/test/api.jl | 2 ++ stdlib/Pkg/test/test_packages/x1/src/x1.jl | 2 ++ stdlib/Pkg/test/test_packages/x2/src/x2.jl | 2 ++ stdlib/Pkg/test/test_packages/x3/src/x3.jl | 2 ++ stdlib/Pkg/test/test_packages/x3/test/runtests.jl | 2 ++ 7 files changed, 14 insertions(+) diff --git a/stdlib/Pkg/src/REPLMode.jl b/stdlib/Pkg/src/REPLMode.jl index e3803371282b9..db18d952e538e 100644 --- a/stdlib/Pkg/src/REPLMode.jl +++ b/stdlib/Pkg/src/REPLMode.jl @@ -1,3 +1,5 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + module REPLMode using Markdown diff --git a/stdlib/Pkg/src/precompile.jl b/stdlib/Pkg/src/precompile.jl index 75b1b05e48827..adfebb709a63f 100644 --- a/stdlib/Pkg/src/precompile.jl +++ b/stdlib/Pkg/src/precompile.jl @@ -1,3 +1,5 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + precompile(Tuple{Type{Base.Dict{K, V} where V where K}, Array{Base.Pair{A, B} where B where A, 1}}) precompile(Tuple{Type{Base.Dict{Pkg.Types.VersionRange, Base.Dict{String, Base.UUID}}}}) precompile(Tuple{Type{Base.Dict{Pkg.Types.VersionRange, Base.Dict{String, Pkg.Types.VersionSpec}}}}) diff --git a/stdlib/Pkg/test/api.jl b/stdlib/Pkg/test/api.jl index 452eca69126c5..5ead22ccc9bf8 100644 --- a/stdlib/Pkg/test/api.jl +++ b/stdlib/Pkg/test/api.jl @@ -1,3 +1,5 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + module APITests using Pkg, Test diff --git a/stdlib/Pkg/test/test_packages/x1/src/x1.jl b/stdlib/Pkg/test/test_packages/x1/src/x1.jl index bd929422af3f4..61d85d63da27f 100644 --- a/stdlib/Pkg/test/test_packages/x1/src/x1.jl +++ b/stdlib/Pkg/test/test_packages/x1/src/x1.jl @@ -1,3 +1,5 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + module x1 greet() = print("Hello World!") diff --git a/stdlib/Pkg/test/test_packages/x2/src/x2.jl b/stdlib/Pkg/test/test_packages/x2/src/x2.jl index 8afcc2e013477..e4530c034da07 100644 --- a/stdlib/Pkg/test/test_packages/x2/src/x2.jl +++ b/stdlib/Pkg/test/test_packages/x2/src/x2.jl @@ -1,3 +1,5 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + module x2 greet() = print("Hello World!") diff --git a/stdlib/Pkg/test/test_packages/x3/src/x3.jl b/stdlib/Pkg/test/test_packages/x3/src/x3.jl index a9b26ef703c75..28b4ff3b9d16c 100644 --- a/stdlib/Pkg/test/test_packages/x3/src/x3.jl +++ b/stdlib/Pkg/test/test_packages/x3/src/x3.jl @@ -1,3 +1,5 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + module x3 greet() = print("Hello World!") diff --git a/stdlib/Pkg/test/test_packages/x3/test/runtests.jl b/stdlib/Pkg/test/test_packages/x3/test/runtests.jl index 85b0336d373e1..9540e3095e5d5 100644 --- a/stdlib/Pkg/test/test_packages/x3/test/runtests.jl +++ b/stdlib/Pkg/test/test_packages/x3/test/runtests.jl @@ -1,3 +1,5 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + module X3Tests using x2 From b7a7d8f6e28978ffc9960178345dea04d446954d Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Sat, 4 Aug 2018 22:42:45 +0100 Subject: [PATCH 31/36] increase isolation of test (cherry picked from commit fee0392482b84ea8c44923098652361354821887, Julia PR #28443) --- stdlib/Pkg/test/api.jl | 62 ++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/stdlib/Pkg/test/api.jl b/stdlib/Pkg/test/api.jl index 5ead22ccc9bf8..e8b7c7ccb7716 100644 --- a/stdlib/Pkg/test/api.jl +++ b/stdlib/Pkg/test/api.jl @@ -4,37 +4,41 @@ module APITests using Pkg, Test +include("utils.jl") + @testset "Pkg.activate" begin - cd(mktempdir()) do - path = pwd() - Pkg.activate(".") - mkdir("Foo") - cd(mkdir("modules")) do - Pkg.generate("Foo") + temp_pkg_dir() do project_path + cd(mktempdir()) do + path = pwd() + Pkg.activate(".") + mkdir("Foo") + cd(mkdir("modules")) do + Pkg.generate("Foo") + end + Pkg.develop(Pkg.Types.PackageSpec(path="modules/Foo")) # to avoid issue #542 + Pkg.activate("Foo") # activate path Foo over deps Foo + @test Base.active_project() == joinpath(path, "Foo", "Project.toml") + Pkg.activate(".") + rm("Foo"; force=true, recursive=true) + Pkg.activate("Foo") # activate path from developed Foo + @test Base.active_project() == joinpath(path, "modules", "Foo", "Project.toml") + Pkg.activate(".") + Pkg.activate("./Foo") # activate empty directory Foo (sidestep the developed Foo) + @test Base.active_project() == joinpath(path, "Foo", "Project.toml") + Pkg.activate(".") + Pkg.activate("Bar") # activate empty directory Bar + @test Base.active_project() == joinpath(path, "Bar", "Project.toml") + Pkg.activate(".") + Pkg.add("Example") # non-deved deps should not be activated + Pkg.activate("Example") + @test Base.active_project() == joinpath(path, "Example", "Project.toml") + Pkg.activate(".") + cd(mkdir("tests")) + Pkg.activate("Foo") # activate developed Foo from another directory + @test Base.active_project() == joinpath(path, "modules", "Foo", "Project.toml") + Pkg.activate() # activate home project + @test Base.ACTIVE_PROJECT[] === nothing end - Pkg.develop(Pkg.Types.PackageSpec(path="modules/Foo")) # to avoid issue #542 - Pkg.activate("Foo") # activate path Foo over deps Foo - @test Base.active_project() == joinpath(path, "Foo", "Project.toml") - Pkg.activate(".") - rm("Foo"; force=true, recursive=true) - Pkg.activate("Foo") # activate path from developed Foo - @test Base.active_project() == joinpath(path, "modules", "Foo", "Project.toml") - Pkg.activate(".") - Pkg.activate("./Foo") # activate empty directory Foo (sidestep the developed Foo) - @test Base.active_project() == joinpath(path, "Foo", "Project.toml") - Pkg.activate(".") - Pkg.activate("Bar") # activate empty directory Bar - @test Base.active_project() == joinpath(path, "Bar", "Project.toml") - Pkg.activate(".") - Pkg.add("Example") # non-deved deps should not be activated - Pkg.activate("Example") - @test Base.active_project() == joinpath(path, "Example", "Project.toml") - Pkg.activate(".") - cd(mkdir("tests")) - Pkg.activate("Foo") # activate developed Foo from another directory - @test Base.active_project() == joinpath(path, "modules", "Foo", "Project.toml") - Pkg.activate() # activate home project - @test Base.ACTIVE_PROJECT[] === nothing end end From d0c6fa684d7cfddf005b887e12e79248a571a097 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Mon, 6 Aug 2018 15:06:40 +0100 Subject: [PATCH 32/36] Fix mix-type arithmetic detection in umin/max expansion (#28465) Pointers can have different types. For these, a simple bitcast suffices rather than going through inttoptr. Fixes #28464 (cherry picked from commit 717ff908200b1900bae53564533d8545ede0fde4) --- deps/patches/llvm-D50167-scev-umin.patch | 46 +++++++++++++++++++++--- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/deps/patches/llvm-D50167-scev-umin.patch b/deps/patches/llvm-D50167-scev-umin.patch index f70649eeac37c..5a968a407ee44 100644 --- a/deps/patches/llvm-D50167-scev-umin.patch +++ b/deps/patches/llvm-D50167-scev-umin.patch @@ -621,10 +621,46 @@ index bfff7afb5b4..750c1fdfdfb 100644 bool Proper = true; for (const SCEV *NAryOp : NAry->operands()) { diff --git a/lib/Analysis/ScalarEvolutionExpander.cpp b/lib/Analysis/ScalarEvolutionExpander.cpp -index 53ce33bacbe..3179de31b92 100644 +index 01a8732b0b8..8160a1eaa0b 100644 --- a/lib/Analysis/ScalarEvolutionExpander.cpp +++ b/lib/Analysis/ScalarEvolutionExpander.cpp -@@ -1671,6 +1671,54 @@ Value *SCEVExpander::visitUMaxExpr(const SCEVUMaxExpr *S) { +@@ -1634,14 +1634,15 @@ Value *SCEVExpander::visitSMaxExpr(const SCEVSMaxExpr *S) { + for (int i = S->getNumOperands()-2; i >= 0; --i) { + // In the case of mixed integer and pointer types, do the + // rest of the comparisons as integer. +- if (S->getOperand(i)->getType() != Ty) { ++ Type *OpTy = S->getOperand(i)->getType(); ++ if (OpTy->isIntegerTy() != Ty->isIntegerTy()) { + Ty = SE.getEffectiveSCEVType(Ty); + LHS = InsertNoopCastOfTo(LHS, Ty); + } + Value *RHS = expandCodeFor(S->getOperand(i), Ty); + Value *ICmp = Builder.CreateICmpSGT(LHS, RHS); + rememberInstruction(ICmp); +- Value *Sel = Builder.CreateSelect(ICmp, LHS, RHS, "smax"); ++ Value *Sel = Builder.CreateSelect(ICmp, LHS, RHS, "smin"); + rememberInstruction(Sel); + LHS = Sel; + } +@@ -1658,14 +1659,15 @@ Value *SCEVExpander::visitUMaxExpr(const SCEVUMaxExpr *S) { + for (int i = S->getNumOperands()-2; i >= 0; --i) { + // In the case of mixed integer and pointer types, do the + // rest of the comparisons as integer. +- if (S->getOperand(i)->getType() != Ty) { ++ Type *OpTy = S->getOperand(i)->getType(); ++ if (OpTy->isIntegerTy() != Ty->isIntegerTy()) { + Ty = SE.getEffectiveSCEVType(Ty); + LHS = InsertNoopCastOfTo(LHS, Ty); + } + Value *RHS = expandCodeFor(S->getOperand(i), Ty); + Value *ICmp = Builder.CreateICmpUGT(LHS, RHS); + rememberInstruction(ICmp); +- Value *Sel = Builder.CreateSelect(ICmp, LHS, RHS, "umax"); ++ Value *Sel = Builder.CreateSelect(ICmp, LHS, RHS, "umin"); + rememberInstruction(Sel); + LHS = Sel; + } +@@ -1671,6 +1671,56 @@ Value *SCEVExpander::visitUMaxExpr(const SCEVUMaxExpr *S) { return LHS; } @@ -634,7 +670,8 @@ index 53ce33bacbe..3179de31b92 100644 + for (int i = S->getNumOperands()-2; i >= 0; --i) { + // In the case of mixed integer and pointer types, do the + // rest of the comparisons as integer. -+ if (S->getOperand(i)->getType() != Ty) { ++ Type *OpTy = S->getOperand(i)->getType(); ++ if (OpTy->isIntegerTy() != Ty->isIntegerTy()) { + Ty = SE.getEffectiveSCEVType(Ty); + LHS = InsertNoopCastOfTo(LHS, Ty); + } @@ -658,7 +695,8 @@ index 53ce33bacbe..3179de31b92 100644 + for (int i = S->getNumOperands()-2; i >= 0; --i) { + // In the case of mixed integer and pointer types, do the + // rest of the comparisons as integer. -+ if (S->getOperand(i)->getType() != Ty) { ++ Type *OpTy = S->getOperand(i)->getType(); ++ if (OpTy->isIntegerTy() != Ty->isIntegerTy()) { + Ty = SE.getEffectiveSCEVType(Ty); + LHS = InsertNoopCastOfTo(LHS, Ty); + } From 3e5238803583892733eea46ef3feafc51b440842 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Mon, 6 Aug 2018 15:07:27 +0100 Subject: [PATCH 33/36] Fix race condition when building LLVM for Windows (#28433) `llvm-tblgen` and `llvm-config` both try to build in the same NATIVE directory and end up stomping on each other. (cherry picked from commit 4fce960517c5927402d74bc0c0c79c10520d53e2) --- deps/llvm.mk | 1 + deps/patches/llvm-windows-race.patch | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 deps/patches/llvm-windows-race.patch diff --git a/deps/llvm.mk b/deps/llvm.mk index 4086d9d255485..4f350aa443b25 100644 --- a/deps/llvm.mk +++ b/deps/llvm.mk @@ -506,6 +506,7 @@ $(eval $(call LLVM_PATCH,llvm-D49832-SCEVPred)) # Remove for 7.0 $(eval $(call LLVM_PATCH,llvm-rL323946-LSRTy)) # Remove for 7.0 $(eval $(call LLVM_PATCH,llvm-D50010-VNCoercion-ni)) $(eval $(call LLVM_PATCH,llvm-D50167-scev-umin)) +$(eval $(call LLVM_PATCH,llvm-windows-race)) endif # LLVM_VER # Remove hardcoded OS X requirements in compilter-rt cmake build diff --git a/deps/patches/llvm-windows-race.patch b/deps/patches/llvm-windows-race.patch new file mode 100644 index 0000000000000..fdb56f4948d48 --- /dev/null +++ b/deps/patches/llvm-windows-race.patch @@ -0,0 +1,25 @@ +commit c0be37352f6d91505d964a7d33ad79b40750d370 +Author: Keno Fischer +Date: Fri Aug 3 21:03:32 2018 -0400 + + [CrossCompile] Add a dependency llvm-config-host -> llvm-tblgen-host + + These use the same working directory and without a dependency + edge between them race to build some of the utility libraries + causing build failures. + +diff --git a/tools/llvm-config/CMakeLists.txt b/tools/llvm-config/CMakeLists.txt +index f59402ac4b0..f3b4e60fd99 100644 +--- a/tools/llvm-config/CMakeLists.txt ++++ b/tools/llvm-config/CMakeLists.txt +@@ -77,5 +77,10 @@ if(CMAKE_CROSSCOMPILING AND NOT LLVM_CONFIG_PATH) + add_custom_target(${project}NativeLLVMConfig DEPENDS ${${project}_LLVM_CONFIG_EXE}) + add_dependencies(${project}NativeLLVMConfig CONFIGURE_LLVM_NATIVE) + ++ # Add a dependency on the host tblgen, which uses the same working ++ # directory and with which we're otherwise racing to build some ++ # of the utility libraries. ++ add_dependencies(${project}NativeLLVMConfig LLVM-tablegen-host) ++ + add_dependencies(llvm-config ${project}NativeLLVMConfig) + endif(CMAKE_CROSSCOMPILING) From 0c76bfaa5ce09a76abe05ebf654f483a51e8ba73 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Mon, 6 Aug 2018 15:06:16 +0100 Subject: [PATCH 34/36] [GCLowering] Expand support for vectors of pointers (#28455) Most of the support was already there, but it was mostly unexercised. The recent activation of the SLP vectorizer made these patterns appear in the IR, so fixup the support. Fixes #28445 (cherry picked from commit f5a0b034a4133263736c07934f3eb60567889396) --- src/llvm-late-gc-lowering.cpp | 47 +++++++++++++++++++++++++++-------- test/core.jl | 20 +++++++++++++++ test/llvmpasses/gcroots.ll | 13 ++++++++++ 3 files changed, 70 insertions(+), 10 deletions(-) diff --git a/src/llvm-late-gc-lowering.cpp b/src/llvm-late-gc-lowering.cpp index a48fd1a96eb8f..d97bf02a05f22 100644 --- a/src/llvm-late-gc-lowering.cpp +++ b/src/llvm-late-gc-lowering.cpp @@ -486,7 +486,9 @@ static std::pair FindBaseValue(const State &S, Value *V, bool UseCac isa(CurrentV) || isa(CurrentV) || isa(CurrentV) || isa(CurrentV) || isa(CurrentV) || isa(CurrentV) || - isa(CurrentV)); + isa(CurrentV) || + isa(CurrentV) || + isa(CurrentV)); return std::make_pair(CurrentV, fld_idx); } @@ -602,22 +604,37 @@ std::vector LateLowerGCFrame::NumberVectorBase(State &S, Value *CurrentV) { ((isa(CurrentV) || isa(CurrentV) || isa(CurrentV)) && getValueAddrSpace(CurrentV) != AddressSpace::Tracked)) { + Numbers.resize(cast(CurrentV->getType())->getNumElements(), -1); } /* We (the frontend) don't insert either of these, but it would be legal - though a bit strange, considering they're pointers - for the optimizer to do so. All that's needed here is to NumberVector the previous vector/value and lift the operation */ - else if (isa(CurrentV)) { - assert(false && "TODO Shuffle"); - } else if (isa(CurrentV)) { - assert(false && "TODO Insert"); - } else if (isa(CurrentV)) { + else if (auto *SVI = dyn_cast(CurrentV)) { + std::vector Numbers1 = NumberVectorBase(S, SVI->getOperand(0)); + std::vector Numbers2 = NumberVectorBase(S, SVI->getOperand(1)); + auto Mask = SVI->getShuffleMask(); + for (unsigned idx : Mask) { + if (idx < Numbers1.size()) { + Numbers.push_back(Numbers1[idx]); + } else { + Numbers.push_back(Numbers2[idx - Numbers1.size()]); + } + } + } else if (auto *IEI = dyn_cast(CurrentV)) { + unsigned idx = cast(IEI->getOperand(2))->getZExtValue(); + Numbers = NumberVectorBase(S, IEI->getOperand(0)); + int ElNumber = Number(S, IEI->getOperand(1)); + Numbers[idx] = ElNumber; + } else if (isa(CurrentV) || isa(CurrentV) || isa(CurrentV)) { // This is simple, we can just number them sequentially for (unsigned i = 0; i < cast(CurrentV->getType())->getNumElements(); ++i) { int Num = ++S.MaxPtrNumber; Numbers.push_back(Num); S.ReversePtrNumbering[Num] = CurrentV; } + } else { + assert(false && "Unexpected vector generating operating"); } S.AllVectorNumbering[CurrentV] = Numbers; return Numbers; @@ -629,9 +646,17 @@ std::vector LateLowerGCFrame::NumberVector(State &S, Value *V) { return it->second; auto CurrentV = FindBaseValue(S, V); assert(CurrentV.second == -1); - auto Numbers = NumberVectorBase(S, CurrentV.first); - S.AllVectorNumbering[V] = Numbers; - return Numbers; + // E.g. if this is a gep, it's possible for the base to be a single ptr + if (isSpecialPtrVec(CurrentV.first->getType())) { + auto Numbers = NumberVectorBase(S, CurrentV.first); + S.AllVectorNumbering[V] = Numbers; + return Numbers; + } else { + std::vector Numbers{}; + Numbers.resize(cast(V->getType())->getNumElements(), + NumberBase(S, V, CurrentV.first)); + return Numbers; + } } static void MaybeResize(BBState &BBS, unsigned Idx) { @@ -714,6 +739,8 @@ void LateLowerGCFrame::NoteUse(State &S, BBState &BBS, Value *V, BitVector &Uses std::vector Nums = NumberVector(S, V); for (int Num : Nums) { MaybeResize(BBS, Num); + if (Num < 0) + continue; Uses[Num] = 1; } } @@ -729,7 +756,7 @@ void LateLowerGCFrame::NoteUse(State &S, BBState &BBS, Value *V, BitVector &Uses void LateLowerGCFrame::NoteOperandUses(State &S, BBState &BBS, User &UI, BitVector &Uses) { for (Use &U : UI.operands()) { Value *V = U; - if (!isSpecialPtr(V->getType())) + if (!isSpecialPtr(V->getType()) && !isSpecialPtrVec(V->getType())) continue; NoteUse(S, BBS, V, Uses); } diff --git a/test/core.jl b/test/core.jl index 3891ae71e099e..015135ae14e6d 100644 --- a/test/core.jl +++ b/test/core.jl @@ -6674,3 +6674,23 @@ c28399 = 42 @test g28399(0)() == 42 @test g28399(1)() == 42 @test_throws UndefVarError(:__undef_28399__) f28399() + +# issue #28445 +mutable struct foo28445 + x::Int +end + +@noinline make_foo28445() = (foo28445(1), foo28445(rand(1:10)), foo28445(rand(1:10))) +@noinline function use_tuple28445(c) + @test isa(c[2], foo28445) + @test isa(c[3], foo28445) +end + +function repackage28445() + (_, a, b) = make_foo28445() + GC.gc() + c = (foo28445(1), foo28445(2), a, b) + use_tuple28445(c) + true +end +@test repackage28445() diff --git a/test/llvmpasses/gcroots.ll b/test/llvmpasses/gcroots.ll index 25d75a8a7a0d1..958a735b8efca 100644 --- a/test/llvmpasses/gcroots.ll +++ b/test/llvmpasses/gcroots.ll @@ -401,6 +401,19 @@ top: ret i8 %val } +define %jl_value_t addrspace(10)* @vecstoreload(<2 x %jl_value_t addrspace(10)*> *%arg) { +; CHECK-LABEL: @vecstoreload +; CHECK: %gcframe = alloca %jl_value_t addrspace(10)*, i32 4 +top: + %ptls = call %jl_value_t*** @julia.ptls_states() + %loaded = load <2 x %jl_value_t addrspace(10)*>, <2 x %jl_value_t addrspace(10)*> *%arg + call void @jl_safepoint() + %obj = call %jl_value_t addrspace(10) *@alloc() + %casted = bitcast %jl_value_t addrspace(10)* %obj to <2 x %jl_value_t addrspace(10)*> addrspace(10)* + store <2 x %jl_value_t addrspace(10)*> %loaded, <2 x %jl_value_t addrspace(10)*> addrspace(10)* %casted + ret %jl_value_t addrspace(10)* %obj +} + !0 = !{!"jtbaa"} !1 = !{!"jtbaa_const", !0, i64 0} !2 = !{!1, !1, i64 0, i64 1} From 7db57509285e410e47d4ebf11ccbb4888d1b16d5 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Mon, 6 Aug 2018 11:29:23 -0400 Subject: [PATCH 35/36] Fix legality check in SROA (#28478) The legality check was using use counts after `finish(compact)` got to delete, which made them inaccurate. Instead, take a copy of the use counts before. Additionally, ignore any uses that got deleted during `finish(compact)`. Fixes #28444. (cherry picked from commit 0f3d58620d8e8fbe8416580c76c1d3b0f7b93992) --- base/compiler/ssair/passes.jl | 15 ++++++++++++--- test/compiler/compiler.jl | 13 +++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/base/compiler/ssair/passes.jl b/base/compiler/ssair/passes.jl index 0eaa190f94a5b..ce04b81bac1eb 100644 --- a/base/compiler/ssair/passes.jl +++ b/base/compiler/ssair/passes.jl @@ -688,6 +688,9 @@ function getfield_elim_pass!(ir::IRCode, domtree::DomTree) compact[idx] = val === nothing ? nothing : val.x end + # Copy the use count, `finish` may modify it and for our predicate + # below we need it consistent with the state of the IR here. + used_ssas = copy(compact.used_ssas) ir = finish(compact) # Now go through any mutable structs and see which ones we can eliminate for (idx, (intermediaries, defuse)) in defuses @@ -699,9 +702,9 @@ function getfield_elim_pass!(ir::IRCode, domtree::DomTree) nleaves = length(defuse.uses) + length(defuse.defs) + length(defuse.ccall_preserve_uses) nuses = 0 for idx in intermediaries - nuses += compact.used_ssas[idx] + nuses += used_ssas[idx] end - nuses_total = compact.used_ssas[idx] + nuses - length(intermediaries) + nuses_total = used_ssas[idx] + nuses - length(intermediaries) nleaves == nuses_total || continue # Find the type for this allocation defexpr = ir[SSAValue(idx)] @@ -717,7 +720,13 @@ function getfield_elim_pass!(ir::IRCode, domtree::DomTree) fielddefuse = SSADefUse[SSADefUse() for _ = 1:fieldcount(typ)] ok = true for use in defuse.uses - field = try_compute_fieldidx_expr(typ, ir[SSAValue(use)]) + stmt = ir[SSAValue(use)] + # We may have discovered above that this use is dead + # after the getfield elim of immutables. In that case, + # it would have been deleted. That's fine, just ignore + # the use in that case. + stmt === nothing && continue + field = try_compute_fieldidx_expr(typ, stmt) field === nothing && (ok = false; break) push!(fielddefuse[field].uses, use) end diff --git a/test/compiler/compiler.jl b/test/compiler/compiler.jl index 539afaebfca35..2098b5f2b6267 100644 --- a/test/compiler/compiler.jl +++ b/test/compiler/compiler.jl @@ -1950,3 +1950,16 @@ end h28356() = f28356(Any[Float64][1]) @test h28356() isa S28356{Float64} + +# Issue #28444 +mutable struct foo28444 + a::Int + b::Int +end +function bar28444() + a = foo28444(1, 2) + c, d = a.a, a.b + e = (c, d) + e[1] +end +@test bar28444() == 1 From a4ab298ba17f66ccd30a59153a5fe91589705b77 Mon Sep 17 00:00:00 2001 From: Alex Arslan Date: Mon, 6 Aug 2018 19:44:25 +0100 Subject: [PATCH 36/36] Work around invalid register errors with 64-bit Windows (#28449) Adding `-fno-asynchronous-unwind-tables` to the C compiler flags passed to OpenBLAS works around errors claiming an invalid register for `.seh_savexmm`. We've been running into this on the 64-bit Windows buildbots. See discussion in https://github.com/xianyi/OpenBLAS/issues/1708. (cherry picked from commit 651a727a201e08aa1e2aa8d9007a7088cbbdc997) --- deps/blas.mk | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/deps/blas.mk b/deps/blas.mk index 26e985be75869..c025d4ac26e39 100644 --- a/deps/blas.mk +++ b/deps/blas.mk @@ -62,6 +62,15 @@ OPENBLAS_FFLAGS += -mincoming-stack-boundary=2 endif endif +# Work around invalid register errors on 64-bit Windows +# See discussion in https://github.com/xianyi/OpenBLAS/issues/1708 +# TODO: Remove this once we use a version of OpenBLAS where this is set automatically +ifeq ($(OS),WINNT) +ifeq ($(ARCH),x86_64) +OPENBLAS_CFLAGS += -fno-asynchronous-unwind-tables +endif +endif + OPENBLAS_BUILD_OPTS += CFLAGS="$(CFLAGS) $(OPENBLAS_CFLAGS)" OPENBLAS_BUILD_OPTS += FFLAGS="$(FFLAGS) $(OPENBLAS_FFLAGS)" OPENBLAS_BUILD_OPTS += LDFLAGS="$(LDFLAGS) $(RPATH_ESCAPED_ORIGIN)"