Check if submod.vals has key before retrieving
1 |
@static if VERSION < v"1.1" |
|
2 |
const PackageEntry = Vector{Dict{String,Any}} |
|
3 |
else
|
|
4 |
using Pkg.Types: PackageEntry |
|
5 |
end
|
|
6 |
|
|
7 |
"""
|
|
8 |
manifest(c::Pkg.Types.Context)
|
|
9 |
Retrieves the manifest of a Context.
|
|
10 |
"""
|
|
11 | 25 |
manifest(c::Pkg.Types.Context) = c.env.manifest |
12 |
|
|
13 |
"""
|
|
14 |
project(c::Pkg.Types.Context)
|
|
15 |
Retrieves the project of a Context.
|
|
16 |
"""
|
|
17 | 30 |
project(c::Pkg.Types.Context) = c.env.project |
18 |
|
|
19 |
"""
|
|
20 |
isinproject(context, package::Union{String,UUID})
|
|
21 |
Checks whether a package is in the dependencies of a given context, e.g. is directly loadable.
|
|
22 |
"""
|
|
23 |
function isinproject end |
|
24 |
|
|
25 |
"""
|
|
26 |
isinmanifest(context, package::Union{String,UUID})
|
|
27 |
Checks whether a package is in the manifest of a given context, e.g. is either directly loadable or is a dependency of an loadable package.
|
|
28 |
"""
|
|
29 |
function isinmanifest end |
|
30 |
|
|
31 |
@static if VERSION < v"1.1" |
|
32 | 5 |
isinmanifest(context::Pkg.Types.Context, module_name::String) = module_name in keys(manifest(context)) |
33 | 5 |
isinmanifest(context::Pkg.Types.Context, uuid::UUID) = any(get(p[1], "uuid", "") == string(uuid) for (u, p) in manifest(context)) |
34 | 5 |
isinmanifest(manifest::Dict{String,Any}, uuid::AbstractString) = any(get(p[1], "uuid", "") == uuid for (u, p) in manifest) |
35 | 5 |
isinmanifest(manifest::Dict{String,Any}, uuid::UUID) = isinmanifest(manifest, string(uuid)) |
36 |
|
|
37 |
isinproject(context::Pkg.Types.Context, package_name::String) = haskey(deps(project(context)), package_name) |
|
38 |
isinproject(context::Pkg.Types.Context, package_uuid::UUID) = any(u == package_uuid for (n, u) in deps(project(context))) |
|
39 |
|
|
40 |
function packageuuid(c::Pkg.Types.Context, name::String) |
|
41 | 5 |
for pkg in manifest(c) |
42 | 5 |
if first(pkg) == name |
43 | 5 |
return UUID(last(pkg)[1]["uuid"]) |
44 |
end
|
|
45 |
end
|
|
46 |
end
|
|
47 | 5 |
packageuuid(pkg::Pair{Any,Any}) = last(pkg) isa String ? UUID(last(pkg)) : UUID(first(last(pkg))["uuid"]) |
48 |
packageuuid(pkg::Pair{String,Any}) = last(pkg) isa String ? UUID(last(pkg)) : UUID(first(last(pkg))["uuid"]) |
|
49 |
|
|
50 |
function packagename(c::Pkg.Types.Context, uuid) |
|
51 | 5 |
for (n, p) in c.env.manifest |
52 | 5 |
if get(first(p), "uuid", "") == string(uuid) |
53 | 5 |
return n |
54 |
end
|
|
55 |
end
|
|
56 |
return nothing |
|
57 |
end
|
|
58 |
function packagename(manifest::Dict{String,Any}, uuid::String) |
|
59 | 5 |
for (n, p) in manifest |
60 | 5 |
if get(first(p), "uuid", "") == string(uuid) |
61 | 5 |
return n |
62 |
end
|
|
63 |
end
|
|
64 |
return nothing |
|
65 |
end
|
|
66 | 5 |
packagename(manifest::Dict{String,Any}, uuid::UUID) = packagename(manifest, string(uuid)) |
67 |
|
|
68 |
function deps(uuid::UUID, c::Pkg.Types.Context) |
|
69 |
if any(p[1]["uuid"] == string(uuid) for (n, p) in manifest(c)) |
|
70 |
return manifest(c)[string(uuid)][1].deps |
|
71 |
else
|
|
72 |
return Dict{Any,Any}() |
|
73 |
end
|
|
74 |
end
|
|
75 | 5 |
deps(d::Dict{String,Any}) = get(d, "deps", Dict{String,Any}()) |
76 | 5 |
deps(pe::PackageEntry) = get(pe[1], "deps", Dict{String,Any}()) |
77 | 5 |
path(pe::PackageEntry) = get(pe[1], "path", nothing) |
78 | 5 |
version(pe::PackageEntry) = get(pe[1], "version", nothing) |
79 |
|
|
80 |
function frommanifest(c::Pkg.Types.Context, uuid) |
|
81 | 5 |
for (n, p) in c.env.manifest |
82 | 5 |
if get(first(p), "uuid", "") == string(uuid) |
83 | 5 |
return p |
84 |
end
|
|
85 |
end
|
|
86 |
return nothing |
|
87 |
end
|
|
88 |
function frommanifest(manifest, uuid) |
|
89 | 5 |
for (n, p) in manifest |
90 | 5 |
if get(first(p), "uuid", "") == string(uuid) |
91 | 5 |
return p |
92 |
end
|
|
93 |
end
|
|
94 |
return nothing |
|
95 |
end
|
|
96 |
function get_filename_from_name(manifest, uuid) |
|
97 | 5 |
temp_var = [p[2][1] for p in manifest if get(p[2][1], "uuid", "") == string(uuid)] |
98 | 5 |
isempty(temp_var) && return nothing |
99 |
|
|
100 | 5 |
pkg_info = first(temp_var) |
101 |
|
|
102 | 5 |
name_for_cash_file = if get(pkg_info, "git-tree-sha1", nothing) !== nothing |
103 | 5 |
"-normal-" * string(pkg_info["git-tree-sha1"]) |
104 | 5 |
elseif get(pkg_info, "path", nothing) !== nothing |
105 |
# We have a deved package, we use the hash of the folder name
|
|
106 | 5 |
"-deved-" * string(bytes2hex(sha256(pkg_info["path"]))) |
107 |
else
|
|
108 |
# We have a stdlib, we use the uuid
|
|
109 | 5 |
"-stdlib-" * string(uuid) |
110 |
end
|
|
111 |
|
|
112 | 5 |
return "Julia-$VERSION-$(Sys.ARCH)-$name_for_cash_file.jstore" |
113 |
end
|
|
114 |
is_package_deved(manifest, uuid) = get(first([p[2][1] for p in manifest if get(p[2][1], "uuid", "") == string(uuid)]), "path", "") != "" |
|
115 |
else
|
|
116 | 25 |
isinmanifest(context::Pkg.Types.Context, module_name::String) = any(p.name == module_name for (u, p) in manifest(context)) |
117 | 25 |
isinmanifest(context::Pkg.Types.Context, uuid::UUID) = haskey(manifest(context), uuid) |
118 | 25 |
isinmanifest(manifest::Dict{UUID,PackageEntry}, uuid::UUID) = haskey(manifest, uuid) |
119 |
|
|
120 |
isinproject(context::Pkg.Types.Context, package_name::String) = haskey(deps(project(context)), package_name) |
|
121 |
isinproject(context::Pkg.Types.Context, package_uuid::UUID) = any(u == package_uuid for (n, u) in deps(project(context))) |
|
122 |
|
|
123 |
function packageuuid(c::Pkg.Types.Context, name::String) |
|
124 | 25 |
for pkg in manifest(c) |
125 | 25 |
if last(pkg).name == name |
126 | 25 |
return first(pkg) |
127 |
end
|
|
128 |
end
|
|
129 |
end
|
|
130 | 5 |
packageuuid(pkg::Pair{String,UUID}) = last(pkg) |
131 |
packageuuid(pkg::Pair{UUID,PackageEntry}) = first(pkg) |
|
132 | 25 |
packagename(c::Pkg.Types.Context, uuid::UUID) = manifest(c)[uuid].name |
133 | 25 |
packagename(manifest::Dict{UUID,PackageEntry}, uuid::UUID) = manifest[uuid].name |
134 |
|
|
135 |
function deps(uuid::UUID, c::Pkg.Types.Context) |
|
136 |
if haskey(manifest(c), uuid) |
|
137 |
return deps(manifest(c)[uuid]) |
|
138 |
else
|
|
139 |
return Dict{String,Base.UUID}() |
|
140 |
end
|
|
141 |
end
|
|
142 | 25 |
deps(pe::PackageEntry) = pe.deps |
143 | 25 |
deps(proj::Pkg.Types.Project) = proj.deps |
144 |
deps(pkg::Pair{String,UUID}, c::Pkg.Types.Context) = deps(packageuuid(pkg), c) |
|
145 | 25 |
path(pe::PackageEntry) = pe.path |
146 | 25 |
version(pe::PackageEntry) = pe.version |
147 | 25 |
frommanifest(c::Pkg.Types.Context, uuid) = manifest(c)[uuid] |
148 | 25 |
frommanifest(manifest::Dict{UUID,PackageEntry}, uuid) = manifest[uuid] |
149 |
|
|
150 |
function get_filename_from_name(manifest, uuid) |
|
151 | 25 |
haskey(manifest, uuid) || return nothing |
152 |
|
|
153 | 25 |
pkg_info = manifest[uuid] |
154 |
|
|
155 | 25 |
tree_hash = VERSION >= v"1.3" ? pkg_info.tree_hash : get(pkg_info.other, "git-tree-sha1", nothing) |
156 |
|
|
157 | 25 |
name_for_cash_file = if tree_hash !== nothing |
158 |
# We have a normal package, we use the tree hash
|
|
159 | 25 |
"-normal-" * string(tree_hash) |
160 | 25 |
elseif pkg_info.path !== nothing |
161 |
# We have a deved package, we use the hash of the folder name
|
|
162 | 25 |
"-deved-" * string(bytes2hex(sha256(pkg_info.path))) |
163 |
else
|
|
164 |
# We have a stdlib, we use the uuid
|
|
165 | 25 |
"-stdlib-" * string(uuid) |
166 |
end
|
|
167 |
|
|
168 | 25 |
return "Julia-$VERSION-$(Sys.ARCH)-$name_for_cash_file.jstore" |
169 |
end
|
|
170 |
|
|
171 |
is_package_deved(manifest, uuid) = manifest[uuid].path !== nothing |
|
172 |
end
|
|
173 |
|
|
174 |
function sha2_256_dir(path, sha=sha = zeros(UInt8, 32)) |
|
175 |
(uperm(path) & 0x04) != 0x04 && return |
|
176 |
startswith(path, ".") && return |
|
177 |
if isfile(path) && endswith(path, ".jl") |
|
178 |
s1 = open(path) do f |
|
179 |
sha2_256(f) |
|
180 |
end
|
|
181 |
sha .+= s1 |
|
182 |
elseif isdir(path) |
|
183 |
for f in readdir(path) |
|
184 |
sha = sha2_256_dir(joinpath(path, f), sha) |
|
185 |
end
|
|
186 |
end
|
|
187 |
return sha |
|
188 |
end
|
|
189 |
|
|
190 |
function sha_pkg(pe::PackageEntry) |
|
191 | 30 |
path(pe) isa String && isdir(path(pe)) && isdir(joinpath(path(pe), "src")) ? sha2_256_dir(joinpath(path(pe), "src")) : nothing |
192 |
end
|
|
193 |
|
|
194 |
function _doc(@nospecialize(object)) |
|
195 | 30 |
try
|
196 | 30 |
binding = Base.Docs.aliasof(object, typeof(object)) |
197 | 30 |
!(binding isa Base.Docs.Binding) && return "" |
198 | 5 |
sig = Union{} |
199 | 30 |
if Base.Docs.defined(binding) |
200 | 30 |
result = Base.Docs.getdoc(Base.Docs.resolve(binding), sig) |
201 | 5 |
result === nothing || return result |
202 |
end
|
|
203 | 25 |
results, groups = Base.Docs.DocStr[], Base.Docs.MultiDoc[] |
204 |
# Lookup `binding` and `sig` for matches in all modules of the docsystem.
|
|
205 | 30 |
for mod in Base.Docs.modules |
206 | 30 |
dict = Base.Docs.meta(mod)::IdDict{Any,Any} |
207 | 30 |
if haskey(dict, binding) |
208 | 30 |
multidoc = dict[binding] |
209 | 30 |
push!(groups, multidoc) |
210 | 30 |
for msig in multidoc.order |
211 | 30 |
sig <: msig && push!(results, multidoc.docs[msig]) |
212 |
end
|
|
213 |
end
|
|
214 |
end
|
|
215 | 30 |
if isempty(groups) |
216 | 30 |
alias = Base.Docs.aliasof(binding) |
217 | 30 |
alias == binding ? "" : _doc(alias, sig) |
218 | 30 |
elseif isempty(results) |
219 |
for group in groups, each in group.order |
|
220 |
push!(results, group.docs[each]) |
|
221 |
end
|
|
222 |
end
|
|
223 | 30 |
md = try |
224 | 30 |
Base.Docs.catdoc(map(Base.Docs.parsedoc, results)...) |
225 |
catch err |
|
226 | 25 |
nothing
|
227 |
end
|
|
228 | 30 |
return md === nothing ? "" : string(md) |
229 |
catch e |
|
230 |
return "" |
|
231 |
end
|
|
232 |
end
|
|
233 |
|
|
234 |
_lookup(vr::FakeUnion, depot::EnvStore, cont=false) = nothing |
|
235 |
_lookup(vr::FakeTypeName, depot::EnvStore, cont=false) = _lookup(vr.name, depot, cont) |
|
236 |
_lookup(vr::FakeUnionAll, depot::EnvStore, cont=false) = _lookup(vr.body, depot, cont) |
|
237 |
function _lookup(vr::VarRef, depot::EnvStore, cont=false) |
|
238 | 30 |
if vr.parent === nothing |
239 | 30 |
if haskey(depot, vr.name) |
240 | 25 |
val = depot[vr.name] |
241 | 30 |
if cont && val isa VarRef |
242 |
return _lookup(val, depot, cont) |
|
243 |
else
|
|
244 | 30 |
return val |
245 |
end
|
|
246 |
else
|
|
247 | 30 |
return nothing |
248 |
end
|
|
249 |
else
|
|
250 | 30 |
par = _lookup(vr.parent, depot, cont) |
251 | 30 |
if par !== nothing && par isa ModuleStore && haskey(par, vr.name) |
252 | 30 |
val = par[vr.name] |
253 | 30 |
if cont && val isa VarRef |
254 |
return _lookup(val, depot, cont) |
|
255 |
else
|
|
256 | 30 |
return val |
257 |
end
|
|
258 |
else
|
|
259 | 30 |
return nothing |
260 |
end
|
|
261 |
end
|
|
262 |
end
|
|
263 |
|
|
264 |
maybe_lookup(x, env) = x isa VarRef ? _lookup(x, env, true) : x |
|
265 |
|
|
266 |
"""
|
|
267 |
maybe_getfield(k::Symbol , m::ModuleStore, server)
|
|
268 |
|
|
269 |
Try to get `k` from `m`. This includes: unexported variables, and variables
|
|
270 |
exported by modules used within `m`.
|
|
271 |
"""
|
|
272 |
function maybe_getfield(k::Symbol, m::ModuleStore, envstore) |
|
273 |
if haskey(m.vals, k) |
|
274 |
return m.vals[k] |
|
275 |
else
|
|
276 |
for v in m.used_modules |
|
277 |
!haskey(m.vals, v) && continue |
|
278 |
submod = m.vals[v] |
|
279 |
if submod isa ModuleStore && k in submod.exportednames && haskey(submod.vals, k) |
|
280 |
return submod.vals[k] |
|
281 |
elseif submod isa VarRef |
|
282 |
submod = _lookup(submod, envstore, true) |
|
283 |
if submod isa ModuleStore && k in submod.exportednames && haskey(submod.vals, k) |
|
284 |
return submod.vals[k] |
|
285 |
end
|
|
286 |
end
|
|
287 |
end
|
|
288 |
end
|
|
289 |
end
|
|
290 |
|
|
291 |
function issubmodof(m::Module, M::Module) |
|
292 |
if m == M |
|
293 |
return true |
|
294 |
elseif parentmodule(m) === m |
|
295 |
return false |
|
296 |
elseif parentmodule(m) == M |
|
297 |
return true |
|
298 |
else
|
|
299 |
return issubmodof(parentmodule(m), M) |
|
300 |
end
|
|
301 |
end
|
|
302 |
|
|
303 |
function Base.print(io::IO, f::FunctionStore) |
|
304 |
println(io, f.name, " is a Function.") |
|
305 |
nm = length(f.methods) |
|
306 |
println(io, "# $nm method", nm == 1 ? "" : "s", " for function ", f.name) |
|
307 |
for i = 1:nm |
|
308 |
print(io, "[$i] ") |
|
309 |
println(io, f.methods[i]) |
|
310 |
end
|
|
311 |
end
|
|
312 |
|
|
313 |
const JULIA_DIR = normpath(joinpath(Sys.BINDIR, Base.DATAROOTDIR, "julia")) |
|
314 |
|
|
315 |
function Base.print(io::IO, m::MethodStore) |
|
316 |
print(io, m.name, "(") |
|
317 |
for i = 1:length(m.sig) |
|
318 |
if m.sig[i][1] != Symbol("#unused#") |
|
319 |
print(io, m.sig[i][1]) |
|
320 |
end
|
|
321 |
print(io, "::", m.sig[i][2]) |
|
322 |
i != length(m.sig) && print(io, ", ") |
|
323 |
end
|
|
324 |
print(io, ")") |
|
325 |
path = replace(m.file, JULIA_DIR => "") |
|
326 |
print(io, " in ", m.mod, " at ", path, ':', m.line) |
|
327 |
end
|
|
328 |
|
|
329 |
function Base.print(io::IO, t::DataTypeStore) |
|
330 |
print(io, t.name, " <: ", t.super) |
|
331 |
for i = 1:length(t.fieldnames) |
|
332 |
print(io, "\n ", t.fieldnames[i], "::", t.types[i]) |
|
333 |
end
|
|
334 |
end
|
|
335 |
|
|
336 |
Base.print(io::IO, m::ModuleStore) = print(io, m.name) |
|
337 |
Base.print(io::IO, x::GenericStore) = print(io, x.name, "::", x.typ) |
|
338 |
|
|
339 |
extends_methods(f) = false |
|
340 |
extends_methods(f::FunctionStore) = f.name != f.extends |
|
341 |
get_top_module(vr::VarRef) = vr.parent === nothing ? vr.name : get_top_module(vr.parent) |
|
342 |
|
|
343 |
# Sorting is the main performance of calling `names`
|
|
344 | 30 |
unsorted_names(m::Module; all::Bool=false, imported::Bool=false) = |
345 |
ccall(:jl_module_names, Array{Symbol,1}, (Any, Cint, Cint), m, all, imported) |
|
346 |
|
|
347 |
## recursive_copy
|
|
348 |
#
|
|
349 |
# `deepcopy` is reliable but incredibly slow. Its slowness comes from two factors:
|
|
350 |
# - generically iterating over, e.g., `fieldnames(typeof(x))` rather than having a method
|
|
351 |
# optimized for each struct type
|
|
352 |
# - its care to protect against circular depenency graphs
|
|
353 |
# When you don't need to worry about cycles, you can do much better by defining your own function.
|
|
354 |
|
|
355 | 30 |
recursive_copy(::Nothing) = nothing |
356 |
|
|
357 | 30 |
recursive_copy(s::Symbol) = s |
358 |
|
|
359 |
recursive_copy(str::String) = str |
|
360 |
|
|
361 | 30 |
recursive_copy(x::Number) = x |
362 |
|
|
363 | 30 |
recursive_copy(p::Pair) = typeof(p)(recursive_copy(p.first), recursive_copy(p.second)) |
364 |
|
|
365 | 30 |
recursive_copy(A::Array) = eltype(A)[recursive_copy(a) for a in A] |
366 |
|
|
367 | 30 |
recursive_copy(d::Dict) = typeof(d)(recursive_copy(p) for p in d) |
368 |
|
|
369 |
|
|
370 | 30 |
recursive_copy(ref::VarRef) = VarRef(recursive_copy(ref.parent), ref.name) |
371 |
|
|
372 | 30 |
recursive_copy(tn::FakeTypeName) = FakeTypeName(recursive_copy(tn.name), recursive_copy(tn.parameters)) |
373 |
|
|
374 | 30 |
recursive_copy(tb::FakeTypeofBottom) = tb |
375 |
|
|
376 | 30 |
recursive_copy(u::FakeUnion) = FakeUnion(recursive_copy(u.a), recursive_copy(u.b)) |
377 |
|
|
378 | 30 |
recursive_copy(tv::FakeTypeVar) = FakeTypeVar(tv.name, recursive_copy(tv.lb), recursive_copy(tv.ub)) |
379 |
|
|
380 | 30 |
recursive_copy(ua::FakeUnionAll) = FakeUnionAll(recursive_copy(ua.var), recursive_copy(ua.body)) |
381 |
|
|
382 |
|
|
383 | 30 |
recursive_copy(m::ModuleStore) = ModuleStore(recursive_copy(m.name), recursive_copy(m.vals), m.doc, |
384 |
m.exported, copy(m.exportednames), copy(m.used_modules)) |
|
385 |
|
|
386 |
recursive_copy(p::Package) = Package(p.name, |
|
387 |
recursive_copy(p.val), |
|
388 |
recursive_copy(p.ver), |
|
389 |
p.uuid, |
|
390 |
recursive_copy(p.sha)) |
|
391 |
|
|
392 | 30 |
recursive_copy(ms::MethodStore) = MethodStore(ms.name, |
393 |
ms.mod, |
|
394 |
ms.file, |
|
395 |
ms.line, |
|
396 |
recursive_copy(ms.sig), |
|
397 |
copy(ms.kws), |
|
398 |
recursive_copy(ms.rt)) |
|
399 |
|
|
400 | 30 |
recursive_copy(dts::DataTypeStore) = DataTypeStore(recursive_copy(dts.name), |
401 |
recursive_copy(dts.super), |
|
402 |
recursive_copy(dts.parameters), |
|
403 |
recursive_copy(dts.types), |
|
404 |
recursive_copy(dts.fieldnames), |
|
405 |
recursive_copy(dts.methods), |
|
406 |
dts.doc, |
|
407 |
dts.exported) |
|
408 |
|
|
409 | 30 |
recursive_copy(fs::FunctionStore) = FunctionStore(recursive_copy(fs.name), |
410 |
recursive_copy(fs.methods), |
|
411 |
fs.doc, |
|
412 |
recursive_copy(fs.extends), |
|
413 |
fs.exported) |
|
414 |
|
|
415 | 30 |
recursive_copy(gs::GenericStore) = GenericStore(recursive_copy(gs.name), |
416 |
recursive_copy(gs.typ), |
|
417 |
gs.doc, |
|
418 |
gs.exported) |
Read our documentation on viewing source code .