dirsql 0.3.17__tar.gz → 0.3.18__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dirsql-0.3.17 → dirsql-0.3.18}/Cargo.lock +1 -1
- {dirsql-0.3.17 → dirsql-0.3.18}/PKG-INFO +1 -1
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/Cargo.toml +1 -1
- dirsql-0.3.18/packages/python/tests/integration/__fixtures__/dirsql.config.py +29 -0
- dirsql-0.3.18/packages/python/tests/integration/__fixtures__/interpret/data/a/meta.json +1 -0
- dirsql-0.3.18/packages/python/tests/integration/__fixtures__/interpret/data/b/meta.json +1 -0
- dirsql-0.3.18/packages/python/tests/integration/test_native_config.py +100 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/src/bin/dirsql.rs +67 -1
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/src/cli/mod.rs +1 -0
- dirsql-0.3.18/packages/rust/src/cli/native_config.rs +694 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/Cargo.toml +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/README.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/__init__.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/_async.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/_dirsql.pyi +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/cli/__init__.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/cli/binary_path.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/cli/binary_path_test.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/cli/interpret/__init__.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/cli/interpret/dispatch_extract.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/cli/interpret/dispatch_extract_test.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/cli/interpret/load_app.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/cli/interpret/load_app_test.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/cli/interpret/run.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/cli/interpret/run_test.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/cli/interpret/write_message.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/cli/interpret/write_message_test.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/cli/is_windows.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/cli/is_windows_test.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/cli/main.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/cli/main_test.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/py.typed +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/resolve_config.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/resolve_config_test.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/dirsql/test_async.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/.vitepress/config.ts +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/AGENTS.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/api/index.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/cli/config.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/cli/http-api.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/cli/index.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/cli/init.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/cli/server.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/getting-started.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/guide/async.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/guide/crdt.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/guide/persistence.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/guide/querying.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/guide/tables.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/guide/watching.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/index.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/migrations.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/package.json +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/playwright.config.ts +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/tests/integration/home.spec.ts +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/tests/integration/language-flag.spec.ts +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/tests/unit/config.test.ts +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/tests/unit/lang.test.ts +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/docs/vitest.config.ts +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/README.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/conftest.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/.vitepress/config.ts +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/AGENTS.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/api/index.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/cli/config.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/cli/http-api.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/cli/index.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/cli/init.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/cli/server.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/getting-started.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/guide/async.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/guide/crdt.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/guide/persistence.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/guide/querying.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/guide/tables.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/guide/watching.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/index.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/migrations.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/package.json +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/playwright.config.ts +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/tests/integration/home.spec.ts +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/tests/integration/language-flag.spec.ts +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/tests/unit/config.test.ts +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/tests/unit/lang.test.ts +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/docs/vitest.config.ts +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/src/lib.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/tests/__init__.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/tests/conftest.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/tests/e2e/__init__.py +0 -0
- {dirsql-0.3.17/packages/python/tests/integration/__fixtures__/interpret → dirsql-0.3.18/packages/python/tests/integration/__fixtures__}/data/a/meta.json +0 -0
- {dirsql-0.3.17/packages/python/tests/integration/__fixtures__/interpret → dirsql-0.3.18/packages/python/tests/integration/__fixtures__}/data/b/meta.json +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/tests/integration/__fixtures__/interpret/dirsql.config.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/tests/integration/__fixtures__/interpret/dirsql.config_no_app.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/tests/integration/__fixtures__/interpret/dirsql.config_raises.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/tests/integration/__init__.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/tests/integration/interpret_subprocess.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/tests/integration/test_async_dirsql.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/tests/integration/test_binding.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/tests/integration/test_dirsql.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/tests/integration/test_docs_examples.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/tests/integration/test_docs_gaps.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/tests/integration/test_from_config.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/tests/integration/test_interpret.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/tests/integration/test_persist.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/python/tests/integration/test_serialization.py +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/Cargo.toml +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/README.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/benches/db_bench.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/benches/differ_bench.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/benches/matcher_bench.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/benches/scanner_bench.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/docs/api/index.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/docs/cli/config.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/docs/cli/http-api.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/docs/cli/index.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/docs/cli/init.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/docs/cli/server.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/docs/getting-started.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/docs/guide/async.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/docs/guide/crdt.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/docs/guide/persistence.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/docs/guide/querying.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/docs/guide/tables.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/docs/guide/watching.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/docs/index.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/docs/migrations.md +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/src/cli/init.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/src/cli/router.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/src/cli/serialize.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/src/cli/server.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/src/config.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/src/db.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/src/differ.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/src/lib.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/src/matcher.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/src/persist.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/src/scanner.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/src/watcher.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/tests/async_sdk.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/tests/cli_e2e.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/tests/cli_integration.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/tests/docs_examples.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/tests/docs_gaps.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/tests/from_config.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/tests/init_e2e.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/tests/init_integration.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/tests/persist.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/tests/readonly_query.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/tests/sdk.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/packages/rust/tests/serialization.rs +0 -0
- {dirsql-0.3.17 → dirsql-0.3.18}/pyproject.toml +0 -0
|
@@ -4,7 +4,7 @@ name = "dirsql-py-ext"
|
|
|
4
4
|
# pypi/maturin handler can rewrite it via `write-version` before
|
|
5
5
|
# `maturin build`. `pyproject.toml` declares `dynamic = ["version"]`
|
|
6
6
|
# and maturin reads this field. Mirrors `packages/rust/Cargo.toml`.
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.18"
|
|
8
8
|
edition.workspace = true
|
|
9
9
|
publish = false
|
|
10
10
|
readme = "README.md"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""A native Python config file for dirsql.
|
|
2
|
+
|
|
3
|
+
When ``dirsql --config <path-to-this-file>`` runs, the Rust binary
|
|
4
|
+
spawns ``dirsql interpret`` against this file. The helper loads the
|
|
5
|
+
module, takes its module-level ``app``, and dispatches ``extract``
|
|
6
|
+
callbacks over NDJSON.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
from dirsql import DirSQL, Table
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _extract(path):
|
|
16
|
+
with open(path) as f:
|
|
17
|
+
return [json.load(f)]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
app = DirSQL(
|
|
21
|
+
root=os.path.join(os.path.dirname(__file__), "data"),
|
|
22
|
+
tables=[
|
|
23
|
+
Table(
|
|
24
|
+
ddl="CREATE TABLE papers (title TEXT)",
|
|
25
|
+
glob="**/meta.json",
|
|
26
|
+
extract=_extract,
|
|
27
|
+
)
|
|
28
|
+
],
|
|
29
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"title": "Alpha"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"title": "Beta"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""CLI integration test for native Python config file support.
|
|
2
|
+
|
|
3
|
+
Spawns the bundled Rust binary directly against the
|
|
4
|
+
``__fixtures__/dirsql.config.py`` fixture and asserts the HTTP server
|
|
5
|
+
serves the ``papers`` table. Bypasses the Python launcher because the
|
|
6
|
+
architectural property under test ("the Rust binary dispatches
|
|
7
|
+
non-TOML configs to ``dirsql interpret``") is the binary's job — the
|
|
8
|
+
launcher is a transparent forwarder.
|
|
9
|
+
|
|
10
|
+
The binary's `dirsql interpret <X>` subprocess resolves via PATH; in
|
|
11
|
+
this dev/CI tree the pip-installed `dirsql` console script (entry
|
|
12
|
+
point ``dirsql.cli.main:main``) is on PATH and handles the
|
|
13
|
+
``interpret`` subcommand directly.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
import os
|
|
18
|
+
import socket
|
|
19
|
+
import subprocess
|
|
20
|
+
import time
|
|
21
|
+
import urllib.error
|
|
22
|
+
import urllib.request
|
|
23
|
+
|
|
24
|
+
FIXTURE_DIR = os.path.join(os.path.dirname(__file__), "__fixtures__")
|
|
25
|
+
CONFIG_PATH = os.path.join(FIXTURE_DIR, "dirsql.config.py")
|
|
26
|
+
|
|
27
|
+
# Workspace root → cargo's target dir. The CI workflow builds the
|
|
28
|
+
# binary with `cargo build --release -p dirsql --features cli` before
|
|
29
|
+
# running integration tests; locally, `cargo build --release` does the
|
|
30
|
+
# same. Fall back to debug if release isn't present.
|
|
31
|
+
_REPO_ROOT = os.path.abspath(
|
|
32
|
+
os.path.join(os.path.dirname(__file__), "..", "..", "..", "..")
|
|
33
|
+
)
|
|
34
|
+
_RELEASE = os.path.join(_REPO_ROOT, "target", "release", "dirsql")
|
|
35
|
+
_DEBUG = os.path.join(_REPO_ROOT, "target", "debug", "dirsql")
|
|
36
|
+
BINARY = _RELEASE if os.path.exists(_RELEASE) else _DEBUG
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _free_port() -> int:
|
|
40
|
+
with socket.socket() as s:
|
|
41
|
+
s.bind(("", 0))
|
|
42
|
+
return s.getsockname()[1]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _wait_for_server(proc: subprocess.Popen, port: int, timeout: float = 5.0) -> bool:
|
|
46
|
+
"""Return True once the server accepts a connection, False if the process
|
|
47
|
+
exits first or the timeout elapses."""
|
|
48
|
+
deadline = time.monotonic() + timeout
|
|
49
|
+
while time.monotonic() < deadline:
|
|
50
|
+
if proc.poll() is not None:
|
|
51
|
+
return False
|
|
52
|
+
try:
|
|
53
|
+
urllib.request.urlopen(f"http://localhost:{port}/query", timeout=0.5)
|
|
54
|
+
return True
|
|
55
|
+
except urllib.error.HTTPError:
|
|
56
|
+
return True # any HTTP response means the server is up
|
|
57
|
+
except Exception:
|
|
58
|
+
time.sleep(0.05)
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _query(port: int, sql: str) -> list:
|
|
63
|
+
body = json.dumps({"sql": sql}).encode()
|
|
64
|
+
req = urllib.request.Request(
|
|
65
|
+
f"http://localhost:{port}/query",
|
|
66
|
+
data=body,
|
|
67
|
+
headers={"content-type": "application/json"},
|
|
68
|
+
)
|
|
69
|
+
with urllib.request.urlopen(req) as resp:
|
|
70
|
+
return json.loads(resp.read())
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def describe_cli_py_config():
|
|
74
|
+
def it_starts_an_http_server_serving_the_config_tables():
|
|
75
|
+
assert os.path.exists(BINARY), (
|
|
76
|
+
f"dirsql binary not built at {BINARY}; "
|
|
77
|
+
"run `cargo build --release -p dirsql --features cli` first"
|
|
78
|
+
)
|
|
79
|
+
port = _free_port()
|
|
80
|
+
proc = subprocess.Popen(
|
|
81
|
+
[
|
|
82
|
+
BINARY,
|
|
83
|
+
"--config",
|
|
84
|
+
CONFIG_PATH,
|
|
85
|
+
"--host",
|
|
86
|
+
"127.0.0.1",
|
|
87
|
+
"--port",
|
|
88
|
+
str(port),
|
|
89
|
+
],
|
|
90
|
+
stderr=subprocess.PIPE,
|
|
91
|
+
)
|
|
92
|
+
try:
|
|
93
|
+
assert _wait_for_server(proc, port), (
|
|
94
|
+
"dirsql server did not start with --config .py"
|
|
95
|
+
)
|
|
96
|
+
rows = _query(port, "SELECT title FROM papers ORDER BY title")
|
|
97
|
+
assert rows == [{"title": "Alpha"}, {"title": "Beta"}]
|
|
98
|
+
finally:
|
|
99
|
+
proc.terminate()
|
|
100
|
+
proc.wait(timeout=5)
|
|
@@ -8,7 +8,12 @@ use std::path::{Path, PathBuf};
|
|
|
8
8
|
use std::process::ExitCode;
|
|
9
9
|
|
|
10
10
|
use clap::{Args, Parser, Subcommand};
|
|
11
|
-
use dirsql::cli::{
|
|
11
|
+
use dirsql::cli::{
|
|
12
|
+
AppState, ServerConfig,
|
|
13
|
+
init::InitOptions,
|
|
14
|
+
native_config::{InterpretHelper, build_dirsql},
|
|
15
|
+
serve_with_state,
|
|
16
|
+
};
|
|
12
17
|
use dirsql::{DirSQL, Row, Table};
|
|
13
18
|
|
|
14
19
|
#[derive(Debug, Parser)]
|
|
@@ -152,12 +157,73 @@ fn load_state(cli: &Cli) -> AppState {
|
|
|
152
157
|
}
|
|
153
158
|
};
|
|
154
159
|
|
|
160
|
+
if is_native_config(&resolved) {
|
|
161
|
+
return load_native_state(&resolved);
|
|
162
|
+
}
|
|
163
|
+
|
|
155
164
|
match DirSQL::from_config_path(&resolved) {
|
|
156
165
|
Ok(db) => AppState::Ready(db),
|
|
157
166
|
Err(err) => AppState::Unavailable(format!("failed to load config: {err}")),
|
|
158
167
|
}
|
|
159
168
|
}
|
|
160
169
|
|
|
170
|
+
/// Native-language config support: `--config X.{py,js,mjs,cjs}` delegates
|
|
171
|
+
/// to `dirsql interpret <X>` (spawned via PATH) for `extract` execution.
|
|
172
|
+
/// The binary still owns SQL, HTTP, and the file watcher.
|
|
173
|
+
fn is_native_config(path: &Path) -> bool {
|
|
174
|
+
matches!(
|
|
175
|
+
path.extension().and_then(|s| s.to_str()),
|
|
176
|
+
Some("py") | Some("js") | Some("mjs") | Some("cjs")
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
fn load_native_state(config_path: &Path) -> AppState {
|
|
181
|
+
let (helper, config) = match spawn_interpret_helper(config_path) {
|
|
182
|
+
Ok(x) => x,
|
|
183
|
+
Err(err) => return AppState::Unavailable(err),
|
|
184
|
+
};
|
|
185
|
+
match build_dirsql(helper, config) {
|
|
186
|
+
Ok(db) => AppState::Ready(db),
|
|
187
|
+
Err(err) => AppState::Unavailable(format!(
|
|
188
|
+
"failed to build DirSQL from {}: {err}",
|
|
189
|
+
config_path.display()
|
|
190
|
+
)),
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/// Spawn `dirsql interpret <config_path>` via PATH and hand the child
|
|
195
|
+
/// off to [`InterpretHelper::from_child`]. Lives in the CLI binary
|
|
196
|
+
/// (rather than the lib's `cli::native_config` module) because the
|
|
197
|
+
/// `Command::new("dirsql")` plumbing is only meaningfully exercised
|
|
198
|
+
/// end-to-end via the `dirsql --config X.{py,js,mjs,cjs}` integration
|
|
199
|
+
/// path — there's no useful in-process unit test for it.
|
|
200
|
+
fn spawn_interpret_helper(
|
|
201
|
+
config_path: &Path,
|
|
202
|
+
) -> Result<
|
|
203
|
+
(
|
|
204
|
+
std::sync::Arc<InterpretHelper>,
|
|
205
|
+
dirsql::cli::native_config::NativeConfig,
|
|
206
|
+
),
|
|
207
|
+
String,
|
|
208
|
+
> {
|
|
209
|
+
use std::process::{Command, Stdio};
|
|
210
|
+
let child = Command::new("dirsql")
|
|
211
|
+
.arg("interpret")
|
|
212
|
+
.arg(config_path)
|
|
213
|
+
.stdin(Stdio::piped())
|
|
214
|
+
.stdout(Stdio::piped())
|
|
215
|
+
.stderr(Stdio::inherit())
|
|
216
|
+
.spawn()
|
|
217
|
+
.map_err(|e| {
|
|
218
|
+
format!(
|
|
219
|
+
"failed to spawn `dirsql interpret`: {e}. \
|
|
220
|
+
Native-language configs require a launcher that implements `interpret` \
|
|
221
|
+
on PATH (install dirsql via pip/uv or npm/npx)."
|
|
222
|
+
)
|
|
223
|
+
})?;
|
|
224
|
+
InterpretHelper::from_child(child)
|
|
225
|
+
}
|
|
226
|
+
|
|
161
227
|
/// Zero-config fallback. When no `.dirsql.toml` is found, dirsql indexes the
|
|
162
228
|
/// directory that would have held the config with a single default `files`
|
|
163
229
|
/// table — one row per file, columns drawn entirely from filesystem facts —
|