1
+ use crate :: commands:: pip:: loggers:: { DefaultInstallLogger , DefaultResolveLogger , InstallLogger } ;
2
+ use crate :: commands:: pip:: operations:: Modifications ;
3
+ use crate :: commands:: project:: lock:: do_safe_lock;
4
+ use crate :: commands:: project:: { ProjectError , SharedState } ;
5
+ use crate :: commands:: { pip, project, ExitStatus } ;
6
+ use crate :: printer:: Printer ;
7
+ use crate :: settings:: { InstallerSettingsRef , ResolverInstallerSettings } ;
1
8
use anyhow:: { Context , Result } ;
2
- use itertools:: Itertools ;
3
-
4
9
use distribution_types:: { DirectorySourceDist , Dist , ResolvedDist , SourceDist } ;
5
- use pep508_rs:: MarkerTree ;
6
- use uv_auth:: store_credentials_from_url;
10
+ use itertools:: Itertools ;
11
+ use pep508_rs:: { MarkerTree , Requirement , VersionOrUrl } ;
12
+ use pypi_types:: {
13
+ LenientRequirement , ParsedArchiveUrl , ParsedGitUrl , ParsedUrl , VerbatimParsedUrl ,
14
+ } ;
15
+ use std:: borrow:: Cow ;
16
+ use std:: str:: FromStr ;
7
17
use uv_cache:: Cache ;
8
18
use uv_client:: { Connectivity , FlatIndexClient , RegistryClientBuilder } ;
9
19
use uv_configuration:: {
@@ -18,16 +28,9 @@ use uv_python::{PythonDownloads, PythonEnvironment, PythonPreference, PythonRequ
18
28
use uv_resolver:: { FlatIndex , Lock } ;
19
29
use uv_types:: { BuildIsolation , HashStrategy } ;
20
30
use uv_warnings:: warn_user;
31
+ use uv_workspace:: pyproject:: { Source , ToolUvSources } ;
21
32
use uv_workspace:: { DiscoveryOptions , InstallTarget , MemberDiscovery , VirtualProject , Workspace } ;
22
33
23
- use crate :: commands:: pip:: loggers:: { DefaultInstallLogger , DefaultResolveLogger , InstallLogger } ;
24
- use crate :: commands:: pip:: operations:: Modifications ;
25
- use crate :: commands:: project:: lock:: do_safe_lock;
26
- use crate :: commands:: project:: { ProjectError , SharedState } ;
27
- use crate :: commands:: { pip, project, ExitStatus } ;
28
- use crate :: printer:: Printer ;
29
- use crate :: settings:: { InstallerSettingsRef , ResolverInstallerSettings } ;
30
-
31
34
/// Sync the project environment.
32
35
#[ allow( clippy:: fn_params_excessive_bools) ]
33
36
pub ( crate ) async fn sync (
@@ -250,9 +253,12 @@ pub(super) async fn do_sync(
250
253
251
254
// Add all authenticated sources to the cache.
252
255
for url in index_locations. urls ( ) {
253
- store_credentials_from_url ( url) ;
256
+ uv_auth :: store_credentials_from_url ( url) ;
254
257
}
255
258
259
+ // Populate credentials from the workspace.
260
+ store_credentials_from_workspace ( target. workspace ( ) ) ;
261
+
256
262
// Initialize the registry client.
257
263
let client = RegistryClientBuilder :: new ( cache. clone ( ) )
258
264
. native_tls ( native_tls)
@@ -399,3 +405,78 @@ fn apply_editable_mode(
399
405
} ) ,
400
406
}
401
407
}
408
+
409
+ fn store_credentials_from_workspace ( workspace : & Workspace ) {
410
+ for member in workspace. packages ( ) . values ( ) {
411
+ // Iterate over the `tool.uv.sources`.
412
+ for source in member
413
+ . pyproject_toml ( )
414
+ . tool
415
+ . as_ref ( )
416
+ . and_then ( |tool| tool. uv . as_ref ( ) )
417
+ . and_then ( |uv| uv. sources . as_ref ( ) )
418
+ . map ( ToolUvSources :: inner)
419
+ . iter ( )
420
+ . flat_map ( |sources| sources. values ( ) )
421
+ {
422
+ match source {
423
+ Source :: Git { git, .. } => {
424
+ uv_git:: store_credentials_from_url ( git) ;
425
+ }
426
+ Source :: Url { url, .. } => {
427
+ uv_auth:: store_credentials_from_url ( url) ;
428
+ }
429
+ _ => { }
430
+ }
431
+ }
432
+
433
+ // Iterate over all dependencies.
434
+ let dependencies = member
435
+ . pyproject_toml ( )
436
+ . project
437
+ . as_ref ( )
438
+ . and_then ( |project| project. dependencies . as_ref ( ) )
439
+ . into_iter ( )
440
+ . flatten ( ) ;
441
+ let optional_dependencies = member
442
+ . pyproject_toml ( )
443
+ . project
444
+ . as_ref ( )
445
+ . and_then ( |project| project. optional_dependencies . as_ref ( ) )
446
+ . into_iter ( )
447
+ . flat_map ( |optional| optional. values ( ) )
448
+ . flatten ( ) ;
449
+ let dev_dependencies = member
450
+ . pyproject_toml ( )
451
+ . tool
452
+ . as_ref ( )
453
+ . and_then ( |tool| tool. uv . as_ref ( ) )
454
+ . and_then ( |uv| uv. dev_dependencies . as_ref ( ) )
455
+ . into_iter ( )
456
+ . flatten ( ) ;
457
+
458
+ for requirement in dependencies
459
+ . chain ( optional_dependencies)
460
+ . filter_map ( |requires_dist| {
461
+ LenientRequirement :: < VerbatimParsedUrl > :: from_str ( requires_dist)
462
+ . map ( Requirement :: from)
463
+ . map ( Cow :: Owned )
464
+ . ok ( )
465
+ } )
466
+ . chain ( dev_dependencies. map ( Cow :: Borrowed ) )
467
+ {
468
+ let Some ( VersionOrUrl :: Url ( url) ) = & requirement. version_or_url else {
469
+ continue ;
470
+ } ;
471
+ match & url. parsed_url {
472
+ ParsedUrl :: Git ( ParsedGitUrl { url, .. } ) => {
473
+ uv_git:: store_credentials_from_url ( url. repository ( ) ) ;
474
+ }
475
+ ParsedUrl :: Archive ( ParsedArchiveUrl { url, .. } ) => {
476
+ uv_auth:: store_credentials_from_url ( url) ;
477
+ }
478
+ _ => { }
479
+ }
480
+ }
481
+ }
482
+ }
0 commit comments