Repository: conan-io/conan

Issue:
Problems with '%' in paths
When using Jenkins with the github plugin branch names are automatically used to generate the workspace dir. If the branchname contains a slash, it is escaped by using '%2F'. This leads to problems when using conan inside this workspace dir:
```conan config set log.trace_file=\"/home_local/jenkins/workspace/3rdparty/yaml-cpp/recipe-release%2F0.6.1/conan_home/conan_log.log\"```

Error:
File "/opt/rmc-build-tools/any/conan/1.10.0/python/conans/client/command.py", line 1428, in run
    method(args[0][1:])
  File "/opt/rmc-build-tools/any/conan/1.10.0/python/conans/client/command.py", line 437, in config
    return self._conan.config_set(key, value)
  File "/opt/rmc-build-tools/any/conan/1.10.0/python/conans/client/conan_api.py", line 89, in wrapper
    return f(*args, **kwargs)
  File "/opt/rmc-build-tools/any/conan/1.10.0/python/conans/client/conan_api.py", line 554, in config_set
    config_parser.set_item(item, value)
  File "/opt/rmc-build-tools/any/conan/1.10.0/python/conans/client/conf/__init__.py", line 264, in set_item
    super(ConanClientConfigParser, self).set(section_name, key, value)
  File "/opt/rmc-build-tools/osl42-x86_64/python3/default/lib/python3.6/configparser.py", line 1193, in set
    super().set(section, option, value)
  File "/opt/rmc-build-tools/osl42-x86_64/python3/default/lib/python3.6/configparser.py", line 894, in set
    value)
  File "/opt/rmc-build-tools/osl42-x86_64/python3/default/lib/python3.6/configparser.py", line 402, in before_set
    "position %d" % (value, tmp_value.find('%')))
ValueError: invalid interpolation syntax in '"/home_local/jenkins/workspace/3rdparty/yaml-cpp/recipe-release%2F0.6.1/conan_home/conan_log.log"' at position 63

Conan version: 1.10.0
Jenkins version: 2.150.1


Discussion:
Hi @Crejan 

I am not sure how conan should handle that. I'd say that it is the responsibility of the caller to provide a valid filepath for the log file. Or is there a folder actually called "release%2F0.6.1" in the filesystem?

Hi memsharded,
> Or is there a folder actually called "release%2F0.6.1" in the filesystem?

Actually yes, '%' is a valid char for pathnames (at least on linux). Our jenkins replaces every slash in the job item name with '%2F' to generate a workspace dir. The problem suddenly appeared after updating jenkins so this seems to be the default in newer jenkins versions.

I solved this for now by writing a jenkins plugin that generates workspace locations in a different way (replacing every special character in jobname with underscore). But I decided to post this issue here, because in my opinion conan should nevertheless be able to handle every valid path.

Resolving patch:
diff --git a/conans/client/conf/__init__.py b/conans/client/conf/__init__.py
--- a/conans/client/conf/__init__.py
+++ b/conans/client/conf/__init__.py
@@ -261,7 +261,12 @@ def set_item(self, key, value):
             raise ConanException("You can't set a full section, please specify a key=value")
 
         key = tokens[1]
-        super(ConanClientConfigParser, self).set(section_name, key, value)
+        try:
+            super(ConanClientConfigParser, self).set(section_name, key, value)
+        except ValueError:
+            # https://github.com/conan-io/conan/issues/4110
+            value = value.replace("%", "%%")
+            super(ConanClientConfigParser, self).set(section_name, key, value)
 
         with open(self.filename, "w") as f:
             self.write(f)
@@ -300,8 +305,8 @@ def default_profile(self):
                 ret = os.path.abspath(os.path.join(profiles_folder, ret))
 
             if not os.path.exists(ret):
-                raise ConanException("Environment variable 'CONAN_DEFAULT_PROFILE_PATH' must point to "
-                                     "an existing profile file.")
+                raise ConanException("Environment variable 'CONAN_DEFAULT_PROFILE_PATH' "
+                                     "must point to an existing profile file.")
             return ret
         else:
             try:


Test patch:
diff --git a/conans/test/command/config_test.py b/conans/test/command/config_test.py
--- a/conans/test/command/config_test.py
+++ b/conans/test/command/config_test.py
@@ -60,6 +60,12 @@ def define_test(self):
         conf_file = load(self.client.paths.conan_conf_path)
         self.assertIn("https = myurl", conf_file.splitlines())
 
+    def set_with_weird_path_test(self):
+        # https://github.com/conan-io/conan/issues/4110
+        self.client.run("config set log.trace_file=/recipe-release%2F0.6.1")
+        self.client.run("config get log.trace_file")
+        self.assertIn("/recipe-release%2F0.6.1", self.client.out)
+
     def remove_test(self):
         self.client.run('config set proxies.https=myurl')
         self.client.run('config rm proxies.https')