Repository navigation
feat(build)!: run every build through the coordinator - #655
Conversation
f6db2f9 to
4aebc1f
Compare
18ee40c to
04d10d9
Compare
04d10d9 to
57ca7c7
Compare
57ca7c7 to
122b508
Compare
122b508 to
3afdcae
Compare
3afdcae to
0370b07
Compare
0370b07 to
e1876cf
Compare
TimoStoff
left a comment
There was a problem hiding this comment.
Why can't they all be like this 😍
37081c7 to
69ed889
Compare
69ed889 to
c8ceb49
Compare
c5df932 to
ea48d99
Compare
ea48d99 to
3b3041a
Compare
There was a problem hiding this comment.
I reviewed this PR and found no bugs. It is a large breaking change to the public builder protocol, the client's build path and the remote put_dataset behaviour, so a human should still look at it. New commits were also pushed after the existing approval.
What was reviewed:
_obtainand_prepareinclient.pynow go throughbuild_release(). A pinned version is passed asid@ versionand "latest" sentinels are passed as a bare ID. The payload-source builds still get theirpinned_bypins.plan_parents/_locatenow take only aLocalRegistry. Because the output is always local, the old remote-output guard and therequires_open_accesshandling are no longer needed.LazyReadRegistry.put_dataset(force=True)raises before it stages anything.run_isolated_buildand_run_buildinenv.py: with the child's stdout sent to DEVNULL, reading stderr inline cannot deadlock. I also checked the candidate concern that third-party backends still on the oldbuild()signature would get aTypeError. I ruled it out because the PR declares that protocol break.
Extended reasoning...
The change touches 25 files across timenet and timenet-connectors, about 350 lines added and 1,280 removed. It removes knows(), declared_version(), build_one(), run_isolated(), prepare_parents(), publish_pipeline() and has_connector(), and changes the BuilderBackend.build() signature. It also routes the client's missing-version and payload-source builds through coordinator.build_release(), and makes put_dataset(force=True) refuse on remote and S3 registries. The only security-relevant surface is the subprocess call in env.py, which still runs a fixed argument vector, plus the existing open-access checks. I deferred because of the size and the breaking changes to the public and plugin API, and because commits landed after the human approval.
3b3041a to
f621061
Compare
f621061 to
c1f6efa
Compare
The TimeNet client now builds a missing version and a missing payload source with build_release(), like the build command and timenet_connectors.build(). So every build entry point runs through the same coordinator, and the old build path goes away. The client maps its fetch_from and auto_build onto build_release(), with build_parents set. A version that the connector does not declare raises TimeNetVersionUnavailableError before the build starts. That error is a TimeNetDatasetNotFoundError, as before, and also a TimeFValidationError. The BuilderBackend protocol loses knows() and declared_version(), and its build() now builds one prepared release into a local store. A backend now implements dataset_ids(), card() and build(). ConnectorBuilder changes the same way. Its card() returns None for a spelling that no card declares, such as timenet/hello_world. run_isolated(), build_one() and its helpers, prepare_parents() and the hidden --pinned-by option of build go away. Each backend now builds every release that it claims, the requested release too. build_one() always built the requested release on the built-in path. So a subclass of ConnectorBuilder that overrides build() now builds all of its releases through it. Every build now writes into a local store first. So engine.publish_pipeline(), which built straight into a registry, goes away, and open_parents() takes a LocalRegistry. put_dataset() with force=True on a remote or S3 registry raises TimeFValidationError, because a published version never changes. The planner writes only into a LocalRegistry, so its checks for a remote output go away. The isolated child writes nothing to stdout, so the parent discards it. timenet_connectors.builder imports none of its modules, and the backend no longer imports the CLI. So loading the backend through its entry point loads neither Typer nor the console of the CLI. The plan tests that ran prepare_parents() now run build_release(). When the client builds, it now copies a parent like the build command does: with each payload source at every depth. So such a copy fails if the registry to copy from holds a payload source without its own payload sources. BREAKING CHANGE: BuilderBackend no longer has knows() and declared_version(), and its build() takes a prepared release: build(release, store, *, force, pinned_by, options). A backend of another package must implement dataset_ids(), card() and build(). timenet_connectors.builder no longer exports app and main: import them from timenet_connectors.builder.cli. has_connector() of timenet_connectors.discovery is gone, because nothing calls it now. The hidden --pinned-by option of timenet-build build is gone. TimeNet.open() and TimeNet.load() raise TimeNetVersionUnavailableError for a version that the connector does not declare. timenet.engine.publish_pipeline() is gone: build into a local registry, then publish the release. open_parents() takes a LocalRegistry. put_dataset(force=True) on a remote or S3 registry raises TimeFValidationError. Part of TNET-157.
The client builds with the default BuildOptions, so quiet stays unset. A new test opens a missing release with the built-in backend, isolation on and the child faked, and makes sure that the child is not quiet. Before the backend read BuildOptions.quiet, a client build ran the child with --quiet, because the client sends no progress callback. Part of TNET-157.
Module docstrings now say what the module does, not who loads it. Part of TNET-157.
The two comments on this mapping now start with "Glue:", as in later changes. They say that it stays until the client takes a list of sources. Part of TNET-157.
The two glue comments now start with TODO(adrian), so a search finds each one that is left. Part of TNET-157.
Say only what a caller of the builder backend and of the client reads needs to know. Part of TNET-157.
Shorter docstrings for the code that this change adds or changes. Part of TNET-157.
Drop tests that cannot fail or repeat other tests, and sharpen the rest. Part of TNET-157.
c1f6efa to
7048dc7
Compare
The Stack
This stack covers refactoring the internal logic of how releases are resolved during read, download & build, in particular also in the context of parent releases / parent datasets. On top of that it refactors the public TimeNet APIs and CLI interfaces around these actions, to streamline the behavior across them.
This PR
Moves the client onto the coordinator, so that every build runs through
build_release(), and removes the old build path.Details
After #654, the client is the last caller of the old build path (TNET-157). It still builds through
ConnectorBuilder.build()andbuild_one(), so the builder protocol keeps two ways to build.build_release(). It maps itsfetch_fromandauto_buildontobuild_release(), withbuild_parentsset.TimeNetVersionUnavailableErrorbefore the build starts.BuilderBackendprotocol losesknows(),declared_version()and the oldbuild().build_prepared()is nowbuild(), so a backend implementsdataset_ids(),card()andbuild(). The hidden command keeps its name,build-prepared-release.ConnectorBuilder.card()returnsNonefor a spelling that no card declares.run_isolated(),build_one()and its helpers,prepare_parents()and the hidden--pinned-byoption ofbuildgo away.timenet.engine.publish_pipeline()goes away too.open_parents()takes theLocalRegistrythat the build writes to.put_dataset(force=True)on a remote or S3 registry raisesTimeFValidationErrorbefore it uploads, because a published version never changes.timenet_connectors.builderimports none of its modules. So loading the backend through its entry point loads neither Typer nor the console of the CLI. A test makes sure of that.Design decisions
build_one()always built the requested release on the built-in path. So a subclass ofConnectorBuilderthat overridesbuild()now builds all of its releases through it.rich, becausehttpxloadsrichwheneverrichis installed.Breaking changes
BuilderBackendno longer hasknows()anddeclared_version(), andbuild()takes(release, store, *, force, pinned_by, options). A backend of another package must implementdataset_ids(),card()and the newbuild().timenet.engine.publish_pipeline()is gone. Build withrun_pipeline(), then publish withcopy_release().open_parents()takes aLocalRegistry. It no longer opens parents from a remote registry.put_dataset(force=True)on a remote or S3 registry raisesTimeFValidationError.timenet_connectors.builderno longer exportsappandmain. Import them fromtimenet_connectors.builder.cli.--pinned-byoption oftimenet-build buildis gone.timenet_connectors.discovery.has_connector()is gone, because nothing calls it now.TimeNet.open()andTimeNet.load()raiseTimeNetVersionUnavailableErrorfor a version that the connector does not declare. It is aTimeNetDatasetNotFoundError, as before.Stack
Changes later in the stack:
fetch_fromandauto_buildontobuild_release()in_obtain()and_prepare()is thin glue. "Client reads on the coordinator" replaces it with the entry machinery.Merge message