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 0
    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 0
    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
                                     p.uuid,
389
                                     recursive_copy(p.sha))
390

391 30
recursive_copy(ms::MethodStore) = MethodStore(ms.name,
392
                                              ms.mod,
393
                                              ms.file,
394
                                              ms.line,
395
                                              recursive_copy(ms.sig),
396
                                              copy(ms.kws),
397
                                              recursive_copy(ms.rt))
398

399 30
recursive_copy(dts::DataTypeStore) = DataTypeStore(recursive_copy(dts.name),
400
                                                   recursive_copy(dts.super),
401
                                                   recursive_copy(dts.parameters),
402
                                                   recursive_copy(dts.types),
403
                                                   recursive_copy(dts.fieldnames),
404
                                                   recursive_copy(dts.methods),
405
                                                   dts.doc,
406
                                                   dts.exported)
407

408 30
recursive_copy(fs::FunctionStore) = FunctionStore(recursive_copy(fs.name),
409
                                                  recursive_copy(fs.methods),
410
                                                  fs.doc,
411
                                                  recursive_copy(fs.extends),
412
                                                  fs.exported)
413

414 30
recursive_copy(gs::GenericStore) = GenericStore(recursive_copy(gs.name),
415
                                                recursive_copy(gs.typ),
416
                                                gs.doc,
417
                                                gs.exported)
418

419 0
function todo_path(x::ModuleStore)
420 0
    for (_, a) in x.vals
421 0
        todo_path(a)
422
    end
423
end
424

425 0
function todo_path(x::Union{DataTypeStore,FunctionStore})
426 0
    for m in x.methods
427 0
        todo_path(m)
428
    end
429
end
430 0
function todo_path(x::MethodStore)
431
    # @info x.file
432 0
end
433 0
function todo_path(x)
434 0
end

Read our documentation on viewing source code .

Loading