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 } ;
18use anyhow:: { Context , Result } ;
2- use itertools:: Itertools ;
3-
49use 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 ;
717use uv_cache:: Cache ;
818use uv_client:: { Connectivity , FlatIndexClient , RegistryClientBuilder } ;
919use uv_configuration:: {
@@ -18,16 +28,9 @@ use uv_python::{PythonDownloads, PythonEnvironment, PythonPreference, PythonRequ
1828use uv_resolver:: { FlatIndex , Lock } ;
1929use uv_types:: { BuildIsolation , HashStrategy } ;
2030use uv_warnings:: warn_user;
31+ use uv_workspace:: pyproject:: { Source , ToolUvSources } ;
2132use uv_workspace:: { DiscoveryOptions , InstallTarget , MemberDiscovery , VirtualProject , Workspace } ;
2233
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-
3134/// Sync the project environment.
3235#[ allow( clippy:: fn_params_excessive_bools) ]
3336pub ( crate ) async fn sync (
@@ -250,9 +253,12 @@ pub(super) async fn do_sync(
250253
251254 // Add all authenticated sources to the cache.
252255 for url in index_locations. urls ( ) {
253- store_credentials_from_url ( url) ;
256+ uv_auth :: store_credentials_from_url ( url) ;
254257 }
255258
259+ // Populate credentials from the workspace.
260+ store_credentials_from_workspace ( target. workspace ( ) ) ;
261+
256262 // Initialize the registry client.
257263 let client = RegistryClientBuilder :: new ( cache. clone ( ) )
258264 . native_tls ( native_tls)
@@ -399,3 +405,78 @@ fn apply_editable_mode(
399405 } ) ,
400406 }
401407}
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