Repository: Azure/iotedgedev

Issue:
Add solution create to env check exclude list
(venv) C:\temp>iotedgedev solution create monitortest

=======================================
======== ENVIRONMENT VARIABLES ========
=======================================

.env file not found on disk. Without a file on disk, you must specify all Environment Variables at the system level. (C:\temp\.env)

Discussion:

Patch:
diff --git a/iotedgedev/args.py b/iotedgedev/args.py
index a24e2cc..80ce565 100644
--- a/iotedgedev/args.py
+++ b/iotedgedev/args.py
@@ -1,12 +1,13 @@
 import sys
 
-# We had to implement this custom arg parsing class because Click doesn't have a handler to detect command before any arguments are parsed, which we need for the dotenv load command.  We don't want to load dotenv for some commands and we terse output for other commands.
+# We had to implement this custom arg parsing class because Click doesn't have a handler to detect command before any arguments are parsed,
+# which we need for the dotenv load command.  We don't want to load dotenv for some commands and we terse output for other commands.
 
 
 class Args():
     def get_current_command(self):
         if sys.argv and len(sys.argv) > 1 and not self.is_info_command():
-            return sys.argv[1]
+            return ' '.join(sys.argv[1:]).strip()
         else:
             return ''
 
diff --git a/iotedgedev/envvars.py b/iotedgedev/envvars.py
index def4ca2..861acb5 100644
--- a/iotedgedev/envvars.py
+++ b/iotedgedev/envvars.py
@@ -15,13 +15,15 @@ class EnvVars:
     def __init__(self, output):
         self.output = output
         self.loaded = False
-        self.args = Args()
-        self.current_command = self.args.get_current_command()
-        self.terse_commands = ['', 'azure']
-        self.bypass_dotenv_load_commands = ['init', 'e2e']
 
+        current_command = Args().get_current_command()
+        # for some commands we don't want to load dotenv
+        # TODO: temporary hack. A more grace solution would be a decorator on the command to indicate whether to bypass env
+        self.bypass_dotenv_load_commands = ['solution init', 'solution e2e', 'solution create', 'create', 'simulator stop', 'simulator modulecred']
+        self.bypass = self.is_bypass_command(current_command)
         # for some commands we don't want verbose dotenv load output
-        self.verbose = self.current_command not in self.terse_commands
+        self.terse_commands = ['', 'iothub setup']
+        self.verbose = not self.is_terse_command(current_command)
 
     def clean(self):
         """docker-py had py2 issues with shelling out to docker api if unicode characters are in any environment variable. This will convert to utf-8 if py2."""
@@ -40,7 +42,7 @@ class EnvVars:
                     environment[k] = environment[k].encode('utf-8')
 
                 clean_enviro[key] = environment[k]
-        
+
             os.environ = clean_enviro
 
     def backup_dotenv(self):
@@ -86,7 +88,7 @@ class EnvVars:
     def load(self, force=False):
 
         # for some commands we don't want to load dotenv
-        if self.current_command in self.bypass_dotenv_load_commands and not force:
+        if self.bypass and not force:
             return
 
         if not self.loaded or force:
@@ -174,7 +176,6 @@ class EnvVars:
 
         self.loaded = True
 
-
     def __getattribute__(self, name):
         try:
             return object.__getattribute__(self, name)
@@ -248,3 +249,24 @@ class EnvVars:
     def is_posix(self):
         plat = platform.system().lower()
         return plat == "linux" or plat == "darwin"
+
+    def is_bypass_command(self, command):
+        return self.in_command_list(command, self.bypass_dotenv_load_commands)
+
+    def is_terse_command(self, command):
+        return self.in_command_list(command, self.terse_commands)
+
+    def in_command_list(self, command, command_list):
+        for cmd in command_list:
+            if cmd == '':
+                if command == '':
+                    return True
+                else:
+                    continue
+
+            if command.startswith(cmd):
+                if len(command) == len(cmd) or command[len(cmd)] == ' ':
+                    return True
+                else:
+                    continue
+        return False


Test patch:
diff --git a/tests/test_envvars.py b/tests/test_envvars.py
index 12bbfc0..a2a336a 100644
--- a/tests/test_envvars.py
+++ b/tests/test_envvars.py
@@ -1,6 +1,8 @@
 import os
 import sys
+
 import pytest
+
 from iotedgedev.envvars import EnvVars
 from iotedgedev.output import Output
 
@@ -61,10 +63,88 @@ def test_set_envvar():
 def test_envvar_clean():
     output = Output()
     envvars = EnvVars(output)
-    envvar_clean_name = u'IOTEDGEDEV_ENVVAR_CLEAN_TEST'
-    os.environ[envvar_clean_name] = u'test unicode string'
+    envvar_clean_name = u"IOTEDGEDEV_ENVVAR_CLEAN_TEST"
+    os.environ[envvar_clean_name] = u"test unicode string"
 
     envvars.clean()
 
     if not (sys.version_info > (3, 0)):
         assert isinstance(os.environ[envvar_clean_name], str)
+
+
+def test_in_command_list_true_1():
+    output = Output()
+    envvars = EnvVars(output)
+    assert envvars.in_command_list("solution create test_solution", ["init", "e2e", "solution create", "create", "simulator stop"])
+
+
+def test_in_command_list_true_2():
+    output = Output()
+    envvars = EnvVars(output)
+    assert envvars.in_command_list("solution create", ["init", "e2e", "solution create", "create", "simulator stop"])
+
+
+def test_in_command_list_false_1():
+    output = Output()
+    envvars = EnvVars(output)
+    assert not envvars.in_command_list("solution add filtermodule", ["init", "e2e", "solution create", "create", "simulator stop"])
+
+
+def test_in_command_list_false_2():
+    output = Output()
+    envvars = EnvVars(output)
+    assert not envvars.in_command_list("solution addotherstuff filtermodule", ["init", "e2e", "solution add", "create", "simulator stop"])
+
+
+def test_in_command_list_empty_1():
+    output = Output()
+    envvars = EnvVars(output)
+    assert not envvars.in_command_list("", ["init", "e2e", "solution create", "create", "simulator stop"])
+
+
+def test_in_command_list_empty_2():
+    output = Output()
+    envvars = EnvVars(output)
+    assert not envvars.in_command_list("solution create test_solution", ["init", "e2e", "", "create", "simulator stop"])
+
+
+def test_in_command_list_empty_3():
+    output = Output()
+    envvars = EnvVars(output)
+    assert envvars.in_command_list("", ["init", "e2e", "", "create", "simulator stop"])
+
+
+def test_is_bypass_command_true():
+    output = Output()
+    envvars = EnvVars(output)
+    assert envvars.is_bypass_command("solution create EdgeSolution")
+
+
+def test_is_bypass_command_false():
+    output = Output()
+    envvars = EnvVars(output)
+    assert not envvars.is_bypass_command("solution add")
+
+
+def test_is_bypass_command_empty():
+    output = Output()
+    envvars = EnvVars(output)
+    assert not envvars.is_bypass_command("")
+
+
+def test_is_terse_command_true():
+    output = Output()
+    envvars = EnvVars(output)
+    assert envvars.is_terse_command("iothub setup --update-dotenv")
+
+
+def test_is_terse_command_false():
+    output = Output()
+    envvars = EnvVars(output)
+    assert not envvars.is_terse_command("solution create")
+
+
+def test_is_terse_command_empty():
+    output = Output()
+    envvars = EnvVars(output)
+    assert envvars.is_terse_command("")