dirsql 0.3.57__tar.gz → 0.3.58__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.
Files changed (124) hide show
  1. {dirsql-0.3.57 → dirsql-0.3.58}/Cargo.lock +1 -1
  2. {dirsql-0.3.57 → dirsql-0.3.58}/PKG-INFO +1 -1
  3. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/Cargo.toml +1 -1
  4. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/e2e-attestation.json +2 -2
  5. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/src/cli/init.rs +17 -0
  6. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/src/cli/server.rs +29 -0
  7. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/src/command.rs +99 -0
  8. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/src/lib.rs +559 -0
  9. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/src/persist.rs +70 -0
  10. {dirsql-0.3.57 → dirsql-0.3.58}/Cargo.toml +0 -0
  11. {dirsql-0.3.57 → dirsql-0.3.58}/README.md +0 -0
  12. {dirsql-0.3.57 → dirsql-0.3.58}/dirsql/__init__.py +0 -0
  13. {dirsql-0.3.57 → dirsql-0.3.58}/dirsql/_async.py +0 -0
  14. {dirsql-0.3.57 → dirsql-0.3.58}/dirsql/_dirsql.pyi +0 -0
  15. {dirsql-0.3.57 → dirsql-0.3.58}/dirsql/cli/__init__.py +0 -0
  16. {dirsql-0.3.57 → dirsql-0.3.58}/dirsql/cli/binary_path.py +0 -0
  17. {dirsql-0.3.57 → dirsql-0.3.58}/dirsql/cli/interpret/__init__.py +0 -0
  18. {dirsql-0.3.57 → dirsql-0.3.58}/dirsql/cli/is_windows.py +0 -0
  19. {dirsql-0.3.57 → dirsql-0.3.58}/dirsql/cli/main.py +0 -0
  20. {dirsql-0.3.57 → dirsql-0.3.58}/dirsql/cli/resolve_config_extensions.py +0 -0
  21. {dirsql-0.3.57 → dirsql-0.3.58}/dirsql/py.typed +0 -0
  22. {dirsql-0.3.57 → dirsql-0.3.58}/dirsql/resolve_config_extensions.py +0 -0
  23. {dirsql-0.3.57 → dirsql-0.3.58}/dirsql/resolve_extension.py +0 -0
  24. {dirsql-0.3.57 → dirsql-0.3.58}/docs/.claude/CLAUDE.md +0 -0
  25. {dirsql-0.3.57 → dirsql-0.3.58}/docs/.vitepress/config.ts +0 -0
  26. {dirsql-0.3.57 → dirsql-0.3.58}/docs/.vitepress/theme/index.ts +0 -0
  27. {dirsql-0.3.57 → dirsql-0.3.58}/docs/.vitepress/theme/lang.ts +0 -0
  28. {dirsql-0.3.57 → dirsql-0.3.58}/docs/AGENTS.md +0 -0
  29. {dirsql-0.3.57 → dirsql-0.3.58}/docs/api/index.md +0 -0
  30. {dirsql-0.3.57 → dirsql-0.3.58}/docs/cli/config.md +0 -0
  31. {dirsql-0.3.57 → dirsql-0.3.58}/docs/cli/http-api.md +0 -0
  32. {dirsql-0.3.57 → dirsql-0.3.58}/docs/cli/index.md +0 -0
  33. {dirsql-0.3.57 → dirsql-0.3.58}/docs/cli/init.md +0 -0
  34. {dirsql-0.3.57 → dirsql-0.3.58}/docs/cli/server.md +0 -0
  35. {dirsql-0.3.57 → dirsql-0.3.58}/docs/getting-started.md +0 -0
  36. {dirsql-0.3.57 → dirsql-0.3.58}/docs/guide/async.md +0 -0
  37. {dirsql-0.3.57 → dirsql-0.3.58}/docs/guide/crdt.md +0 -0
  38. {dirsql-0.3.57 → dirsql-0.3.58}/docs/guide/persistence.md +0 -0
  39. {dirsql-0.3.57 → dirsql-0.3.58}/docs/guide/querying.md +0 -0
  40. {dirsql-0.3.57 → dirsql-0.3.58}/docs/guide/tables.md +0 -0
  41. {dirsql-0.3.57 → dirsql-0.3.58}/docs/guide/watching.md +0 -0
  42. {dirsql-0.3.57 → dirsql-0.3.58}/docs/index.md +0 -0
  43. {dirsql-0.3.57 → dirsql-0.3.58}/docs/migrations.md +0 -0
  44. {dirsql-0.3.57 → dirsql-0.3.58}/docs/package.json +0 -0
  45. {dirsql-0.3.57 → dirsql-0.3.58}/docs/playwright.config.ts +0 -0
  46. {dirsql-0.3.57 → dirsql-0.3.58}/docs/pnpm-lock.yaml +0 -0
  47. {dirsql-0.3.57 → dirsql-0.3.58}/docs/pnpm-workspace.yaml +0 -0
  48. {dirsql-0.3.57 → dirsql-0.3.58}/docs/tests/integration/home.spec.ts +0 -0
  49. {dirsql-0.3.57 → dirsql-0.3.58}/docs/tests/integration/language-flag.spec.ts +0 -0
  50. {dirsql-0.3.57 → dirsql-0.3.58}/docs/tests/integration/sidebar.spec.ts +0 -0
  51. {dirsql-0.3.57 → dirsql-0.3.58}/docs/tests/unit/config.test.ts +0 -0
  52. {dirsql-0.3.57 → dirsql-0.3.58}/docs/tests/unit/lang.test.ts +0 -0
  53. {dirsql-0.3.57 → dirsql-0.3.58}/docs/vitest.config.ts +0 -0
  54. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/README.md +0 -0
  55. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/conftest.py +0 -0
  56. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/.claude/CLAUDE.md +0 -0
  57. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/.vitepress/config.ts +0 -0
  58. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/.vitepress/theme/index.ts +0 -0
  59. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
  60. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/AGENTS.md +0 -0
  61. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/api/index.md +0 -0
  62. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/cli/config.md +0 -0
  63. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/cli/http-api.md +0 -0
  64. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/cli/index.md +0 -0
  65. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/cli/init.md +0 -0
  66. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/cli/server.md +0 -0
  67. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/getting-started.md +0 -0
  68. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/guide/async.md +0 -0
  69. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/guide/crdt.md +0 -0
  70. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/guide/persistence.md +0 -0
  71. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/guide/querying.md +0 -0
  72. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/guide/tables.md +0 -0
  73. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/guide/watching.md +0 -0
  74. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/index.md +0 -0
  75. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/migrations.md +0 -0
  76. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/package.json +0 -0
  77. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/playwright.config.ts +0 -0
  78. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/pnpm-lock.yaml +0 -0
  79. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/pnpm-workspace.yaml +0 -0
  80. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/tests/integration/home.spec.ts +0 -0
  81. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/tests/integration/language-flag.spec.ts +0 -0
  82. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/tests/integration/sidebar.spec.ts +0 -0
  83. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/tests/unit/config.test.ts +0 -0
  84. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/tests/unit/lang.test.ts +0 -0
  85. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/docs/vitest.config.ts +0 -0
  86. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/src/lib.rs +0 -0
  87. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/tests/__init__.py +0 -0
  88. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/tests/binding/__init__.py +0 -0
  89. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/tests/conftest.py +0 -0
  90. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/tests/e2e/__init__.py +0 -0
  91. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/tests/integration/__init__.py +0 -0
  92. {dirsql-0.3.57 → dirsql-0.3.58}/packages/python/tests/smoke/__init__.py +0 -0
  93. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/Cargo.toml +0 -0
  94. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/README.md +0 -0
  95. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/benches/db_bench.rs +0 -0
  96. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/benches/differ_bench.rs +0 -0
  97. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/benches/matcher_bench.rs +0 -0
  98. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/benches/scanner_bench.rs +0 -0
  99. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/docs/api/index.md +0 -0
  100. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/docs/cli/config.md +0 -0
  101. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/docs/cli/http-api.md +0 -0
  102. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/docs/cli/index.md +0 -0
  103. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/docs/cli/init.md +0 -0
  104. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/docs/cli/server.md +0 -0
  105. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/docs/getting-started.md +0 -0
  106. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/docs/guide/async.md +0 -0
  107. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/docs/guide/crdt.md +0 -0
  108. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/docs/guide/persistence.md +0 -0
  109. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/docs/guide/querying.md +0 -0
  110. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/docs/guide/tables.md +0 -0
  111. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/docs/guide/watching.md +0 -0
  112. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/docs/index.md +0 -0
  113. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/docs/migrations.md +0 -0
  114. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/src/bin/dirsql.rs +0 -0
  115. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/src/cli/mod.rs +0 -0
  116. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/src/cli/router.rs +0 -0
  117. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/src/cli/serialize.rs +0 -0
  118. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/src/config.rs +0 -0
  119. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/src/db.rs +0 -0
  120. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/src/differ.rs +0 -0
  121. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/src/matcher.rs +0 -0
  122. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/src/scanner.rs +0 -0
  123. {dirsql-0.3.57 → dirsql-0.3.58}/packages/rust/src/watcher.rs +0 -0
  124. {dirsql-0.3.57 → dirsql-0.3.58}/pyproject.toml +0 -0
