55installation, and synchronization with other tools.
66"""
77
8- import subprocess
8+ import os
99from logging import getLogger
1010from pathlib import Path
1111from typing import Any
1212
13+ from conan .api .conan_api import ConanAPI
14+ from conan .cli .cli import Cli
15+
1316from cppython .core .plugin_schema .generator import SyncConsumer
1417from cppython .core .plugin_schema .provider import Provider , ProviderPluginGroupData , SupportedProviderFeatures
1518from cppython .core .schema import CorePluginData , Information , SupportedFeatures , SyncData
@@ -34,6 +37,11 @@ def __init__(
3437 self .data : ConanData = resolve_conan_data (configuration_data , core_data )
3538
3639 self .builder = Builder ()
40+ # Initialize ConanAPI once and reuse it
41+ self ._conan_api = ConanAPI ()
42+ # Initialize CLI for command API to work properly
43+ self ._cli = Cli (self ._conan_api )
44+ self ._cli .add_commands ()
3745
3846 @staticmethod
3947 def features (directory : Path ) -> SupportedFeatures :
@@ -107,44 +115,45 @@ def _prepare_installation(self) -> Path:
107115 return conanfile_path
108116
109117 def _run_conan_install (self , conanfile_path : Path , update : bool , logger ) -> None :
110- """Run conan install command.
118+ """Run conan install command using Conan API .
111119
112120 Args:
113121 conanfile_path: Path to the conanfile.py
114122 update: Whether to check for updates
115123 logger: Logger instance
116124 """
117- # Build conan install command
118- command = ['conan' , 'install' , str (conanfile_path )]
125+ # Build conan install command arguments
126+ command_args = ['install' , str (conanfile_path )]
119127
120128 # Add build missing flag
121- command .extend (['--build' , 'missing' ])
129+ command_args .extend (['--build' , 'missing' ])
122130
123131 # Add profiles if specified
124- command .extend (['--profile:host' , 'default' ])
125- command .extend (['--profile:build' , 'default' ])
132+ command_args .extend (['--profile:host' , 'default' ])
133+ command_args .extend (['--profile:build' , 'default' ])
126134
127135 # Add update flag if needed
128136 if update :
129- command .append ('--update' )
137+ command_args .append ('--update' )
130138
131139 # Add output folder
132140 build_path = self .core_data .cppython_data .build_path
133- command .extend (['--output-folder' , str (build_path )])
141+ command_args .extend (['--output-folder' , str (build_path )])
134142
135143 # Log the command being executed
136- logger .info ('Executing conan command: %s' , ' ' .join (command ))
144+ logger .info ('Executing conan command: conan %s' , ' ' .join (command_args ))
137145
138146 try :
139- subprocess .run (
140- command ,
141- cwd = str (self .core_data .project_data .project_root ),
142- check = True ,
143- capture_output = True ,
144- text = True ,
145- )
146- except subprocess .CalledProcessError as e :
147- error_msg = e .stderr if e .stderr else str (e )
147+ # Use reusable Conan API instance instead of subprocess
148+ # Change to project directory since Conan API might not handle cwd like subprocess
149+ original_cwd = os .getcwd ()
150+ try :
151+ os .chdir (str (self .core_data .project_data .project_root ))
152+ self ._conan_api .command .run (command_args )
153+ finally :
154+ os .chdir (original_cwd )
155+ except Exception as e :
156+ error_msg = str (e )
148157 logger .error ('Conan install failed: %s' , error_msg , exc_info = True )
149158 raise ProviderInstallationError ('conan' , error_msg , e ) from e
150159
@@ -212,77 +221,65 @@ def publish(self) -> None:
212221 raise FileNotFoundError (f'conanfile.py not found at { conanfile_path } ' )
213222
214223 try :
215- # Build conan create command
216- command = ['conan' , 'create' , str (conanfile_path )]
224+ # Build conan create command arguments
225+ command_args = ['create' , str (conanfile_path )]
217226
218227 # Add build mode (build everything for publishing)
219- command .extend (['--build' , 'missing' ])
228+ command_args .extend (['--build' , 'missing' ])
220229
221230 # Add profiles
222- command .extend (['--profile:host' , 'default' ])
223- command .extend (['--profile:build' , 'default' ])
231+ command_args .extend (['--profile:host' , 'default' ])
232+ command_args .extend (['--profile:build' , 'default' ])
224233
225234 # Log the command being executed
226- logger .info ('Executing conan create command: %s' , ' ' .join (command ))
235+ logger .info ('Executing conan create command: conan %s' , ' ' .join (command_args ))
227236
228- # Run conan create
229- subprocess . run (
230- command ,
231- cwd = str ( project_root ),
232- check = True ,
233- capture_output = True ,
234- text = True ,
235- )
237+ # Run conan create using reusable Conan API instance
238+ # Change to project directory since Conan API might not handle cwd like subprocess
239+ original_cwd = os . getcwd ()
240+ try :
241+ os . chdir ( str ( project_root ))
242+ self . _conan_api . command . run ( command_args )
243+ finally :
244+ os . chdir ( original_cwd )
236245
237246 # Upload if not skipped
238247 if not self .data .skip_upload :
239248 self ._upload_package (logger )
240249
241- except subprocess . CalledProcessError as e :
242- error_msg = e . stderr if e . stderr else str (e )
250+ except Exception as e :
251+ error_msg = str (e )
243252 logger .error ('Conan create failed: %s' , error_msg , exc_info = True )
244253 raise ProviderInstallationError ('conan' , error_msg , e ) from e
245254
246255 def _upload_package (self , logger ) -> None :
247- """Upload the package to configured remotes using CLI commands ."""
256+ """Upload the package to configured remotes using Conan API ."""
248257 # If no remotes configured, upload to all remotes
249258 if not self .data .remotes :
250259 # Upload to all available remotes
251- command = ['conan' , 'upload' , '*' , '--all' , '--confirm' ]
260+ command_args = ['upload' , '*' , '--all' , '--confirm' ]
252261 else :
253262 # Upload only to specified remotes
254263 for remote in self .data .remotes :
255- command = ['conan' , 'upload' , '*' , '--remote' , remote , '--all' , '--confirm' ]
264+ command_args = ['upload' , '*' , '--remote' , remote , '--all' , '--confirm' ]
256265
257266 # Log the command being executed
258- logger .info ('Executing conan upload command: %s' , ' ' .join (command ))
267+ logger .info ('Executing conan upload command: conan %s' , ' ' .join (command_args ))
259268
260269 try :
261- subprocess .run (
262- command ,
263- cwd = str (self .core_data .project_data .project_root ),
264- check = True ,
265- capture_output = True ,
266- text = True ,
267- )
268- except subprocess .CalledProcessError as e :
269- error_msg = e .stderr if e .stderr else str (e )
270+ self ._conan_api .command .run (command_args )
271+ except Exception as e :
272+ error_msg = str (e )
270273 logger .error ('Conan upload failed for remote %s: %s' , remote , error_msg , exc_info = True )
271274 raise ProviderInstallationError ('conan' , f'Upload to { remote } failed: { error_msg } ' , e ) from e
272275 return
273276
274277 # Log the command for uploading to all remotes
275- logger .info ('Executing conan upload command: %s' , ' ' .join (command ))
278+ logger .info ('Executing conan upload command: conan %s' , ' ' .join (command_args ))
276279
277280 try :
278- subprocess .run (
279- command ,
280- cwd = str (self .core_data .project_data .project_root ),
281- check = True ,
282- capture_output = True ,
283- text = True ,
284- )
285- except subprocess .CalledProcessError as e :
286- error_msg = e .stderr if e .stderr else str (e )
281+ self ._conan_api .command .run (command_args )
282+ except Exception as e :
283+ error_msg = str (e )
287284 logger .error ('Conan upload failed: %s' , error_msg , exc_info = True )
288285 raise ProviderInstallationError ('conan' , error_msg , e ) from e
0 commit comments