Skip to content
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

backport LOADPATH fix #24

Merged
merged 4 commits into from
Aug 4, 2021
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
8 changes: 6 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
name = "TestEnv"
uuid = "1e6cf692-eddd-4d53-88a5-2d735e33781b"
version = "1.4.0"
version = "1.4.1"

[deps]
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"

[compat]
ChainRulesCore = "=1.0.2"
MCMCDiagnosticTools = "=0.1.0"
YAXArrays = "0.1.3"
julia = "~1.4, ~1.5, ~1.6"

[extras]
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
MCMCDiagnosticTools = "be115224-59cd-429b-ad48-344e309966f0"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
YAXArrays = "c21b50f5-aa40-41ea-b809-c0f5e47bfa5c"

[targets]
test = ["ChainRulesCore", "Test"]
test = ["ChainRulesCore", "MCMCDiagnosticTools", "Test", "YAXArrays"]
44 changes: 7 additions & 37 deletions src/TestEnv.jl
Original file line number Diff line number Diff line change
@@ -1,45 +1,15 @@
module TestEnv
using Pkg
using Pkg: PackageSpec
using Pkg.Types: Context, ensure_resolved, is_project_uuid, write_env
using Pkg.Types: Context, ensure_resolved, is_project_uuid, write_env, is_stdlib
using Pkg.Types: Types, projectfile_path, manifestfile_path
using Pkg.Operations: manifest_info, manifest_resolve!, project_deps_resolve!
using Pkg.Operations: project_rel_path, project_resolve!
using Pkg.Operations: sandbox, source_path, sandbox_preserve, abspath!
using Pkg.Operations: gen_target_project, update_package_test!

using Pkg.Types: Types, projectfile_path, manifestfile_path

# Version specific imports
@static if VERSION >= v"1.4.0"
using Pkg.Operations: gen_target_project
else
using Pkg.Operations: with_dependencies_loadable_at_toplevel
end
@static if isdefined(Pkg.Operations, :update_package_test!)
using Pkg.Operations: update_package_test!
else
function update_package_test!(pkg, entry)
is_stdlib(pkg.uuid) && return
pkg.version = entry.version
pkg.tree_hash = entry.tree_hash
pkg.repo = entry.repo
pkg.path = entry.path
pkg.pinned = entry.pinned
end
end

@static if VERSION >= v"1.2.0"
using Pkg.Types: is_stdlib
using Pkg.Operations: sandbox, source_path, sandbox_preserve, abspath!
else
using Pkg.Operations: find_installed
using Pkg.Types: SHA1
end


include("exceptions.jl")

include("activate.jl")
include("make_test_env.jl")
include("sandbox.jl")
include("test_dir.jl")
include("common.jl")
include("activate_do.jl")
include("activate_set.jl")

end
69 changes: 0 additions & 69 deletions src/activate.jl

This file was deleted.

19 changes: 19 additions & 0 deletions src/activate_do.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""
TestEnv.activate(f, [pkg])

Activate the test enviroment of `pkg` (defaults to current enviroment), and run `f()`,
then deactivate the enviroment.
This is not useful for many people: Julia is not really designed to have the enviroment
being changed while you are executing code.
However, this *is* useful for anyone doing something like making a alternative to
`Pkg.test()`.
Indeed this is basically extracted from what `Pkg.test()` does.
"""
function activate(f, pkg::AbstractString=current_pkg_name())
ctx, pkgspec = ctx_and_pkgspec(pkg)
test_project_override = maybe_gen_project_override!(ctx, pkgspec)
return sandbox(ctx, pkgspec, pkgspec.path, joinpath(pkgspec.path, "test"), test_project_override) do
flush(stdout)
f()
end
end
78 changes: 78 additions & 0 deletions src/activate_set.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
"""
TestEnv.activate([pkg])

