@@ -85,19 +85,20 @@ func (p *LocalPluginRuntime) preparePipArgs() []string {
8585 args = append (args , "-vvv" )
8686 }
8787
88- if p .appConfig .PipExtraArgs != "" {
89- extraArgs := strings .Split (p .appConfig .PipExtraArgs , " " )
90- args = append (args , extraArgs ... )
91- }
88+ args = append (args , p .parseExtraArgs ()... )
9289
9390 args = append ([]string {"pip" }, args ... )
9491
9592 return args
9693}
9794
98- func (p * LocalPluginRuntime ) prepareSyncArgs () []string {
95+ func (p * LocalPluginRuntime ) prepareSyncArgs (hasUvLock bool ) []string {
9996 args := []string {"sync" , "--no-dev" }
10097
98+ if hasUvLock {
99+ args = append (args , "--frozen" )
100+ }
101+
101102 if p .appConfig .PipMirrorUrl != "" {
102103 args = append (args , "-i" , p .appConfig .PipMirrorUrl )
103104 }
@@ -106,14 +107,31 @@ func (p *LocalPluginRuntime) prepareSyncArgs() []string {
106107 args = append (args , "-v" )
107108 }
108109
109- if p . appConfig . PipExtraArgs != "" {
110- extraArgs := strings . Split ( p . appConfig . PipExtraArgs , " " )
111- args = append ( args , extraArgs ... )
110+ extraArgs := p . parseExtraArgs ()
111+ if hasUvLock {
112+ extraArgs = p . deduplicateArgs ( extraArgs , "--frozen" )
112113 }
113-
114+ args = append ( args , extraArgs ... )
114115 return args
115116}
116117
118+ func (p * LocalPluginRuntime ) parseExtraArgs () []string {
119+ if p .appConfig .PipExtraArgs == "" {
120+ return nil
121+ }
122+ return strings .Fields (p .appConfig .PipExtraArgs )
123+ }
124+
125+ func (p * LocalPluginRuntime ) deduplicateArgs (args []string , exclude string ) []string {
126+ var result []string
127+ for _ , arg := range args {
128+ if arg != exclude {
129+ result = append (result , arg )
130+ }
131+ }
132+ return result
133+ }
134+
117135func (p * LocalPluginRuntime ) detectDependencyFileType () (PythonDependencyFileType , error ) {
118136 _ , span := p .startSpan ("python.detect_dependency_file" )
119137 defer span .End ()
@@ -143,12 +161,18 @@ func (p *LocalPluginRuntime) installDependencies(
143161 var args []string
144162 switch dependencyFileType {
145163 case pyprojectTomlFile :
146- args = p .prepareSyncArgs ()
164+ uvLockPath := path .Join (p .State .WorkingPath , "uv.lock" )
165+ hasUvLock := false
166+ if _ , err := os .Stat (uvLockPath ); err == nil {
167+ hasUvLock = true
168+ }
169+ args = p .prepareSyncArgs (hasUvLock )
147170 parent .SetAttributes (
148171 attribute .String ("python.install.method" , "uv sync" ),
149172 attribute .String ("python.install.file" , string (pyprojectTomlFile )),
173+ attribute .Bool ("python.install.frozen" , hasUvLock ),
150174 )
151- log .Info ("installing plugin dependencies" , "plugin" , p .Config .Identity (), "method" , "uv sync" , "file" , pyprojectTomlFile )
175+ log .Info ("installing plugin dependencies" , "plugin" , p .Config .Identity (), "method" , "uv sync" , "file" , pyprojectTomlFile , "frozen" , hasUvLock )
152176 case requirementsTxtFile :
153177 args = p .preparePipArgs ()
154178 parent .SetAttributes (
@@ -160,6 +184,8 @@ func (p *LocalPluginRuntime) installDependencies(
160184 return fmt .Errorf ("unsupported dependency file type: %s" , dependencyFileType )
161185 }
162186
187+ log .Info ("uv command" , "cmd" , uvPath , "args" , args )
188+
163189 virtualEnvPath := path .Join (p .State .WorkingPath , ".venv" )
164190 uvCacheDir := path .Join (p .State .WorkingPath , ".uv-cache" )
165191 cmd := exec .CommandContext (ctx , uvPath , args ... )
0 commit comments