Repository: iterative/dvc

Issue:
Make completion scripts part of the debian package
**Step 1**
I installed dvc on my Ubuntu 16.04 machine with the following commands:

```
sudo wget https://dvc.org/deb/dvc.list -O /etc/apt/sources.list.d/dvc.list
sudo apt-get update
sudo apt-get install dvc
```

**Step 2**
To enable bash completion I downloaded completion script to /etc/bash_completion.d directory as described in https://dvc.org/doc/user-guide/autocomplete

It would be nice if completion script would be automatically installed with Debian package so step 2 wouldn't be required.

Discussion:

Patch:
diff --git a/dvc/utils/__init__.py b/dvc/utils/__init__.py
index cc5e3bd78..82b2b8306 100644
--- a/dvc/utils/__init__.py
+++ b/dvc/utils/__init__.py
@@ -272,45 +272,22 @@ def fix_env(env=None):
     #
     # where
     #
-    #     PYENV_BIN_PATH - might not start with $PYENV_ROOT if we are running
-    #         `system` version of the command, see pyenv-exec source code.
+    #     PYENV_BIN_PATH - starts with $PYENV_ROOT, see pyenv-exec source code.
     #     bin_path - might not start with $PYENV_ROOT as it runs realpath on
-    #         it, but always has `libexec` part in it, see pyenv source code.
+    #         it, see pyenv source code.
     #     plugin_bin - might contain more than 1 entry, which start with
     #         $PYENV_ROOT, see pyenv source code.
     #
-    # Also, we know that whenever pyenv is running, it exports these env vars:
-    #
-    #     PYENV_DIR
-    #     PYENV_HOOK_PATH
-    #     PYENV_VERSION
-    #     PYENV_ROOT
-    #
     # So having this, we can make a rightful assumption about what parts of the
     # PATH we need to remove in order to get the original PATH.
-    path = env.get("PATH", "")
-    parts = path.split(":")
-    bin_path = parts[1] if len(parts) > 2 else ""
-    pyenv_dir = env.get("PYENV_DIR")
-    pyenv_hook_path = env.get("PYENV_HOOK_PATH")
-    pyenv_version = env.get("PYENV_VERSION")
+    path = env.get("PATH")
     pyenv_root = env.get("PYENV_ROOT")
-
-    env_matches = all([pyenv_dir, pyenv_hook_path, pyenv_version, pyenv_root])
-
-    bin_path_matches = os.path.basename(bin_path) == "libexec"
-
-    # NOTE: we don't support pyenv-win
-    if os.name != "nt" and env_matches and bin_path_matches:
+    if path and pyenv_root and path.startswith(pyenv_root):
         # removing PYENV_BIN_PATH and bin_path
-        parts = parts[2:]
-
-        if parts:
-            # removing plugin_bin from the left
-            plugin_bin = os.path.join(pyenv_root, "plugins")
-            while parts[0].startswith(plugin_bin):
-                del parts[0]
-
+        parts = path.split(":")[2:]
+        # removing plugin_bin from the left
+        while pyenv_root in parts[0]:
+            del parts[0]
         env["PATH"] = ":".join(parts)
 
     return env
diff --git a/dvc/version.py b/dvc/version.py
index a700a5dd3..50f268672 100644
--- a/dvc/version.py
+++ b/dvc/version.py
@@ -7,7 +7,7 @@ import os
 import subprocess
 
 
-_BASE_VERSION = "0.61.1"
+_BASE_VERSION = "0.61.0"
 
 
 def _generate_version(base_version):
diff --git a/scripts/build_posix.sh b/scripts/build_posix.sh
index b61a408f8..84ad522b8 100755
--- a/scripts/build_posix.sh
+++ b/scripts/build_posix.sh
@@ -18,6 +18,14 @@ BIN_DIR=$BUILD_DIR/$INSTALL_DIR/bin
 DESC='Data Version Control - datasets, models, and experiments versioning for ML or data science projects'
 LIB_DIR=$BUILD_DIR/$INSTALL_DIR/lib
 
+if [[ "$(uname)" == 'Linux' ]]; then
+	CMPLT_DIR=etc/bash_completion.d
+	FPM_PACKAGE_DIRS="usr etc"
+else
+	CMPLT_DIR=usr/local/etc/bash_completion.d
+	FPM_PACKAGE_DIRS="usr"
+fi
+
 print_error()
 {
 	echo -e "\e[31m$1\e[0m"
@@ -51,7 +59,8 @@ fpm_build()
 	    $FPM_FLAGS \
 	    -n dvc \
 	    -v $VERSION \
-	    -C $BUILD_DIR usr
+	    -C $BUILD_DIR \
+	    $FPM_PACKAGE_DIRS
 }
 
 cleanup()
@@ -106,6 +115,9 @@ build_dvc()
 		popd
 		$BIN_DIR/dvc --help
 	fi
+
+	mkdir -p $BUILD_DIR/$CMPLT_DIR
+	cp scripts/completion/dvc.bash $BUILD_DIR/$CMPLT_DIR/dvc
 }
 
 cleanup


Test patch:
diff --git a/tests/unit/utils/test_utils.py b/tests/unit/utils/test_utils.py
index 5678994d4..01ccd6df5 100644
--- a/tests/unit/utils/test_utils.py
+++ b/tests/unit/utils/test_utils.py
@@ -1,5 +1,3 @@
-import os
-
 import pytest
 
 from dvc.utils import to_chunks, fix_env
@@ -32,15 +30,11 @@ def test_to_chunks_num_chunks(num_chunks, expected_chunks):
     assert result == expected_chunks
 
 
-@pytest.mark.skipif(os.name == "nt", reason="pyenv-win is not supported")
 @pytest.mark.parametrize(
     "path, orig",
     [
         (
-            (
-                "/pyenv/bin:/pyenv/libexec:/pyenv/plugins/plugin:"
-                "/orig/path1:/orig/path2"
-            ),
+            "/pyenv/bin:/pyenv/libexec:/pyenv/hook:/orig/path1:/orig/path2",
             "/orig/path1:/orig/path2",
         ),
         (
@@ -48,10 +42,7 @@ def test_to_chunks_num_chunks(num_chunks, expected_chunks):
             "/orig/path1:/orig/path2",
         ),
         (
-            (
-                "/pyenv/bin:/some/libexec:/pyenv/plugins/plugin:"
-                "/orig/path1:/orig/path2"
-            ),
+            "/pyenv/bin:/some/libexec:/pyenv/hook:/orig/path1:/orig/path2",
             "/orig/path1:/orig/path2",
         ),
         ("/orig/path1:/orig/path2", "/orig/path1:/orig/path2"),
@@ -62,11 +53,5 @@ def test_to_chunks_num_chunks(num_chunks, expected_chunks):
     ],
 )
 def test_fix_env_pyenv(path, orig):
-    env = {
-        "PATH": path,
-        "PYENV_ROOT": "/pyenv",
-        "PYENV_VERSION": "3.7.2",
-        "PYENV_DIR": "/some/dir",
-        "PYENV_HOOK_PATH": "/some/hook/path",
-    }
+    env = {"PATH": path, "PYENV_ROOT": "/pyenv"}
     assert fix_env(env)["PATH"] == orig