@@ -500,7 +500,7 @@ dependencies = [
500
500
 
501
501
  [[package]]
502
502
  name = "dirsql-py-ext"
503
- version = "0.3.57"
503
+ version = "0.3.58"
504
504
  dependencies = [
505
505
  "dirsql",
506
506
  "pyo3",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dirsql
3
- Version: 0.3.57
3
+ Version: 0.3.58
4
4
  Requires-Dist: pytest>=8 ; extra == 'dev'
5
5
  Requires-Dist: pytest-describe>=2 ; extra == 'dev'
6
6
  Requires-Dist: pytest-asyncio>=0.23 ; extra == 'dev'
@@ -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.57"
7
+ version = "0.3.58"
8
8
  edition.workspace = true
9
9
  publish = false
10
10
  readme = "README.md"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "command": "uv run python -m pytest tests/e2e/ -x -q",
3
- "ran_at": 1783105847,
3
+ "ran_at": 1783118080,
4
4
  "exit_code": 0,
5
- "commit": "d94d40b0448b03171f2e8ffd60635575da1353d5"
5
+ "commit": "b45791b9ad04fbac360618f3ff885e5f84a8289e"
6
6
  }
@@ -149,4 +149,21 @@ mod tests {
149
149
  let msg = format!("{err}").to_lowercase();
150
150
  assert!(msg.contains("claude"));
151
151
  }
152
+
153
+ /// `run` bails before spawning the agent when the output already exists and
154
+ /// `--force` was not passed (the temp dir itself is an existing path).
155
+ #[test]
156
+ fn run_bails_when_output_exists_without_force() {
157
+ let dir = tempfile::tempdir().unwrap();
158
+ let opts = InitOptions {
159
+ root: dir.path().to_path_buf(),
160
+ output: dir.path().to_path_buf(),
161
+ force: false,
162
+ };
163
+ let err = run(opts).unwrap_err();
164
+ assert!(
165
+ matches!(err, InitError::AlreadyExists { .. }),
166
+ "got: {err:?}"
167
+ );
168
+ }
152
169
  }
