1use std::env;
2use std::error::Error;
3use std::fmt;
4
5use anyhow::bail;
6
7use uv_cache::Refresh;
8use uv_configuration::{
9 BuildIsolation, ExcludeNewerPackage, PrereleaseMode, PrereleasePackage, Reinstall, Upgrade,
10};
11use uv_distribution_types::{ConfigSettings, Index, PackageConfigSettings, Requirement};
12use uv_normalize::PackageName;
13use uv_settings::{
14 Combine, EnvFlag, IndexOptions, PipOptions, ResolverInstallerOptions, ResolverOptions,
15};
16use uv_warnings::owo_colors::OwoColorize;
17
18use crate::{
19 BuildIsolationArgs, BuildOptionsArgs, CompileBytecodeArgs, ExcludeNewerArgs, FetchArgs,
20 IndexArgs, InstallerArgs, Maybe, PackageBuildIsolationArgs, PackageExcludeNewerArgs,
21 RefreshArgs, RegistryClientArgs, ReinstallArgs, ResolverArgs, ResolverInstallerArgs,
22 SourcesArgs, UpgradeArgs, VersionSelectionArgs,
23};
24
25#[derive(Debug)]
27pub struct ArgumentError(String);
28
29impl fmt::Display for ArgumentError {
30 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
31 self.0.fmt(formatter)
32 }
33}
34
35impl Error for ArgumentError {}
36
37pub(crate) fn flag(yes: bool, no: bool, name: &str) -> anyhow::Result<Option<bool>> {
39 debug_assert!(
40 !name.starts_with("no-"),
41 "flag names must not include the `no-` prefix"
42 );
43
44 match (yes, no) {
45 (true, false) => Ok(Some(true)),
46 (false, true) => Ok(Some(false)),
47 (false, false) => Ok(None),
48 (..) => {
49 bail!(ArgumentError(format!(
50 "`{}` and `{}` cannot be used together. \
51 Boolean flags on different levels are currently not supported \
52 (https://github.com/clap-rs/clap/issues/6049)",
53 format!("--{name}").green(),
54 format!("--no-{name}").green(),
55 )));
56 }
57 }
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub(crate) enum FlagSource {
63 Cli,
65 Env(&'static str),
67 Config,
69}
70
71impl fmt::Display for FlagSource {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 match self {
74 Self::Cli => write!(f, "command-line argument"),
75 Self::Env(name) => write!(f, "environment variable `{name}`"),
76 Self::Config => write!(f, "workspace configuration"),
77 }
78 }
79}
80
81#[derive(Debug, Clone, Copy)]
83pub(crate) enum Flag {
84 Disabled,
86 Enabled {
88 source: FlagSource,
89 name: &'static str,
91 },
92}
93
94impl Flag {
95 pub(crate) const fn disabled() -> Self {
97 Self::Disabled
98 }
99
100 pub(crate) const fn from_cli(name: &'static str) -> Self {
102 Self::Enabled {
103 source: FlagSource::Cli,
104 name,
105 }
106 }
107
108 pub(crate) const fn from_config(name: &'static str) -> Self {
110 Self::Enabled {
111 source: FlagSource::Config,
112 name,
113 }
114 }
115
116 pub(crate) fn is_enabled(self) -> bool {
118 matches!(self, Self::Enabled { .. })
119 }
120}
121
122impl From<Flag> for bool {
123 fn from(flag: Flag) -> Self {
124 flag.is_enabled()
125 }
126}
127
128pub(crate) fn resolve_flag(cli_flag: bool, name: &'static str, env_flag: EnvFlag) -> Flag {
133 if cli_flag {
134 Flag::Enabled {
135 source: FlagSource::Cli,
136 name,
137 }
138 } else if env_flag.value == Some(true) {
139 Flag::Enabled {
140 source: FlagSource::Env(env_flag.env_var),
141 name,
142 }
143 } else {
144 Flag::Disabled
145 }
146}
147
148pub(crate) fn resolve_flag_pair(
153 cli_flag: bool,
154 cli_no_flag: bool,
155 name: &'static str,
156 no_name: &'static str,
157 env_flag: Option<EnvFlag>,
158 env_no_flag: Option<EnvFlag>,
159) -> (Flag, Flag) {
160 if cli_flag || cli_no_flag {
161 (
162 if cli_flag {
163 Flag::from_cli(name)
164 } else {
165 Flag::disabled()
166 },
167 if cli_no_flag {
168 Flag::from_cli(no_name)
169 } else {
170 Flag::disabled()
171 },
172 )
173 } else {
174 (
175 env_flag.map_or_else(Flag::disabled, |env_flag| {
176 resolve_flag(false, name, env_flag)
177 }),
178 env_no_flag.map_or_else(Flag::disabled, |env_no_flag| {
179 resolve_flag(false, no_name, env_no_flag)
180 }),
181 )
182 }
183}
184
185pub(crate) fn check_conflicts(flag_a: Flag, flag_b: Flag) -> anyhow::Result<()> {
190 if let (
191 Flag::Enabled {
192 source: source_a,
193 name: name_a,
194 },
195 Flag::Enabled {
196 source: source_b,
197 name: name_b,
198 },
199 ) = (flag_a, flag_b)
200 {
201 let display_a = match source_a {
202 FlagSource::Cli => format!("`--{name_a}`"),
203 FlagSource::Env(env) => format!("`{env}` (environment variable)"),
204 FlagSource::Config => format!("`{name_a}` (workspace configuration)"),
205 };
206 let display_b = match source_b {
207 FlagSource::Cli => format!("`--{name_b}`"),
208 FlagSource::Env(env) => format!("`{env}` (environment variable)"),
209 FlagSource::Config => format!("`{name_b}` (workspace configuration)"),
210 };
211 bail!(ArgumentError(format!(
212 "the argument {} cannot be used with {}",
213 display_a.green(),
214 display_b.green()
215 )));
216 }
217 Ok(())
218}
219
220impl TryFrom<RefreshArgs> for Refresh {
221 type Error = anyhow::Error;
222
223 fn try_from(value: RefreshArgs) -> anyhow::Result<Self> {
224 let RefreshArgs {
225 refresh,
226 no_refresh,
227 refresh_package,
228 } = value;
229
230 Ok(Self::from_args(
231 flag(refresh, no_refresh, "refresh")?,
232 refresh_package,
233 ))
234 }
235}
236
237pub(crate) trait IntoPipOptions {
239 fn into_pip_options(self, configured_indexes: &[Index]) -> anyhow::Result<PipOptions>;
241}
242
243impl IntoPipOptions for ResolverArgs {
244 fn into_pip_options(self, configured_indexes: &[Index]) -> anyhow::Result<PipOptions> {
246 let Self {
247 index_args,
248 upgrade,
249 no_upgrade,
250 upgrade_package,
251 upgrade_group,
252 registry_client:
253 RegistryClientArgs {
254 index_strategy,
255 keyring_provider,
256 },
257 version_selection:
258 VersionSelectionArgs {
259 resolution,
260 prerelease,
261 prerelease_package,
262 pre,
263 fork_strategy,
264 },
265 config_setting,
266 config_settings_package,
267 build_isolation:
268 PackageBuildIsolationArgs {
269 build_isolation:
270 BuildIsolationArgs {
271 no_build_isolation,
272 build_isolation,
273 },
274 no_build_isolation_package,
275 },
276 exclude_newer:
277 PackageExcludeNewerArgs {
278 exclude_newer: ExcludeNewerArgs { exclude_newer },
279 exclude_newer_package,
280 },
281 link_mode,
282 sources:
283 SourcesArgs {
284 no_sources,
285 no_sources_package,
286 },
287 } = self;
288
289 if !upgrade_group.is_empty() {
290 bail!(ArgumentError(format!(
291 "`{}` is not supported in `uv pip` commands",
292 "--upgrade-group".green()
293 )));
294 }
295
296 Ok(PipOptions {
297 upgrade: flag(upgrade, no_upgrade, "upgrade")?,
298 upgrade_package: Some(upgrade_package),
299 index_strategy,
300 keyring_provider,
301 resolution,
302 fork_strategy,
303 prerelease: if pre {
304 Some(PrereleaseMode::Allow)
305 } else {
306 prerelease
307 },
308 prerelease_package: prerelease_package.map(PrereleasePackage::from_iter),
309 config_settings: config_setting
310 .map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
311 config_settings_package: config_settings_package.map(|config_settings| {
312 config_settings
313 .into_iter()
314 .collect::<PackageConfigSettings>()
315 }),
316 no_build_isolation: flag(no_build_isolation, build_isolation, "build-isolation")?,
317 no_build_isolation_package: Some(no_build_isolation_package),
318 exclude_newer,
319 exclude_newer_package: exclude_newer_package.map(ExcludeNewerPackage::from_iter),
320 link_mode,
321 no_sources: if no_sources { Some(true) } else { None },
322 no_sources_package: if no_sources_package.is_empty() {
323 None
324 } else {
325 Some(no_sources_package)
326 },
327 ..index_args.into_pip_options(configured_indexes)?
328 })
329 }
330}
331
332impl IntoPipOptions for InstallerArgs {
333 fn into_pip_options(self, configured_indexes: &[Index]) -> anyhow::Result<PipOptions> {
335 let Self {
336 index_args,
337 reinstall:
338 ReinstallArgs {
339 reinstall,
340 no_reinstall,
341 reinstall_package,
342 },
343 registry_client:
344 RegistryClientArgs {
345 index_strategy,
346 keyring_provider,
347 },
348 config_setting,
349 config_settings_package,
350 build_isolation:
351 BuildIsolationArgs {
352 no_build_isolation,
353 build_isolation,
354 },
355 exclude_newer:
356 PackageExcludeNewerArgs {
357 exclude_newer: ExcludeNewerArgs { exclude_newer },
358 exclude_newer_package,
359 },
360 link_mode,
361 compile_bytecode:
362 CompileBytecodeArgs {
363 compile_bytecode,
364 no_compile_bytecode,
365 },
366 sources:
367 SourcesArgs {
368 no_sources,
369 no_sources_package,
370 },
371 } = self;
372
373 Ok(PipOptions {
374 reinstall: flag(reinstall, no_reinstall, "reinstall")?,
375 reinstall_package: Some(reinstall_package),
376 index_strategy,
377 keyring_provider,
378 config_settings: config_setting
379 .map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
380 config_settings_package: config_settings_package.map(|config_settings| {
381 config_settings
382 .into_iter()
383 .collect::<PackageConfigSettings>()
384 }),
385 no_build_isolation: flag(no_build_isolation, build_isolation, "build-isolation")?,
386 exclude_newer,
387 exclude_newer_package: exclude_newer_package.map(ExcludeNewerPackage::from_iter),
388 link_mode,
389 compile_bytecode: flag(compile_bytecode, no_compile_bytecode, "compile-bytecode")?,
390 no_sources: if no_sources { Some(true) } else { None },
391 no_sources_package: if no_sources_package.is_empty() {
392 None
393 } else {
394 Some(no_sources_package)
395 },
396 ..index_args.into_pip_options(configured_indexes)?
397 })
398 }
399}
400
401impl IntoPipOptions for ResolverInstallerArgs {
402 fn into_pip_options(self, configured_indexes: &[Index]) -> anyhow::Result<PipOptions> {
404 let Self {
405 index_args,
406 upgrade,
407 no_upgrade,
408 upgrade_package,
409 upgrade_group,
410 reinstall:
411 ReinstallArgs {
412 reinstall,
413 no_reinstall,
414 reinstall_package,
415 },
416 registry_client:
417 RegistryClientArgs {
418 index_strategy,
419 keyring_provider,
420 },
421 version_selection:
422 VersionSelectionArgs {
423 resolution,
424 prerelease,
425 prerelease_package,
426 pre,
427 fork_strategy,
428 },
429 config_setting,
430 config_settings_package,
431 build_isolation:
432 PackageBuildIsolationArgs {
433 build_isolation:
434 BuildIsolationArgs {
435 no_build_isolation,
436 build_isolation,
437 },
438 no_build_isolation_package,
439 },
440 exclude_newer:
441 PackageExcludeNewerArgs {
442 exclude_newer: ExcludeNewerArgs { exclude_newer },
443 exclude_newer_package,
444 },
445 link_mode,
446 compile_bytecode:
447 CompileBytecodeArgs {
448 compile_bytecode,
449 no_compile_bytecode,
450 },
451 sources:
452 SourcesArgs {
453 no_sources,
454 no_sources_package,
455 },
456 } = self;
457
458 if !upgrade_group.is_empty() {
459 bail!(ArgumentError(format!(
460 "`{}` is not supported in `uv pip` commands",
461 "--upgrade-group".green()
462 )));
463 }
464
465 Ok(PipOptions {
466 upgrade: flag(upgrade, no_upgrade, "upgrade")?,
467 upgrade_package: Some(upgrade_package),
468 reinstall: flag(reinstall, no_reinstall, "reinstall")?,
469 reinstall_package: Some(reinstall_package),
470 index_strategy,
471 keyring_provider,
472 resolution,
473 prerelease: if pre {
474 Some(PrereleaseMode::Allow)
475 } else {
476 prerelease
477 },
478 prerelease_package: prerelease_package.map(PrereleasePackage::from_iter),
479 fork_strategy,
480 config_settings: config_setting
481 .map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
482 config_settings_package: config_settings_package.map(|config_settings| {
483 config_settings
484 .into_iter()
485 .collect::<PackageConfigSettings>()
486 }),
487 no_build_isolation: flag(no_build_isolation, build_isolation, "build-isolation")?,
488 no_build_isolation_package: Some(no_build_isolation_package),
489 exclude_newer,
490 exclude_newer_package: exclude_newer_package.map(ExcludeNewerPackage::from_iter),
491 link_mode,
492 compile_bytecode: flag(compile_bytecode, no_compile_bytecode, "compile-bytecode")?,
493 no_sources: if no_sources { Some(true) } else { None },
494 no_sources_package: if no_sources_package.is_empty() {
495 None
496 } else {
497 Some(no_sources_package)
498 },
499 ..index_args.into_pip_options(configured_indexes)?
500 })
501 }
502}
503
504impl IntoPipOptions for FetchArgs {
505 fn into_pip_options(self, configured_indexes: &[Index]) -> anyhow::Result<PipOptions> {
507 let Self {
508 index_args,
509 registry_client:
510 RegistryClientArgs {
511 index_strategy,
512 keyring_provider,
513 },
514 exclude_newer:
515 PackageExcludeNewerArgs {
516 exclude_newer: ExcludeNewerArgs { exclude_newer },
517 exclude_newer_package,
518 },
519 } = self;
520
521 Ok(PipOptions {
522 index_strategy,
523 keyring_provider,
524 exclude_newer,
525 exclude_newer_package: exclude_newer_package.map(ExcludeNewerPackage::from_iter),
526 ..index_args.into_pip_options(configured_indexes)?
527 })
528 }
529}
530
531impl IndexArgs {
532 fn resolve(self, configured_indexes: &[Index]) -> anyhow::Result<IndexOptions> {
534 let Self {
535 default_index,
536 index,
537 index_url,
538 extra_index_url,
539 no_index,
540 find_links,
541 } = self;
542
543 let default_index = default_index
544 .and_then(Maybe::into_option)
545 .map(|index| index.resolve(configured_indexes))
546 .transpose()?
547 .map(|index| vec![index]);
548 let index = index
549 .map(|indexes| {
550 indexes
551 .into_iter()
552 .flatten()
553 .filter_map(Maybe::into_option)
554 .map(|index| index.resolve(configured_indexes))
555 .collect::<anyhow::Result<Vec<_>>>()
556 })
557 .transpose()?;
558
559 Ok(IndexOptions {
560 index: default_index.combine(index),
561 index_url: index_url.and_then(Maybe::into_option),
562 extra_index_url: extra_index_url
563 .map(|indexes| indexes.into_iter().filter_map(Maybe::into_option).collect()),
564 no_index: no_index.then_some(true),
565 find_links: find_links
566 .map(|links| links.into_iter().filter_map(Maybe::into_option).collect()),
567 })
568 }
569}
570
571impl IntoPipOptions for IndexArgs {
572 fn into_pip_options(self, configured_indexes: &[Index]) -> anyhow::Result<PipOptions> {
574 Ok(PipOptions::from(
575 self.resolve(configured_indexes)?
576 .relative_to(&env::current_dir()?)?,
577 ))
578 }
579}
580
581pub(crate) fn resolver_options(
583 resolver_args: ResolverArgs,
584 build_args: BuildOptionsArgs,
585 configured_indexes: &[Index],
586) -> anyhow::Result<ResolverOptions> {
587 let ResolverArgs {
588 index_args,
589 upgrade,
590 no_upgrade,
591 upgrade_package,
592 upgrade_group,
593 registry_client:
594 RegistryClientArgs {
595 index_strategy,
596 keyring_provider,
597 },
598 version_selection:
599 VersionSelectionArgs {
600 resolution,
601 prerelease,
602 prerelease_package,
603 pre,
604 fork_strategy,
605 },
606 config_setting,
607 config_settings_package,
608 build_isolation:
609 PackageBuildIsolationArgs {
610 build_isolation:
611 BuildIsolationArgs {
612 no_build_isolation,
613 build_isolation,
614 },
615 no_build_isolation_package,
616 },
617 exclude_newer:
618 PackageExcludeNewerArgs {
619 exclude_newer: ExcludeNewerArgs { exclude_newer },
620 exclude_newer_package,
621 },
622 link_mode,
623 sources: SourcesArgs {
624 no_sources,
625 no_sources_package,
626 },
627 } = resolver_args;
628
629 let BuildOptionsArgs {
630 no_build,
631 build,
632 no_build_package,
633 no_binary,
634 binary,
635 no_binary_package,
636 require_build_hashes,
637 no_require_build_hashes,
638 } = build_args;
639
640 ResolverOptions {
641 indexes: index_args.resolve(configured_indexes)?,
642 upgrade: Upgrade::from_args(
643 flag(upgrade, no_upgrade, "upgrade")?,
644 upgrade_package.into_iter().map(Requirement::from).collect(),
645 upgrade_group,
646 ),
647 index_strategy,
648 keyring_provider,
649 resolution,
650 prerelease: if pre {
651 Some(PrereleaseMode::Allow)
652 } else {
653 prerelease
654 },
655 prerelease_package: prerelease_package.map(PrereleasePackage::from_iter),
656 fork_strategy,
657 dependency_metadata: None,
658 config_settings: config_setting
659 .map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
660 config_settings_package: config_settings_package.map(|config_settings| {
661 config_settings
662 .into_iter()
663 .collect::<PackageConfigSettings>()
664 }),
665 build_isolation: BuildIsolation::from_args(
666 flag(no_build_isolation, build_isolation, "build-isolation")?,
667 no_build_isolation_package,
668 ),
669 require_build_hashes: flag(
670 require_build_hashes,
671 no_require_build_hashes,
672 "require-build-hashes",
673 )?,
674 extra_build_dependencies: None,
675 extra_build_variables: None,
676 exclude_newer,
677 exclude_newer_package: exclude_newer_package.map(ExcludeNewerPackage::from_iter),
678 link_mode,
679 torch_backend: None,
680 no_build: flag(no_build, build, "build")?,
681 no_build_package: if no_build_package.is_empty() {
682 None
683 } else {
684 Some(no_build_package)
685 },
686 no_binary: flag(no_binary, binary, "binary")?,
687 no_binary_package: if no_binary_package.is_empty() {
688 None
689 } else {
690 Some(no_binary_package)
691 },
692 no_sources: if no_sources { Some(true) } else { None },
693 no_sources_package: if no_sources_package.is_empty() {
694 None
695 } else {
696 Some(no_sources_package)
697 },
698 }
699 .relative_to(&env::current_dir()?)
700 .map_err(Into::into)
701}
702
703pub(crate) fn upgrade_options(
705 args: UpgradeArgs,
706 configured_indexes: &[Index],
707) -> anyhow::Result<(Vec<PackageName>, Vec<PackageName>, ResolverOptions)> {
708 let UpgradeArgs {
709 packages,
710 exclude,
711 require_build_hashes,
712 no_require_build_hashes,
713 index_args,
714 registry_client:
715 RegistryClientArgs {
716 index_strategy,
717 keyring_provider,
718 },
719 } = args;
720
721 let options = ResolverOptions {
722 indexes: index_args.resolve(configured_indexes)?,
723 index_strategy,
724 keyring_provider,
725 require_build_hashes: flag(
726 require_build_hashes,
727 no_require_build_hashes,
728 "require-build-hashes",
729 )?,
730 ..ResolverOptions::default()
731 }
732 .relative_to(&env::current_dir()?)?;
733
734 Ok((packages, exclude, options))
735}
736
737pub(crate) fn resolver_installer_options(
739 resolver_installer_args: ResolverInstallerArgs,
740 build_args: BuildOptionsArgs,
741 configured_indexes: &[Index],
742) -> anyhow::Result<ResolverInstallerOptions> {
743 let ResolverInstallerArgs {
744 index_args,
745 upgrade,
746 no_upgrade,
747 upgrade_package,
748 upgrade_group,
749 reinstall:
750 ReinstallArgs {
751 reinstall,
752 no_reinstall,
753 reinstall_package,
754 },
755 registry_client:
756 RegistryClientArgs {
757 index_strategy,
758 keyring_provider,
759 },
760 version_selection:
761 VersionSelectionArgs {
762 resolution,
763 prerelease,
764 prerelease_package,
765 pre,
766 fork_strategy,
767 },
768 config_setting,
769 config_settings_package,
770 build_isolation:
771 PackageBuildIsolationArgs {
772 build_isolation:
773 BuildIsolationArgs {
774 no_build_isolation,
775 build_isolation,
776 },
777 no_build_isolation_package,
778 },
779 exclude_newer:
780 PackageExcludeNewerArgs {
781 exclude_newer: ExcludeNewerArgs { exclude_newer },
782 exclude_newer_package,
783 },
784 link_mode,
785 compile_bytecode:
786 CompileBytecodeArgs {
787 compile_bytecode,
788 no_compile_bytecode,
789 },
790 sources: SourcesArgs {
791 no_sources,
792 no_sources_package,
793 },
794 } = resolver_installer_args;
795
796 let BuildOptionsArgs {
797 no_build,
798 build,
799 no_build_package,
800 no_binary,
801 binary,
802 no_binary_package,
803 require_build_hashes,
804 no_require_build_hashes,
805 } = build_args;
806
807 ResolverInstallerOptions {
808 indexes: index_args.resolve(configured_indexes)?,
809 upgrade: Upgrade::from_args(
810 flag(upgrade, no_upgrade, "upgrade")?,
811 upgrade_package.into_iter().map(Requirement::from).collect(),
812 upgrade_group,
813 ),
814 reinstall: Reinstall::from_args(
815 flag(reinstall, no_reinstall, "reinstall")?,
816 reinstall_package,
817 ),
818 index_strategy,
819 keyring_provider,
820 resolution,
821 prerelease: if pre {
822 Some(PrereleaseMode::Allow)
823 } else {
824 prerelease
825 },
826 prerelease_package: prerelease_package.map(PrereleasePackage::from_iter),
827 fork_strategy,
828 dependency_metadata: None,
829 config_settings: config_setting
830 .map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
831 config_settings_package: config_settings_package.map(|config_settings| {
832 config_settings
833 .into_iter()
834 .collect::<PackageConfigSettings>()
835 }),
836 build_isolation: BuildIsolation::from_args(
837 flag(no_build_isolation, build_isolation, "build-isolation")?,
838 no_build_isolation_package,
839 ),
840 require_build_hashes: flag(
841 require_build_hashes,
842 no_require_build_hashes,
843 "require-build-hashes",
844 )?,
845 extra_build_dependencies: None,
846 extra_build_variables: None,
847 exclude_newer,
848 exclude_newer_package: exclude_newer_package.map(ExcludeNewerPackage::from_iter),
849 link_mode,
850 compile_bytecode: flag(compile_bytecode, no_compile_bytecode, "compile-bytecode")?,
851 no_build: flag(no_build, build, "build")?,
852 no_build_package: if no_build_package.is_empty() {
853 None
854 } else {
855 Some(no_build_package)
856 },
857 no_binary: flag(no_binary, binary, "binary")?,
858 no_binary_package: if no_binary_package.is_empty() {
859 None
860 } else {
861 Some(no_binary_package)
862 },
863 no_sources: if no_sources { Some(true) } else { None },
864 no_sources_package: if no_sources_package.is_empty() {
865 None
866 } else {
867 Some(no_sources_package)
868 },
869 torch_backend: None,
870 }
871 .relative_to(&env::current_dir()?)
872 .map_err(Into::into)
873}