@@ -9,23 +9,27 @@ use install_wheel_rs::linker::LinkMode;
9
9
use pep508_rs:: MarkerEnvironment ;
10
10
use platform_tags:: Tags ;
11
11
use pypi_types:: Yanked ;
12
+ use tracing:: debug;
12
13
use uv_cache:: Cache ;
13
- use uv_client:: RegistryClient ;
14
- use uv_configuration:: { Concurrency , Constraints , NoBinary , Overrides , Reinstall } ;
14
+ use uv_client:: { BaseClientBuilder , RegistryClient , RegistryClientBuilder } ;
15
+ use uv_configuration:: {
16
+ Concurrency , ConfigSettings , Constraints , NoBinary , NoBuild , Overrides , PreviewMode , Reinstall ,
17
+ SetupPyStrategy ,
18
+ } ;
15
19
use uv_dispatch:: BuildDispatch ;
16
20
use uv_distribution:: DistributionDatabase ;
17
21
use uv_fs:: Simplified ;
18
- use uv_installer:: { Downloader , Plan , Planner , SitePackages } ;
22
+ use uv_installer:: { Downloader , Plan , Planner , SatisfiesResult , SitePackages } ;
19
23
use uv_interpreter:: { find_default_python, Interpreter , PythonEnvironment } ;
20
24
use uv_requirements:: {
21
- ExtrasSpecification , LookaheadResolver , NamedRequirementsResolver , RequirementsSpecification ,
22
- SourceTreeResolver ,
25
+ ExtrasSpecification , LookaheadResolver , NamedRequirementsResolver , RequirementsSource ,
26
+ RequirementsSpecification , SourceTreeResolver ,
23
27
} ;
24
28
use uv_resolver:: {
25
- Exclusions , FlatIndex , InMemoryIndex , Manifest , Options , PythonRequirement , ResolutionGraph ,
26
- Resolver ,
29
+ Exclusions , FlatIndex , InMemoryIndex , Manifest , Options , OptionsBuilder , PythonRequirement ,
30
+ ResolutionGraph , Resolver ,
27
31
} ;
28
- use uv_types:: { HashStrategy , InFlight , InstalledPackagesProvider } ;
32
+ use uv_types:: { BuildIsolation , HashStrategy , InFlight , InstalledPackagesProvider } ;
29
33
30
34
use crate :: commands:: project:: discovery:: Project ;
31
35
use crate :: commands:: reporters:: { DownloadReporter , InstallReporter , ResolverReporter } ;
@@ -434,3 +438,155 @@ pub(crate) async fn install(
434
438
435
439
Ok ( ( ) )
436
440
}
441
+
442
+ /// Update a [`PythonEnvironment`] to satisfy a set of [`RequirementsSource`]s.
443
+ async fn update_environment (
444
+ venv : PythonEnvironment ,
445
+ requirements : & [ RequirementsSource ] ,
446
+ preview : PreviewMode ,
447
+ cache : & Cache ,
448
+ printer : Printer ,
449
+ ) -> Result < PythonEnvironment > {
450
+ // TODO(zanieb): Support client configuration
451
+ let client_builder = BaseClientBuilder :: default ( ) ;
452
+
453
+ // Read all requirements from the provided sources.
454
+ // TODO(zanieb): Consider allowing constraints and extras
455
+ // TODO(zanieb): Allow specifying extras somehow
456
+ let spec = RequirementsSpecification :: from_sources (
457
+ requirements,
458
+ & [ ] ,
459
+ & [ ] ,
460
+ & ExtrasSpecification :: None ,
461
+ & client_builder,
462
+ preview,
463
+ )
464
+ . await ?;
465
+
466
+ // Check if the current environment satisfies the requirements
467
+ let site_packages = SitePackages :: from_executable ( & venv) ?;
468
+
469
+ // If the requirements are already satisfied, we're done.
470
+ if spec. source_trees . is_empty ( ) {
471
+ match site_packages. satisfies ( & spec. requirements , & spec. editables , & spec. constraints ) ? {
472
+ SatisfiesResult :: Fresh {
473
+ recursive_requirements,
474
+ } => {
475
+ debug ! (
476
+ "All requirements satisfied: {}" ,
477
+ recursive_requirements
478
+ . iter( )
479
+ . map( |entry| entry. requirement. to_string( ) )
480
+ . sorted( )
481
+ . join( " | " )
482
+ ) ;
483
+ debug ! (
484
+ "All editables satisfied: {}" ,
485
+ spec. editables. iter( ) . map( ToString :: to_string) . join( ", " )
486
+ ) ;
487
+ return Ok ( venv) ;
488
+ }
489
+ SatisfiesResult :: Unsatisfied ( requirement) => {
490
+ debug ! ( "At least one requirement is not satisfied: {requirement}" ) ;
491
+ }
492
+ }
493
+ }
494
+
495
+ // Determine the tags, markers, and interpreter to use for resolution.
496
+ let interpreter = venv. interpreter ( ) . clone ( ) ;
497
+ let tags = venv. interpreter ( ) . tags ( ) ?;
498
+ let markers = venv. interpreter ( ) . markers ( ) ;
499
+
500
+ // Initialize the registry client.
501
+ // TODO(zanieb): Support client options e.g. offline, tls, etc.
502
+ let client = RegistryClientBuilder :: new ( cache. clone ( ) )
503
+ . markers ( markers)
504
+ . platform ( venv. interpreter ( ) . platform ( ) )
505
+ . build ( ) ;
506
+
507
+ // TODO(charlie): Respect project configuration.
508
+ let build_isolation = BuildIsolation :: default ( ) ;
509
+ let config_settings = ConfigSettings :: default ( ) ;
510
+ let flat_index = FlatIndex :: default ( ) ;
511
+ let hasher = HashStrategy :: default ( ) ;
512
+ let in_flight = InFlight :: default ( ) ;
513
+ let index = InMemoryIndex :: default ( ) ;
514
+ let index_locations = IndexLocations :: default ( ) ;
515
+ let link_mode = LinkMode :: default ( ) ;
516
+ let no_binary = NoBinary :: default ( ) ;
517
+ let no_build = NoBuild :: default ( ) ;
518
+ let setup_py = SetupPyStrategy :: default ( ) ;
519
+ let concurrency = Concurrency :: default ( ) ;
520
+
521
+ // Create a build dispatch.
522
+ let build_dispatch = BuildDispatch :: new (
523
+ & client,
524
+ cache,
525
+ & interpreter,
526
+ & index_locations,
527
+ & flat_index,
528
+ & index,
529
+ & in_flight,
530
+ setup_py,
531
+ & config_settings,
532
+ build_isolation,
533
+ link_mode,
534
+ & no_build,
535
+ & no_binary,
536
+ concurrency,
537
+ ) ;
538
+
539
+ let options = OptionsBuilder :: new ( )
540
+ // TODO(zanieb): Support resolver options
541
+ // .resolution_mode(resolution_mode)
542
+ // .prerelease_mode(prerelease_mode)
543
+ // .dependency_mode(dependency_mode)
544
+ // .exclude_newer(exclude_newer)
545
+ . build ( ) ;
546
+
547
+ // Resolve the requirements.
548
+ let resolution = match resolve (
549
+ spec,
550
+ site_packages. clone ( ) ,
551
+ & hasher,
552
+ & interpreter,
553
+ tags,
554
+ markers,
555
+ & client,
556
+ & flat_index,
557
+ & index,
558
+ & build_dispatch,
559
+ options,
560
+ printer,
561
+ concurrency,
562
+ )
563
+ . await
564
+ {
565
+ Ok ( resolution) => Resolution :: from ( resolution) ,
566
+ Err ( err) => return Err ( err. into ( ) ) ,
567
+ } ;
568
+
569
+ // Re-initialize the in-flight map.
570
+ let in_flight = InFlight :: default ( ) ;
571
+
572
+ // Sync the environment.
573
+ install (
574
+ & resolution,
575
+ site_packages,
576
+ & no_binary,
577
+ link_mode,
578
+ & index_locations,
579
+ & hasher,
580
+ tags,
581
+ & client,
582
+ & in_flight,
583
+ & build_dispatch,
584
+ cache,
585
+ & venv,
586
+ printer,
587
+ concurrency,
588
+ )
589
+ . await ?;
590
+
591
+ Ok ( venv)
592
+ }
0 commit comments