-
-
Save KristofferC/e6d9bbed08f689705f73cbcb0f672866 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Pkg | |
import Pkg.TOML | |
import Pkg.Types: VersionRange, ≲ | |
using UUIDs | |
# Copied from Registrator.jl | |
#=====================# | |
struct RegistryData | |
name::String | |
uuid::UUID | |
repo::Union{String, Nothing} | |
description::Union{String, Nothing} | |
packages::Dict{String, Dict{String, Any}} | |
extra::Dict{String, Any} | |
end | |
function RegistryData( | |
name::AbstractString, | |
uuid::Union{UUID, AbstractString}; | |
repo::Union{AbstractString, Nothing}=nothing, | |
description::Union{AbstractString, Nothing}=nothing, | |
packages::Dict=Dict(), | |
extras::Dict=Dict(), | |
) | |
RegistryData(name, UUID(uuid), repo, description, packages, extras) | |
end | |
function Base.copy(reg::RegistryData) | |
RegistryData( | |
reg.name, | |
reg.uuid, | |
reg.repo, | |
reg.description, | |
deepcopy(reg.packages), | |
deepcopy(reg.extra), | |
) | |
end | |
function parse_registry(io::IO) | |
data = TOML.parse(io) | |
name = pop!(data, "name") | |
uuid = pop!(data, "uuid") | |
repo = pop!(data, "repo", nothing) | |
description = pop!(data, "description", nothing) | |
packages = pop!(data, "packages", Dict()) | |
RegistryData(name, UUID(uuid), repo, description, packages, data) | |
end | |
parse_registry(str::AbstractString) = open(parse_registry, str) | |
function TOML.print(io::IO, reg::RegistryData) | |
println(io, "name = ", repr(reg.name)) | |
println(io, "uuid = ", repr(string(reg.uuid))) | |
if reg.repo !== nothing | |
println(io, "repo = ", repr(reg.repo)) | |
end | |
if reg.description !== nothing | |
# print long-form string if there are multiple lines | |
if '\n' in reg.description | |
print(io, """\n | |
description = \"\"\" | |
$(reg.description)\"\"\" | |
""" | |
) | |
else | |
println(io, "description = ", repr(reg.description)) | |
end | |
end | |
for (k, v) in pairs(reg.extra) | |
TOML.print(io, Dict(k => v), sorted=true) | |
end | |
println(io, "\n[packages]") | |
for (uuid, data) in sort!(collect(reg.packages), by=first) | |
print(io, uuid, " = { ") | |
print(io, "name = ", repr(data["name"])) | |
print(io, ", path = ", repr(data["path"])) | |
println(io, " }") | |
end | |
nothing | |
end | |
#===============================================================# | |
struct Package | |
uuid::UUID | |
name::String | |
path::String | |
versions::Dict{VersionNumber, Base.SHA1} | |
end | |
Package(uuid, name, path) = Package(uuid, name, path, Dict{VersionNumber, Base.SHA1}()) | |
function remove_registry(filter; print_deletions=false) | |
regpath = joinpath(homedir(), ".julia/registries/General") | |
packages = Package[] | |
reg = parse_registry(joinpath(regpath, "Registry.toml")) | |
for (uuid, data) in reg.packages | |
push!(packages, Package(UUID(uuid), data["name"], data["path"])) | |
end | |
# Using the fact that there is only one uuid per name in General right now | |
pkgs_completely_deleted = Set{String}() | |
for pkg in packages | |
pkgpath = joinpath(regpath, pkg.path) | |
compatfile = joinpath(pkgpath, "Compat.toml") | |
depfile = joinpath(pkgpath, "Deps.toml") | |
merge!(pkg.versions, Pkg.Operations.load_versions(pkgpath; include_yanked = true)) | |
# @show pkg.versions | |
versions_to_delete = VersionNumber[] | |
compats = nothing | |
if isfile(compatfile) | |
compats = Pkg.Compress.load(joinpath(pkgpath, "Compat.toml")) | |
end | |
deps = nothing | |
if isfile(depfile) | |
deps = Pkg.Compress.load(joinpath(pkgpath, "Deps.toml")) | |
end | |
versions_to_delete = filter(compats, deps, pkg) | |
foreach(v -> delete!(pkg.versions, v), versions_to_delete) | |
if isempty(pkg.versions) | |
delete!(reg.packages, string(pkg.uuid)) | |
rm(pkgpath, force=true, recursive=true) | |
push!(pkgs_completely_deleted, pkg.name) | |
@info "Deleting $(pkg.name) completely..." | |
else | |
if !isempty(versions_to_delete) | |
# Write out new versions | |
versions_file = joinpath(pkgpath, "Versions.toml") | |
open(versions_file, "w") do io | |
versions_string = Dict(string(v) => Dict{String,Any}("git-tree-sha1" => string(sha)) for (v, sha) in pkg.versions) | |
Pkg.TOML.print(io, versions_string; sorted=true, by=x->VersionNumber(x)) | |
end | |
# Write out the new compressed versions | |
for file in (compatfile, depfile) | |
if isfile(file) | |
data = Pkg.Compress.load(file) | |
foreach(v -> delete!(data, v), versions_to_delete) | |
Pkg.Compress.save(file, data) | |
end | |
end | |
end | |
end | |
end | |
open(joinpath(regpath, "Registry.toml"), "w") do io | |
TOML.print(io, reg) | |
end | |
return pkgs_completely_deleted | |
end | |
function cleanup_registry() | |
pkgs_completely_deleted = remove_registry() do compats, deps, pkg | |
versions_to_delete = VersionNumber[] | |
compats == nothing && return versions_to_delete | |
for (version, compat) in compats | |
for (dep, version_range) in compat | |
if dep === "julia" | |
if version_range isa Vector | |
version_range = maximum(VersionNumber.(version_range)) | |
end | |
vr = VersionRange(version_range) | |
if vr.upper ≲ v"0.7" && vr.upper != Pkg.Types.VersionBound("*") # Special case because it seems bugged | |
push!(versions_to_delete, version) | |
end | |
end | |
end | |
end | |
return versions_to_delete | |
end | |
@info "---------------------------------------" | |
stdlibs = readdir(Sys.STDLIB) | |
pkgs_completely_deleted_pass_2 = remove_registry(; print_deletions=true) do compats, deps, pkg | |
versions_to_delete = VersionNumber[] | |
deps == nothing && return versions_to_delete | |
for (version, compat) in deps | |
#@show version => compat | |
for (deppkg, uuid) in compat | |
# Packages that got moved to STDLIB kept their UUID | |
deppkg in stdlibs && continue | |
if deppkg in pkgs_completely_deleted | |
@info "Deleting $(pkg.name):$(version) because it depends on $deppkg which was completely removed" | |
push!(versions_to_delete, version) | |
break | |
end | |
end | |
end | |
return versions_to_delete | |
end | |
pkgs_completely_deleted = union(pkgs_completely_deleted, pkgs_completely_deleted_pass_2) | |
write("packagages_deleted", join(sort(collect(pkgs_completely_deleted)), '\n')) | |
return | |
end | |
function check_registry_consistency() | |
regpath = joinpath(homedir(), ".julia/registries/General") | |
packages = Package[] | |
reg = parse_registry(joinpath(regpath, "Registry.toml")) | |
all_uuids = Set{UUID}() | |
for (uuid, data) in reg.packages | |
push!(packages, Package(UUID(uuid), data["name"], data["path"])) | |
push!(all_uuids, UUID(uuid)) | |
end | |
stdlibs = readdir(Sys.STDLIB) | |
for pkg in packages | |
pkgpath = joinpath(regpath, pkg.path) | |
depfile = joinpath(pkgpath, "Deps.toml") | |
if isfile(depfile) | |
deps = Pkg.Compress.load(joinpath(pkgpath, "Deps.toml")) | |
for (version, compat) in deps | |
for (deppkg, uuid) in compat | |
deppkg in stdlibs && continue | |
if !(UUID(uuid) in all_uuids) | |
error("$(pkg.name) depends on unknown package with uuid $uuid") | |
end | |
end | |
end | |
end | |
end | |
end | |
cleanup_registry() | |
check_registry_consistency() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment