fix(self-packaging #62): bundled-mode HTTP serving end-to-end#69
Merged
Conversation
Before this change, `flapi pack` produced a working binary at the CLI
level (`info`, `unpack`, etc.) but `./flapi-bundled` started from a
clean cwd crashed with "Could not open file: flapi.yaml" -- the
EmbeddedArchiveFileProvider was registered globally but the config /
endpoint / template loaders bypassed it via std::ifstream and
std::filesystem::recursive_directory_iterator.
Four call sites had to be routed through FileProviderFactory so the
in-memory archive is actually consulted when SetBundleContents has
fired:
- extended_yaml_parser: parseFile and the static loadYamlFile now
read via FileProviderFactory::CreateProvider(path)->ReadFile(...)
instead of std::ifstream. resolveIncludePath swaps
std::filesystem::exists for a provider-aware ConfigFileExists so
{{include from ...}} directives find their targets inside the
bundle.
- config_manager::parseTemplateConfig: in bundled mode, skip the
std::filesystem::absolute() step -- the template path is a bundle
key like "sqls", not a filesystem path; turning it into
"/cwd/sqls" prevents the embedded provider from finding it.
- config_manager::loadEndpointConfigsRecursively: in bundled mode,
enumerate .yaml/.yml entries by prefix-scanning the bundle map
instead of std::filesystem::recursive_directory_iterator. The
EmbeddedArchiveFileProvider's ListFiles is non-recursive by
contract, so the walk is inlined here.
- config_manager::getFileProvider: in bundled mode, return a fresh
provider from FileProviderFactory so SQLTemplateProcessor reads
SQL templates from the bundle rather than the LocalFileProvider
baked into ConfigLoader.
Plus a small fix in sql_template_processor::getFullTemplatePath:
when the endpoint parser has already resolved templateSource against
its YAML's parent dir (which in bundled mode produces a full bundle
key like "sqls/hello.sql"), don't re-prepend the basePath. Mirrors
the existing absolute-path short-circuit just above.
test_self_packaging_http.py adds the three pytest cases from the
issue acceptance:
- #1 unbundled flapi serves /hello with 200 + body
- #3 bundled flapi from clean cwd (with the source tree deleted)
serves the same /hello
- #9 a SQL template using read_csv('embed://data/cities.csv')
returns the bundled CSV rows over HTTP
All 17 integration tests pass (existing CLI-level self-packaging
suite + env-override suite + the 3 new HTTP cases). 637/637 C++ unit
tests pass.
Closes #62.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Surfaced while planning the integration test for #62: bundled-mode
HTTP serving was broken on
main, not just untested. Packingexamples/and running the result from an empty cwd crashed with:The
EmbeddedArchiveFileProviderwas registered globally bydetectAndRegisterEmbeddedBundle, but the config / endpoint /template loaders bypassed it via
std::ifstreamandstd::filesystem::recursive_directory_iterator. All existingself-packaging tests are CLI-level (
pack,info,unpack,idempotence, truncation fallback); nobody had ever started the
bundled binary as a server, which is exactly why #62 was deferred
in PR #56.
This PR fixes the underlying machinery and adds the three pytest
cases that were originally scoped for #62.
Changes
Provider-aware reads (
src/extended_yaml_parser.cpp)parseFileand the staticloadYamlFilenow read viaFileProviderFactory::CreateProvider(path)->ReadFile(...).resolveIncludePathswapsstd::filesystem::existsfor aprovider-aware
ConfigFileExistsso{{include from ...}}directives find their targets inside the bundle.
Provider-aware path resolution (
src/config_manager.cpp)parseTemplateConfig: in bundled mode, skip thestd::filesystem::absolute()step -- the template path is abundle key like
sqls, not a filesystem path. Turning it into/cwd/sqlsprevents the embedded provider from finding it.loadEndpointConfigsRecursively: in bundled mode, enumerate.yaml/.ymlentries by prefix-scanning the bundle map.EmbeddedArchiveFileProvider::ListFilesis non-recursive bycontract, so the walk is inlined.
getFileProvider: in bundled mode, return a fresh provider fromFileProviderFactorysoSQLTemplateProcessorreads SQLtemplates from the bundle rather than the
LocalFileProviderbaked into
ConfigLoader.Endpoint-vs-template path collision
(
src/sql_template_processor.cpp)getFullTemplatePath: when the endpoint parser has alreadyresolved
templateSourceagainst its YAML's parent dir (whichin bundled mode produces a full bundle key like
sqls/hello.sql),don't re-prepend the basePath. Mirrors the existing absolute-path
short-circuit just above; this prevented the previous
sqls/sqls/hello.sqllookup miss.Test (
test/integration/test_self_packaging_http.py)Three new pytest cases covering the deferred behaviours:
/hellowith 200 + JSON bodyserves the same
/helloread_csv('embed://data/cities.csv')returns the bundled CSV rows over HTTP
Test plan
cmake --build build/releasecleanctest-- 637 / 637 pass seriallypytest test/integration/test_self_packaging.py test_self_packaging_http.py test_env_overrides.py -v-- all 17 pass (8 existing CLI-level + 3 new HTTP + 6 env overrides)
examples/, started from clean cwd, hit/hello-> 200; hit/citiesreadingembed://data/cities.csv-> 200 with 3 expected rows
Notes
--portinstead ofFLAPI_PORTin the new tests so this PRdoesn't depend on feat: 12-factor env vars FLAPI_PORT + FLAPI_HOST (#63) #67 (FLAPI_PORT / FLAPI_HOST).
clang-tidyflagged unrelated pre-existing warnings in the touchedfiles (
std::endl,push_backvsemplace_back, etc.); leftuntouched per the no-incidental-cleanup convention.
Closes #62.