Skip to content

Commit ebd1b10

Browse files
committed
Update Provider Usage
1 parent 74fed9a commit ebd1b10

File tree

13 files changed

+1516
-293
lines changed

13 files changed

+1516
-293
lines changed

cppython/plugins/conan/plugin.py

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from cppython.plugins.conan.builder import Builder
2121
from cppython.plugins.conan.resolution import resolve_conan_data, resolve_conan_dependency
2222
from cppython.plugins.conan.schema import ConanData
23-
from cppython.utility.exception import NotSupportedError
23+
from cppython.utility.exception import NotSupportedError, ProviderConfigurationError, ProviderInstallationError
2424
from cppython.utility.utility import TypeName
2525

2626

@@ -69,21 +69,64 @@ def information() -> Information:
6969
"""
7070
return Information()
7171

72-
def install(self) -> None:
73-
"""Installs the provider"""
74-
resolved_dependencies = [resolve_conan_dependency(req) for req in self.core_data.cppython_data.dependencies]
72+
def _install_dependencies(self, *, update: bool = False) -> None:
73+
"""Common implementation for installing/updating dependencies.
74+
75+
Args:
76+
update: If True, check remotes for newer versions/revisions and install those.
77+
If False, use cached versions when available.
78+
"""
79+
try:
80+
resolved_dependencies = [resolve_conan_dependency(req) for req in self.core_data.cppython_data.dependencies]
81+
82+
self.builder.generate_conanfile(self.core_data.project_data.project_root, resolved_dependencies)
83+
84+
self.core_data.cppython_data.build_path.mkdir(parents=True, exist_ok=True)
85+
86+
# Install/update dependencies using Conan API
87+
project_root = self.core_data.project_data.project_root
88+
conanfile_path = project_root / 'conanfile.py'
89+
90+
if conanfile_path.exists():
91+
# Initialize Conan API
92+
conan_api = ConanAPI()
93+
94+
# Get default profiles
95+
profile_host_path = conan_api.profiles.get_default_host()
96+
profile_build_path = conan_api.profiles.get_default_build()
97+
profile_host = conan_api.profiles.get_profile([profile_host_path])
98+
profile_build = conan_api.profiles.get_profile([profile_build_path])
99+
100+
# Build dependency graph for the package
101+
deps_graph = conan_api.graph.load_graph_consumer(
102+
path=str(conanfile_path),
103+
name=None,
104+
version=None,
105+
user=None,
106+
channel=None,
107+
profile_host=profile_host,
108+
profile_build=profile_build,
109+
lockfile=None,
110+
remotes=conan_api.remotes.list(),
111+
update=update,
112+
check_updates=update,
113+
is_build_require=False,
114+
)
75115

76-
self.builder.generate_conanfile(self.core_data.project_data.project_root, resolved_dependencies)
116+
# Install dependencies
117+
conan_api.install.install_binaries(deps_graph=deps_graph, remotes=conan_api.remotes.list())
118+
except Exception as e:
119+
operation = 'update' if update else 'install'
120+
error_msg = str(e)
121+
raise ProviderInstallationError('conan', f'Failed to {operation} dependencies: {error_msg}', e) from e
77122

78-
self.core_data.cppython_data.build_path.mkdir(parents=True, exist_ok=True)
123+
def install(self) -> None:
124+
"""Installs the provider"""
125+
self._install_dependencies(update=False)
79126

80127
def update(self) -> None:
81128
"""Updates the provider"""
82-
resolved_dependencies = [resolve_conan_dependency(req) for req in self.core_data.cppython_data.dependencies]
83-
84-
self.builder.generate_conanfile(self.core_data.project_data.project_root, resolved_dependencies)
85-
86-
self.core_data.cppython_data.build_path.mkdir(parents=True, exist_ok=True)
129+
self._install_dependencies(update=True)
87130

88131
@staticmethod
89132
def supported_sync_type(sync_type: type[SyncData]) -> bool:
@@ -148,7 +191,10 @@ def publish(self) -> None:
148191
)
149192

150193
# Step 2: Get default profiles
151-
profile_host, profile_build = conan_api.profiles.get_profiles_from_args([])
194+
profile_host_path = conan_api.profiles.get_default_host()
195+
profile_build_path = conan_api.profiles.get_default_build()
196+
profile_host = conan_api.profiles.get_profile([profile_host_path])
197+
profile_build = conan_api.profiles.get_profile([profile_build_path])
152198

153199
# Step 3: Build dependency graph for the package
154200
deps_graph = conan_api.graph.load_graph_consumer(
@@ -188,7 +234,7 @@ def publish(self) -> None:
188234
# Get the first configured remote or raise an error
189235
remotes = conan_api.remotes.list()
190236
if not remotes:
191-
raise RuntimeError('No remotes configured for upload')
237+
raise ProviderConfigurationError('conan', 'No remotes configured for upload', 'remotes')
192238

193239
remote = remotes[0] # Use first remote
194240

@@ -203,4 +249,4 @@ def publish(self) -> None:
203249
dry_run=False,
204250
)
205251
else:
206-
raise RuntimeError('No packages found to upload')
252+
raise ProviderInstallationError('conan', 'No packages found to upload')

cppython/plugins/vcpkg/plugin.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from cppython.plugins.cmake.schema import CMakeSyncData
1818
from cppython.plugins.vcpkg.resolution import generate_manifest, resolve_vcpkg_data
1919
from cppython.plugins.vcpkg.schema import VcpkgData
20-
from cppython.utility.exception import NotSupportedError
20+
from cppython.utility.exception import NotSupportedError, ProviderInstallationError, ProviderToolingError
2121
from cppython.utility.utility import TypeName
2222

2323

@@ -92,10 +92,9 @@ def _update_provider(cls, path: Path) -> None:
9292
capture_output=True,
9393
)
9494
except subprocess.CalledProcessError as e:
95-
logger.error(
96-
'Unable to bootstrap the vcpkg repository: %s', e.stderr.decode() if e.stderr else str(e), exc_info=True
97-
)
98-
raise
95+
error_msg = e.stderr.decode() if e.stderr else str(e)
96+
logger.error('Unable to bootstrap the vcpkg repository: %s', error_msg, exc_info=True)
97+
raise ProviderToolingError('vcpkg', 'bootstrap', error_msg, e) from e
9998

10099
def sync_data(self, consumer: SyncConsumer) -> SyncData:
101100
"""Gathers a data object for the given generator
@@ -167,8 +166,9 @@ async def download_tooling(cls, directory: Path) -> None:
167166
capture_output=True,
168167
)
169168
except subprocess.CalledProcessError as e:
170-
logger.exception('Unable to update the vcpkg repository: %s', e.stderr.decode() if e.stderr else str(e))
171-
raise
169+
error_msg = e.stderr.decode() if e.stderr else str(e)
170+
logger.error('Unable to update the vcpkg repository: %s', error_msg, exc_info=True)
171+
raise ProviderToolingError('vcpkg', 'update', error_msg, e) from e
172172
else:
173173
try:
174174
logger.debug("Cloning the vcpkg repository to '%s'", directory.absolute())
@@ -182,8 +182,9 @@ async def download_tooling(cls, directory: Path) -> None:
182182
)
183183

