@@ -88,30 +88,41 @@ pub(crate) async fn lock(
88
88
// Find the project requirements.
89
89
let workspace = Workspace :: discover ( project_dir, & DiscoveryOptions :: default ( ) ) . await ?;
90
90
91
- // Find an interpreter for the project
92
- let interpreter = ProjectInterpreter :: discover (
93
- & workspace,
94
- python. as_deref ( ) . map ( PythonRequest :: parse) ,
95
- python_preference,
96
- python_downloads,
97
- connectivity,
98
- native_tls,
99
- cache,
100
- printer,
101
- )
102
- . await ?
103
- . into_interpreter ( ) ;
91
+ // Determine the lock mode.
92
+ let interpreter;
93
+ let mode = if frozen {
94
+ LockMode :: Frozen
95
+ } else {
96
+ // Find an interpreter for the project
97
+ interpreter = ProjectInterpreter :: discover (
98
+ & workspace,
99
+ python. as_deref ( ) . map ( PythonRequest :: parse) ,
100
+ python_preference,
101
+ python_downloads,
102
+ connectivity,
103
+ native_tls,
104
+ cache,
105
+ printer,
106
+ )
107
+ . await ?
108
+ . into_interpreter ( ) ;
109
+
110
+ if locked {
111
+ LockMode :: Locked ( & interpreter)
112
+ } else if dry_run {
113
+ LockMode :: DryRun ( & interpreter)
114
+ } else {
115
+ LockMode :: Write ( & interpreter)
116
+ }
117
+ } ;
104
118
105
119
// Initialize any shared state.
106
120
let state = SharedState :: default ( ) ;
107
121
108
122
// Perform the lock operation.
109
123
match do_safe_lock (
110
- locked,
111
- frozen,
112
- dry_run,
124
+ mode,
113
125
& workspace,
114
- & interpreter,
115
126
settings. as_ref ( ) ,
116
127
LowerBound :: Warn ,
117
128
& state,
@@ -169,14 +180,23 @@ pub(crate) async fn lock(
169
180
}
170
181
}
171
182
183
+ #[ derive( Debug , Clone , Copy ) ]
184
+ pub ( super ) enum LockMode < ' env > {
185
+ /// Write the lockfile to disk.
186
+ Write ( & ' env Interpreter ) ,
187
+ /// Perform a resolution, but don't write the lockfile to disk.
188
+ DryRun ( & ' env Interpreter ) ,
189
+ /// Error if the lockfile is not up-to-date with the project requirements.
190
+ Locked ( & ' env Interpreter ) ,
191
+ /// Use the existing lockfile without performing a resolution.
192
+ Frozen ,
193
+ }
194
+
172
195
/// Perform a lock operation, respecting the `--locked` and `--frozen` parameters.
173
196
#[ allow( clippy:: fn_params_excessive_bools) ]
174
197
pub ( super ) async fn do_safe_lock (
175
- locked : bool ,
176
- frozen : bool ,
177
- dry_run : bool ,
198
+ mode : LockMode < ' _ > ,
178
199
workspace : & Workspace ,
179
- interpreter : & Interpreter ,
180
200
settings : ResolverSettingsRef < ' _ > ,
181
201
bounds : LowerBound ,
182
202
state : & SharedState ,
@@ -187,78 +207,84 @@ pub(super) async fn do_safe_lock(
187
207
cache : & Cache ,
188
208
printer : Printer ,
189
209
) -> Result < LockResult , ProjectError > {
190
- if frozen {
191
- // Read the existing lockfile, but don't attempt to lock the project.
192
- let existing = read ( workspace)
193
- . await ?
194
- . ok_or_else ( || ProjectError :: MissingLockfile ) ?;
195
- Ok ( LockResult :: Unchanged ( existing) )
196
- } else if locked {
197
- // Read the existing lockfile.
198
- let existing = read ( workspace)
199
- . await ?
200
- . ok_or_else ( || ProjectError :: MissingLockfile ) ?;
201
-
202
- // Perform the lock operation, but don't write the lockfile to disk.
203
- let result = do_lock (
204
- workspace,
205
- interpreter,
206
- Some ( existing) ,
207
- settings,
208
- bounds,
209
- state,
210
- logger,
211
- connectivity,
212
- concurrency,
213
- native_tls,
214
- cache,
215
- printer,
216
- )
217
- . await ?;
218
-
219
- // If the lockfile changed, return an error.
220
- if matches ! ( result, LockResult :: Changed ( _, _) ) {
221
- return Err ( ProjectError :: LockMismatch ) ;
210
+ match mode {
211
+ LockMode :: Frozen => {
212
+ // Read the existing lockfile, but don't attempt to lock the project.
213
+ let existing = read ( workspace)
214
+ . await ?
215
+ . ok_or_else ( || ProjectError :: MissingLockfile ) ?;
216
+ Ok ( LockResult :: Unchanged ( existing) )
222
217
}
218
+ LockMode :: Locked ( interpreter) => {
219
+ // Read the existing lockfile.
220
+ let existing = read ( workspace)
221
+ . await ?
222
+ . ok_or_else ( || ProjectError :: MissingLockfile ) ?;
223
+
224
+ // Perform the lock operation, but don't write the lockfile to disk.
225
+ let result = do_lock (
226
+ workspace,
227
+ interpreter,
228
+ Some ( existing) ,
229
+ settings,
230
+ bounds,
231
+ state,
232
+ logger,
233
+ connectivity,
234
+ concurrency,
235
+ native_tls,
236
+ cache,
237
+ printer,
238
+ )
239
+ . await ?;
223
240
224
- Ok ( result)
225
- } else {
226
- // Read the existing lockfile.
227
- let existing = match read ( workspace) . await {
228
- Ok ( Some ( existing) ) => Some ( existing) ,
229
- Ok ( None ) => None ,
230
- Err ( ProjectError :: Lock ( err) ) => {
231
- warn_user ! ( "Failed to read existing lockfile; ignoring locked requirements: {err}" ) ;
232
- None
241
+ // If the lockfile changed, return an error.
242
+ if matches ! ( result, LockResult :: Changed ( _, _) ) {
243
+ return Err ( ProjectError :: LockMismatch ) ;
233
244
}
234
- Err ( err) => return Err ( err) ,
235
- } ;
236
245
237
- // Perform the lock operation.
238
- let result = do_lock (
239
- workspace,
240
- interpreter,
241
- existing,
242
- settings,
243
- bounds,
244
- state,
245
- logger,
246
- connectivity,
247
- concurrency,
248
- native_tls,
249
- cache,
250
- printer,
251
- )
252
- . await ?;
246
+ Ok ( result)
247
+ }
248
+ LockMode :: Write ( interpreter) | LockMode :: DryRun ( interpreter) => {
249
+ // Read the existing lockfile.
250
+ let existing = match read ( workspace) . await {
251
+ Ok ( Some ( existing) ) => Some ( existing) ,
252
+ Ok ( None ) => None ,
253
+ Err ( ProjectError :: Lock ( err) ) => {
254
+ warn_user ! (
255
+ "Failed to read existing lockfile; ignoring locked requirements: {err}"
256
+ ) ;
257
+ None
258
+ }
259
+ Err ( err) => return Err ( err) ,
260
+ } ;
253
261
254
- // If the lockfile changed, write it to disk.
255
- if !dry_run {
256
- if let LockResult :: Changed ( _, lock) = & result {
257
- commit ( lock, workspace) . await ?;
262
+ // Perform the lock operation.
263
+ let result = do_lock (
264
+ workspace,
265
+ interpreter,
266
+ existing,
267
+ settings,
268
+ bounds,
269
+ state,
270
+ logger,
271
+ connectivity,
272
+ concurrency,
273
+ native_tls,
274
+ cache,
275
+ printer,
276
+ )
277
+ . await ?;
278
+
279
+ // If the lockfile changed, write it to disk.
280
+ if !matches ! ( mode, LockMode :: DryRun ( _) ) {
281
+ if let LockResult :: Changed ( _, lock) = & result {
282
+ commit ( lock, workspace) . await ?;
283
+ }
258
284
}
259
- }
260
285
261
- Ok ( result)
286
+ Ok ( result)
287
+ }
262
288
}
263
289
}
264
290
0 commit comments