Repository: iterative/dvc

Issue:
add: Filenames containing the : character give an error.
# Bug Report

<!--
## Issue name

Issue names must follow the pattern `command: description` where the command is the dvc command that you are trying to run. The description should describe the consequence of the bug.

Example: `repro: doesn't detect input changes`
-->

## Description

<!--
A clear and concise description of what the bug is.
-->

DVC doesn't recognise file paths containing the : character, and instead tries to treat them as URLs, giving the error (for the file filena:me):

```console
ERROR: config file error: Unsupported URL type filena:// 
```

### Reproduce

<!--
Step list of how to reproduce the bug
-->

<!--
Example:

1. dvc init
2. Copy dataset.zip to the directory
3. dvc add dataset.zip
4. dvc run -d dataset.zip -o model ./train.sh
5. modify dataset.zip
6. dvc repro
-->
1. dvc init
2. touch filena:me
3. dvc add filena:me
### Expected

<!--
A clear and concise description of what you expect to happen.
-->
File should be added to the dvc repository.
### Environment information

<!--
This is required to ensure that we can reproduce the bug.
-->

**Output of `dvc doctor`:**

```console
DVC version: 2.38.1 (conda)
---------------------------------
Platform: Python 3.11.0 on macOS-13.1-arm64-arm-64bit
Subprojects:
	dvc_data = 0.28.4
	dvc_objects = 0.14.0
	dvc_render = 0.0.15
	dvc_task = 0.1.8
	dvclive = 1.3.0
	scmrepo = 0.1.4
Supports:
	http (aiohttp = 3.8.3, aiohttp-retry = 2.8.3),
	https (aiohttp = 3.8.3, aiohttp-retry = 2.8.3),
	ssh (sshfs = 2022.6.0)
Cache types: <https://error.dvc.org/no-dvc-cache>
Caches: local
Remotes: None
Workspace directory: apfs on /dev/disk3s1s1
Repo: dvc, git
```

**Additional Information (if any):**

<!--
Please check https://github.com/iterative/dvc/wiki/Debugging-DVC on ways to gather more information regarding the issue.

If applicable, please also provide a `--verbose` output of the command, eg: `dvc add --verbose`.
If the issue is regarding the performance, please attach the profiling information and the benchmark comparisons.
-->

add: Filenames containing the : character give an error.
# Bug Report

<!--
## Issue name

Issue names must follow the pattern `command: description` where the command is the dvc command that you are trying to run. The description should describe the consequence of the bug.

Example: `repro: doesn't detect input changes`
-->

## Description

<!--
A clear and concise description of what the bug is.
-->

DVC doesn't recognise file paths containing the : character, and instead tries to treat them as URLs, giving the error (for the file filena:me):

```console
ERROR: config file error: Unsupported URL type filena:// 
```

### Reproduce

<!--
Step list of how to reproduce the bug
-->

<!--
Example:

1. dvc init
2. Copy dataset.zip to the directory
3. dvc add dataset.zip
4. dvc run -d dataset.zip -o model ./train.sh
5. modify dataset.zip
6. dvc repro
-->
1. dvc init
2. touch filena:me
3. dvc add filena:me
### Expected

<!--
A clear and concise description of what you expect to happen.
-->
File should be added to the dvc repository.
### Environment information

<!--
This is required to ensure that we can reproduce the bug.
-->

**Output of `dvc doctor`:**

```console
DVC version: 2.38.1 (conda)
---------------------------------
Platform: Python 3.11.0 on macOS-13.1-arm64-arm-64bit
Subprojects:
	dvc_data = 0.28.4
	dvc_objects = 0.14.0
	dvc_render = 0.0.15
	dvc_task = 0.1.8
	dvclive = 1.3.0
	scmrepo = 0.1.4
Supports:
	http (aiohttp = 3.8.3, aiohttp-retry = 2.8.3),
	https (aiohttp = 3.8.3, aiohttp-retry = 2.8.3),
	ssh (sshfs = 2022.6.0)
Cache types: <https://error.dvc.org/no-dvc-cache>
Caches: local
Remotes: None
Workspace directory: apfs on /dev/disk3s1s1
Repo: dvc, git
```

**Additional Information (if any):**

<!--
Please check https://github.com/iterative/dvc/wiki/Debugging-DVC on ways to gather more information regarding the issue.

If applicable, please also provide a `--verbose` output of the command, eg: `dvc add --verbose`.
If the issue is regarding the performance, please attach the profiling information and the benchmark comparisons.
-->



Discussion:
I can reproduce it. it's a bug of `dvc add`
related: https://github.com/iterative/dvc-objects/issues/177
It is happening because we consider the filename also a URL. And urlparse returns filena as scheme.
This should be resolved by https://github.com/iterative/dvc-objects/pull/179
> This should be resolved by https://github.com/iterative/dvc-objects/pull/179

@pmrowla This one is different and not resolved by the link. It fails at config validation:

https://github.com/iterative/dvc/blob/f68a12558aac7da25c721877e855d5c115d07261/dvc/config_schema.py#L50-L55






I can reproduce it. it's a bug of `dvc add`
related: https://github.com/iterative/dvc-objects/issues/177
It is happening because we consider the filename also a URL. And urlparse returns filena as scheme.
This should be resolved by https://github.com/iterative/dvc-objects/pull/179
> This should be resolved by https://github.com/iterative/dvc-objects/pull/179

@pmrowla This one is different and not resolved by the link. It fails at config validation:

https://github.com/iterative/dvc/blob/f68a12558aac7da25c721877e855d5c115d07261/dvc/config_schema.py#L50-L55







Resolving patch:
diff --git a/dvc/config_schema.py b/dvc/config_schema.py
--- a/dvc/config_schema.py
+++ b/dvc/config_schema.py
@@ -51,6 +51,8 @@ def validate(data):
         # Windows absolute paths should really have scheme == "" (local)
         if os.name == "nt" and len(parsed.scheme) == 1 and parsed.netloc == "":
             return schemas[""](data)
+        if parsed.netloc == "":
+            return schemas[""](data)
         if parsed.scheme not in schemas:
             raise Invalid(f"Unsupported URL type {parsed.scheme}://")
 


Test patch:
diff --git a/tests/func/test_add.py b/tests/func/test_add.py
--- a/tests/func/test_add.py
+++ b/tests/func/test_add.py
@@ -342,6 +342,13 @@ def test_double_add_unchanged_dir(tmp_dir, dvc):
     assert ret == 0
 
 
+@pytest.mark.skipif(os.name == "nt", reason="unsupported on Windows")
+def test_add_colon_in_filename(tmp_dir, dvc):
+    tmp_dir.gen("fo:o", "foo")
+    ret = main(["add", "fo:o"])
+    assert ret == 0
+
+
 def test_should_update_state_entry_for_file_after_add(mocker, dvc, tmp_dir):
     file_md5_counter = mocker.spy(dvc_data.hashfile.hash, "file_md5")
     tmp_dir.gen("foo", "foo")