Created
October 8, 2019 07:39
-
-
Save KristofferC/a0c56b731a55e071ccf58da682cc1e40 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 | |
using GitHub | |
using ProgressMeter | |
#const auth = GitHub.authenticate(ENV["GITHUB_KEY"]) | |
# 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 | |
url::String | |
versions::Dict{VersionNumber, Base.SHA1} | |
end | |
Package(uuid, name, path, url) = Package(uuid, name, path, url, 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 | |
path = data["path"] | |
pkgpath = joinpath(regpath, path) | |
pkgfile = Pkg.TOML.parsefile(joinpath(pkgpath, "Package.toml")) | |
url = pkgfile["repo"] | |
push!(packages, Package(UUID(uuid), data["name"], path, url)) | |
end | |
# Using the fact that there is only one uuid per name in General right now | |
pkgs_completely_deleted = Set{String}() | |
sort!(packages; by= x -> x.name) | |
@showprogress 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() | |
@info "Removing versions that are not compatible with Julia 1.0..." | |
pkgs_completely_deleted = remove_registry(; print_deletions=true) 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" | |
pkg.name === "AlgebraicMultiGrid" && @show version_range | |
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 "Removing packages which repo does not exist" | |
stdlibs = readdir(Sys.STDLIB) | |
# Explicitly list these since checking availability on every run is slow | |
repos_deleted = ["DigitalComm", "Keys", "LibGit2", "MackeyGlass"] | |
pkgs_completely_deleted_pass_2 = remove_registry(; print_deletions=true) do compats, deps, pkg | |
versions_to_delete = VersionNumber[] | |
rep = match(r"https://github.com/(.*?).git", pkg.url) | |
if rep === nothing | |
@warn pkg.url | |
else | |
rep = rep.captures[1] | |
# | |
#repo = GitHub.repo(rep; handle_error=false, auth=auth) | |
deps === nothing && return versions_to_delete | |
repo_deleted = pkg.name in repos_deleted | |
if repo_deleted #repo.id === nothing | |
@info "Deleting $(pkg.name) because its repo does not exist anymore" | |
end | |
for (version, compat) in deps | |
if repo_deleted | |
push!(versions_to_delete, version) | |
end | |
end | |
end | |
return versions_to_delete | |
end | |
pkgs_completely_deleted = union(pkgs_completely_deleted, pkgs_completely_deleted_pass_2) | |
pkgs_completely_deleted_pass_3 = 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_3) | |
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