Skip to content

Commit 5f498bb

Browse files
committed
WIP. moving to other machine
1 parent a1e817b commit 5f498bb

File tree

4 files changed

+177
-37
lines changed

4 files changed

+177
-37
lines changed

docs/src/api.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,19 @@ Pkg.Artifacts.ensure_all_artifacts_installed
8787
Pkg.Artifacts.@artifact_str
8888
Pkg.Artifacts.archive_artifact
8989
```
90+
91+
## [Preferences API Reference](@id Preferences-Reference)
92+
93+
!!! compat "Julia 1.6"
94+
Pkg's preferences API requires at least Julia 1.6.
95+
96+
```@docs
97+
Pkg.Preferences.load_preferences
98+
Pkg.Preferences.@load_preferences
99+
Pkg.Preferences.save_preferences!
100+
Pkg.Preferences.@save_preferences!
101+
Pkg.Preferences.modify_preferences!
102+
Pkg.Preferences.@modify_preferences!
103+
Pkg.Preferences.clear_preferences!
104+
Pkg.Preferences.@clear_preferences!
105+
```

src/Preferences.jl

Lines changed: 108 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ export load_preferences, @load_preferences,
1111

1212

1313
"""
14-
preferences_path(uuid::UUID)
14+
depot_preferences_paths(uuid::UUID)
1515
16-
Return the path of the preferences file for the given package `UUID`.
16+
Return the possible paths of all preferences file for the given package `UUID` saved in
17+
depot-wide `prefs` locations.
1718
"""
18-
function preferences_path(uuid::UUID)
19-
return joinpath(Pkg.depots1(), "prefs", string(uuid, ".toml"))
19+
function depot_preferences_paths(uuid::UUID)
20+
depots = reverse(Pkg.depots())
21+
return [joinpath(depot, "prefs", string(uuid, ".toml")) for depot in depots]
2022
end
2123

2224
"""
@@ -34,6 +36,26 @@ function get_uuid_throw(m::Module)
3436
return uuid
3537
end
3638

39+
"""
40+
recursive_merge(base::Dict, overrides::Dict...)
41+
42+
Helper function to merge preference dicts recursively, honoring overrides in nested
43+
dictionaries properly.
44+
"""
45+
function recursive_merge(base::Dict, overrides::Dict...)
46+
new_base = Base._typeddict(base, overrides...)
47+
for override in overrides
48+
for (k, v) in override
49+
if haskey(new_base, k) && isa(new_base[k], Dict) && isa(override[k], Dict)
50+
new_base[k] = recursive_merge(new_base[k], override[k])
51+
else
52+
new_base[k] = override[k]
53+
end
54+
end
55+
end
56+
return new_base
57+
end
58+
3759
"""
3860
load_preferences(uuid::UUID)
3961
load_preferences(m::Module)
@@ -42,33 +64,72 @@ Load the preferences for the given package, returning them as a `Dict`. Most us
4264
should use the `@load_preferences()` macro which auto-determines the calling `Module`.
4365
"""
4466
function load_preferences(uuid::UUID)
45-
path = preferences_path(uuid)
46-
if !isfile(path)
47-
return Dict{String,Any}()
67+
# First, load from depots, merging as we go:
68+
prefs = Dict{String,Any}()
69+
for path in depot_preferences_paths(uuid)
70+
if isfile(path)
71+
prefs = recursive_merge(prefs, parse_toml(path))
72+
end
73+
end
74+
75+
# Finally, load from the currently-active project:
76+
proj_path = Base.active_project()
77+
if isfile(proj_path)
78+
project = parse_toml(proj_path)
79+
if haskey(project, "preferences") && isa(project["preferences"], Dict)
80+
proj_prefs = get(project["preferences"], string(uuid), Dict())
81+
prefs = recursive_merge(prefs, proj_prefs)
82+
end
4883
end
49-
return parse_toml(path)
84+
return prefs
5085
end
5186
load_preferences(m::Module) = load_preferences(get_uuid_throw(m))
5287

5388
"""
54-
save_preferences!(uuid::UUID, prefs::Dict)
55-
save_preferences!(m::Module, prefs::Dict)
89+
save_preferences!(uuid::UUID, prefs::Dict; depot::Union{String,Nothing} = nothing)
90+
save_preferences!(m::Module, prefs::Dict; depot::Union{String,Nothing} = nothing)
5691
5792
Save the preferences for the given package. Most users should use the
58-
`@load_preferences()` macro which auto-determines the calling `Module`. See also the
93+
`@save_preferences!()` macro which auto-determines the calling `Module`. See also the
5994
`modify_preferences!()` function (and the associated `@modifiy_preferences!()` macro) for
6095
easy load/modify/save workflows.
61-
"""
62-
function save_preferences!(uuid::UUID, prefs::Dict)
63-
path = preferences_path(uuid)
64-
mkpath(dirname(path))
65-
open(path, "w") do io
66-
TOML.print(io, prefs, sorted=true)
96+
97+
The `depot` keyword argument allows saving of depot-wide preferences, as opposed to the
98+
default of project-specific preferences. Simply set the `depot` keyword argument to the
99+
path of a depot (use `Pkg.depots1()` for the default depot) and the preferences will be
100+
saved to that location.
101+
"""
102+
function save_preferences!(uuid::UUID, prefs::Dict;
103+
depot::Union{AbstractString,Nothing} = nothing)
104+
if depot === nothing
105+
# Save to project
106+
proj_path = Base.active_project()
107+
project = Dict{String,Any}()
108+
if isfile(proj_path)
109+
project = parse_toml(proj_path)
110+
end
111+
if !haskey(project, "preferences")
112+
project["preferences"] = Dict{String,Any}()
113+
end
114+
if !isa(project["preferences"], Dict)
115+
error("$(proj_path) has conflicting `preferences` entry type: Not a Dict!")
116+
end
117+
project["preferences"][string(uuid)] = prefs
118+
open(proj_path, "w") do io
119+
TOML.print(io, project, sorted=true)
120+
end
121+
else
122+
path = joinpath(depot, "prefs", string(uuid, ".toml"))
123+
mkpath(dirname(path))
124+
open(path, "w") do io
125+
TOML.print(io, prefs, sorted=true)
126+
end
67127
end
68128
return nothing
69129
end
70-
function save_preferences!(m::Module, prefs::Dict)
71-
return save_preferences!(get_uuid_throw(m), prefs)
130+
function save_preferences!(m::Module, prefs::Dict;
131+
depot::Union{AbstractString,Nothing} = nothing)
132+
return save_preferences!(get_uuid_throw(m), prefs; depot=depot)
72133
end
73134

74135
"""
@@ -86,6 +147,9 @@ end
86147
87148
This function returns the full preferences object. Most users should use the
88149
`@modify_preferences!()` macro which auto-determines the calling `Module`.
150+
151+
Note that this method does not support modifying depot-wide preferences; modifications
152+
always are saved to the active project.
89153
"""
90154
function modify_preferences!(f::Function, uuid::UUID)
91155
prefs = load_preferences(uuid)
@@ -100,10 +164,30 @@ modify_preferences!(f::Function, m::Module) = modify_preferences!(f, get_uuid_th
100164
clear_preferences!(m::Module)
101165
102166
Convenience method to remove all preferences for the given package. Most users should
103-
use the `@clear_preferences!()` macro, which auto-determines the calling `Module`.
167+
use the `@clear_preferences!()` macro, which auto-determines the calling `Module`. This
168+
method clears not only project-specific preferences, but also depot-wide preferences, if
169+
the current user has the permissions to do so.
104170
"""
105171
function clear_preferences!(uuid::UUID)
106-
rm(preferences_path(uuid); force=true)
172+
for path in depot_preferences_paths(uuid)
173+
try
174+
rm(path; force=true)
175+
catch
176+
@warn("Unable to remove preference path $(path)")
177+
end
178+
end
179+
180+
# Clear the project preferences key, if it exists
181+
proj_path = Base.active_project()
182+
if isfile(proj_path)
183+
project = parse_toml(proj_path)
184+
if haskey(project, "preferences") && isa(project["preferences"], Dict)
185+
delete!(project["preferences"], string(uuid))
186+
open(proj_path, "w") do io
187+
TOML.print(io, project, sorted=true)
188+
end
189+
end
190+
end
107191
end
108192

109193
"""
@@ -120,7 +204,9 @@ end
120204
"""
121205
@save_preferences!(prefs)
122206
123-
Convenience macro to call `save_preferences!()` for the current package.
207+
Convenience macro to call `save_preferences!()` for the current package. Note that
208+
saving to a depot path is not supported in this macro, use `save_preferences!()` if you
209+
wish to do that.
124210
"""
125211
macro save_preferences!(prefs)
126212
return quote

test/preferences.jl

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,41 @@ using ..Utils, ..Pkg.TOML
44
using Test, Pkg.Preferences
55

66
@testset "Preferences" begin
7+
# Create a temporary package, store some preferences within it.
8+
with_temp_env() do project_dir
9+
uuid = Base.UUID(UInt128(0))
10+
save_preferences!(uuid, Dict("foo" => "bar"))
11+
12+
project_path = joinpath(project_dir, "Project.toml")
13+
@test isfile(project_path)
14+
proj = Pkg.Types.parse_toml(project_path)
15+
@test haskey(proj, "preferences")
16+
@test isa(proj["preferences"], Dict)
17+
@test haskey(proj["preferences"], string(uuid))
18+
@test isa(proj["preferences"][string(uuid)], Dict)
19+
@test proj["preferences"][string(uuid)]["foo"] == "bar"
20+
21+
prefs = modify_preferences!(uuid) do prefs
22+
prefs["foo"] = "baz"
23+
prefs["spoon"] = [Dict("qux" => "idk")]
24+
end
25+
@test prefs == load_preferences(uuid)
26+
27+
clear_preferences!(uuid)
28+
proj = Pkg.Types.parse_toml(project_path)
29+
@test !haskey(proj, "preferences")
30+
end
731

832
temp_pkg_dir() do project_dir
9-
# Test creation of preferences within this temporary depot
33+
# Test setting of depot-wide preferences
1034
uuid = Base.UUID(UInt128(0))
11-
toml_path = Pkg.Preferences.preferences_path(uuid)
35+
toml_path = last(Pkg.Preferences.depot_preferences_paths(uuid))
1236

1337
@test isempty(load_preferences(uuid))
1438
@test !isfile(toml_path)
1539

1640
# Now, save something
17-
save_preferences!(uuid, Dict("foo" => "bar"))
18-
@show toml_path
41+
save_preferences!(uuid, Dict("foo" => "bar"); depot=Pkg.depots1())
1942
@test isfile(toml_path)
2043
prefs = load_preferences(uuid)
2144
@test load_preferences(uuid)["foo"] == "bar"
@@ -24,7 +47,16 @@ using Test, Pkg.Preferences
2447
prefs["foo"] = "baz"
2548
prefs["spoon"] = [Dict("qux" => "idk")]
2649
end
50+
51+
# Test that we get the properly-merged prefs, but that the
52+
# depot-wide file stays the same:
2753
@test prefs == load_preferences(uuid)
54+
toml_prefs = Pkg.Types.parse_toml(toml_path)
55+
@test toml_prefs["foo"] != prefs["foo"]
56+
@test !haskey(toml_prefs, "spoon")
57+
58+
clear_preferences!(uuid)
59+
@test !isfile(toml_path)
2860
end
2961

3062
# Do a test within a package to ensure that we can use the macros
@@ -38,6 +70,12 @@ using Test, Pkg.Preferences
3870
prefs = load_preferences(up_uuid)
3971
@test haskey(prefs, "backend")
4072
@test prefs["backend"] == "jlFPGA"
73+
74+
# Set a new depot-level preference, ensure that it's ignored:
75+
save_preferences!(up_uuid, Dict("backend" => "CUDA"); depot=Pkg.depots1())
76+
prefs = load_preferences(up_uuid)
77+
@test haskey(prefs, "backend")
78+
@test prefs["backend"] == "jlFPGA"
4179
end
4280
end
4381

test/runtests.jl

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@ import Pkg
88
rm(joinpath(@__DIR__, "registries"); force = true, recursive = true)
99

1010
include("utils.jl")
11-
include("new.jl")
12-
include("pkg.jl")
13-
include("repl.jl")
14-
include("api.jl")
15-
include("registry.jl")
16-
include("subdir.jl")
17-
include("artifacts.jl")
18-
include("binaryplatforms.jl")
19-
include("platformengines.jl")
20-
include("sandbox.jl")
21-
include("resolve.jl")
11+
# include("new.jl")
12+
# include("pkg.jl")
13+
# include("repl.jl")
14+
# include("api.jl")
15+
# include("registry.jl")
16+
# include("subdir.jl")
17+
# include("artifacts.jl")
18+
# include("binaryplatforms.jl")
19+
# include("platformengines.jl")
20+
# include("sandbox.jl")
21+
# include("resolve.jl")
2222
include("preferences.jl")
2323

2424
# clean up locally cached registry

0 commit comments

Comments
 (0)