@@ -114,4 +114,33 @@ mod tests {
114
114
 
115
115
  handle.shutdown().await.expect("graceful shutdown");
116
116
  }
117
+
118
+ // A `Ready` state drives the `serve` convenience wrapper plus
119
+ // `start_watch_task` (which attaches `DirSQL::watch` and pumps its stream
120
+ // into the broadcast channel). Built over an empty temp dir so the scan
121
+ // touches nothing; the port-0 bind and graceful shutdown are real.
122
+ #[tokio::test]
123
+ async fn serve_with_a_ready_db_attaches_the_watcher_then_shuts_down() {
124
+ let dir = tempfile::tempdir().unwrap();
125
+ let db = DirSQL::new(dir.path(), Vec::new()).unwrap();
126
+ let config = ServerConfig::bind("127.0.0.1".to_string(), 0);
127
+ let handle = serve(config, db).await.expect("bind on an ephemeral port");
128
+ assert_ne!(handle.local_addr().port(), 0);
129
+ handle.shutdown().await.expect("graceful shutdown");
130
+ }
131
+
132
+ // Binding to a non-local TEST-NET address (RFC 5737) fails with
133
+ // "cannot assign requested address", surfacing `ServerError::Bind` rather
134
+ // than panicking — deterministic and DNS-free.
135
+ #[tokio::test]
136
+ async fn serve_with_state_surfaces_a_bind_error_for_a_nonlocal_address() {
137
+ let config = ServerConfig::bind("192.0.2.1".to_string(), 9);
138
+ // `serve_with_state` returns `Result<ServerHandle, _>`; ServerHandle is
139
+ // not Debug, so match rather than `unwrap_err`.
140
+ let err = match serve_with_state(config, AppState::Unavailable("x".to_string())).await {
141
+ Ok(_) => panic!("expected a bind error"),
142
+ Err(e) => e,
143
+ };
144
+ assert!(matches!(err, ServerError::Bind { .. }), "got: {err:?}");
145
+ }
117
146
  }
