Repository: dataversioncontrol/dvc (python)

Issue:
Show all remotes
Something similar to Git is needed:
```
$ git remote
origin
$ git remote -v
origin	https://github.com/dataversioncontrol/dvc.git (fetch)
origin	https://github.com/dataversioncontrol/dvc.git (push)
```

Pull request description:
dvc: introduce 'dvc remote list'
Fixes #690

Signed-off-by: Ruslan Kuprieiev <kupruser@gmail.com>

Patch:
diff --git a/dvc/cli.py b/dvc/cli.py
index 0ea61e3a5..075aff008 100644
--- a/dvc/cli.py
+++ b/dvc/cli.py
@@ -16,7 +16,7 @@ from dvc.command.gc import CmdGC
 from dvc.command.add import CmdAdd
 from dvc.command.config import CmdConfig
 from dvc.command.checkout import CmdCheckout
-from dvc.command.remote import CmdRemoteAdd, CmdRemoteRemove, CmdRemoteModify
+from dvc.command.remote import CmdRemoteAdd, CmdRemoteRemove, CmdRemoteModify, CmdRemoteList
 from dvc.command.metrics import CmdMetrics
 from dvc.command.install import CmdInstall
 from dvc.stage import Stage
@@ -327,6 +327,18 @@ def parse_args(argv=None):
                         help='Use local config')
     remote_modify_parser.set_defaults(func=CmdRemoteModify)
 
+
+    remote_list_parser = remote_subparsers.add_parser(
+                        'list',
+                        parents=[parent_parser],
+                        help='List remotes')
+    remote_list_parser.add_argument(
+                        '--local',
+                        action='store_true',
+                        default=False,
+                        help='Use local config')
+    remote_list_parser.set_defaults(func=CmdRemoteList)
+
     # Metrics
     metrics_parser = subparsers.add_parser(
                         'metrics',
diff --git a/dvc/command/config.py b/dvc/command/config.py
index dc669c657..7e33b1f99 100644
--- a/dvc/command/config.py
+++ b/dvc/command/config.py
@@ -42,16 +42,15 @@ class CmdConfig(CmdBase):
             return 1
         return 0
 
-    def unset(self, section, opt):
+    def unset(self, section, opt=None):
         if section not in self.configobj.keys():
             Logger.error("Section '{}' doesn't exist".format(section))
             return 1
 
-        if opt not in self.configobj[section].keys():
-            return 0
+        if opt in self.configobj[section].keys():
+            del self.configobj[section][opt]
 
-        del self.configobj[section][opt]
-        if len(self.configobj[section]) == 0:
+        if len(self.configobj[section]) == 0 or opt == None:
             del self.configobj[section]
 
         return self.save()
diff --git a/dvc/command/remote.py b/dvc/command/remote.py
index 48c0dd853..d0335d830 100644
--- a/dvc/command/remote.py
+++ b/dvc/command/remote.py
@@ -1,6 +1,8 @@
-from dvc.command.common.base import CmdBase
+import re
+
 from dvc.config import Config
 from dvc.command.config import CmdConfig
+from dvc.logger import Logger
 
 
 class CmdRemoteAdd(CmdConfig):
@@ -20,3 +22,14 @@ class CmdRemoteModify(CmdConfig):
         section = Config.SECTION_REMOTE_FMT.format(self.args.name)
         self.args.name = '{}.{}'.format(section, self.args.option)
         return super(CmdRemoteModify, self).run()
+
+
+class CmdRemoteList(CmdConfig):
+    def run(self):
+        for section in self.configobj.keys():
+            r = re.match(Config.SECTION_REMOTE_REGEX, section)
+            if r:
+                name = r.group('name')
+                url = self.configobj[section].get(Config.SECTION_REMOTE_URL, '')
+                Logger.info('{}\t{}'.format(name, url))
+        return 0
diff --git a/dvc/config.py b/dvc/config.py
index a98454d9a..110a46d38 100644
--- a/dvc/config.py
+++ b/dvc/config.py
@@ -82,7 +82,7 @@ class Config(object):
     }
 
 
-    SECTION_REMOTE_REGEX = r'^\s*remote\s*"(.*)"\s*$'
+    SECTION_REMOTE_REGEX = r'^\s*remote\s*"(?P<name>.*)"\s*$'
     SECTION_REMOTE_FMT = 'remote "{}"'
     SECTION_REMOTE_URL = 'url'
     SECTION_REMOTE_SCHEMA = {
diff --git a/dvc/main.py b/dvc/main.py
index b62ce0801..1f708d00f 100644
--- a/dvc/main.py
+++ b/dvc/main.py
@@ -1,11 +1,17 @@
 from dvc.logger import Logger
 from dvc.cli import parse_args
+from dvc.command.common.base import CmdBase
+
 
 def main(argv=None):
     Logger.init()
 
     args = parse_args(argv)
 
+    # Init loglevel early in case we'll run
+    # into errors before setting it properly
+    CmdBase._set_loglevel(args)
+
     try:
         cmd = args.func(args)
     except Exception as ex:


Test patch:
diff --git a/tests/test_remote.py b/tests/test_remote.py
new file mode 100644
index 000000000..8ad6b35b6
--- /dev/null
+++ b/tests/test_remote.py
@@ -0,0 +1,21 @@
+from dvc.main import main
+
+from tests.basic_env import TestDvc
+
+
+class TestRemote(TestDvc):
+    def test(self):
+        remotes = ['a', 'b', 'c']
+
+        self.assertEqual(main(['remote', 'list']), 0)
+        self.assertNotEqual(main(['remote', 'remove', remotes[0]]), 0)
+
+        for r in remotes:
+            self.assertEqual(main(['remote', 'add', r, 's3://bucket/name']), 0)
+
+        self.assertEqual(main(['remote', 'list']), 0)
+
+        self.assertEqual(main(['remote', 'remove', remotes[0]]), 0)
+        self.assertEqual(main(['remote', 'modify', remotes[0], 'option', 'value']), 0)
+
+        self.assertEqual(main(['remote', 'list']), 0)