Skip to content

Commit 57b0596

Browse files
committed
state: quote % in path
Fixes #2885
1 parent 516e3b1 commit 57b0596

File tree

2 files changed

+29
-1
lines changed

2 files changed

+29
-1
lines changed

dvc/state.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,8 +496,14 @@ def _connect_sqlite(filename, options):
496496

497497

498498
def _build_sqlite_uri(filename, options):
499+
# In the doc mentioned below we only need to replace ? -> %3f and
500+
# # -> %23, but, if present, we also need to replace % -> %25 first
501+
# (happens when we are on a weird FS that shows urlencoded filenames
502+
# instead of proper ones) to not confuse sqlite.
503+
uri_path = filename.replace("%", "%25")
504+
499505
# Convert filename to uri according to https://www.sqlite.org/uri.html, 3.1
500-
uri_path = filename.replace("?", "%3f").replace("#", "%23")
506+
uri_path = uri_path.replace("?", "%3f").replace("#", "%23")
501507
if os.name == "nt":
502508
uri_path = uri_path.replace("\\", "/")
503509
uri_path = re.sub(r"^([a-z]:)", "/\\1", uri_path, flags=re.I)

tests/unit/test_state.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import pytest
2+
from dvc.state import _build_sqlite_uri
3+
4+
5+
@pytest.mark.parametrize(
6+
"path, osname, result",
7+
[
8+
("/abs/path", "posix", "file:///abs/path"),
9+
("C:\\abs\\path", "nt", "file:///C:/abs/path"),
10+
("/abs/p?ath", "posix", "file:///abs/p%3fath"),
11+
("C:\\abs\\p?ath", "nt", "file:///C:/abs/p%3fath"),
12+
("/abs/p#ath", "posix", "file:///abs/p%23ath"),
13+
("C:\\abs\\p#ath", "nt", "file:///C:/abs/p%23ath"),
14+
("/abs/path space", "posix", "file:///abs/path space"),
15+
("C:\\abs\\path space", "nt", "file:///C:/abs/path space"),
16+
("/abs/path%20encoded", "posix", "file:///abs/path%2520encoded"),
17+
("C:\\abs\\path%20encoded", "nt", "file:///C:/abs/path%2520encoded"),
18+
],
19+
)
20+
def test_build_uri(path, osname, result, mocker):
21+
mocker.patch("os.name", osname)
22+
assert _build_sqlite_uri(path, {}) == result

0 commit comments

Comments
 (0)