Skip to content

Commit

Permalink
Add query interface
Browse files Browse the repository at this point in the history
  • Loading branch information
00vareladavid committed Aug 23, 2019
1 parent 8631324 commit da3d38b
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 49 deletions.
1 change: 1 addition & 0 deletions docs/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Pkg.gc
Pkg.status
Pkg.precompile
Pkg.setprotocol!
Pkg.dependencies
```


Expand Down
31 changes: 20 additions & 11 deletions src/API.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,26 @@ preview_info() = printstyled("───── Preview mode ─────\n"; c

include("generate.jl")

dependencies() = dependencies(Context())
function dependencies(ctx::Context)::Dict{UUID, PackageInfo}
pkgs = PackageSpec[]
Operations.load_all_deps!(ctx, pkgs)
find_registered!(ctx.env, UUID[pkg.uuid for pkg in pkgs])
return Dict(pkg.uuid => Operations.package_info(ctx, pkg) for pkg in pkgs)
end

project() = project(Context())
function project(ctx::Context)
ctx.env.pkg !== nothing || pkgerror("Active environment is not a project.")
return ProjectInfo(
name = ctx.env.pkg.name,
uuid = ctx.env.pkg.uuid,
version = ctx.env.pkg.version,
dependencies = ctx.env.project.deps,
path = ctx.env.project_file
)
end

function check_package_name(x::AbstractString, mode=nothing)
if !(occursin(Pkg.REPLMode.name_re, x))
message = "$x is not a valid packagename."
Expand Down Expand Up @@ -251,17 +271,6 @@ function test(ctx::Context, pkgs::Vector{PackageSpec};
return
end

installed() = __installed(PKGMODE_PROJECT)
function __installed(mode::PackageMode=PKGMODE_MANIFEST)
diffs = Display.status(Context(), PackageSpec[], mode=mode, use_as_api=true)
version_status = Dict{String, Union{VersionNumber,Nothing}}()
diffs == nothing && return version_status
for entry in diffs
version_status[entry.name] = entry.new.ver
end
return version_status
end

"""
gc(ctx::Context=Context(); collect_delay::Period=Day(30), kwargs...)
Expand Down
24 changes: 23 additions & 1 deletion src/Operations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ is_dep(env::EnvCache, pkg::PackageSpec) =
function load_direct_deps!(ctx::Context, pkgs::Vector{PackageSpec}; version::Bool=true)
# load rest of deps normally
for (name::String, uuid::UUID) in ctx.env.project.deps
pkgs[uuid] === nothing || continue # dont duplicate packages
pkgs[uuid] === nothing || continue # do not duplicate packages
entry = manifest_info(ctx.env, uuid)
push!(pkgs, entry === nothing ?
PackageSpec(;uuid=uuid, name=name) :
Expand All @@ -66,6 +66,7 @@ end

function load_all_deps!(ctx::Context, pkgs::Vector{PackageSpec}; version::Bool=true)
for (uuid, entry) in ctx.env.manifest
pkgs[uuid] === nothing || continue # do not duplicate packages
push!(pkgs, PackageSpec(name=entry.name, uuid=uuid, path=entry.path,
version = version ? something(entry.version, VersionSpec()) : VersionSpec(),
repo=entry.repo, tree_hash=entry.tree_hash))
Expand Down Expand Up @@ -1323,4 +1324,25 @@ function test(ctx::Context, pkgs::Vector{PackageSpec};
end
end

function package_info(ctx::Context, pkg::PackageSpec)::PackageInfo
entry = manifest_info(ctx.env, pkg.uuid)
if entry === nothing
pkgerror("Can not query `$(pkg.name)` because it does not exist in the manifest.",
" Use `Pkg.resolve()` to populate the manifest.")
end
package_info(ctx, pkg, entry)
end

function package_info(ctx::Context, pkg::PackageSpec, entry::PackageEntry)::PackageInfo
info = PackageInfo(
name = pkg.name,
version = pkg.version != VersionSpec() ? pkg.version : nothing,
ispinned = pkg.pinned,
isdeveloped = pkg.path !== nothing,
source = project_rel_path(ctx, source_path(pkg)),
dependencies = collect(values(entry.deps)),
)
return info
end

end # module
38 changes: 35 additions & 3 deletions src/Pkg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,6 @@ redirecting to the `build.log` file.
"""
const build = API.build

# TODO: decide what to do with this
const installed = API.installed

"""
Pkg.pin(pkg::Union{String, Vector{String}})
Pkg.pin(pkgs::Union{PackageSpec, Vector{PackageSpec}})
Expand Down Expand Up @@ -273,6 +270,41 @@ const develop = API.develop
#TODO: Will probably be deprecated for something in PkgDev
const generate = API.generate

"""
Pkg.dependencies()::Dict{UUID, PackageInfo}
Query the dependecy graph.
The result is a `Dict` that maps a package UUID to a `PackageInfo` struct representing the dependency (a package).
PackageInfo fields:
| `field` | `Description` |
|:---------------|:-----------------------------------------------------------|
| `name` | The name of the package |
| `version` | The version of the package (this is `Nothing` for stdlibs) |
| `isdeveloped` | Whether a package is directly tracking a directory |
| `ispinned` | Whether a package is pinned |
| `source` | The directory containing the source code for that package |
| `dependencies` | The dependencies of that package as a vector of UUIDs |
"""
const dependencies = API.dependencies

"""
Pkg.project()::ProjectInfo
Request a `ProjectInfo` struct which contains information about the active project.
ProjectInfo fields:
| `field` | `Description` |
|:---------------|:--------------------------------------------------------------------------------------------|
| `name` | The project's name |
| `uuid` | The project's UUID |
| `version` | The project's version |
| `dependencies` | The project's direct dependencies as a `Dict` which maps dependency name to dependency UUID |
| `path` | The location of the project file which defines the active project |
"""
const project = API.project

"""
Pkg.instantiate(; verbose = false)
Expand Down
27 changes: 26 additions & 1 deletion src/Types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ using SHA

export UUID, pkgID, SHA1, VersionRange, VersionSpec, empty_versionspec,
Requires, Fixed, merge_requires!, satisfies, ResolverError,
PackageSpec, EnvCache, Context, GitRepo, Context!, get_deps,
PackageSpec, EnvCache, Context, PackageInfo, ProjectInfo, GitRepo, Context!, get_deps,
PkgError, pkgerror, has_name, has_uuid, is_stdlib, write_env, write_env_usage, parse_toml, find_registered!,
project_resolve!, project_deps_resolve!, manifest_resolve!, registry_resolve!, stdlib_resolve!, handle_repos_develop!, handle_repos_add!, ensure_resolved, instantiate_pkg_repo!,
manifest_info, registered_uuids, registered_paths, registered_uuid, registered_name,
Expand Down Expand Up @@ -1366,4 +1366,29 @@ function write_env(ctx::Context; display_diff=true)
write_manifest(env.manifest, env, old_env, ctx; display_diff=display_diff)
end

###
### PackageInfo
###

Base.@kwdef struct PackageInfo
name::String
version::Union{Nothing,VersionNumber}
ispinned::Bool
isdeveloped::Bool
source::String
dependencies::Vector{UUID}
end

###
### ProjectInfo
###

Base.@kwdef struct ProjectInfo
name::String
uuid::UUID
version::VersionNumber
dependencies::Dict{String,UUID}
path::String
end

end # module
48 changes: 30 additions & 18 deletions test/pkg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -151,21 +151,21 @@ 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.API.__installed()[TEST_PKG.name] == v"0.3"
@test Pkg.dependencies()[TEST_PKG.uuid].version == v"0.3"
Pkg.add(PackageSpec(TEST_PKG.name, v"0.3.1"))
@test Pkg.API.__installed()[TEST_PKG.name] == v"0.3.1"
@test Pkg.dependencies()[TEST_PKG.uuid].version == 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.API.__installed()[TEST_PKG.name] == v"0.3.2"
@test Pkg.dependencies()[TEST_PKG.uuid].version == v"0.3.2"
# Check that adding another packages doesn't upgrade other packages
Pkg.add("Test")
@test Pkg.API.__installed()[TEST_PKG.name] == v"0.3.2"
@test Pkg.dependencies()[TEST_PKG.uuid].version == v"0.3.2"
Pkg.update(; level = UPLEVEL_PATCH)
@test Pkg.API.__installed()[TEST_PKG.name] == v"0.3.3"
@test Pkg.dependencies()[TEST_PKG.uuid].version == v"0.3.3"
Pkg.update(; level = UPLEVEL_MINOR)
@test Pkg.API.__installed()[TEST_PKG.name].minor != 3
@test Pkg.dependencies()[TEST_PKG.uuid].version.minor != 3
Pkg.rm(TEST_PKG.name)
end

Expand All @@ -181,27 +181,27 @@ temp_pkg_dir() do project_path

@testset "pinning / freeing" begin
Pkg.add(TEST_PKG.name)
old_v = Pkg.API.__installed()[TEST_PKG.name]
old_v = Pkg.dependencies()[TEST_PKG.uuid].version
Pkg.pin(PackageSpec(TEST_PKG.name, v"0.2"))
@test Pkg.API.__installed()[TEST_PKG.name].minor == 2
@test Pkg.dependencies()[TEST_PKG.uuid].version.minor == 2
Pkg.update(TEST_PKG.name)
@test Pkg.API.__installed()[TEST_PKG.name].minor == 2
@test Pkg.dependencies()[TEST_PKG.uuid].version.minor == 2
Pkg.free(TEST_PKG.name)
Pkg.update()
@test Pkg.API.__installed()[TEST_PKG.name] == old_v
@test Pkg.dependencies()[TEST_PKG.uuid].version == old_v
Pkg.rm(TEST_PKG.name)
end

@testset "develop / freeing" begin
Pkg.add(TEST_PKG.name)
old_v = Pkg.API.__installed()[TEST_PKG.name]
old_v = Pkg.dependencies()[TEST_PKG.uuid].version
Pkg.rm(TEST_PKG.name)
mktempdir() do devdir
withenv("JULIA_PKG_DEVDIR" => devdir) do
@test_throws PkgError Pkg.develop(Pkg.PackageSpec(url="bleh", rev="blurg"))
Pkg.develop(TEST_PKG.name)
@test isinstalled(TEST_PKG)
@test Pkg.API.__installed()[TEST_PKG.name] > old_v
@test Pkg.dependencies()[TEST_PKG.uuid].version > old_v
test_pkg_main_file = joinpath(devdir, TEST_PKG.name, "src", TEST_PKG.name * ".jl")
@test isfile(test_pkg_main_file)
# Pkg #152
Expand All @@ -227,7 +227,7 @@ temp_pkg_dir() do project_path
@test isfile(joinpath(devdir, TEST_PKG.name, "deps", "deps.jl"))
Pkg.test(TEST_PKG.name)
Pkg.free(TEST_PKG.name)
@test Pkg.API.__installed()[TEST_PKG.name] == old_v
@test Pkg.dependencies()[TEST_PKG.uuid].version == old_v
end
end
end
Expand All @@ -239,7 +239,7 @@ temp_pkg_dir() do project_path
@testset "stdlibs as direct dependency" begin
uuid_pkg = (name = "CRC32c", uuid = UUID("8bf52ea8-c179-5cab-976a-9e18b702a9bc"))
Pkg.add("CRC32c")
@test haskey(Pkg.API.__installed(), uuid_pkg.name)
@test haskey(Pkg.dependencies(), TEST_PKG.uuid)
Pkg.update()
# Disable until fixed in Base
# Pkg.test("CRC32c")
Expand Down Expand Up @@ -336,7 +336,7 @@ 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.dependencies(), TEST_PKG.uuid)
@eval import $(Symbol(TEST_PKG.name))
@test_throws SystemError open(pathof(eval(Symbol(TEST_PKG.name))), "w") do io end # check read-only
Pkg.rm(TEST_PKG.name)
Expand All @@ -348,7 +348,7 @@ temp_pkg_dir() do project_path
cd(joinpath(dir, "UnregisteredWithProject")) do
with_current_env() do
Pkg.update()
@test haskey(Pkg.API.__installed(), "Example")
@test haskey(Pkg.dependencies(), TEST_PKG.uuid)
end
end
end
Expand All @@ -358,12 +358,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.API.__installed(), TEST_PKG.name)
@test haskey(Pkg.dependencies(), TEST_PKG.uuid)
Pkg.rm(TEST_PKG.name)
end
@testset "tarball downloads" begin
Pkg.add("JSON"; use_only_tarballs_for_downloads=true)
@test haskey(Pkg.API.__installed(), "JSON")
@test "JSON" in [pkg.name for (uuid, pkg) in Pkg.dependencies()]
Pkg.rm("JSON")
end
end
Expand Down Expand Up @@ -790,6 +790,18 @@ end
end end
end

@testset "query interface basic tests" begin
temp_pkg_dir() do project_path; with_temp_env() do
Pkg.develop("Example")
Pkg.add("Unicode")
Pkg.add("Markdown")
@test length(Pkg.project().dependencies) == 3
xs = Dict(uuid => pkg for (uuid, pkg) in Pkg.dependencies() if pkg.isdeveloped)
@test length(xs) == 1
@test xs[TEST_PKG.uuid].ispinned == false
end end
end

include("repl.jl")
include("api.jl")
include("registry.jl")
Expand Down
Loading

0 comments on commit da3d38b

Please sign in to comment.