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
|
0
|
isinproject(context::Pkg.Types.Context, package_name::String) = haskey(deps(project(context)), package_name)
|
38
|
0
|
isinproject(context::Pkg.Types.Context, package_uuid::UUID) = any(u == package_uuid for (n, u) in deps(project(context)))
|
39
|
|
|
40
|
0
|
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
|
0
|
packageuuid(pkg::Pair{String,Any}) = last(pkg) isa String ? UUID(last(pkg)) : UUID(first(last(pkg))["uuid"])
|
49
|
|
|
50
|
0
|
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
|
0
|
return nothing
|
57
|
|
end
|
58
|
0
|
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
|
0
|
return nothing
|
65
|
|
end
|
66
|
5
|
packagename(manifest::Dict{String,Any}, uuid::UUID) = packagename(manifest, string(uuid))
|
67
|
|
|
68
|
0
|
function deps(uuid::UUID, c::Pkg.Types.Context)
|
69
|
0
|
if any(p[1]["uuid"] == string(uuid) for (n, p) in manifest(c))
|
70
|
0
|
return manifest(c)[string(uuid)][1].deps
|
71
|
|
else
|
72
|
0
|
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
|
0
|
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
|
0
|
return nothing
|
87
|
|
end
|
88
|
0
|
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
|
0
|
return nothing
|
95
|
|
end
|
96
|
0
|
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
|
0
|
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
|
0
|
isinproject(context::Pkg.Types.Context, package_name::String) = haskey(deps(project(context)), package_name)
|
121
|
0
|
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
|
0
|
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
|
0
|
function deps(uuid::UUID, c::Pkg.Types.Context)
|
136
|
0
|
if haskey(manifest(c), uuid)
|
137
|
0
|
return deps(manifest(c)[uuid])
|
138
|
|
else
|
139
|
0
|
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
|
0
|
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
|
0
|
is_package_deved(manifest, uuid) = manifest[uuid].path !== nothing
|
172
|
|
end
|
173
|
|
|
174
|
|
function sha2_256_dir(path, sha=sha = zeros(UInt8, 32))
|
175
|
0
|
(uperm(path) & 0x04) != 0x04 && return
|
176
|
0
|
startswith(path, ".") && return
|
177
|
0
|
if isfile(path) && endswith(path, ".jl")
|
178
|
0
|
s1 = open(path) do f
|
179
|
|
sha2_256(f)
|
180
|
|
end
|
181
|
0
|
sha .+= s1
|
182
|
0
|
elseif isdir(path)
|
183
|
0
|
for f in readdir(path)
|
184
|
0
|
sha = sha2_256_dir(joinpath(path, f), sha)
|
185
|
|
end
|
186
|
|
end
|
187
|
0
|
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
|
0
|
for group in groups, each in group.order
|
220
|
0
|
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
|
0
|
return ""
|
231
|
|
end
|
232
|
|
end
|
233
|
|
|
234
|
0
|
_lookup(vr::FakeUnion, depot::EnvStore, cont=false) = nothing
|
235
|
0
|
_lookup(vr::FakeTypeName, depot::EnvStore, cont=false) = _lookup(vr.name, depot, cont)
|
236
|
0
|
_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
|
0
|
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
|
0
|
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
|
0
|
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
|
0
|
function maybe_getfield(k::Symbol, m::ModuleStore, envstore)
|
273
|
0
|
if haskey(m.vals, k)
|
274
|
0
|
return m.vals[k]
|
275
|
|
else
|
276
|
0
|
for v in m.used_modules
|
277
|
0
|
!haskey(m.vals, v) && continue
|
278
|
0
|
submod = m.vals[v]
|
279
|
0
|
if submod isa ModuleStore && k in submod.exportednames
|
280
|
0
|
return submod.vals[k]
|
281
|
0
|
elseif submod isa VarRef
|
282
|
0
|
submod = _lookup(submod, envstore, true)
|
283
|
0
|
if submod isa ModuleStore && k in submod.exportednames && haskey(submod.vals, k)
|
284
|
0
|
return submod.vals[k]
|
285
|
|
end
|
286
|
|
end
|
287
|
|
end
|
288
|
|
end
|
289
|
|
end
|
290
|
|
|
291
|
0
|
function issubmodof(m::Module, M::Module)
|
292
|
0
|
if m == M
|
293
|
0
|
return true
|
294
|
0
|
elseif parentmodule(m) === m
|
295
|
0
|
return false
|
296
|
0
|
elseif parentmodule(m) == M
|
297
|
0
|
return true
|
298
|
|
else
|
299
|
0
|
return issubmodof(parentmodule(m), M)
|
300
|
|
end
|
301
|
|
end
|
302
|
|
|
303
|
0
|
function Base.print(io::IO, f::FunctionStore)
|
304
|
0
|
println(io, f.name, " is a Function.")
|
305
|
0
|
nm = length(f.methods)
|
306
|
0
|
println(io, "# $nm method", nm == 1 ? "" : "s", " for function ", f.name)
|
307
|
0
|
for i = 1:nm
|
308
|
0
|
print(io, "[$i] ")
|
309
|
0
|
println(io, f.methods[i])
|
310
|
|
end
|
311
|
|
end
|
312
|
|
|
313
|
|
const JULIA_DIR = normpath(joinpath(Sys.BINDIR, Base.DATAROOTDIR, "julia"))
|
314
|
|
|
315
|
0
|
function Base.print(io::IO, m::MethodStore)
|
316
|
0
|
print(io, m.name, "(")
|
317
|
0
|
for i = 1:length(m.sig)
|
318
|
0
|
if m.sig[i][1] != Symbol("#unused#")
|
319
|
0
|
print(io, m.sig[i][1])
|
320
|
|
end
|
321
|
0
|
print(io, "::", m.sig[i][2])
|
322
|
0
|
i != length(m.sig) && print(io, ", ")
|
323
|
|
end
|
324
|
0
|
print(io, ")")
|
325
|
0
|
path = replace(m.file, JULIA_DIR => "")
|
326
|
0
|
print(io, " in ", m.mod, " at ", path, ':', m.line)
|
327
|
|
end
|
328
|
|
|
329
|
0
|
function Base.print(io::IO, t::DataTypeStore)
|
330
|
0
|
print(io, t.name, " <: ", t.super)
|
331
|
0
|
for i = 1:length(t.fieldnames)
|
332
|
0
|
print(io, "\n ", t.fieldnames[i], "::", t.types[i])
|
333
|
|
end
|
334
|
|
end
|
335
|
|
|
336
|
0
|
Base.print(io::IO, m::ModuleStore) = print(io, m.name)
|
337
|
0
|
Base.print(io::IO, x::GenericStore) = print(io, x.name, "::", x.typ)
|
338
|
|
|
339
|
0
|
extends_methods(f) = false
|
340
|
0
|
extends_methods(f::FunctionStore) = f.name != f.extends
|
341
|
0
|
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
|
0
|
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
|
0
|
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)
|