diff --git a/README.md b/README.md index d34c9b0..134c03e 100644 --- a/README.md +++ b/README.md @@ -100,3 +100,4 @@ of the package's `Project.toml` file. * [Working with a Private Registry and/or Private Repositories](docs/ssh_keys.md) * [Registering a Package in a Subdirectory of a Repository](docs/subdir.md) +* [Merging Registries](docs/merge.md) diff --git a/docs/merge.md b/docs/merge.md new file mode 100644 index 0000000..23a466d --- /dev/null +++ b/docs/merge.md @@ -0,0 +1,22 @@ +If you for some reason have two registries that should only be one or +you want to copy some packages from one registry to another, you can +use the function `LocalRegistry.merge` (not exported). + + LocalRegistry.merge(target_path, source_path) + +Copy all packages in the registry at `source_path` into the +registry at `target_path`. + + LocalRegistry.merge(target_path, source_path, include = ["A", "B"]) + +Copy only the packages `A` and `B`. + + LocalRegistry.merge(target_path, source_path, exclude = ["A", "B"]) + +Copy all packages except `A` and `B`. + +---- + +This gives an error if you try to copy a package that already exists +in the target repository. There is no built in support for commiting +or pushing the target registry. diff --git a/src/LocalRegistry.jl b/src/LocalRegistry.jl index c00d6e6..874df52 100644 --- a/src/LocalRegistry.jl +++ b/src/LocalRegistry.jl @@ -14,12 +14,14 @@ module LocalRegistry using RegistryTools: RegistryTools, gitcmd, Compress, check_and_update_registry_files, ReturnStatus, haserror, - find_registered_version + find_registered_version, parse_registry, using UUIDs: uuid4 using Pkg: Pkg, TOML export create_registry, register +include("merge.jl") + # Note: The `uuid` keyword argument is intentionally omitted from the # documentation string since it's not intended for users. """ diff --git a/src/merge.jl b/src/merge.jl new file mode 100644 index 0000000..5108165 --- /dev/null +++ b/src/merge.jl @@ -0,0 +1,62 @@ +using RegistryTools: write_registry + +function merge(target_path::AbstractString, + source_path::AbstractString; + include::Union{Nothing, Vector{<:AbstractString}} = nothing, + exclude::Union{Nothing, Vector{<:AbstractString}} = nothing) + if !isnothing(include) && !isnothing(exclude) + error("Packages can be either included or excluded, not both.") + end + + target_registry = parse_registry(joinpath(target_path, "Registry.toml")) + source_registry = parse_registry(joinpath(source_path, "Registry.toml")) + + target_packages = target_registry.packages + packages = source_registry.packages + + if !isnothing(include) + packages = filter(p -> last(p)["name"] in include, packages) + if length(packages) != length(include) + missing_packages = setdiff(include, [p["name"] for p in values(packages)]) + error("Included packages $(missing_packages) do not exist in the source repository") + end + end + + if !isnothing(exclude) + missing_packages = setdiff(exclude, [p["name"] for p in values(packages)]) + if !isempty(missing_packages) + error("Excluded packages $(missing_packages) do not exist in the source repository") + end + packages = filter(p -> last(p)["name"] ∉ exclude, packages) + end + + colliding_names = intersect([p["name"] for p in values(target_packages)], + [p["name"] for p in values(packages)]) + if !isempty(colliding_names) + error("The target registry already contains these packages: $(colliding_names).") + end + + colliding_uuids = intersect(keys(target_packages), keys(packages)) + if !isempty(colliding_uuids) + error("The target registry already contains these uuids: $(colliding_uuids).") + end + + for (uuid, package) in packages + push!(target_packages, uuid => package) + package_dir = joinpath(target_path, package["path"]) + if isdir(package_dir) + error("Package dir ", package["path"], " already exists in target registry.") + end + mkpath(package_dir) + for filename in ("Package.toml", "Versions.toml", + "Deps.toml", "Compat.toml") + from = joinpath(source_path, package["path"], filename) + to = joinpath(target_path, package["path"], filename) + if isfile(from) + cp(from, to) + end + end + end + + write_registry(joinpath(target_path, "Registry.toml"), target_registry) +end