Activate the test enviroment of `pkg` (defaults to current enviroment).
"""
function activate(pkg::AbstractString=current_pkg_name())
ctx, pkgspec = ctx_and_pkgspec(pkg)
# This needs to be first as `gen_target_project` fixes `pkgspec.path` if it is nothing
sandbox_project_override = maybe_gen_project_override!(ctx, pkgspec)

sandbox_path = joinpath(pkgspec.path, "test")
sandbox_project = projectfile_path(sandbox_path)

tmp = mktempdir()
tmp_project = projectfile_path(tmp)
tmp_manifest = manifestfile_path(tmp)

# Copy env info over to temp env
if sandbox_project_override !== nothing
Types.write_project(sandbox_project_override, tmp_project)
elseif isfile(sandbox_project)
cp(sandbox_project, tmp_project)
chmod(tmp_project, 0o600)
end
# create merged manifest
# - copy over active subgraph
# - abspath! to maintain location of all deved nodes
working_manifest = abspath!(ctx, sandbox_preserve(ctx, pkgspec, tmp_project))

# - copy over fixed subgraphs from test subgraph
# really only need to copy over "special" nodes
sandbox_env = Types.EnvCache(projectfile_path(sandbox_path))
sandbox_manifest = abspath!(sandbox_path, sandbox_env.manifest)

for (name, uuid) in sandbox_env.project.deps
entry = get(sandbox_manifest, uuid, nothing)
if entry !== nothing && isfixed(entry)
subgraph = prune_manifest(sandbox_manifest, [uuid])
for (uuid, entry) in subgraph
if haskey(working_manifest, uuid)
pkgerror("can not merge projects")
end
working_manifest[uuid] = entry
end
end
end

Types.write_manifest(working_manifest, tmp_manifest)

Base.ACTIVE_PROJECT[] = tmp_project

temp_ctx = Context()
temp_ctx.env.project.deps[pkgspec.name] = pkgspec.uuid

try
Pkg.resolve(temp_ctx; io=devnull)
@debug "Using _parent_ dep graph"
catch err# TODO
@debug err
@warn "Could not use exact versions of packages in manifest, re-resolving"
temp_ctx.env.manifest.deps = Dict(
uuid => entry for
(uuid, entry) in temp_ctx.env.manifest.deps if isfixed(entry)
)
Pkg.resolve(temp_ctx; io=devnull)
@debug "Using _clean_ dep graph"
end

# Absolutify stdlibs paths
for (uuid, entry) in temp_ctx.env.manifest
if is_stdlib(uuid)
entry.path = Types.stdlib_path(entry.name)
end
end
write_env(temp_ctx.env; update_undo=false)

return Base.active_project()
end
81 changes: 81 additions & 0 deletions src/common.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
struct TestEnvError <: Exception
msg::AbstractString
end

function Base.showerror(io::IO, ex::TestEnvError, bt; backtrace=true)
printstyled(io, ex.msg, color=Base.error_color())
end


current_pkg_name() = Context().env.pkg.name

"""
ctx, pkgspec = ctx_and_pkgspec(pkg::AbstractString)

For a given package name `pkg`, instantiate a `Context` for it, and return that `Context`,
and it's `PackageSpec`.
"""
function ctx_and_pkgspec(pkg::AbstractString)
pkgspec = deepcopy(PackageSpec(pkg))
ctx = Context()
isinstalled!(ctx, pkgspec) || throw(TestEnvError("$pkg not installed 👻"))
Pkg.instantiate(ctx)
return ctx, pkgspec
end


"""
isinstalled!(ctx::Context, pkgspec::Pkg.Types.PackageSpec)

Checks if the package is installed by using `ensure_resolved` from `Pkg/src/Types.jl`.
This function fails if the package is not installed, but here we wrap it in a
try-catch as we may want to test another package after the one that isn't installed.

For Julia versions V1.4 and later, the first arguments of the Pkg functions used
is of type `Pkg.Types.Context`. For earlier versions, they are of type
`Pkg.Types.EnvCache`.
"""
function isinstalled!(ctx::Context, pkgspec::Pkg.Types.PackageSpec)
project_resolve!(ctx, [pkgspec])
project_deps_resolve!(ctx, [pkgspec])
manifest_resolve!(ctx, [pkgspec])

try
ensure_resolved(ctx, [pkgspec])
catch err
err isa MethodError && rethrow()
return false
end
return true
end

function test_dir_has_project_file(ctx, pkgspec)
return isfile(joinpath(get_test_dir(ctx, pkgspec), "Project.toml"))
end

"""
get_test_dir(ctx::Context, pkgspec::Pkg.Types.PackageSpec)

Gets the testfile path of the package. Code for each Julia version mirrors that found
in `Pkg/src/Operations.jl`.
"""
function get_test_dir(ctx::Context, pkgspec::Pkg.Types.PackageSpec)
if is_project_uuid(ctx, pkgspec.uuid)
pkgspec.path = dirname(ctx.env.project_file)
pkgspec.version = ctx.env.pkg.version
else
update_package_test!(pkgspec, manifest_info(ctx, pkgspec.uuid))
pkgspec.path = project_rel_path(ctx, source_path(ctx, pkgspec))
end
pkgfilepath = source_path(ctx, pkgspec)
return joinpath(pkgfilepath, "test")
end


function maybe_gen_project_override!(ctx, pkgspec)
if !test_dir_has_project_file(ctx, pkgspec)
sandbox_project_override = gen_target_project(ctx, pkgspec, pkgspec.path, "test")
else
nothing
end
end
7 changes: 0 additions & 7 deletions src/exceptions.jl

This file was deleted.

Loading