Repository: conan-io/conan

Issue:
Scope variables do not accept a value containing a ':'
Hi,
I modified the Boost package recipe so that I can specify an alternate url for downloading the source zip file. I used a scope variable for this purpose. However it seems that conan does not allow scope variables to contain a ':'.

When issuing this command:
conan install Boost/1.61.0@epr-eliaskousk/stable --build -s os=Windows -s arch=x86_64 -s compiler="Visual Studio" -s compiler.version=14 -s compiler.runtime=MDd -s build_type=Debug -sc ALL:source_url=http://sourceforge.net/projects/boost/files/boost

Here is the error message I get:
ERROR: Bad scope ALL:source_url=http://sourceforge.net/projects/boost/files/boost

I suppose there is an issue because the parsing treats the ':' as a special separator?...

Would it be possible to fix this or is it supposed to be like that?
(I can workaround the issue by replacing the character ':' in my string value by yet-another special character)

thanks



Discussion:
Hi @menuet !

First thing, just to be sure: the alternate download url retrieves different source code, or exactly the same source code? Scopes only make sense if the source code is exactly the same, otherwise, the package would be different, and you need an `option` to model that.

About the special character, it is true, conan use `:` to delimit/parse packages, e.g. the options can be specified as: `-o Boost:shared=True`. Same for scopes, you can see the parsing code here: https://github.com/conan-io/conan/blob/develop/conans/model/scope.py#L57

It doesn't seem simple to change that, an even if we changed that, the problem just would be moved to a different special character. So I suggest keeping `:` in conan syntax, and if you can workaround by using a different character in your string, that would be great. Thanks for your feedback!

Thanks for your quick answer.
Yes, the source package is exactly the same source package than the one in sourceforge.net, except that it is local (and then very fast and not depending on internet). This is why I used a scope variable. Actually, I first used an option and then realized that the option was part of the identity of the package, which I wanted to avoid.
As a workaround, I already use the character ',' in place of ':' in my url, but I think that conan's user may encounter the same issue when using scopes (also, it is not consistent with options, which do not have the limitation of not allowing ':').
In the python code, couldn't it be possible to split first on the character '=' and then to split only the left part on the character ':'?

Oh, I see! Yes, now I remember changing that for options, also for URLs, so it might be possible. Thanks for the tip, will try to address it.

OK Thanks


Resolving patch:
diff --git a/conans/model/scope.py b/conans/model/scope.py
--- a/conans/model/scope.py
+++ b/conans/model/scope.py
@@ -54,17 +54,8 @@ def package_scope(self, name=None):
     def from_list(items):
         result = Scopes()
         for item in items:
-            chunks = item.split(":")
-            if len(chunks) == 2:
-                root = chunks[0]
-                scope = chunks[1]
-            elif len(chunks) == 1:
-                root = _root
-                scope = chunks[0]
-            else:
-                raise ConanException("Bad scope %s" % item)
             try:
-                key, value = scope.split("=")
+                key, value = item.split("=")
             except:
                 raise ConanException("Bad scope %s" % item)
             v = value.upper()
@@ -74,7 +65,18 @@ def from_list(items):
                 value = False
             elif v == "NONE":
                 value = None
-            result[root][key] = value
+
+            chunks = key.split(":")
+            if len(chunks) == 2:
+                root = chunks[0]
+                scope = chunks[1]
+            elif len(chunks) == 1:
+                root = _root
+                scope = chunks[0]
+            else:
+                raise ConanException("Bad scope %s" % item)
+
+            result[root][scope] = value
         return result
 
     def update_scope(self, other):


Test patch:
diff --git a/conans/test/model/scope_test.py b/conans/test/model/scope_test.py
new file mode 100644
--- /dev/null
+++ b/conans/test/model/scope_test.py
@@ -0,0 +1,25 @@
+import unittest
+from conans.model.scope import Scopes
+
+
+class ScopeTest(unittest.TestCase):
+
+    def from_list_test(self):
+        scope = Scopes.from_list(["theroot:thescope=http://conan.io"])
+        self.assertEquals(scope["theroot"]["thescope"], "http://conan.io")
+        self.assertEquals(scope.package_scope("theroot")["thescope"], "http://conan.io")
+
+        scope = Scopes.from_list(["thescope=http://conan.io"])
+        self.assertEquals(scope["0CONAN_ROOT*"]["thescope"], "http://conan.io")
+
+        scope = Scopes.from_list(["theroot:thescope=TRUE"])
+        self.assertTrue(scope["theroot"]["thescope"])
+
+        scope = Scopes.from_list(["theroot:thescope=true"])
+        self.assertTrue(scope["theroot"]["thescope"])
+
+        scope = Scopes.from_list(["theroot:thescope=FALSE"])
+        self.assertFalse(scope["theroot"]["thescope"])
+
+        scope = Scopes.from_list(["theroot:thescope=false"])
+        self.assertFalse(scope["theroot"]["thescope"])