@@ -17,8 +17,8 @@ use uv_cache::Cache;
17
17
use uv_cli:: ExternalCommand ;
18
18
use uv_client:: { BaseClientBuilder , Connectivity } ;
19
19
use uv_configuration:: {
20
- Concurrency , DevGroupsSpecification , EditableMode , ExtrasSpecification , GroupsSpecification ,
21
- InstallOptions , LowerBound , PreviewMode , SourceStrategy , TrustedHost ,
20
+ Concurrency , DevGroupsManifest , DevGroupsSpecification , EditableMode , ExtrasSpecification ,
21
+ GroupsSpecification , InstallOptions , LowerBound , PreviewMode , SourceStrategy , TrustedHost ,
22
22
} ;
23
23
use uv_dispatch:: SharedState ;
24
24
use uv_distribution:: LoweredRequirement ;
@@ -200,109 +200,57 @@ pub(crate) async fn run(
200
200
. await ?
201
201
. into_interpreter ( ) ;
202
202
203
- // Determine the working directory for the script.
204
- let script_dir = match & script {
205
- Pep723Item :: Script ( script) => std:: path:: absolute ( & script. path ) ?
206
- . parent ( )
207
- . expect ( "script path has no parent" )
208
- . to_owned ( ) ,
209
- Pep723Item :: Stdin ( ..) | Pep723Item :: Remote ( ..) => std:: env:: current_dir ( ) ?,
210
- } ;
211
- let script = script. into_metadata ( ) ;
212
-
213
- // Install the script requirements, if necessary. Otherwise, use an isolated environment.
214
- if let Some ( dependencies) = script. dependencies {
215
- // Collect any `tool.uv.index` from the script.
216
- let empty = Vec :: default ( ) ;
217
- let script_indexes = match settings. sources {
218
- SourceStrategy :: Enabled => script
219
- . tool
220
- . as_ref ( )
221
- . and_then ( |tool| tool. uv . as_ref ( ) )
222
- . and_then ( |uv| uv. top_level . index . as_deref ( ) )
223
- . unwrap_or ( & empty) ,
224
- SourceStrategy :: Disabled => & empty,
225
- } ;
203
+ // If a lockfile already exists, lock the script.
204
+ if let Some ( target) = script
205
+ . as_script ( )
206
+ . map ( LockTarget :: from)
207
+ . filter ( |target| target. lock_path ( ) . is_file ( ) )
208
+ {
209
+ debug ! ( "Found existing lockfile for script" ) ;
226
210
227
- // Collect any `tool.uv.sources` from the script.
228
- let empty = BTreeMap :: default ( ) ;
229
- let script_sources = match settings. sources {
230
- SourceStrategy :: Enabled => script
231
- . tool
232
- . as_ref ( )
233
- . and_then ( |tool| tool. uv . as_ref ( ) )
234
- . and_then ( |uv| uv. sources . as_ref ( ) )
235
- . unwrap_or ( & empty) ,
236
- SourceStrategy :: Disabled => & empty,
211
+ // Determine the lock mode.
212
+ let mode = if frozen {
213
+ LockMode :: Frozen
214
+ } else if locked {
215
+ LockMode :: Locked ( & interpreter)
216
+ } else {
217
+ LockMode :: Write ( & interpreter)
237
218
} ;
238
219
239
- let requirements = dependencies
240
- . into_iter ( )
241
- . flat_map ( |requirement| {
242
- LoweredRequirement :: from_non_workspace_requirement (
243
- requirement,
244
- script_dir. as_ref ( ) ,
245
- script_sources,
246
- script_indexes,
247
- & settings. index_locations ,
248
- LowerBound :: Allow ,
249
- )
250
- . map_ok ( LoweredRequirement :: into_inner)
251
- } )
252
- . collect :: < Result < _ , _ > > ( ) ?;
253
- let constraints = script
254
- . tool
255
- . as_ref ( )
256
- . and_then ( |tool| tool. uv . as_ref ( ) )
257
- . and_then ( |uv| uv. constraint_dependencies . as_ref ( ) )
258
- . into_iter ( )
259
- . flatten ( )
260
- . cloned ( )
261
- . flat_map ( |requirement| {
262
- LoweredRequirement :: from_non_workspace_requirement (
263
- requirement,
264
- script_dir. as_ref ( ) ,
265
- script_sources,
266
- script_indexes,
267
- & settings. index_locations ,
268
- LowerBound :: Allow ,
269
- )
270
- . map_ok ( LoweredRequirement :: into_inner)
271
- } )
272
- . collect :: < Result < Vec < _ > , _ > > ( ) ?;
273
- let overrides = script
274
- . tool
275
- . as_ref ( )
276
- . and_then ( |tool| tool. uv . as_ref ( ) )
277
- . and_then ( |uv| uv. override_dependencies . as_ref ( ) )
278
- . into_iter ( )
279
- . flatten ( )
280
- . cloned ( )
281
- . flat_map ( |requirement| {
282
- LoweredRequirement :: from_non_workspace_requirement (
283
- requirement,
284
- script_dir. as_ref ( ) ,
285
- script_sources,
286
- script_indexes,
287
- & settings. index_locations ,
288
- LowerBound :: Allow ,
289
- )
290
- . map_ok ( LoweredRequirement :: into_inner)
291
- } )
292
- . collect :: < Result < Vec < _ > , _ > > ( ) ?;
293
-
294
- let spec =
295
- RequirementsSpecification :: from_overrides ( requirements, constraints, overrides) ;
296
- let result = CachedEnvironment :: get_or_create (
297
- EnvironmentSpecification :: from ( spec) ,
298
- interpreter,
299
- & settings,
220
+ // Generate a lockfile.
221
+ let lock = project:: lock:: do_safe_lock (
222
+ mode,
223
+ target,
224
+ settings. as_ref ( ) . into ( ) ,
225
+ LowerBound :: Allow ,
300
226
& state,
301
227
if show_resolution {
302
228
Box :: new ( DefaultResolveLogger )
303
229
} else {
304
230
Box :: new ( SummaryResolveLogger )
305
231
} ,
232
+ connectivity,
233
+ concurrency,
234
+ native_tls,
235
+ allow_insecure_host,
236
+ cache,
237
+ printer,
238
+ preview,
239
+ )
240
+ . await ?
241
+ . into_lock ( ) ;
242
+
243
+ let result = CachedEnvironment :: from_lock (
244
+ InstallTarget :: Script {
245
+ script : script. as_script ( ) . unwrap ( ) ,
246
+ lock : & lock,
247
+ } ,
248
+ & ExtrasSpecification :: default ( ) ,
249
+ & DevGroupsManifest :: default ( ) ,
250
+ InstallOptions :: default ( ) ,
251
+ & settings,
252
+ interpreter,
253
+ & state,
306
254
if show_resolution {
307
255
Box :: new ( DefaultInstallLogger )
308
256
} else {
@@ -331,19 +279,151 @@ pub(crate) async fn run(
331
279
332
280
Some ( environment. into_interpreter ( ) )
333
281
} else {
334
- // Create a virtual environment.
335
- temp_dir = cache. venv_dir ( ) ?;
336
- let environment = uv_virtualenv:: create_venv (
337
- temp_dir. path ( ) ,
338
- interpreter,
339
- uv_virtualenv:: Prompt :: None ,
340
- false ,
341
- false ,
342
- false ,
343
- false ,
344
- ) ?;
282
+ // Determine the working directory for the script.
283
+ let script_dir = match & script {
284
+ Pep723Item :: Script ( script) => std:: path:: absolute ( & script. path ) ?
285
+ . parent ( )
286
+ . expect ( "script path has no parent" )
287
+ . to_owned ( ) ,
288
+ Pep723Item :: Stdin ( ..) | Pep723Item :: Remote ( ..) => std:: env:: current_dir ( ) ?,
289
+ } ;
290
+ let script = script. into_metadata ( ) ;
291
+
292
+ // Install the script requirements, if necessary. Otherwise, use an isolated environment.
293
+ if let Some ( dependencies) = script. dependencies {
294
+ // Collect any `tool.uv.index` from the script.
295
+ let empty = Vec :: default ( ) ;
296
+ let script_indexes = match settings. sources {
297
+ SourceStrategy :: Enabled => script
298
+ . tool
299
+ . as_ref ( )
300
+ . and_then ( |tool| tool. uv . as_ref ( ) )
301
+ . and_then ( |uv| uv. top_level . index . as_deref ( ) )
302
+ . unwrap_or ( & empty) ,
303
+ SourceStrategy :: Disabled => & empty,
304
+ } ;
345
305
346
- Some ( environment. into_interpreter ( ) )
306
+ // Collect any `tool.uv.sources` from the script.
307
+ let empty = BTreeMap :: default ( ) ;
308
+ let script_sources = match settings. sources {
309
+ SourceStrategy :: Enabled => script
310
+ . tool
311
+ . as_ref ( )
312
+ . and_then ( |tool| tool. uv . as_ref ( ) )
313
+ . and_then ( |uv| uv. sources . as_ref ( ) )
314
+ . unwrap_or ( & empty) ,
315
+ SourceStrategy :: Disabled => & empty,
316
+ } ;
317
+
318
+ let requirements = dependencies
319
+ . into_iter ( )
320
+ . flat_map ( |requirement| {
321
+ LoweredRequirement :: from_non_workspace_requirement (
322
+ requirement,
323
+ script_dir. as_ref ( ) ,
324
+ script_sources,
325
+ script_indexes,
326
+ & settings. index_locations ,
327
+ LowerBound :: Allow ,
328
+ )
329
+ . map_ok ( LoweredRequirement :: into_inner)
330
+ } )
331
+ . collect :: < Result < _ , _ > > ( ) ?;
332
+ let constraints = script
333
+ . tool
334
+ . as_ref ( )
335
+ . and_then ( |tool| tool. uv . as_ref ( ) )
336
+ . and_then ( |uv| uv. constraint_dependencies . as_ref ( ) )
337
+ . into_iter ( )
338
+ . flatten ( )
339
+ . cloned ( )
340
+ . flat_map ( |requirement| {
341
+ LoweredRequirement :: from_non_workspace_requirement (
342
+ requirement,
343
+ script_dir. as_ref ( ) ,
344
+ script_sources,
345
+ script_indexes,
346
+ & settings. index_locations ,
347
+ LowerBound :: Allow ,
348
+ )
349
+ . map_ok ( LoweredRequirement :: into_inner)
350
+ } )
351
+ . collect :: < Result < Vec < _ > , _ > > ( ) ?;
352
+ let overrides = script
353
+ . tool
354
+ . as_ref ( )
355
+ . and_then ( |tool| tool. uv . as_ref ( ) )
356
+ . and_then ( |uv| uv. override_dependencies . as_ref ( ) )
357
+ . into_iter ( )
358
+ . flatten ( )
359
+ . cloned ( )
360
+ . flat_map ( |requirement| {
361
+ LoweredRequirement :: from_non_workspace_requirement (
362
+ requirement,
363
+ script_dir. as_ref ( ) ,
364
+ script_sources,
365
+ script_indexes,
366
+ & settings. index_locations ,
367
+ LowerBound :: Allow ,
368
+ )
369
+ . map_ok ( LoweredRequirement :: into_inner)
370
+ } )
371
+ . collect :: < Result < Vec < _ > , _ > > ( ) ?;
372
+
373
+ let spec =
374
+ RequirementsSpecification :: from_overrides ( requirements, constraints, overrides) ;
375
+ let result = CachedEnvironment :: from_spec (
376
+ EnvironmentSpecification :: from ( spec) ,
377
+ interpreter,
378
+ & settings,
379
+ & state,
380
+ if show_resolution {
381
+ Box :: new ( DefaultResolveLogger )
382
+ } else {
383
+ Box :: new ( SummaryResolveLogger )
384
+ } ,
385
+ if show_resolution {
386
+ Box :: new ( DefaultInstallLogger )
387
+ } else {
388
+ Box :: new ( SummaryInstallLogger )
389
+ } ,
390
+ installer_metadata,
391
+ connectivity,
392
+ concurrency,
393
+ native_tls,
394
+ allow_insecure_host,
395
+ cache,
396
+ printer,
397
+ preview,
398
+ )
399
+ . await ;
400
+
401
+ let environment = match result {
402
+ Ok ( resolution) => resolution,
403
+ Err ( ProjectError :: Operation ( err) ) => {
404
+ return diagnostics:: OperationDiagnostic :: with_context ( "script" )
405
+ . report ( err)
406
+ . map_or ( Ok ( ExitStatus :: Failure ) , |err| Err ( err. into ( ) ) )
407
+ }
408
+ Err ( err) => return Err ( err. into ( ) ) ,
409
+ } ;
410
+
411
+ Some ( environment. into_interpreter ( ) )
412
+ } else {
413
+ // Create a virtual environment.
414
+ temp_dir = cache. venv_dir ( ) ?;
415
+ let environment = uv_virtualenv:: create_venv (
416
+ temp_dir. path ( ) ,
417
+ interpreter,
418
+ uv_virtualenv:: Prompt :: None ,
419
+ false ,
420
+ false ,
421
+ false ,
422
+ false ,
423
+ ) ?;
424
+
425
+ Some ( environment. into_interpreter ( ) )
426
+ }
347
427
}
348
428
} else {
349
429
None
@@ -846,7 +926,7 @@ pub(crate) async fn run(
846
926
Some ( spec) => {
847
927
debug ! ( "Syncing ephemeral requirements" ) ;
848
928
849
- let result = CachedEnvironment :: get_or_create (
929
+ let result = CachedEnvironment :: from_spec (
850
930
EnvironmentSpecification :: from ( spec) . with_lock (
851
931
lock. as_ref ( )
852
932
. map ( |( lock, install_path) | ( lock, install_path. as_ref ( ) ) ) ,
0 commit comments