Skip to content

[release-1.9] 1.9.1 Backports #3480

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
May 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions docs/src/creating-packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,8 +354,8 @@ end
end # module
```

The name of the extension (here `PlottingContourExt`) is not very important but using something similar to the suggest here is likely a good
idea.
Extensions can have any arbitrary name (here `PlottingContourExt`), but using something similar to the format of
this example that makes the extended functionality and dependency of the extension clear is likely a good idea.

A user that depends only on `Plotting` will not pay the cost of the "extension" inside the `PlottingContourExt` module.
It is only when the `Contour` package actually gets loaded that the `PlottingContourExt` extension is loaded
Expand All @@ -366,8 +366,6 @@ If one considers `PlottingContourExt` as a completely separate package, it could
However, for extensions, it is ok to assume that the extension owns the methods in its parent package.
In fact, this form of type piracy is one of the most standard use cases for extensions.

An extension will only be loaded if the extension dependencies are loaded from the same environment or environments higher in the environment stack than the package itself.

!!! compat
Often you will put the extension dependencies into the `test` target so they are loaded when running e.g. `Pkg.test()`. On earlier Julia versions
this requires you to also put the package in the `[extras]` section. This is unfortunate but the project verifier on older Julia versions will
Expand Down
25 changes: 22 additions & 3 deletions src/API.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1137,7 +1137,7 @@ function precompile(ctx::Context, pkgs::Vector{PackageSpec}; internal_call::Bool
]
stale_cache = Dict{StaleCacheKey, Bool}()
exts = Dict{Base.PkgId, String}() # ext -> parent
# make a flat map of each dep and its deps
# make a flat map of each dep and its direct deps
depsmap = Dict{Base.PkgId, Vector{Base.PkgId}}()
pkg_specs = PackageSpec[]
for dep in ctx.env.manifest
Expand All @@ -1147,6 +1147,7 @@ function precompile(ctx::Context, pkgs::Vector{PackageSpec}; internal_call::Bool
depsmap[pkg] = filter!(!Base.in_sysimage, deps)
# add any extensions
weakdeps = last(dep).weakdeps
pkg_exts = Dict{Base.PkgId, Vector{Base.PkgId}}()
for (ext_name, extdep_names) in last(dep).exts
ext_deps = Base.PkgId[]
push!(ext_deps, pkg) # depends on parent package
Expand All @@ -1165,8 +1166,26 @@ function precompile(ctx::Context, pkgs::Vector{PackageSpec}; internal_call::Bool
ext_uuid = Base.uuid5(pkg.uuid, ext_name)
ext = Base.PkgId(ext_uuid, ext_name)
push!(pkg_specs, PackageSpec(uuid = ext_uuid, name = ext_name)) # create this here as the name cannot be looked up easily later via the uuid
depsmap[ext] = filter!(!Base.in_sysimage, ext_deps)
filter!(!Base.in_sysimage, ext_deps)
depsmap[ext] = ext_deps
exts[ext] = pkg.name
pkg_exts[ext] = ext_deps
end
if !isempty(pkg_exts)
# find any packages that depend on the extension(s)'s deps and replace those deps in their deps list with the extension(s),
# basically injecting the extension into the precompile order in the graph, to avoid race to precompile extensions
for (_pkg, deps) in depsmap # for each manifest dep
if !in(_pkg, keys(exts)) # if not an extension
all_ext_deps = Base.PkgId[]
for (ext, ext_deps) in pkg_exts # for each extension of this package
if any(in(ext_deps), deps) # if any of the outer package deps are extension deps
push!(deps, ext) # add the extension to deps
append!(all_ext_deps, ext_deps) # collect all extension deps for later filtering
end
end
filter!(!in(all_ext_deps), deps) # remove the extension deps once all extensions have been added because they could share deps
end
end
end
end

Expand Down Expand Up @@ -1261,7 +1280,7 @@ function precompile(ctx::Context, pkgs::Vector{PackageSpec}; internal_call::Bool
printloop_should_exit::Bool = !fancyprint # exit print loop immediately if not fancy printing
interrupted_or_done = Base.Event()

function color_string(cstr::String, col::Symbol)
function color_string(cstr::String, col::Union{Int64, Symbol})
enable_ansi = get(Base.text_colors, col, Base.text_colors[:default])
disable_ansi = get(Base.disable_text_style, col, Base.text_colors[:default])
return string(enable_ansi, cstr, disable_ansi)
Expand Down
16 changes: 15 additions & 1 deletion src/Operations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1659,6 +1659,20 @@ function gen_test_precompile_code(source_path::String; coverage, julia_args::Cmd
return gen_subprocess_cmd(code, source_path; coverage, julia_args)
end

@static if VERSION >= v"1.9.0" # has threadpools
function get_threads_spec()
if Threads.nthreads(:interactive) > 0
"$(Threads.nthreads(:default)),$(Threads.nthreads(:interactive))"
else
"$(Threads.nthreads(:default))"
end
end
else # no threadpools
function get_threads_spec()
"$(Threads.nthreads())"
end
end

function gen_subprocess_cmd(code::String, source_path::String; coverage, julia_args)
coverage_arg = if coverage isa Bool
coverage ? string("@", source_path) : "none"
Expand All @@ -1677,7 +1691,7 @@ function gen_subprocess_cmd(code::String, source_path::String; coverage, julia_a
--inline=$(Bool(Base.JLOptions().can_inline) ? "yes" : "no")
--startup-file=$(Base.JLOptions().startupfile == 1 ? "yes" : "no")
--track-allocation=$(("none", "user", "all")[Base.JLOptions().malloc_log + 1])
--threads=$(Threads.nthreads())
--threads=$(get_threads_spec())
$(julia_args)
--eval $(code)
```
Expand Down
2 changes: 1 addition & 1 deletion src/Pkg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ This includes:
* The `name` of the package.
* The package's unique `uuid`.
* A `version` (for example when adding a package). When upgrading, can also be an instance of
the enum [`UpgradeLevel`](@ref). If the version is given as a `String`` this means that unspecified versions
the enum [`UpgradeLevel`](@ref). If the version is given as a `String` this means that unspecified versions
are "free", for example `version="0.5"` allows any version `0.5.x` to be installed. If given as a `VersionNumber`,
the exact version is used, for example `version=v"0.5.3"`.
* A `url` and an optional git `rev`ision. `rev` can be a branch name or a git commit SHA1.
Expand Down
6 changes: 5 additions & 1 deletion src/REPLMode/REPLMode.jl
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,11 @@ function try_prompt_pkg_add(pkgs::Vector{Symbol})
push!(shown_envs, expanded_env)
end
menu = TerminalMenus.RadioMenu(option_list, keybindings=keybindings, pagesize=length(option_list))
default = min(2, length(option_list))
default = something(
# select the first non-default env by default, if possible
findfirst(!=(Base.active_project()), shown_envs),
1
)
print(ctx.io, "\e[1A\e[1G\e[0J") # go up one line, to the start, and clear it
printstyled(ctx.io, " └ "; color=:green)
choice = try
Expand Down