1use anyhow::{Result, anyhow};
2use clap::{Args, ValueEnum};
3
4use uv_warnings::warn_user;
5
6pub trait CompatArgs {
7 fn validate(&self) -> Result<()>;
8}
9
10#[derive(Args)]
16pub struct PipCompileCompatArgs {
17 #[clap(long, hide = true)]
18 allow_unsafe: bool,
19
20 #[clap(long, hide = true)]
21 no_allow_unsafe: bool,
22
23 #[clap(long, hide = true)]
24 reuse_hashes: bool,
25
26 #[clap(long, hide = true)]
27 no_reuse_hashes: bool,
28
29 #[clap(long, hide = true)]
30 resolver: Option<Resolver>,
31
32 #[clap(long, hide = true)]
33 max_rounds: Option<usize>,
34
35 #[clap(long, hide = true)]
36 cert: Option<String>,
37
38 #[clap(long, hide = true)]
39 client_cert: Option<String>,
40
41 #[clap(long, hide = true)]
42 emit_trusted_host: bool,
43
44 #[clap(long, hide = true)]
45 no_emit_trusted_host: bool,
46
47 #[clap(long, hide = true)]
48 config: Option<String>,
49
50 #[clap(long, hide = true)]
51 no_config: bool,
52
53 #[clap(long, hide = true)]
54 emit_options: bool,
55
56 #[clap(long, hide = true)]
57 no_emit_options: bool,
58
59 #[clap(long, hide = true)]
60 pip_args: Option<String>,
61}
62
63impl CompatArgs for PipCompileCompatArgs {
64 fn validate(&self) -> Result<()> {
70 if self.allow_unsafe {
71 warn_user!(
72 "pip-compile's `--allow-unsafe` has no effect (uv can safely pin `pip` and other packages)"
73 );
74 }
75
76 if self.no_allow_unsafe {
77 warn_user!(
78 "pip-compile's `--no-allow-unsafe` has no effect (uv can safely pin `pip` and other packages)"
79 );
80 }
81
82 if self.reuse_hashes {
83 return Err(anyhow!(
84 "pip-compile's `--reuse-hashes` is unsupported (uv doesn't reuse hashes)"
85 ));
86 }
87
88 if self.no_reuse_hashes {
89 warn_user!("pip-compile's `--no-reuse-hashes` has no effect (uv doesn't reuse hashes)");
90 }
91
92 if let Some(resolver) = self.resolver {
93 match resolver {
94 Resolver::Backtracking => {
95 warn_user!(
96 "pip-compile's `--resolver=backtracking` has no effect (uv always backtracks)"
97 );
98 }
99 Resolver::Legacy => {
100 return Err(anyhow!(
101 "pip-compile's `--resolver=legacy` is unsupported (uv always backtracks)"
102 ));
103 }
104 }
105 }
106
107 if self.max_rounds.is_some() {
108 return Err(anyhow!(
109 "pip-compile's `--max-rounds` is unsupported (uv always resolves until convergence)"
110 ));
111 }
112
113 if self.client_cert.is_some() {
114 return Err(anyhow!(
115 "pip-compile's `--client-cert` is unsupported (uv doesn't support dedicated client certificates)"
116 ));
117 }
118
119 if self.emit_trusted_host {
120 return Err(anyhow!(
121 "pip-compile's `--emit-trusted-host` is unsupported"
122 ));
123 }
124
125 if self.no_emit_trusted_host {
126 warn_user!(
127 "pip-compile's `--no-emit-trusted-host` has no effect (uv never emits trusted hosts)"
128 );
129 }
130
131 if self.config.is_some() {
132 return Err(anyhow!(
133 "pip-compile's `--config` is unsupported (uv does not use a configuration file)"
134 ));
135 }
136
137 if self.emit_options {
138 return Err(anyhow!(
139 "pip-compile's `--emit-options` is unsupported (uv never emits options)"
140 ));
141 }
142
143 if self.no_emit_options {
144 warn_user!("pip-compile's `--no-emit-options` has no effect (uv never emits options)");
145 }
146
147 if self.pip_args.is_some() {
148 return Err(anyhow!(
149 "pip-compile's `--pip-args` is unsupported (try passing arguments to uv directly)"
150 ));
151 }
152
153 Ok(())
154 }
155}
156
157#[derive(Args)]
161pub struct PipListCompatArgs {
162 #[clap(long, hide = true)]
163 disable_pip_version_check: bool,
164}
165
166impl CompatArgs for PipListCompatArgs {
167 fn validate(&self) -> Result<()> {
173 if self.disable_pip_version_check {
174 warn_user!("pip's `--disable-pip-version-check` has no effect");
175 }
176
177 Ok(())
178 }
179}
180
181#[derive(Args)]
185pub struct PipSyncCompatArgs {
186 #[clap(short, long, hide = true)]
187 ask: bool,
188
189 #[clap(long, hide = true)]
190 python_executable: Option<String>,
191
192 #[clap(long, hide = true)]
193 user: bool,
194
195 #[clap(long, hide = true)]
196 cert: Option<String>,
197
198 #[clap(long, hide = true)]
199 client_cert: Option<String>,
200
201 #[clap(long, hide = true)]
202 config: Option<String>,
203
204 #[clap(long, hide = true)]
205 no_config: bool,
206
207 #[clap(long, hide = true)]
208 pip_args: Option<String>,
209}
210
211impl CompatArgs for PipSyncCompatArgs {
212 fn validate(&self) -> Result<()> {
218 if self.ask {
219 return Err(anyhow!(
220 "pip-sync's `--ask` is unsupported (uv never asks for confirmation)"
221 ));
222 }
223
224 if self.python_executable.is_some() {
225 return Err(anyhow!(
226 "pip-sync's `--python-executable` is unsupported (to install into a separate Python environment, try setting `VIRTUAL_ENV` instead)"
227 ));
228 }
229
230 if self.user {
231 return Err(anyhow!(
232 "pip-sync's `--user` is unsupported (use a virtual environment instead)"
233 ));
234 }
235
236 if self.client_cert.is_some() {
237 return Err(anyhow!(
238 "pip-sync's `--client-cert` is unsupported (uv doesn't support dedicated client certificates)"
239 ));
240 }
241
242 if self.config.is_some() {
243 return Err(anyhow!(
244 "pip-sync's `--config` is unsupported (uv does not use a configuration file)"
245 ));
246 }
247
248 if self.pip_args.is_some() {
249 return Err(anyhow!(
250 "pip-sync's `--pip-args` is unsupported (try passing arguments to uv directly)"
251 ));
252 }
253
254 Ok(())
255 }
256}
257
258#[derive(Debug, Copy, Clone, ValueEnum)]
259enum Resolver {
260 Backtracking,
261 Legacy,
262}
263
264#[derive(Args)]
268pub struct VenvCompatArgs {
269 #[clap(long, hide = true)]
270 no_seed: bool,
271
272 #[clap(long, hide = true)]
273 no_pip: bool,
274
275 #[clap(long, hide = true)]
276 no_setuptools: bool,
277
278 #[clap(long, hide = true)]
279 no_wheel: bool,
280}
281
282impl CompatArgs for VenvCompatArgs {
283 fn validate(&self) -> Result<()> {
289 if self.no_seed {
290 warn_user!(
291 "virtualenv's `--no-seed` has no effect (uv omits seed packages by default)"
292 );
293 }
294
295 if self.no_pip {
296 warn_user!("virtualenv's `--no-pip` has no effect (uv omits `pip` by default)");
297 }
298
299 if self.no_setuptools {
300 warn_user!(
301 "virtualenv's `--no-setuptools` has no effect (uv omits `setuptools` by default)"
302 );
303 }
304
305 if self.no_wheel {
306 warn_user!("virtualenv's `--no-wheel` has no effect (uv omits `wheel` by default)");
307 }
308
309 Ok(())
310 }
311}
312
313#[derive(Args)]
317pub struct PipInstallCompatArgs {
318 #[clap(long, hide = true)]
319 disable_pip_version_check: bool,
320
321 #[clap(long, hide = false)]
322 user: bool,
323}
324
325impl CompatArgs for PipInstallCompatArgs {
326 fn validate(&self) -> Result<()> {
332 if self.disable_pip_version_check {
333 warn_user!("pip's `--disable-pip-version-check` has no effect");
334 }
335
336 if self.user {
337 return Err(anyhow!(
338 "pip's `--user` is unsupported (use a virtual environment instead)"
339 ));
340 }
341
342 Ok(())
343 }
344}
345
346#[derive(Args)]
350pub struct PipGlobalCompatArgs {
351 #[clap(long, hide = true)]
352 disable_pip_version_check: bool,
353}
354
355impl CompatArgs for PipGlobalCompatArgs {
356 fn validate(&self) -> Result<()> {
362 if self.disable_pip_version_check {
363 warn_user!("pip's `--disable-pip-version-check` has no effect");
364 }
365
366 Ok(())
367 }
368}