|
708 | 708 | # all versioned packages should have a `tree_hash` |
709 | 709 | function resolve_versions!( |
710 | 710 | env::EnvCache, registries::Vector{Registry.RegistryInstance}, pkgs::Vector{PackageSpec}, julia_version, |
711 | | - installed_only::Bool |
| 711 | + installed_only::Bool, preferred_versions::Dict{UUID, VersionNumber} = Dict{UUID, VersionNumber}() |
712 | 712 | ) |
713 | 713 | installed_only = installed_only || OFFLINE_MODE[] |
714 | 714 |
|
@@ -777,7 +777,10 @@ function resolve_versions!( |
777 | 777 | unbind_stdlibs = julia_version === VERSION |
778 | 778 | reqs = Resolve.Requires(pkg.uuid => is_stdlib(pkg.uuid) && unbind_stdlibs ? VersionSpec("*") : VersionSpec(pkg.version) for pkg in pkgs) |
779 | 779 | deps_map_compressed, compat_map_compressed, weak_deps_map_compressed, weak_compat_map_compressed, pkg_versions_map, pkg_versions_per_registry, uuid_to_name, reqs, fixed = deps_graph(env, registries, names, reqs, fixed, julia_version, installed_only) |
780 | | - graph = Resolve.Graph(deps_map_compressed, compat_map_compressed, weak_deps_map_compressed, weak_compat_map_compressed, pkg_versions_map, pkg_versions_per_registry, uuid_to_name, reqs, fixed, false, julia_version) |
| 780 | + graph = Resolve.Graph( |
| 781 | + deps_map_compressed, compat_map_compressed, weak_deps_map_compressed, weak_compat_map_compressed, |
| 782 | + pkg_versions_map, pkg_versions_per_registry, uuid_to_name, reqs, fixed, false, julia_version, preferred_versions |
| 783 | + ) |
781 | 784 | Resolve.simplify_graph!(graph) |
782 | 785 | vers = Resolve.resolve(graph) |
783 | 786 |
|
@@ -844,6 +847,84 @@ function resolve_versions!( |
844 | 847 | return final_deps_map |
845 | 848 | end |
846 | 849 |
|
| 850 | +function collect_preferred_loaded_versions(env::EnvCache) |
| 851 | + preferred = Dict{UUID, VersionNumber}() |
| 852 | + for (pkgid, mod) in Base.loaded_modules |
| 853 | + pkgid isa Base.PkgId || continue |
| 854 | + pkg_uuid = pkgid.uuid |
| 855 | + pkg_uuid isa UUID || continue |
| 856 | + Types.is_stdlib(pkg_uuid) && continue |
| 857 | + haskey(env.manifest, pkg_uuid) && continue |
| 858 | + env.pkg !== nothing && pkg_uuid == env.pkg.uuid && continue |
| 859 | + version = Base.pkgversion(mod) |
| 860 | + version isa VersionNumber || continue |
| 861 | + preferred[pkg_uuid] = version |
| 862 | + end |
| 863 | + return preferred |
| 864 | +end |
| 865 | + |
| 866 | +function preferred_loaded_packages_usage( |
| 867 | + pkgs::Vector{PackageSpec}, preferred_versions::Dict{UUID, VersionNumber}, manifest_uuids::Set{UUID}, |
| 868 | + direct_requested_uuids::Set{UUID} |
| 869 | + ) |
| 870 | + (isempty(preferred_versions) || isempty(pkgs)) && return String[], 0 |
| 871 | + direct_names = String[] |
| 872 | + indirect_count = 0 |
| 873 | + for pkg in pkgs |
| 874 | + uuid = pkg.uuid |
| 875 | + uuid isa UUID || continue |
| 876 | + uuid in manifest_uuids && continue |
| 877 | + preferred_version = get(preferred_versions, uuid, nothing) |
| 878 | + preferred_version === nothing && continue |
| 879 | + pkg_version = pkg.version |
| 880 | + pkg_version isa VersionNumber || continue |
| 881 | + pkg_version == preferred_version || continue |
| 882 | + pkg.name === nothing && continue |
| 883 | + if uuid in direct_requested_uuids |
| 884 | + push!(direct_names, pkg.name) |
| 885 | + else |
| 886 | + indirect_count += 1 |
| 887 | + end |
| 888 | + end |
| 889 | + sort!(direct_names) |
| 890 | + unique!(direct_names) |
| 891 | + return direct_names, indirect_count |
| 892 | +end |
| 893 | + |
| 894 | +function maybe_print_preferred_loaded_note(io::IO, direct_names::Vector{String}, indirect_count::Int) |
| 895 | + isempty(direct_names) && indirect_count == 0 && return |
| 896 | + parts = String[] |
| 897 | + if !isempty(direct_names) |
| 898 | + push!(parts, join(direct_names, ", ")) |
| 899 | + end |
| 900 | + if indirect_count > 0 |
| 901 | + dep_word = indirect_count == 1 ? "dependency" : "dependencies" |
| 902 | + push!(parts, "$(indirect_count) $(dep_word)") |
| 903 | + end |
| 904 | + joined = length(parts) == 2 ? string(parts[1], " and ", parts[2]) : parts[1] |
| 905 | + msg = if length(direct_names) + indirect_count > 1 |
| 906 | + "Preferring versions of $(joined) that are already loaded" |
| 907 | + else |
| 908 | + "Preferring the version of $(joined) that is already loaded" |
| 909 | + end |
| 910 | + printpkgstyle(io, :Resolve, msg; color = Base.info_color()) |
| 911 | + return |
| 912 | +end |
| 913 | + |
| 914 | +function apply_preferred_versions_to_direct!(pkgs::Vector{PackageSpec}, preferred_versions::Dict{UUID, VersionNumber}) |
| 915 | + isempty(preferred_versions) && return |
| 916 | + empty_spec = VersionSpec() |
| 917 | + for pkg in pkgs |
| 918 | + pkg.version == empty_spec || continue |
| 919 | + uuid = pkg.uuid |
| 920 | + uuid isa UUID || continue |
| 921 | + pref_version = get(preferred_versions, uuid, nothing) |
| 922 | + pref_version === nothing && continue |
| 923 | + pkg.version = VersionSpec(pref_version) |
| 924 | + end |
| 925 | + return |
| 926 | +end |
| 927 | + |
847 | 928 | get_or_make!(d::Dict{K, V}, k::K) where {K, V} = get!(d, k) do; |
848 | 929 | V() |
849 | 930 | end |
@@ -2072,63 +2153,67 @@ end |
2072 | 2153 |
|
2073 | 2154 | function tiered_resolve( |
2074 | 2155 | env::EnvCache, registries::Vector{Registry.RegistryInstance}, pkgs::Vector{PackageSpec}, julia_version, |
2075 | | - try_all_installed::Bool |
| 2156 | + try_all_installed::Bool; preferred_versions::Dict{UUID, VersionNumber} = Dict{UUID, VersionNumber}() |
2076 | 2157 | ) |
2077 | 2158 | if try_all_installed |
2078 | 2159 | try # do not modify existing subgraph and only add installed versions of the new packages |
2079 | 2160 | @debug "tiered_resolve: trying PRESERVE_ALL_INSTALLED" |
2080 | | - return targeted_resolve(env, registries, pkgs, PRESERVE_ALL_INSTALLED, julia_version) |
| 2161 | + return targeted_resolve(env, registries, pkgs, PRESERVE_ALL_INSTALLED, julia_version; preferred_versions) |
2081 | 2162 | catch err |
2082 | 2163 | err isa Resolve.ResolverError || rethrow() |
2083 | 2164 | end |
2084 | 2165 | end |
2085 | 2166 | try # do not modify existing subgraph |
2086 | 2167 | @debug "tiered_resolve: trying PRESERVE_ALL" |
2087 | | - return targeted_resolve(env, registries, pkgs, PRESERVE_ALL, julia_version) |
| 2168 | + return targeted_resolve(env, registries, pkgs, PRESERVE_ALL, julia_version; preferred_versions) |
2088 | 2169 | catch err |
2089 | 2170 | err isa Resolve.ResolverError || rethrow() |
2090 | 2171 | end |
2091 | 2172 | try # do not modify existing direct deps |
2092 | 2173 | @debug "tiered_resolve: trying PRESERVE_DIRECT" |
2093 | | - return targeted_resolve(env, registries, pkgs, PRESERVE_DIRECT, julia_version) |
| 2174 | + return targeted_resolve(env, registries, pkgs, PRESERVE_DIRECT, julia_version; preferred_versions) |
2094 | 2175 | catch err |
2095 | 2176 | err isa Resolve.ResolverError || rethrow() |
2096 | 2177 | end |
2097 | 2178 | try |
2098 | 2179 | @debug "tiered_resolve: trying PRESERVE_SEMVER" |
2099 | | - return targeted_resolve(env, registries, pkgs, PRESERVE_SEMVER, julia_version) |
| 2180 | + return targeted_resolve(env, registries, pkgs, PRESERVE_SEMVER, julia_version; preferred_versions) |
2100 | 2181 | catch err |
2101 | 2182 | err isa Resolve.ResolverError || rethrow() |
2102 | 2183 | end |
2103 | 2184 | @debug "tiered_resolve: trying PRESERVE_NONE" |
2104 | | - return targeted_resolve(env, registries, pkgs, PRESERVE_NONE, julia_version) |
| 2185 | + return targeted_resolve(env, registries, pkgs, PRESERVE_NONE, julia_version; preferred_versions) |
2105 | 2186 | end |
2106 | 2187 |
|
2107 | | -function targeted_resolve(env::EnvCache, registries::Vector{Registry.RegistryInstance}, pkgs::Vector{PackageSpec}, preserve::PreserveLevel, julia_version) |
| 2188 | +function targeted_resolve( |
| 2189 | + env::EnvCache, registries::Vector{Registry.RegistryInstance}, pkgs::Vector{PackageSpec}, preserve::PreserveLevel, |
| 2190 | + julia_version; preferred_versions::Dict{UUID, VersionNumber} = Dict{UUID, VersionNumber}() |
| 2191 | + ) |
2108 | 2192 | if preserve == PRESERVE_ALL || preserve == PRESERVE_ALL_INSTALLED |
2109 | 2193 | pkgs = load_all_deps(env, pkgs; preserve) |
2110 | 2194 | else |
2111 | 2195 | pkgs = load_direct_deps(env, pkgs; preserve) |
2112 | 2196 | end |
2113 | 2197 | check_registered(registries, pkgs) |
2114 | 2198 |
|
2115 | | - deps_map = resolve_versions!(env, registries, pkgs, julia_version, preserve == PRESERVE_ALL_INSTALLED) |
| 2199 | + deps_map = resolve_versions!(env, registries, pkgs, julia_version, preserve == PRESERVE_ALL_INSTALLED, preferred_versions) |
2116 | 2200 | return pkgs, deps_map |
2117 | 2201 | end |
2118 | 2202 |
|
2119 | 2203 | function _resolve( |
2120 | 2204 | io::IO, env::EnvCache, registries::Vector{Registry.RegistryInstance}, |
2121 | | - pkgs::Vector{PackageSpec}, preserve::PreserveLevel, julia_version |
| 2205 | + pkgs::Vector{PackageSpec}, preserve::PreserveLevel, julia_version; |
| 2206 | + preferred_versions::Dict{UUID, VersionNumber} = Dict{UUID, VersionNumber}() |
2122 | 2207 | ) |
2123 | 2208 | usingstrategy = preserve != PRESERVE_TIERED ? " using $preserve" : "" |
2124 | 2209 | printpkgstyle(io, :Resolving, "package versions$(usingstrategy)...") |
2125 | 2210 | return try |
2126 | 2211 | if preserve == PRESERVE_TIERED_INSTALLED |
2127 | | - tiered_resolve(env, registries, pkgs, julia_version, true) |
| 2212 | + tiered_resolve(env, registries, pkgs, julia_version, true; preferred_versions) |
2128 | 2213 | elseif preserve == PRESERVE_TIERED |
2129 | | - tiered_resolve(env, registries, pkgs, julia_version, false) |
| 2214 | + tiered_resolve(env, registries, pkgs, julia_version, false; preferred_versions) |
2130 | 2215 | else |
2131 | | - targeted_resolve(env, registries, pkgs, preserve, julia_version) |
| 2216 | + targeted_resolve(env, registries, pkgs, preserve, julia_version; preferred_versions) |
2132 | 2217 | end |
2133 | 2218 | catch err |
2134 | 2219 |
|
@@ -2235,11 +2320,34 @@ function add( |
2235 | 2320 | return |
2236 | 2321 | end |
2237 | 2322 |
|
| 2323 | + preferred_loaded_versions = Dict{UUID, VersionNumber}() |
| 2324 | + existing_manifest_uuids = Set{UUID}() |
| 2325 | + preferred_direct_note_names = String[] |
| 2326 | + preferred_indirect_note_count = 0 |
| 2327 | + direct_requested_uuids = Set{UUID}() |
2238 | 2328 | foreach(pkg -> target_field[pkg.name] = pkg.uuid, pkgs) # update set of deps/weakdeps/extras |
| 2329 | + for pkg in pkgs |
| 2330 | + uuid = pkg.uuid |
| 2331 | + uuid isa UUID || continue |
| 2332 | + push!(direct_requested_uuids, uuid) |
| 2333 | + end |
| 2334 | + |
| 2335 | + if target == :deps |
| 2336 | + preferred_loaded_versions = collect_preferred_loaded_versions(ctx.env) |
| 2337 | + existing_manifest_uuids = Set(keys(ctx.env.manifest)) |
| 2338 | + end |
2239 | 2339 |
|
2240 | 2340 | if target == :deps # nothing to resolve/install if it's weak or extras |
2241 | 2341 | # resolve |
2242 | | - man_pkgs, deps_map = _resolve(ctx.io, ctx.env, ctx.registries, pkgs, preserve, ctx.julia_version) |
| 2342 | + apply_preferred_versions_to_direct!(pkgs, preferred_loaded_versions) |
| 2343 | + man_pkgs, deps_map = _resolve( |
| 2344 | + ctx.io, ctx.env, ctx.registries, pkgs, preserve, ctx.julia_version; |
| 2345 | + preferred_versions = preferred_loaded_versions |
| 2346 | + ) |
| 2347 | + preferred_direct_note_names, preferred_indirect_note_count = preferred_loaded_packages_usage( |
| 2348 | + man_pkgs, preferred_loaded_versions, existing_manifest_uuids, direct_requested_uuids |
| 2349 | + ) |
| 2350 | + maybe_print_preferred_loaded_note(ctx.io, preferred_direct_note_names, preferred_indirect_note_count) |
2243 | 2351 | update_manifest!(ctx.env, man_pkgs, deps_map, ctx.julia_version, ctx.registries) |
2244 | 2352 | new_apply = download_source(ctx) |
2245 | 2353 | fixups_from_projectfile!(ctx) |
|
0 commit comments