@@ -484,4 +484,103 @@ mod tests {
484
484
  assert!(!Placeholder::new("a", "b").append_if_absent);
485
485
  assert!(Placeholder::append("a", "b").append_if_absent);
486
486
  }
487
+
488
+ // ----- run_command end-to-end (spawns trivial POSIX commands) ----------
489
+ //
490
+ // `run_command` can only be exercised by actually spawning a child, so
491
+ // these drive `sh`/`echo`/`cat` — universally present on the Linux CI
492
+ // runners. The test code itself statically references only `super::` items,
493
+ // `Duration`, and `std::path::Path`, so the `unit lint` isolation rule is
494
+ // satisfied; the effectful process/thread work lives in production code.
495
+
496
+ fn cwd() -> std::path::PathBuf {
497
+ std::path::PathBuf::from(".")
498
+ }
499
+
500
+ #[test]
501
+ fn run_command_returns_last_nonempty_stdout_line() {
502
+ let out = run_command(
503
+ "sh -c 'echo chatter; echo PAYLOAD'",
504
+ &[],
505
+ &cwd(),
506
+ Duration::from_secs(30),
507
+ None,
508
+ )
509
+ .unwrap();
510
+ assert_eq!(out.payload, "PAYLOAD");
511
+ }
512
+
513
+ #[test]
514
+ fn run_command_writes_stdin_payload_to_the_child() {
515
+ // `cat` echoes its stdin, so the payload round-trips through the
516
+ // stdin-writer thread and the stdout drain.
517
+ let out = run_command(
518
+ "cat",
519
+ &[],
520
+ &cwd(),
521
+ Duration::from_secs(30),
522
+ Some(b"hello-stdin"),
523
+ )
524
+ .unwrap();
525
+ assert_eq!(out.payload, "hello-stdin");
526
+ }
527
+
528
+ #[test]
529
+ fn run_command_reports_nonzero_exit_with_stderr_tail() {
530
+ let err = run_command(
531
+ "sh -c 'echo oops >&2; exit 3'",
532
+ &[],
533
+ &cwd(),
534
+ Duration::from_secs(30),
535
+ None,
536
+ )
537
+ .unwrap_err();
538
+ match err {
539
+ CommandError::NonZeroExit {
540
+ code, stderr_tail, ..
541
+ } => {
542
+ assert_eq!(code, "3");
543
+ assert!(stderr_tail.contains("oops"), "got: {stderr_tail}");
544
+ }
545
+ other => panic!("expected NonZeroExit, got {other:?}"),
546
+ }
547
+ }
548
+
549
+ #[test]
550
+ fn run_command_reports_empty_output_when_stdout_is_blank() {
551
+ let err = run_command("true", &[], &cwd(), Duration::from_secs(30), None).unwrap_err();
552
+ assert!(
553
+ matches!(err, CommandError::EmptyOutput { .. }),
554
+ "got: {err:?}"
555
+ );
556
+ }
557
+
558
+ #[test]
559
+ fn run_command_reports_spawn_failure_for_a_missing_program() {
560
+ let err = run_command(
561
+ "definitely-not-a-real-binary-xyzzy",
562
+ &[],
563
+ &cwd(),
564
+ Duration::from_secs(30),
565
+ None,
566
+ )
567
+ .unwrap_err();
568
+ assert!(matches!(err, CommandError::Spawn { .. }), "got: {err:?}");
569
+ }
570
+
571
+ #[test]
572
+ fn run_command_kills_and_reports_timeout_even_with_stdin() {
573
+ // A short timeout against a long sleep drives the timeout branch,
574
+ // including joining the stdin-writer thread. `sh` ignoring stdin closes
575
+ // the pipe early, which the writer treats as a clean EOF.
576
+ let err = run_command(
577
+ "sh -c 'sleep 30'",
578
+ &[],
579
+ &cwd(),
580
+ Duration::from_millis(50),
581
+ Some(b"x"),
582
+ )
583
+ .unwrap_err();
584
+ assert!(matches!(err, CommandError::Timeout { .. }), "got: {err:?}");
585
+ }
487
586
  }