184184
except subprocess.CalledProcessError as e:
185-
logger.exception('Unable to clone the vcpkg repository: %s', e.stderr.decode() if e.stderr else str(e))
186-
raise
185+
error_msg = e.stderr.decode() if e.stderr else str(e)
186+
logger.error('Unable to clone the vcpkg repository: %s', error_msg, exc_info=True)
187+
raise ProviderToolingError('vcpkg', 'clone', error_msg, e) from e
187188

188189
cls._update_provider(directory)
189190

@@ -210,8 +211,9 @@ def install(self) -> None:
210211
capture_output=True,
211212
)
212213
except subprocess.CalledProcessError as e:
213-
logger.exception('Unable to install project dependencies: %s', e.stderr.decode() if e.stderr else str(e))
214-
raise
214+
error_msg = e.stderr.decode() if e.stderr else str(e)
215+
logger.error('Unable to install project dependencies: %s', error_msg, exc_info=True)
216+
raise ProviderInstallationError('vcpkg', error_msg, e) from e
215217

216218
def update(self) -> None:
217219
"""Called when dependencies need to be updated and written to the lock file."""
@@ -237,8 +239,9 @@ def update(self) -> None:
237239
capture_output=True,
238240
)
239241
except subprocess.CalledProcessError as e:
240-
logger.exception('Unable to install project dependencies: %s', e.stderr.decode() if e.stderr else str(e))
241-
raise
242+
error_msg = e.stderr.decode() if e.stderr else str(e)
243+
logger.error('Unable to update project dependencies: %s', error_msg, exc_info=True)
244+
raise ProviderInstallationError('vcpkg', error_msg, e) from e
242245

243246
def publish(self) -> None:
244247
"""Called when the project needs to be published.

cppython/project.py

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def install(self) -> None:
5656
"""Installs project dependencies
5757
5858
Raises:
59-
Exception: Raised if failed
59+
Exception: Provider-specific exceptions are propagated with full context
6060
"""
6161
if not self._enabled:
6262
self.logger.info('Skipping install because the project is not enabled')
@@ -68,19 +68,15 @@ def install(self) -> None:
6868
self.logger.info('Installing project')
6969
self.logger.info('Installing %s provider', self._data.plugins.provider.name())
7070

71-
try:
72-
self._data.plugins.provider.install()
73-
except Exception as exception:
74-
self.logger.error('Unexpected error during installation: %s', str(exception))
75-
raise SystemExit('Error: An unexpected error occurred during installation.') from None
76-
71+
# Let provider handle its own exceptions for better error context
72+
self._data.plugins.provider.install()
7773
self._data.sync()
7874

7975
def update(self) -> None:
8076
"""Updates project dependencies
8177
8278
Raises:
83-
Exception: Raised if failed
79+
Exception: Provider-specific exception
8480
"""
8581
if not self._enabled:
8682
self.logger.info('Skipping update because the project is not enabled')
@@ -92,18 +88,15 @@ def update(self) -> None:
9288
self.logger.info('Updating project')
9389
self.logger.info('Updating %s provider', self._data.plugins.provider.name())
9490

95-
try:
96-
self._data.plugins.provider.update()
97-
except Exception as exception:
98-
self.logger.error('Unexpected error during update: %s', str(exception))
99-
raise SystemExit('Error: An unexpected error occurred during update.') from None
100-
91+
# Let provider handle its own exceptions for better error context
92+
self._data.plugins.provider.update()
10193
self._data.sync()
10294

10395
def publish(self) -> None:
104-
"""Publishes the project"""
105-
try:
106-
self._data.plugins.provider.publish()
107-
except Exception as exception:
108-
self.logger.error('Unexpected error during publish: %s', str(exception))
109-
raise SystemExit('Error: An unexpected error occurred during publish.') from None
96+
"""Publishes the project
97+
98+
Raises:
99+
Exception: Provider-specific exception
100+
"""
101+
# Let provider handle its own exceptions for better error context
102+
self._data.plugins.provider.publish()

0 commit comments

Comments
 (0)