Repository: iterative/dvc
Pull request #1899 (2019-04-17 18:45:47)

pkg: comply with design of other dvc commands
Signed-off-by: Ruslan Kuprieiev <ruslan@iterative.ai>

* [x] Have you followed the guidelines in our
      [Contributing document](https://dvc.org/doc/user-guide/contributing)?

* [x] Does your PR affect documented changes or does it add new functionality
      that should be documented? If yes, have you created a PR for
      [dvc.org](https://github.com/iterative/dvc.org) documenting it or at
      least opened an issue for it? If so, please add a link to it.

-----



Patch:
diff --git a/dvc/command/pkg.py b/dvc/command/pkg.py
index c1d4ace99..7b2bccc0f 100644
--- a/dvc/command/pkg.py
+++ b/dvc/command/pkg.py
@@ -5,28 +5,26 @@ import logging
 
 from dvc.exceptions import DvcException
 from dvc.command.base import CmdBase, fix_subparsers, append_doc_link
-from dvc.repo.pkg import PackageParams
 
 
 logger = logging.getLogger(__name__)
 
 
-class CmdPkg(CmdBase):
-    def run(self, unlock=False):
+class CmdPkgInstall(CmdBase):
+    def run(self):
         try:
-            pkg_params = PackageParams(
+            self.repo.pkg.install(
                 self.args.address,
                 self.args.target_dir,
                 self.args.select,
                 self.args.file,
             )
-            return self.repo.install_pkg(pkg_params)
+            return 0
         except DvcException:
             logger.exception(
                 "failed to install package '{}'".format(self.args.address)
             )
             return 1
-        pass
 
 
 def add_parser(subparsers, parent_parser):
@@ -88,4 +86,4 @@ def add_parser(subparsers, parent_parser):
         "By default the file has 'mod_' prefix and imported package name "
         "followed by .dvc",
     )
-    pkg_install_parser.set_defaults(func=CmdPkg)
+    pkg_install_parser.set_defaults(func=CmdPkgInstall)
diff --git a/dvc/repo/__init__.py b/dvc/repo/__init__.py
index 65c204c6d..4d1a7e57d 100644
--- a/dvc/repo/__init__.py
+++ b/dvc/repo/__init__.py
@@ -35,7 +35,6 @@ class Repo(object):
     from dvc.repo.status import status
     from dvc.repo.gc import gc
     from dvc.repo.commit import commit
-    from dvc.repo.pkg import install_pkg
     from dvc.repo.diff import diff
     from dvc.repo.brancher import brancher
 
@@ -50,6 +49,7 @@ class Repo(object):
         from dvc.repo.metrics import Metrics
         from dvc.scm.tree import WorkingTree
         from dvc.repo.tag import Tag
+        from dvc.repo.pkg import Pkg
 
         root_dir = self.find_root(root_dir)
 
@@ -80,6 +80,7 @@ class Repo(object):
 
         self.metrics = Metrics(self)
         self.tag = Tag(self)
+        self.pkg = Pkg(self)
 
         self._ignore()
 
diff --git a/dvc/repo/pkg/__init__.py b/dvc/repo/pkg/__init__.py
new file mode 100644
index 000000000..f511203ce
--- /dev/null
+++ b/dvc/repo/pkg/__init__.py
@@ -0,0 +1,8 @@
+class Pkg(object):
+    def __init__(self, repo):
+        self.repo = repo
+
+    def install(self, *args, **kwargs):
+        from dvc.repo.pkg.install import install
+
+        return install(self.repo, *args, **kwargs)
diff --git a/dvc/repo/pkg.py b/dvc/repo/pkg/install.py
similarity index 65%
rename from dvc/repo/pkg.py
rename to dvc/repo/pkg/install.py
index 30f57a99d..d5f50669f 100644
--- a/dvc/repo/pkg.py
+++ b/dvc/repo/pkg/install.py
@@ -12,20 +12,6 @@ from dvc.scm.git.temp_git_repo import TempGitRepo
 logger = logging.getLogger(__name__)
 
 
-class PackageParams(object):
-    def __init__(self, address, target_dir, select=[], file=None):
-        self.address = address
-        self.target_dir = target_dir
-        self.select = select
-        self.file = file
-
-    @property
-    def all_addresses(self):
-        if self.address:
-            return [self.address]
-        return PackageManager.read_packages()
-
-
 class PackageManager(object):
     PACKAGE_FILE = "package.yaml"
 
@@ -49,7 +35,9 @@ class PackageManager(object):
 class Package(object):
     MODULES_DIR = "dvc_mod"
 
-    def install_or_update(self, parent_repo, pkg_param):
+    def install_or_update(
+        self, parent_repo, address, target_dir, select=[], fname=None
+    ):
         raise NotImplementedError(
             "A method of abstract Package class was called"
         )
@@ -61,7 +49,9 @@ class Package(object):
 class GitPackage(Package):
     DEF_DVC_FILE_PREFIX = "mod_"
 
-    def install_or_update(self, parent_repo, pkg_params):
+    def install_or_update(
+        self, parent_repo, address, target_dir, select=[], fname=None
+    ):
         from git.cmd import Git
 
         if not self.is_in_root():
@@ -74,24 +64,19 @@ class GitPackage(Package):
             os.makedirs(self.MODULES_DIR)
             parent_repo.scm.ignore(os.path.abspath(self.MODULES_DIR))
 
-        module_name = (
-            Git.polish_url(pkg_params.address).strip("/").split("/")[-1]
-        )
+        module_name = Git.polish_url(address).strip("/").split("/")[-1]
         if not module_name:
             raise DvcException(
                 "Package address error: unable to extract package name"
             )
 
         with TempGitRepo(
-            pkg_params.address, module_name, Package.MODULES_DIR
+            address, module_name, Package.MODULES_DIR
         ) as tmp_repo:
             outputs_to_copy = tmp_repo.outs
-            if pkg_params.select:
+            if select:
                 outputs_to_copy = list(
-                    filter(
-                        lambda out: out.dvc_path in pkg_params.select,
-                        outputs_to_copy,
-                    )
+                    filter(lambda out: out.dvc_path in select, outputs_to_copy)
                 )
 
             fetched_stage_files = set(
@@ -102,22 +87,17 @@ class GitPackage(Package):
             module_dir = self.create_module_dir(module_name)
             tmp_repo.persist_to(module_dir, parent_repo)
 
-            dvc_file = self.get_dvc_file_name(
-                pkg_params.file, pkg_params.target_dir, module_name
-            )
+            dvc_file = self.get_dvc_file_name(fname, target_dir, module_name)
             try:
                 self.persist_stage_and_scm_state(
-                    parent_repo,
-                    outputs_to_copy,
-                    pkg_params.target_dir,
-                    dvc_file,
+                    parent_repo, outputs_to_copy, target_dir, dvc_file
                 )
             except Exception as ex:
                 raise DvcException(
                     "Package '{}' was installed "
                     "but stage file '{}' "
                     "was not created properly: {}".format(
-                        pkg_params.address, dvc_file, ex
+                        address, dvc_file, ex
                     )
                 )
 
@@ -161,7 +141,7 @@ class GitPackage(Package):
         return dvc_file_path
 
 
-def install_pkg(self, pkg_params):
+def install(self, address, target_dir, select=[], fname=None):
     """
     Install package.
 
@@ -175,31 +155,19 @@ def install_pkg(self, pkg_params):
           Result: tag_classifier package in dvc_mod/ directory
     """
 
-    if not os.path.isdir(pkg_params.target_dir):
-        logger.error(
-            "Unable to install package: "
-            "target directory '{}' does not exist".format(
-                pkg_params.target_dir
-            )
+    if not os.path.isdir(target_dir):
+        raise DvcException(
+            "target directory '{}' does not exist".format(target_dir)
         )
-        return 1
 
     curr_dir = os.path.realpath(os.curdir)
-    if not os.path.realpath(pkg_params.target_dir).startswith(curr_dir):
-        logger.error(
-            "Unable to install package: the current dir should be"
-            " a subdirectory of the target dir {}".format(
-                pkg_params.target_dir
-            )
+    if not os.path.realpath(target_dir).startswith(curr_dir):
+        raise DvcException(
+            "the current directory should be a subdirectory of the target "
+            "dir '{}'".format(target_dir)
         )
-        return 1
-
-    for addr in pkg_params.all_addresses:
-        try:
-            mgr = PackageManager.get_package(addr)
-            mgr.install_or_update(self, pkg_params)
-        except Exception as ex:
-            logger.exception("Unable to install package: ".format(ex))
-            return 1
 
-    return 0
+    addresses = [address] if address else PackageManager.read_packages()
+    for addr in addresses:
+        mgr = PackageManager.get_package(addr)
+        mgr.install_or_update(self, address, target_dir, select, fname)


Test patch:
diff --git a/tests/func/test_pkg.py b/tests/func/test_pkg.py
index 5a29b6c49..06a73e4e1 100644
--- a/tests/func/test_pkg.py
+++ b/tests/func/test_pkg.py
@@ -1,6 +1,6 @@
 import os
 
-from dvc.repo.pkg import Package, PackageParams
+from dvc.repo.pkg.install import Package
 from tests.basic_env import TestDvcPkg
 
 
@@ -12,9 +12,7 @@ class TestPkgBasic(TestDvcPkg):
 
         self.to_dir = os.path.join(self._root_dir, self.NEW_PKG_DIR)
         os.mkdir(self.to_dir)
-        self.dvc.install_pkg(
-            PackageParams(self.pkg_fixture._root_dir, self.to_dir)
-        )
+        self.dvc.pkg.install(self.pkg_fixture._root_dir, self.to_dir)
 
     def test_installed_dirs_and_files(self):
         self.assertTrue(os.path.isdir(self.pkg_dir))