1
- use std:: str:: FromStr ;
2
-
3
1
use anyhow:: Result ;
2
+ use uv_client:: { BaseClientBuilder , Connectivity , FlatIndexClient , RegistryClientBuilder } ;
3
+ use uv_dispatch:: BuildDispatch ;
4
+ use uv_distribution:: pyproject_mut:: PyProjectTomlMut ;
5
+ use uv_git:: GitResolver ;
6
+ use uv_requirements:: { NamedRequirementsResolver , RequirementsSource , RequirementsSpecification } ;
7
+ use uv_resolver:: { FlatIndex , InMemoryIndex , OptionsBuilder } ;
8
+ use uv_types:: { BuildIsolation , HashStrategy , InFlight } ;
4
9
5
- use pep508_rs:: Requirement ;
6
10
use uv_cache:: Cache ;
7
- use uv_client :: Connectivity ;
8
- use uv_configuration :: { Concurrency , ExtrasSpecification , PreviewMode } ;
9
- use uv_distribution :: pyproject_mut :: PyProjectTomlMut ;
10
- use uv_distribution:: ProjectWorkspace ;
11
+ use uv_configuration :: {
12
+ Concurrency , ConfigSettings , ExtrasSpecification , PreviewMode , SetupPyStrategy ,
13
+ } ;
14
+ use uv_distribution:: { DistributionDatabase , ProjectWorkspace } ;
11
15
use uv_warnings:: warn_user;
12
16
17
+ use crate :: commands:: pip:: resolution_environment;
18
+ use crate :: commands:: reporters:: ResolverReporter ;
13
19
use crate :: commands:: { project, ExitStatus } ;
14
20
use crate :: printer:: Printer ;
15
21
use crate :: settings:: { InstallerSettings , ResolverSettings } ;
16
22
17
23
/// Add one or more packages to the project requirements.
18
24
#[ allow( clippy:: too_many_arguments) ]
19
25
pub ( crate ) async fn add (
20
- requirements : Vec < String > ,
26
+ requirements : Vec < RequirementsSource > ,
21
27
python : Option < String > ,
28
+ settings : ResolverSettings ,
22
29
preview : PreviewMode ,
23
30
connectivity : Connectivity ,
24
31
concurrency : Concurrency ,
@@ -33,10 +40,93 @@ pub(crate) async fn add(
33
40
// Find the project requirements.
34
41
let project = ProjectWorkspace :: discover ( & std:: env:: current_dir ( ) ?, None ) . await ?;
35
42
43
+ // Discover or create the virtual environment.
44
+ let venv = project:: init_environment ( project. workspace ( ) , python. as_deref ( ) , cache, printer) ?;
45
+
46
+ let client_builder = BaseClientBuilder :: new ( )
47
+ . connectivity ( connectivity)
48
+ . native_tls ( native_tls)
49
+ . keyring ( settings. keyring_provider ) ;
50
+
51
+ // Read the requirements.
52
+ let RequirementsSpecification { requirements, .. } =
53
+ RequirementsSpecification :: from_sources ( & requirements, & [ ] , & [ ] , & client_builder) . await ?;
54
+
55
+ // TODO(charlie): These are all default values. We should consider whether we want to make them
56
+ // optional on the downstream APIs.
57
+ let exclude_newer = None ;
58
+ let python_version = None ;
59
+ let python_platform = None ;
60
+ let hasher = HashStrategy :: default ( ) ;
61
+ let setup_py = SetupPyStrategy :: default ( ) ;
62
+ let config_settings = ConfigSettings :: default ( ) ;
63
+ let build_isolation = BuildIsolation :: default ( ) ;
64
+
65
+ // Use the default settings.
66
+ let settings = ResolverSettings :: default ( ) ;
67
+
68
+ // Determine the environment for the resolution.
69
+ let ( tags, markers) =
70
+ resolution_environment ( python_version, python_platform, venv. interpreter ( ) ) ?;
71
+
72
+ // Initialize the registry client.
73
+ let client = RegistryClientBuilder :: new ( cache. clone ( ) )
74
+ . native_tls ( native_tls)
75
+ . connectivity ( connectivity)
76
+ . index_urls ( settings. index_locations . index_urls ( ) )
77
+ . index_strategy ( settings. index_strategy )
78
+ . keyring ( settings. keyring_provider )
79
+ . markers ( & markers)
80
+ . platform ( venv. interpreter ( ) . platform ( ) )
81
+ . build ( ) ;
82
+
83
+ // Initialize any shared state.
84
+ let git = GitResolver :: default ( ) ;
85
+ let in_flight = InFlight :: default ( ) ;
86
+ let index = InMemoryIndex :: default ( ) ;
87
+
88
+ // Resolve the flat indexes from `--find-links`.
89
+ let flat_index = {
90
+ let client = FlatIndexClient :: new ( & client, cache) ;
91
+ let entries = client. fetch ( settings. index_locations . flat_index ( ) ) . await ?;
92
+ FlatIndex :: from_entries ( entries, Some ( & tags) , & hasher, & settings. build_options )
93
+ } ;
94
+
95
+ // Create a build dispatch.
96
+ let build_dispatch = BuildDispatch :: new (
97
+ & client,
98
+ cache,
99
+ venv. interpreter ( ) ,
100
+ & settings. index_locations ,
101
+ & flat_index,
102
+ & index,
103
+ & git,
104
+ & in_flight,
105
+ setup_py,
106
+ & config_settings,
107
+ build_isolation,
108
+ settings. link_mode ,
109
+ & settings. build_options ,
110
+ concurrency,
111
+ preview,
112
+ )
113
+ . with_options ( OptionsBuilder :: new ( ) . exclude_newer ( exclude_newer) . build ( ) ) ;
114
+
115
+ // Resolve any unnamed requirements.
116
+ let requirements = NamedRequirementsResolver :: new (
117
+ requirements,
118
+ & hasher,
119
+ & index,
120
+ DistributionDatabase :: new ( & client, & build_dispatch, concurrency. downloads , preview) ,
121
+ )
122
+ . with_reporter ( ResolverReporter :: from ( printer) )
123
+ . resolve ( )
124
+ . await ?;
125
+
126
+ // Add the requirements to the `pyproject.toml`.
36
127
let mut pyproject = PyProjectTomlMut :: from_toml ( project. current_project ( ) . pyproject_toml ( ) ) ?;
37
128
for req in requirements {
38
- let req = Requirement :: from_str ( & req) ?;
39
- pyproject. add_dependency ( & req) ?;
129
+ pyproject. add_dependency ( & pep508_rs:: Requirement :: from ( req) ) ?;
40
130
}
41
131
42
132
// Save the modified `pyproject.toml`.
@@ -45,12 +135,6 @@ pub(crate) async fn add(
45
135
pyproject. to_string ( ) ,
46
136
) ?;
47
137
48
- // Discover or create the virtual environment.
49
- let venv = project:: init_environment ( project. workspace ( ) , python. as_deref ( ) , cache, printer) ?;
50
-
51
- // Use the default settings.
52
- let settings = ResolverSettings :: default ( ) ;
53
-
54
138
// Lock and sync the environment.
55
139
let lock = project:: lock:: do_lock (
56
140
project. workspace ( ) ,
0 commit comments