datasette-scan 0.1__tar.gz → 0.1.1__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.
- {datasette_scan-0.1 → datasette_scan-0.1.1}/PKG-INFO +1 -1
- {datasette_scan-0.1 → datasette_scan-0.1.1}/datasette_scan/__init__.py +9 -12
- {datasette_scan-0.1 → datasette_scan-0.1.1}/datasette_scan.egg-info/PKG-INFO +1 -1
- {datasette_scan-0.1 → datasette_scan-0.1.1}/pyproject.toml +1 -1
- {datasette_scan-0.1 → datasette_scan-0.1.1}/tests/test_scan.py +8 -10
- {datasette_scan-0.1 → datasette_scan-0.1.1}/LICENSE +0 -0
- {datasette_scan-0.1 → datasette_scan-0.1.1}/README.md +0 -0
- {datasette_scan-0.1 → datasette_scan-0.1.1}/datasette_scan.egg-info/SOURCES.txt +0 -0
- {datasette_scan-0.1 → datasette_scan-0.1.1}/datasette_scan.egg-info/dependency_links.txt +0 -0
- {datasette_scan-0.1 → datasette_scan-0.1.1}/datasette_scan.egg-info/entry_points.txt +0 -0
- {datasette_scan-0.1 → datasette_scan-0.1.1}/datasette_scan.egg-info/requires.txt +0 -0
- {datasette_scan-0.1 → datasette_scan-0.1.1}/datasette_scan.egg-info/top_level.txt +0 -0
- {datasette_scan-0.1 → datasette_scan-0.1.1}/setup.cfg +0 -0
|
@@ -12,16 +12,19 @@ import time
|
|
|
12
12
|
import sqlite_scanner
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
def validate_databases(paths):
|
|
15
|
+
def validate_databases(paths, nolock=False):
|
|
16
16
|
"""Check each path is a readable SQLite database.
|
|
17
17
|
|
|
18
18
|
Returns (valid, skipped) where skipped is a list of (path, reason) tuples.
|
|
19
19
|
"""
|
|
20
20
|
valid = []
|
|
21
21
|
skipped = []
|
|
22
|
+
qs = "?mode=ro"
|
|
23
|
+
if nolock:
|
|
24
|
+
qs += "&nolock=1"
|
|
22
25
|
for path in paths:
|
|
23
26
|
try:
|
|
24
|
-
conn = sqlite3.connect(f"file:{path}
|
|
27
|
+
conn = sqlite3.connect(f"file:{path}{qs}", uri=True)
|
|
25
28
|
try:
|
|
26
29
|
conn.execute("SELECT * FROM sqlite_master")
|
|
27
30
|
valid.append(path)
|
|
@@ -39,18 +42,14 @@ def scan_directories(directories):
|
|
|
39
42
|
"""
|
|
40
43
|
binary = sqlite_scanner.get_binary_path()
|
|
41
44
|
if not os.path.exists(binary):
|
|
42
|
-
raise click.ClickException(
|
|
43
|
-
f"sqlite-scanner binary not found at {binary}"
|
|
44
|
-
)
|
|
45
|
+
raise click.ClickException(f"sqlite-scanner binary not found at {binary}")
|
|
45
46
|
result = subprocess.run(
|
|
46
47
|
[binary, "--jsonl"] + list(directories),
|
|
47
48
|
capture_output=True,
|
|
48
49
|
text=True,
|
|
49
50
|
)
|
|
50
51
|
if result.returncode != 0:
|
|
51
|
-
raise click.ClickException(
|
|
52
|
-
f"sqlite-scanner failed: {result.stderr.strip()}"
|
|
53
|
-
)
|
|
52
|
+
raise click.ClickException(f"sqlite-scanner failed: {result.stderr.strip()}")
|
|
54
53
|
paths = []
|
|
55
54
|
for line in result.stdout.strip().splitlines():
|
|
56
55
|
if line:
|
|
@@ -117,11 +116,9 @@ def register_commands(cli):
|
|
|
117
116
|
|
|
118
117
|
# Validate scanned files, skip corrupted ones
|
|
119
118
|
if scanned_files:
|
|
120
|
-
valid, skipped = validate_databases(scanned_files)
|
|
119
|
+
valid, skipped = validate_databases(scanned_files, nolock=True)
|
|
121
120
|
for path, reason in skipped:
|
|
122
|
-
click.echo(
|
|
123
|
-
f"Skipping {path}: {reason}", err=True
|
|
124
|
-
)
|
|
121
|
+
click.echo(f"Skipping {path}: {reason}", err=True)
|
|
125
122
|
db_files.extend(valid)
|
|
126
123
|
|
|
127
124
|
# Always use nolock for safety with discovered files
|
|
@@ -2,7 +2,11 @@ import click
|
|
|
2
2
|
from click.testing import CliRunner
|
|
3
3
|
from datasette.app import Datasette
|
|
4
4
|
from datasette.cli import cli
|
|
5
|
-
from datasette_scan import
|
|
5
|
+
from datasette_scan import (
|
|
6
|
+
scan_directories,
|
|
7
|
+
rescan_and_add_databases,
|
|
8
|
+
validate_databases,
|
|
9
|
+
)
|
|
6
10
|
import json
|
|
7
11
|
import os
|
|
8
12
|
import pytest
|
|
@@ -50,9 +54,7 @@ def test_scan_has_serve_options():
|
|
|
50
54
|
serve_option_names = {
|
|
51
55
|
p.name for p in serve_cmd.params if isinstance(p, click.Option)
|
|
52
56
|
}
|
|
53
|
-
scan_option_names = {
|
|
54
|
-
p.name for p in scan_cmd.params if isinstance(p, click.Option)
|
|
55
|
-
}
|
|
57
|
+
scan_option_names = {p.name for p in scan_cmd.params if isinstance(p, click.Option)}
|
|
56
58
|
# All serve options except nolock should be present on scan
|
|
57
59
|
# nolock is always enabled for scan and not exposed as an option
|
|
58
60
|
missing = serve_option_names - scan_option_names - {"nolock"}
|
|
@@ -62,9 +64,7 @@ def test_scan_has_serve_options():
|
|
|
62
64
|
def test_scan_has_scan_interval_option():
|
|
63
65
|
"""scan should have the --scan-interval option that serve doesn't."""
|
|
64
66
|
scan_cmd = cli.commands["scan"]
|
|
65
|
-
scan_option_names = {
|
|
66
|
-
p.name for p in scan_cmd.params if isinstance(p, click.Option)
|
|
67
|
-
}
|
|
67
|
+
scan_option_names = {p.name for p in scan_cmd.params if isinstance(p, click.Option)}
|
|
68
68
|
assert "scan_interval" in scan_option_names
|
|
69
69
|
|
|
70
70
|
|
|
@@ -80,9 +80,7 @@ def test_scan_directories_finds_sqlite_files(tmp_with_dbs):
|
|
|
80
80
|
def test_scan_default_scans_current_directory(tmp_with_dbs):
|
|
81
81
|
"""With no args, scan should scan the current directory."""
|
|
82
82
|
runner = CliRunner()
|
|
83
|
-
result = runner.invoke(
|
|
84
|
-
cli, ["scan", "--get", "/.json"], catch_exceptions=False
|
|
85
|
-
)
|
|
83
|
+
result = runner.invoke(cli, ["scan", "--get", "/.json"], catch_exceptions=False)
|
|
86
84
|
# We just need it to not error - with no SQLite in cwd it may serve
|
|
87
85
|
# empty but should not crash
|
|
88
86
|
assert result.exit_code == 0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|