Repository: iterative/dvc

Issue:
import-url: lock by default
To make it symmetrical to `dvc import` command https://github.com/iterative/dvc/pull/2218 . For updating, we could introduce `dvc update-url`


Discussion:
I don't think we need `update-url`. Why not use `dvc update` to update that?
@Suor to have an ability to update ones or the others. Though, for that one could specify particular .dvc files, so the usefulness is disputable :) 
Had a discussion and decided to go with `dvc update` for urls too.

Need to make import-url lock by default and make `dvc update` work on import-urls.

Resolving patch:
diff --git a/dvc/dependency/base.py b/dvc/dependency/base.py
--- a/dvc/dependency/base.py
+++ b/dvc/dependency/base.py
@@ -22,4 +22,4 @@ class DependencyBase(object):
     IsNotFileOrDirError = DependencyIsNotFileOrDirError
 
     def update(self):
-        raise NotImplementedError
+        pass
diff --git a/dvc/repo/imp_url.py b/dvc/repo/imp_url.py
--- a/dvc/repo/imp_url.py
+++ b/dvc/repo/imp_url.py
@@ -3,7 +3,7 @@
 
 
 @scm_context
-def imp_url(self, url, out=None, fname=None, erepo=None, locked=False):
+def imp_url(self, url, out=None, fname=None, erepo=None, locked=True):
     from dvc.stage import Stage
 
     out = out or pathlib.PurePath(url).name
diff --git a/dvc/stage.py b/dvc/stage.py
--- a/dvc/stage.py
+++ b/dvc/stage.py
@@ -334,7 +334,7 @@ def reproduce(self, interactive=False, **kwargs):
         return self
 
     def update(self):
-        if not self.is_repo_import:
+        if not self.is_repo_import and not self.is_import:
             raise StageUpdateError(self.relpath)
 
         self.deps[0].update()


Test patch:
diff --git a/tests/func/test_repro.py b/tests/func/test_repro.py
--- a/tests/func/test_repro.py
+++ b/tests/func/test_repro.py
@@ -837,7 +837,9 @@ def check_already_cached(self, stage):
             with patch_download as mock_download:
                 with patch_checkout as mock_checkout:
                     with patch_run as mock_run:
+                        stage.locked = False
                         stage.run()
+                        stage.locked = True
 
                         mock_run.assert_not_called()
                         mock_download.assert_not_called()
@@ -918,14 +920,12 @@ def test(self, mock_prompt):
 
         self.assertNotEqual(self.dvc.status(), {})
 
-        stages = self.dvc.reproduce(import_stage.path)
-        self.assertEqual(len(stages), 1)
+        self.dvc.update(import_stage.path)
         self.assertTrue(os.path.exists("import"))
         self.assertTrue(filecmp.cmp("import", self.BAR, shallow=False))
         self.assertEqual(self.dvc.status(import_stage.path), {})
 
-        stages = self.dvc.reproduce(import_remote_stage.path)
-        self.assertEqual(len(stages), 1)
+        self.dvc.update(import_remote_stage.path)
         self.assertEqual(self.dvc.status(import_remote_stage.path), {})
 
         stages = self.dvc.reproduce(cmd_stage.path)
@@ -1323,6 +1323,7 @@ def test_force_import(self):
 
         with patch_download as mock_download:
             with patch_checkout as mock_checkout:
+                assert main(["unlock", "bar.dvc"]) == 0
                 ret = main(["repro", "--force", "bar.dvc"])
                 self.assertEqual(ret, 0)
                 self.assertEqual(mock_download.call_count, 1)
diff --git a/tests/func/test_update.py b/tests/func/test_update.py
--- a/tests/func/test_update.py
+++ b/tests/func/test_update.py
@@ -1,4 +1,6 @@
 import os
+import shutil
+import filecmp
 
 from dvc.repo import Repo
 
@@ -40,3 +42,28 @@ def test_update_import(dvc_repo, erepo):
     assert os.path.isfile(dst)
     with open(dst, "r+") as fobj:
         assert fobj.read() == "updated"
+
+
+def test_update_import_url(repo_dir, dvc_repo):
+    src = "file"
+    dst = src + "_imported"
+
+    shutil.copyfile(repo_dir.FOO, src)
+
+    stage = dvc_repo.imp_url(src, dst)
+
+    assert os.path.exists(dst)
+    assert os.path.isfile(dst)
+    assert filecmp.cmp(src, dst, shallow=False)
+
+    # update data
+    os.unlink(src)
+    shutil.copyfile(repo_dir.BAR, src)
+
+    assert dvc_repo.status(stage.path) == {}
+    dvc_repo.update(stage.path)
+    assert dvc_repo.status(stage.path) == {}
+
+    assert os.path.exists(dst)
+    assert os.path.isfile(dst)
+    assert filecmp.cmp(src, dst, shallow=False)