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/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/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..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() @@ -82,65 +75,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 - Base.include_string(PrecompileStagingArea, statements_ordered) - print(" $(length(statements)) generated in ") - Base.time_print((time() - start_time) * 10^9) - println() + # 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() + 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/deps/blas.mk b/deps/blas.mk index 6035954cb4faa..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)" @@ -73,9 +82,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 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-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); + } 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) 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/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/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/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. 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 diff --git a/stdlib/LibGit2/src/types.jl b/stdlib/LibGit2/src/types.jl index 3348206ffa477..e6bee7a03be41 100644 --- a/stdlib/LibGit2/src/types.jl +++ b/stdlib/LibGit2/src/types.jl @@ -1303,6 +1303,10 @@ end function approve(cache::CachedCredentials, cred::AbstractCredential, url::AbstractString) cred_id = credential_identifier(url) + 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 end @@ -1310,6 +1314,8 @@ end function reject(cache::CachedCredentials, cred::AbstractCredential, url::AbstractString) cred_id = credential_identifier(url) if haskey(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 @@ -1409,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 @@ -1437,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 78251599e264c..b3a243289e0e8 100644 --- a/stdlib/LibGit2/test/libgit2.jl +++ b/stdlib/LibGit2/test/libgit2.jl @@ -1734,14 +1734,43 @@ mktempdir() do dir @test haskey(cache, cred_id) @test cache[cred_id] === cred - # Reject an approved should cause it to be removed - LibGit2.reject(cache, cred, url) + # 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 overwritten `cred` + @test haskey(cache, cred_id) + @test cache[cred_id] === dup_cred + @test cred.user != "julia" + @test cred.pass != password + @test dup_cred.user == "julia" + @test dup_cred.pass == password + + cred = dup_cred + + # 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!(cred) Base.shred!(password) end 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 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 diff --git a/stdlib/Pkg/docs/src/index.md b/stdlib/Pkg/docs/src/index.md index 571f4f157a81a..7e01e44a08584 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 @@ -350,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. @@ -695,7 +692,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: diff --git a/stdlib/Pkg/src/API.jl b/stdlib/Pkg/src/API.jl index 8d6d85fb284f0..a4cc2a363f682 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 @@ -28,22 +28,28 @@ 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, shared::Bool=true, kwargs...) Context!(ctx; kwargs...) # 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; # 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 - 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 @@ -53,7 +59,7 @@ function add_or_develop(ctx::Context, pkgs::Vector{PackageSpec}; mode::Symbol, d 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() @@ -61,13 +67,18 @@ 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...) 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) @@ -101,7 +112,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 @@ -144,6 +155,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) @@ -207,7 +224,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) @@ -226,7 +243,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) @@ -241,7 +258,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 @@ -456,7 +474,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} @@ -492,7 +510,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") + pkgerror("manifest at $(ctx.env.manifest_file) does not exist") end update_registry(ctx) urls = Dict{} @@ -534,8 +552,47 @@ function status(ctx::Context, mode=PKGMODE_PROJECT) return end -function activate(path::Union{String,Nothing}=nothing) - Base.ACTIVE_PROJECT[] = Base.load_path_expand(path) +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 + # 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 + 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) + 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(fullpath) end """ 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 547cebdc75842..f03de979c85dc 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) @@ -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"] @@ -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 @@ -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]" @@ -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 @@ -945,6 +951,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) @@ -1014,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 @@ -1162,33 +1169,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 @@ -1250,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") @@ -1261,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 @@ -1284,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 @@ -1305,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 3efe4bc1b4619..f5e34961758e0 100644 --- a/stdlib/Pkg/src/Pkg.jl +++ b/stdlib/Pkg/src/Pkg.jl @@ -12,8 +12,15 @@ 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) && Pkg.Types.pkgerror("no depots found in DEPOT_PATH") + return d[1] +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 @@ -35,6 +42,7 @@ import .REPLMode: @pkg_str import .Types: UPLEVEL_MAJOR, UPLEVEL_MINOR, UPLEVEL_PATCH, UPLEVEL_FIXED import .Types: PKGMODE_MANIFEST, PKGMODE_PROJECT + """ PackageMode @@ -255,18 +263,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. @@ -283,7 +293,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: @@ -292,8 +302,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). @@ -308,8 +318,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`)| """ @@ -338,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 @@ -348,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/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 diff --git a/stdlib/Pkg/src/REPLMode.jl b/stdlib/Pkg/src/REPLMode.jl index a7df17f52b8a0..db18d952e538e 100644 --- a/stdlib/Pkg/src/REPLMode.jl +++ b/stdlib/Pkg/src/REPLMode.jl @@ -11,45 +11,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 +21,132 @@ 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")) +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 && 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) +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 + Union{Nothing,Function}, # handler + Tuple{ArgClass, Vector{Int}}, # argument count + Vector{OptionDeclaration}, # options + Union{Nothing, Markdown.MD}, #help + } +struct CommandSpec + kind::CommandKind + names::Vector{String} + 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} +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 ################### @@ -147,51 +176,110 @@ 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 ################ # 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 + +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 = lex(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 -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"))) +# vector of words -> structured statement +# minimal checking is done in this phase +function Statement(words)::Statement + is_option(word) = first(word) == '-' + statement = Statement() + + word = popfirst!(words) + # meta options + while is_option(word) + push!(statement.meta_options, word) + isempty(words) && pkgerror("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 || pkgerror("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 + +# 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) ? pkgerror("empty statement") : push!(statements, x) + x = String[] + else + push!(x, word) end end + 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 - commands = Vector{Token}[] - while !isempty(words) - push!(commands, tokenize!(words)) +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 commands + return words 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 @@ -199,661 +287,355 @@ function parse_quotes(cmd::String) 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 end if (in_doublequote || in_singlequote) - ArgumentError("unterminated quote") + pkgerror("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}} +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 - -############# -# 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 +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}, + )::Dict{Symbol, Any} + keyword_vec = 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 + return Dict(keyword_vec) 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) +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 || pkgerror(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 - end - - if cmd.kind == CMD_ACTIVATE - return Base.invokelatest(do_activate!, Base.active_project() === nothing ? - nothing : EnvCache(env_opt), tokens) - 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) +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 - - 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 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""" +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 - generate pkgname + class == ARG_RAW && return raw_args + args::Vector{Token} = map(word2token, raw_args) + class == ARG_ALL && return args - 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 + if class == ARG_PKG && has_types(args, [VersionRange, Rev]) + pkgerror("no versioned packages allowed") + elseif class == ARG_REV && has_types(args, [VersionRange]) + pkgerror("no versioned packages allowed") + elseif class == ARG_VERSION && has_types(args, [Rev]) + pkgerror("no reved packages allowed") 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) - else - cmderror("Sorry, I don't have any help for the `$(token.val)` command.") - end - else - error("invalid usage of help command") - end - end - Base.display(disp, help_md) + return args end -function do_rm!(ctx::Context, tokens::Vector{Token}) - # tokens: package names and/or uuids - mode = PKGMODE_PROJECT +function package_args(args::Vector{Token}, spec::CommandSpec)::Vector{PackageSpec} 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") + 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 + if spec.kind == CMD_DEVELOP + pkgerror("a git revision cannot be given to `develop`") end - end - end - isempty(pkgs) && - cmderror("`rm` – list packages to remove") - API.rm(ctx, pkgs) -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) + pkg.repo = Types.GitRepo("", arg.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") + pkgs[end].repo.rev = arg.rev end + else + assert(false) end 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) + 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 - end - API.up(ctx, pkgs; level=level, mode=mode) +function enforce_arg_count(count::Vector{Int}, args::PkgArguments) + isempty(count) && return + length(args) in count || + pkgerror("Wrong number of arguments") 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_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 - API.pin(ctx, pkgs) + + 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_free!(ctx::Context, tokens::Vector{Token}) - pkgs = PackageSpec[] - while !isempty(tokens) - token = popfirst!(tokens) - if token isa String - push!(pkgs, parse_package(token)) - else - cmderror("free only takes a list of packages") - end +function enforce_option(option::String, specs::Dict{String,OptionSpec})::Option + opt = parse_option(option) + spec = get(specs, opt.val, nothing) + spec !== nothing || + pkgerror("option '$(opt.val)' is not a valid option") + if spec.is_switch + opt.argument === nothing || + pkgerror("option '$(opt.val)' does not take an argument, but '$(opt.argument)' given") + else # option takes an argument + opt.argument !== nothing || + pkgerror("option '$(opt.val)' expects an argument, but no argument given") end - API.free(ctx, pkgs) + return opt 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 +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 || + 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 - Display.status(ctx, mode) 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 +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) || + 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) + pkgerror("Conflicting options: $conflicting") else - # TODO: Better error message - cmderror("invalid usage for `test`") + push!(unique_keys, key) end end - API.test(ctx, pkgs; coverage = coverage) + return toks end -function do_gc!(ctx::Context, tokens::Vector{Token}) - !isempty(tokens) && cmderror("`gc` does not take any arguments") - API.gc(ctx) +# 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 -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)) +Context!(ctx::APIOptions)::Context = Types.Context!(collect(ctx)) + +############# +# 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 PkgError || err isa ResolverError + Base.display_error(repl.t.err_stream, ErrorException(sprint(showerror, err)), Ptr{Nothing}[]) else - cmderror("`build` only takes a list of packages") + Base.display_error(repl.t.err_stream, err, Base.catch_backtrace()) end end - API.build(ctx, pkgs) 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) -end +function do_cmd!(command::PkgCommand, repl) + context = APIOptions(command.meta_options, meta_option_specs) + spec = command.spec + + # REPL specific commands + if spec.kind == CMD_HELP + return Base.invokelatest(do_help!, command, repl) + elseif spec.kind == CMD_PREVIEW + context[:preview] = true + cmd = command.arguments[1] + cmd_spec = get(command_specs, cmd, nothing) + cmd_spec === nothing && + pkgerror("'$cmd' is not a valid command") + spec = cmd_spec + command = PkgCommand([], cmd, [], PackageSpec[]) + end -function do_precompile!(ctx::Context, tokens::Vector{Token}) - if !isempty(tokens) - cmderror("`precompile` does not take any arguments") + # API commands + # TODO is invokelatest still needed? + 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 - API.precompile(ctx) 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_help!(command::PkgCommand, repl::REPL.AbstractREPL) + disp = REPL.REPLDisplay(repl) + if isempty(command.arguments) + Base.display(disp, help) + return end - API.instantiate(ctx; manifest=manifest) + help_md = md"" + for arg in command.arguments + spec = get(command_specs, arg, nothing) + spec === nothing && + pkgerror("'$arg' does not name a command") + spec.help === nothing && + 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) + end + Base.display(disp, help_md) end -function do_resolve!(ctx::Context, tokens::Vector{Token}) - !isempty(tokens) && cmderror("`resolve` does not take any arguments") - API.resolve(ctx) +# TODO set default Display.status keyword: mode = PKGMODE_COMBINED +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::APIOptions, args::PkgArguments, api_opts::APIOptions) + foreach(arg -> arg.mode = PKGMODE_MANIFEST, args) + API.test(Context!(ctx), args; collect(api_opts)...) +end + +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 + println("- $arg") + end end -function do_activate!(env::Union{EnvCache,Nothing}, tokens::Vector{Token}) - if isempty(tokens) +do_precompile!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = + API.precompile(Context!(ctx)) + +do_resolve!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = + API.resolve(Context!(ctx)) + +do_gc!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = + API.gc(Context!(ctx); collect(api_opts)...) + +do_instantiate!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = + API.instantiate(Context!(ctx); collect(api_opts)...) + +do_generate!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = + API.generate(Context!(ctx), args[1]) + +do_build!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = + API.build(Context!(ctx), args; collect(api_opts)...) + +do_rm!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = + API.rm(Context!(ctx), args; collect(api_opts)...) + +do_free!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = + API.free(Context!(ctx), args; collect(api_opts)...) + +do_up!(ctx::APIOptions, args::PkgArguments, api_opts::APIOptions) = + API.up(Context!(ctx), args; collect(api_opts)...) + +function do_activate!(args::PkgArguments, api_opts::APIOptions) + if isempty(args) return API.activate() 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)) + return API.activate(args[1]; collect(api_opts)...) + end +end + +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 + pkgerror("pinning a package requires a single version, not a versionrange") end end + API.pin(Context!(ctx), args; collect(api_opts)...) +end + +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::APIOptions, args::PkgArguments, api_opts::APIOptions) + api_opts[:mode] = :develop + API.add_or_develop(Context!(ctx), args; collect(api_opts)...) end ###################### @@ -872,10 +654,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,10 +666,10 @@ end pkgstr(str::String) = do_cmd(minirepl[], str; do_rethrow=true) # handle completions -all_commands_sorted = sort!(collect(keys(cmds))) -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)))] -long_options = filter(c -> length(c) > 2, all_options_sorted) +all_commands_sorted = [] +long_commands = [] +all_options_sorted = [] +long_options = [] struct PkgCompletionProvider <: LineEdit.CompletionProvider end @@ -912,7 +695,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) @@ -921,7 +704,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) @@ -971,25 +754,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 +786,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 +896,396 @@ 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", "?"], + nothing, + (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, :shared => false), + ("shared", OPT_SWITCH, :shared => true), + ], + md""" + 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 +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]), + [ + ("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!, + (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"], + nothing, + (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) +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/src/Types.jl b/stdlib/Pkg/src/Types.jl index 0a247849650d7..1cd15177f05f6 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 @@ -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) ############### @@ -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 && pkgerror("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) @@ -358,6 +363,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) @@ -385,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 @@ -428,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) @@ -436,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 @@ -511,7 +524,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 @@ -532,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 @@ -558,7 +568,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 @@ -577,17 +587,19 @@ 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 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 @@ -670,6 +682,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 @@ -692,8 +706,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 && 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) @@ -740,7 +758,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 @@ -766,7 +784,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) @@ -869,7 +887,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") @@ -887,7 +905,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") @@ -1049,7 +1067,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 @@ -1057,7 +1075,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/src/precompile.jl b/stdlib/Pkg/src/precompile.jl index b6f5c152b3d0a..adfebb709a63f 100644 --- a/stdlib/Pkg/src/precompile.jl +++ b/stdlib/Pkg/src/precompile.jl @@ -1,82 +1,431 @@ # 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}) diff --git a/stdlib/Pkg/test/api.jl b/stdlib/Pkg/test/api.jl new file mode 100644 index 0000000000000..e8b7c7ccb7716 --- /dev/null +++ b/stdlib/Pkg/test/api.jl @@ -0,0 +1,45 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +module APITests + +using Pkg, Test + +include("utils.jl") + +@testset "Pkg.activate" begin + 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 + end +end + +end # module APITests diff --git a/stdlib/Pkg/test/pkg.jl b/stdlib/Pkg/test/pkg.jl index ae9a706aefbd3..32e1f8d18bb5c 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,27 @@ 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 + @test_throws PkgError Pkg.develop(PackageSpec(url="bleh", rev="blurg")) 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,19 +210,19 @@ 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 @testset "invalid pkg name" begin - @test_throws CommandError Pkg.add(",sa..,--") + @test_throws PkgError Pkg.add(",sa..,--") end @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") @@ -241,7 +242,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 +260,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 +282,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 @@ -298,7 +299,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 +309,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 @@ -390,9 +391,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 @@ -405,10 +406,10 @@ 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() + @test_throws PkgError Pkg.update() end end end @@ -435,6 +436,19 @@ 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") end # module diff --git a/stdlib/Pkg/test/repl.jl b/stdlib/Pkg/test/repl.jl index 2530a4ed5709a..20ebc5395c64c 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 @@ -42,60 +42,59 @@ 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" 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 @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("?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" + 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 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" @@ -109,12 +108,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" @@ -125,9 +124,9 @@ 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 CommandError Pkg.REPLMode.pkgstr("free $pkg2") + @test_throws PkgError Pkg.REPLMode.pkgstr("free $pkg2") Pkg.test("UnregisteredWithProject") write(joinpath(p2, "Project.toml"), """ @@ -140,7 +139,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) @@ -165,7 +164,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) @@ -199,14 +198,10 @@ 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") - - pkg"develop Example#c37b675" - @test Base.find_package("Example") == joinpath(tmp, "Example", "src", "Example.jl") - Pkg.test("Example") end finally empty!(DEPOT_PATH) @@ -227,8 +222,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" @@ -253,6 +248,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.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") cd(mkdir("modules")) do pkg"generate Foo" @@ -261,23 +264,34 @@ 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 end @@ -393,11 +407,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 @@ -424,7 +441,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, "*") @@ -514,8 +533,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 @@ -556,20 +575,295 @@ 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 @0.0.0") - @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 + +@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 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 +end + +@testset "invalid options" begin + temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; + @test_throws PkgError Pkg.REPLMode.pkgstr("rm --minor Example") + @test_throws PkgError 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 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 +end + +@testset "conflicting options" begin + temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; + @test_throws PkgError Pkg.REPLMode.pkgstr("up --major --minor") + @test_throws PkgError 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 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 + end +end + +@testset "precompile" begin + temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; + @test_throws PkgError Pkg.REPLMode.pkgstr("precompile --project") + @test_throws PkgError 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 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 + end +end + +@testset "test" begin + temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; + Pkg.add("Example") + @test_throws PkgError 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 PkgError Pkg.REPLMode.pkgstr("build --project") + @test_throws PkgError 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 PkgError Pkg.REPLMode.pkgstr("free --project") + @test_throws PkgError 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 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 + 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 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"), + Pkg.REPLMode.Option("patch"), + Pkg.REPLMode.Option("plus", "5"), + ], specs) + + @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 + temp_pkg_dir() do project_path; cd_tempdir() do tmpdir; with_temp_env() do; + # unregistered meta options + @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 PkgError 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 to " + @test qwords[3].isquoted + @test qwords[3].word == "\"test\"" + @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 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 # module 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 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..61d85d63da27f --- /dev/null +++ b/stdlib/Pkg/test/test_packages/x1/src/x1.jl @@ -0,0 +1,7 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +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..e4530c034da07 --- /dev/null +++ b/stdlib/Pkg/test/test_packages/x2/src/x2.jl @@ -0,0 +1,7 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +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..28b4ff3b9d16c --- /dev/null +++ b/stdlib/Pkg/test/test_packages/x3/src/x3.jl @@ -0,0 +1,7 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +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..9540e3095e5d5 --- /dev/null +++ b/stdlib/Pkg/test/test_packages/x3/test/runtests.jl @@ -0,0 +1,9 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +module X3Tests + +using x2 + +println("hello") + +end # module 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 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} 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