@@ -11,12 +11,14 @@ export load_preferences, @load_preferences,
11
11
12
12
13
13
"""
14
- preferences_path (uuid::UUID)
14
+ depot_preferences_paths (uuid::UUID)
15
15
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.
17
18
"""
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]
20
22
end
21
23
22
24
"""
@@ -34,6 +36,26 @@ function get_uuid_throw(m::Module)
34
36
return uuid
35
37
end
36
38
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
+
37
59
"""
38
60
load_preferences(uuid::UUID)
39
61
load_preferences(m::Module)
@@ -42,33 +64,72 @@ Load the preferences for the given package, returning them as a `Dict`. Most us
42
64
should use the `@load_preferences()` macro which auto-determines the calling `Module`.
43
65
"""
44
66
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
48
83
end
49
- return parse_toml (path)
84
+ return prefs
50
85
end
51
86
load_preferences (m:: Module ) = load_preferences (get_uuid_throw (m))
52
87
53
88
"""
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 )
56
91
57
92
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
59
94
`modify_preferences!()` function (and the associated `@modifiy_preferences!()` macro) for
60
95
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
67
127
end
68
128
return nothing
69
129
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)
72
133
end
73
134
74
135
"""
86
147
87
148
This function returns the full preferences object. Most users should use the
88
149
`@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.
89
153
"""
90
154
function modify_preferences! (f:: Function , uuid:: UUID )
91
155
prefs = load_preferences (uuid)
@@ -100,10 +164,30 @@ modify_preferences!(f::Function, m::Module) = modify_preferences!(f, get_uuid_th
100
164
clear_preferences!(m::Module)
101
165
102
166
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.
104
170
"""
105
171
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
107
191
end
108
192
109
193
"""
120
204
"""
121
205
@save_preferences!(prefs)
122
206
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.
124
210
"""
125
211
macro save_preferences! (prefs)
126
212
return quote
0 commit comments