11import shutil
2- import subprocess
32from pathlib import Path
4- from typing import Annotated , get_args
3+ from typing import Annotated
54
65import typer
76import zerv
87from bake import command , console
9- from bakelib import PythonLibSpace as _PythonLibSpace
10- from bakelib import RustLibSpace
11- from bakelib .space .lib import BaseLibSpace , PublishResult
12- from bakelib .space .python_lib import PyPIRegistry
13- from bakelib .space .rust_lib import CratesRegistry
8+ from bakelib import PythonSpace , RustSpace
9+ from bakelib .publisher import Publisher
10+ from bakelib .publisher .crates import CratesPublisher
11+ from bakelib .publisher .pypi import PyPIPublisher as _PyPIPublisher
12+ from bakelib .space .lib import BaseLibSpace
13+ from bakelib .space .params import publish_token_option , publish_version_option
1414
1515from tests .python .utils import symlink_zerv_to_venv_bin
1616
1717
18- class PythonLibSpace (_PythonLibSpace ):
18+ class PyPIPublisher (_PyPIPublisher ):
19+ """Custom PyPI publisher for zerv that uses maturin instead of uv build."""
20+
1921 _target : str | None = None
2022
21- def _build_for_publish (self ):
23+ def _build_for_publish (self ) -> None :
2224 cmd = "maturin build --release --strip --out dist/"
2325
2426 if self ._target :
@@ -27,31 +29,23 @@ def _build_for_publish(self):
2729 self .ctx .run (cmd )
2830
2931
30- class MyBakebook (RustLibSpace , PythonLibSpace ):
32+ class MyBakebook (RustSpace , PythonSpace , BaseLibSpace ):
3133 zerv_test_native_git : bool = False
3234 zerv_test_docker : bool = True
3335 zerv_force_rust_log_off : bool = False
34- __registry : CratesRegistry | PyPIRegistry | None = None
35-
36- @property
37- def _registry (self ) -> CratesRegistry | PyPIRegistry :
38- if self .__registry is None :
39- raise RuntimeError ("_registry not set" )
40- return self .__registry
41-
42- @_registry .setter
43- def _registry (self , value : str ):
44- self .__registry = self ._validate_registry (value )
36+ _target : str | None = None
4537
46- @property
47- def _publish_impl (self ) -> type [BaseLibSpace ]:
48- if self ._registry in get_args (PyPIRegistry ):
49- return PythonLibSpace
50- if self ._registry in get_args (CratesRegistry ):
51- return RustLibSpace
52-
53- valid = (* get_args (PyPIRegistry ), * get_args (CratesRegistry ))
54- console .error (f"Invalid registry: { self ._registry !r} . Expected one of { valid } ." )
38+ def get_publisher (self , registry : str ) -> PyPIPublisher | CratesPublisher :
39+ """Return the appropriate publisher, using custom PyPIPublisher for maturin builds."""
40+ if registry in PyPIPublisher .valid_registries :
41+ publisher = PyPIPublisher (self .ctx , registry )
42+ publisher ._target = self ._target
43+ return publisher
44+ if registry in CratesPublisher .valid_registries :
45+ return CratesPublisher (self .ctx , registry )
46+
47+ valid = (* PyPIPublisher .valid_registries , * CratesPublisher .valid_registries )
48+ console .error (f"Invalid registry: { registry !r} . Expected one of { valid } ." )
5549 raise typer .Exit (1 )
5650
5751 def _update_config (self , ** kwargs : bool | None ) -> None :
@@ -145,54 +139,22 @@ def publish(
145139 str ,
146140 typer .Option (help = "Publish registry (test-pypi, pypi, or crates)" ),
147141 ] = "test-pypi" ,
148- token : Annotated [ str | None , typer . Option ( help = "Publish token" )] = None ,
149- version : Annotated [ str | None , typer . Option ( help = "Version to publish" )] = None ,
142+ token : publish_token_option = None ,
143+ version : publish_version_option = None ,
150144 target : Annotated [
151145 str | None ,
152146 typer .Option (
153147 help = "Rust target triple (e.g., aarch64-apple-darwin, x86_64-pc-windows-msvc)"
154148 ),
155149 ] = None ,
156150 ):
157- self ._registry = registry
158151 self ._target = target
159- return self ._publish_impl .publish (
160- self , registry = self ._registry , token = token , version = version
161- )
162-
163- def _validate_registry (self , registry : str ) -> CratesRegistry | PyPIRegistry : # type: ignore[invalid-method-override]
164- if registry in get_args (PyPIRegistry ):
165- impl = PythonLibSpace
166- elif registry in get_args (CratesRegistry ):
167- impl = RustLibSpace
168- else :
169- valid = (* get_args (PyPIRegistry ), * get_args (CratesRegistry ))
170- console .error (f"Invalid registry: { registry !r} . Expected one of { valid } ." )
171- raise typer .Exit (1 )
172-
173- valid_registry = impl ._validate_registry (self , registry )
174-
175- return valid_registry
176-
177- def _get_publish_token_from_remote (self , registry : str ) -> str | None :
178- return self ._publish_impl ._get_publish_token_from_remote (self , registry )
179-
180- def _build_for_publish (self ):
181- return self ._publish_impl ._build_for_publish (self )
182-
183- def _publish_with_token (self , token : str | None , registry : str ) -> PublishResult :
184- return self ._publish_impl ._publish_with_token (self , token , registry )
185-
186- def _is_auth_failure (self , result : subprocess .CompletedProcess [str ]) -> bool :
187- return self ._publish_impl ._is_auth_failure (self , result )
188-
189- def _is_already_exists_error (self , result : subprocess .CompletedProcess [str ]) -> bool :
190- return self ._publish_impl ._is_already_exists_error (self , result )
152+ return super ().publish (registry = registry , token = token , version = version )
191153
192154 @property
193155 def _version (self ) -> str :
194- cargo_raw = RustLibSpace ._version .fget (self )
195- pyproject_raw = PythonLibSpace ._version .fget (self )
156+ cargo_raw = RustSpace ._version .fget (self )
157+ pyproject_raw = PythonSpace ._version .fget (self )
196158
197159 pyproject_semver = zerv .render (version = pyproject_raw , output_format = "semver" )
198160 cargo_semver = zerv .render (version = cargo_raw , output_format = "semver" )
@@ -207,17 +169,21 @@ def _version(self) -> str:
207169
208170 @_version .setter
209171 def _version (self , value : str ) -> None :
210- RustLibSpace ._version .fset (self , value )
211- PythonLibSpace ._version .fset (self , value )
172+ RustSpace ._version .fset (self , value )
173+ PythonSpace ._version .fset (self , value )
174+
175+ def _pre_publish_setup (self , publisher : Publisher ) -> None :
176+ """Custom pre-publish setup for zerv - handles both Rust and Python."""
177+ _ = publisher
212178
213- def _pre_publish_setup (self ):
214179 # zerv uses itself for versioning in _version_bump_context, so build and symlink it first
215180 self .ctx .run ("maturin develop" )
216181 if not self .ctx .dry_run :
217182 symlink_zerv_to_venv_bin ()
218183
219- RustLibSpace ._pre_publish_setup (self )
220- PythonLibSpace ._pre_publish_setup (self )
184+ # Call BOTH publishers' setup (zerv is multi-lang)
185+ CratesPublisher ._pre_publish_setup (self .ctx ) # removes target/package
186+ PyPIPublisher ._pre_publish_setup (self .ctx ) # removes dist
221187
222188 # maturin
223189 for p in Path ("python" ).glob ("*.data" ):
0 commit comments