Repository: conan-io/conan

Issue:
Ancestor's PATH component is repeated in PATH in activate.sh
For the `virtualenv` generator, I'm seeing the path that I append to `env_info` in a distant ancestor repeated in the `PATH=` variable set in the generated `activate.sh` a number of times equal to that ancestor's `requires()` distance from the ultimately installed package.

If my package requires C that requires B  that requires A, then the `PATH` I set up in A is repeated four times in `activate.sh` if I install C.

I only append it once in the `package_info(self)` method of the ancestor.

Is this known, or is there something I might be doing wrong? 


Discussion:
Definitely not an expected behavior. We have this PR #1006 pending to merge. We have refactored the whole env/virtualenv system. Today I'm going to release a development version (pypi package) of the 0.20 release (planned for next Monday), would be nice if you can try it and tell me if it works well. 

I'll write you when I release it.
Thanks
Hi! 
You can (please help us :rofl: ) to try the release candidate installing with `pip install conan==0.20.0rc1`
Please tell me if it still fail or it's ok now.

Thanks!
Hi, currently trying 0.20.0rc1 and found that env val `PATH` definition in `activate.sh` generated in consumer package gets increased like below by performing `conan install` for consumer package.
(in this example, `package_info()` in recipe for `Protobuf/2.6.1@gasuketsu/testing`  appends path to package bin directory)

```activate.sh
PATH="/home/tharada/.conan/data/Protobuf/2.6.1/gasuketsu/testing/package/81a2fd4ff2b1309c415a72710e1b7fcb494ee7e6/bin":"/home/tharada/.conan/data/Protobuf/2.6.1/gasuketsu/testing/package/81a2fd4ff2b1309c415a72710e1b7fcb494ee7e6/bin":"/home/tharada/.conan/data/Protobuf/2.6.1/gasuketsu/testing/package/81a2fd4ff2b1309c415a72710e1b7fcb494ee7e6/bin":"/home/tharada/.conan/data/Protobuf/2.6.1/gasuketsu/testing/package/81a2fd4ff2b1309c415a72710e1b7fcb494ee7e6/bin":"/home/tharada/.conan/data/Protobuf/2.6.1/gasuketsu/testing/package/81a2fd4ff2b1309c415a72710e1b7fcb494ee7e6/bin":"/home/tharada/.conan/data/Protobuf/2.6.1/gasuketsu/testing/package/81a2fd4ff2b1309c415a72710e1b7fcb494ee7e6/bin":"/home/tharada/.conan/data/Protobuf/2.6.1/gasuketsu/testing/package/81a2fd4ff2b1309c415a72710e1b7fcb494ee7e6/bin":"/home/tharada/.conan/data/Protobuf/2.6.1/gasuketsu/testing/package/81a2fd4ff2b1309c415a72710e1b7fcb494ee7e6/bin":"/home/tharada/.conan/data/Protobuf/2.6.1/gasuketsu/testing/package/81a2fd4ff2b1309c415a72710e1b7fcb494ee7e6/bin":"/home/tharada/.conan/data/Protobuf/2.6.1/gasuketsu/testing/package/81a2fd4ff2b1309c415a72710e1b7fcb494ee7e6/bin":$PATH
export PATH
```

Hi @gasuketsu ,
I have been trying to replicate this without success. A couple of questions:
- It is just a 1 level dependency graph? i.e. does this happens if you just depend on Protobuf and nothing else?
- Is it produced when you execute several ``conan install`` one after the other?
If you please could clarify with exact steps to reproduce the issue, I would like to have a look, lets try to solve it for the release. Thanks!
Hi @memsharded ,

> It is just a 1 level dependency graph? i.e. does this happens if you just depend on Protobuf and nothing else?

I was verifying env variables are applied as expected with your [conan-protobuf](https://github.com/memsharded/conan-protobuf) repository plus small change below, and the issue is observed when performing `conan install` under test_package.  So level dependency graph should be 2. (zlib <- Protobuf <- test_package)

```diff
tharada@xubuntu:~/repos/memsharded/conan-protobuf/test_package$ git diff
diff --git a/conanfile.py b/conanfile.py
index d23e28b..079d00b 100644
--- a/conanfile.py
+++ b/conanfile.py
@@ -103,3 +103,4 @@ class ProtobufConan(ConanFile):
             self.cpp_info.libs = ["libprotobuf.a"] if not self.options.shared else ["libprotobuf.9.dylib"]
         else:
             self.cpp_info.libs = ["protobuf"]
+            self.env_info.path.append(os.path.join(self.package_folder, "lib"))
diff --git a/test_package/conanfile.py b/test_package/conanfile.py
index 5255065..f050c1c 100644
--- a/test_package/conanfile.py
+++ b/test_package/conanfile.py
@@ -5,7 +5,7 @@ import os
 class ProtobufTestConan(ConanFile):
     settings = "os", "compiler", "build_type", "arch"
     requires = "Protobuf/2.6.1@memsharded/testing"
-    generators = "cmake"
+    generators = "cmake", "virtualenv", "virtualbuildenv"
 
     def build(self):
         self.run('%s ../../message.proto --proto_path=../.. --cpp_out="."'
```

> Is it produced when you execute several conan install one after the other?
> If you please could clarify with exact steps to reproduce the issue, I would like to have a look, lets try to solve it for the release. Thanks!

Procedure to reproduce the issue is;
1. clone conan-protobuf and apply above patch
2. perform `conan export` under `conan-protobuf`
3. perform `conan install under `conan-protobuf/test_package` several times

env val PATH in `activate.sh` will grow up per number of times you did step 3
Great, thanks very much for the details, I'll work on it later, cheers!
Been able to reproduce it. This is what happens:

- Env values are dumped and cached in ``conaninfo.txt`` file
- ``conaninfo`` is loaded at each command, to get the cached values.
- Env variables that execute an ``append`` add them again while running ``conan install`` for second time.

In the final env-values dict, the strings are not exactly the same, even if they look the same, one is unicode with forward slash, and the other is str with double backward slash (at least in Win-py27). 

Not sure how to address this issue, it is important for @lasote to have a look too. This has not happened before, because other cached values are not cumulative/appendeable:
- It doesn't seem good to just don't cache env vars values. All the other info from ``conan install`` is cached. Conan commands as build, package, etc, need it.
- Maybe overwriting the ``append()`` so it doesn't add already existing values?

Any other ideas?

Thanks @tamboril  and @gasuketsu for your help!

Resolving patch:
diff --git a/conans/client/manager.py b/conans/client/manager.py
--- a/conans/client/manager.py
+++ b/conans/client/manager.py
@@ -62,7 +62,7 @@ def __init__(self, client_cache, user_io, runner, remote_manager, search_manager
         self._search_manager = search_manager
 
     def _loader(self, current_path=None, user_settings_values=None, package_settings=None,
-                user_options_values=None, scopes=None, env_values=None):
+                user_options_values=None, scopes=None, env_values=None, use_conaninfo=True):
 
         # The disk settings definition, already including the default disk values
         settings = self._client_cache.settings
@@ -74,7 +74,7 @@ def _loader(self, current_path=None, user_settings_values=None, package_settings
 
         if current_path:
             conan_info_path = os.path.join(current_path, CONANINFO)
-            if os.path.exists(conan_info_path):
+            if use_conaninfo and os.path.exists(conan_info_path):
                 existing_info = ConanInfo.load_file(conan_info_path)
                 settings.values = existing_info.full_settings
                 options = existing_info.full_options  # Take existing options from conaninfo.txt
@@ -153,7 +153,8 @@ def download(self, reference, package_ids, remote=None):
     def _get_graph(self, reference, current_path, remote, options, settings, filename, update,
                    check_updates, manifest_manager, scopes, package_settings, env_values):
 
-        loader = self._loader(current_path, settings, package_settings, options, scopes, env_values)
+        loader = self._loader(current_path, settings, package_settings, options,
+                              scopes, env_values, use_conaninfo=False)
         # Not check for updates for info command, it'll be checked when dep graph is built
 
         remote_proxy = ConanProxy(self._client_cache, self._user_io, self._remote_manager, remote,


Test patch:
diff --git a/conans/test/command/install_test.py b/conans/test/command/install_test.py
--- a/conans/test/command/install_test.py
+++ b/conans/test/command/install_test.py
@@ -193,7 +193,8 @@ def change_option_txt_test(self):
         info_path = os.path.join(client.current_folder, CONANINFO)
         conan_info = ConanInfo.load_file(info_path)
         self.assertEqual("", conan_info.options.dumps())
-        self.assertIn("Hello0:language=1", conan_info.full_options.dumps())
+        # For conan install options are not cached anymore
+        self.assertIn("Hello0:language=0", conan_info.full_options.dumps())
 
         # it is necessary to clean the cached conaninfo
         client.save(files, clean_first=True)
diff --git a/conans/test/integration/conan_scopes_test.py b/conans/test/integration/conan_scopes_test.py
--- a/conans/test/integration/conan_scopes_test.py
+++ b/conans/test/integration/conan_scopes_test.py
@@ -104,68 +104,60 @@ def build(self):
         self.assertNotIn("WARN: BUILD_CONSUMER DEV", client.user_io.out)
         self.assertNotIn("WARN: BUILD_CONSUMER OTHER", client.user_io.out)
 
-        for command in ("install --build -sc other=True", "install --build"):
-            client.run(command)
-            conaninfo = load(os.path.join(client.current_folder, "conaninfo.txt"))
-            self.assertIn("[scope]    dev=True    other=True", "".join(conaninfo.splitlines()))
-            self.assertIn("dev=True, other=True", client.user_io.out)
-            self.assertNotIn("WARN: DEP DEV", client.user_io.out)
-            self.assertNotIn("WARN: DEP OTHER", client.user_io.out)
-            self.assertIn("WARN: CONFIG_CONSUMER DEV", client.user_io.out)
-            self.assertIn("WARN: CONFIG_CONSUMER OTHER", client.user_io.out)
-            self.assertNotIn("WARN: BUILD_CONSUMER DEV", client.user_io.out)
-            self.assertNotIn("WARN: BUILD_CONSUMER OTHER", client.user_io.out)
-
-        for command in ("install --build -sc Hello:dev=True", "install --build"):
-            client.run(command)
-            conaninfo = load(os.path.join(client.current_folder, "conaninfo.txt"))
-            self.assertIn("[scope]    dev=True    other=True    Hello:dev=True",
-                          "".join(conaninfo.splitlines()))
-            self.assertIn("WARN: DEP DEV", client.user_io.out)
-            self.assertNotIn("WARN: DEP OTHER", client.user_io.out)
-            self.assertIn("WARN: CONFIG_CONSUMER DEV", client.user_io.out)
-            self.assertIn("WARN: CONFIG_CONSUMER OTHER", client.user_io.out)
-            self.assertNotIn("WARN: BUILD_CONSUMER DEV", client.user_io.out)
-            self.assertNotIn("WARN: BUILD_CONSUMER OTHER", client.user_io.out)
-
-        for command in ("install --build -sc Hello:other=True", "install --build"):
-            client.run(command)
-            conaninfo = load(os.path.join(client.current_folder, "conaninfo.txt"))
-            self.assertIn("[scope]    dev=True    other=True"
-                          "    Hello:dev=True    Hello:other=True",
-                          "".join(conaninfo.splitlines()))
-            self.assertIn("WARN: DEP DEV", client.user_io.out)
-            self.assertIn("WARN: DEP OTHER", client.user_io.out)
-            self.assertIn("WARN: CONFIG_CONSUMER DEV", client.user_io.out)
-            self.assertIn("WARN: CONFIG_CONSUMER OTHER", client.user_io.out)
-            self.assertNotIn("WARN: BUILD_CONSUMER DEV", client.user_io.out)
-            self.assertNotIn("WARN: BUILD_CONSUMER OTHER", client.user_io.out)
-
-        for command in ("install --build -sc Hello:other=False", "install --build"):
-            client.run(command)
-            conaninfo = load(os.path.join(client.current_folder, "conaninfo.txt"))
-            self.assertIn("[scope]    dev=True    other=True"
-                          "    Hello:dev=True    Hello:other=False",
-                          "".join(conaninfo.splitlines()))
-            self.assertIn("WARN: DEP DEV", client.user_io.out)
-            self.assertNotIn("WARN: DEP OTHER", client.user_io.out)
-            self.assertIn("WARN: CONFIG_CONSUMER DEV", client.user_io.out)
-            self.assertIn("WARN: CONFIG_CONSUMER OTHER", client.user_io.out)
-            self.assertNotIn("WARN: BUILD_CONSUMER DEV", client.user_io.out)
-            self.assertNotIn("WARN: BUILD_CONSUMER OTHER", client.user_io.out)
-
-        for command in ("build", ):
-            client.run(command)
-            conaninfo = load(os.path.join(client.current_folder, "conaninfo.txt"))
-            self.assertIn("[scope]    dev=True    other=True"
-                          "    Hello:dev=True    Hello:other=False",
-                          "".join(conaninfo.splitlines()))
-            self.assertNotIn("WARN: DEP DEV", client.user_io.out)
-            self.assertNotIn("WARN: DEP OTHER", client.user_io.out)
-            self.assertNotIn("WARN: CONFIG_CONSUMER DEV", client.user_io.out)
-            self.assertNotIn("WARN: CONFIG_CONSUMER OTHER", client.user_io.out)
-            self.assertIn("WARN: BUILD_CONSUMER DEV", client.user_io.out)
-            self.assertIn("WARN: BUILD_CONSUMER OTHER", client.user_io.out)
+        client.run("install --build -sc other=True")
+        conaninfo = load(os.path.join(client.current_folder, "conaninfo.txt"))
+        self.assertIn("[scope]    dev=True    other=True", "".join(conaninfo.splitlines()))
+        self.assertIn("dev=True, other=True", client.user_io.out)
+        self.assertNotIn("WARN: DEP DEV", client.user_io.out)
+        self.assertNotIn("WARN: DEP OTHER", client.user_io.out)
+        self.assertIn("WARN: CONFIG_CONSUMER DEV", client.user_io.out)
+        self.assertIn("WARN: CONFIG_CONSUMER OTHER", client.user_io.out)
+        self.assertNotIn("WARN: BUILD_CONSUMER DEV", client.user_io.out)
+        self.assertNotIn("WARN: BUILD_CONSUMER OTHER", client.user_io.out)
+
+        client.run("install --build -sc Hello:dev=True")
+        conaninfo = load(os.path.join(client.current_folder, "conaninfo.txt"))
+        self.assertIn("[scope]    dev=True    Hello:dev=True",
+                      "".join(conaninfo.splitlines()))
+        self.assertIn("WARN: DEP DEV", client.user_io.out)
+        self.assertNotIn("WARN: DEP OTHER", client.user_io.out)
+        self.assertIn("WARN: CONFIG_CONSUMER DEV", client.user_io.out)
+        self.assertNotIn("WARN: CONFIG_CONSUMER OTHER", client.user_io.out)
+        self.assertNotIn("WARN: BUILD_CONSUMER DEV", client.user_io.out)
+        self.assertNotIn("WARN: BUILD_CONSUMER OTHER", client.user_io.out)
+
+        client.run("install --build -sc Hello:other=True")
+        conaninfo = load(os.path.join(client.current_folder, "conaninfo.txt"))
+        self.assertIn("[scope]    dev=True    Hello:other=True",
+                      "".join(conaninfo.splitlines()))
+        self.assertNotIn("WARN: DEP DEV", client.user_io.out)
+        self.assertIn("WARN: DEP OTHER", client.user_io.out)
+        self.assertIn("WARN: CONFIG_CONSUMER DEV", client.user_io.out)
+        self.assertNotIn("WARN: CONFIG_CONSUMER OTHER", client.user_io.out)
+        self.assertNotIn("WARN: BUILD_CONSUMER DEV", client.user_io.out)
+        self.assertNotIn("WARN: BUILD_CONSUMER OTHER", client.user_io.out)
+
+        client.run("install --build -sc Hello:other=False")
+        conaninfo = load(os.path.join(client.current_folder, "conaninfo.txt"))
+        self.assertIn("[scope]    dev=True    Hello:other=False",
+                      "".join(conaninfo.splitlines()))
+        self.assertNotIn("WARN: DEP DEV", client.user_io.out)
+        self.assertNotIn("WARN: DEP OTHER", client.user_io.out)
+        self.assertIn("WARN: CONFIG_CONSUMER DEV", client.user_io.out)
+        self.assertNotIn("WARN: CONFIG_CONSUMER OTHER", client.user_io.out)
+        self.assertNotIn("WARN: BUILD_CONSUMER DEV", client.user_io.out)
+        self.assertNotIn("WARN: BUILD_CONSUMER OTHER", client.user_io.out)
+
+        client.run("build")
+        conaninfo = load(os.path.join(client.current_folder, "conaninfo.txt"))
+        self.assertIn("[scope]    dev=True    Hello:other=False",
+                      "".join(conaninfo.splitlines()))
+        self.assertNotIn("WARN: DEP DEV", client.user_io.out)
+        self.assertNotIn("WARN: DEP OTHER", client.user_io.out)
+        self.assertNotIn("WARN: CONFIG_CONSUMER DEV", client.user_io.out)
+        self.assertNotIn("WARN: CONFIG_CONSUMER OTHER", client.user_io.out)
+        self.assertIn("WARN: BUILD_CONSUMER DEV", client.user_io.out)
+        self.assertNotIn("WARN: BUILD_CONSUMER OTHER", client.user_io.out)
 
     def conan_scopes_pattern_test(self):
         client = TestClient()
@@ -213,17 +205,16 @@ def build(self):
         self.assertNotIn("WARN: BUILD_CONSUMER DEV", client.user_io.out)
         self.assertNotIn("WARN: BUILD_CONSUMER OTHER", client.user_io.out)
 
-        for command in ("install --build -sc ALL:other=True", "install --build"):
-            client.run(command)
-            conaninfo = load(os.path.join(client.current_folder, "conaninfo.txt"))
-            self.assertIn("[scope]    dev=True    ALL:other=True",
-                          "".join(conaninfo.splitlines()))
-            self.assertNotIn("WARN: DEP DEV", client.user_io.out)
-            self.assertIn("WARN: DEP OTHER", client.user_io.out)
-            self.assertIn("WARN: CONFIG_CONSUMER DEV", client.user_io.out)
-            self.assertIn("WARN: CONFIG_CONSUMER OTHER", client.user_io.out)
-            self.assertNotIn("WARN: BUILD_CONSUMER DEV", client.user_io.out)
-            self.assertNotIn("WARN: BUILD_CONSUMER OTHER", client.user_io.out)
+        client.run("install --build -sc ALL:other=True")
+        conaninfo = load(os.path.join(client.current_folder, "conaninfo.txt"))
+        self.assertIn("[scope]    dev=True    ALL:other=True",
+                      "".join(conaninfo.splitlines()))
+        self.assertNotIn("WARN: DEP DEV", client.user_io.out)
+        self.assertIn("WARN: DEP OTHER", client.user_io.out)
+        self.assertIn("WARN: CONFIG_CONSUMER DEV", client.user_io.out)
+        self.assertIn("WARN: CONFIG_CONSUMER OTHER", client.user_io.out)
+        self.assertNotIn("WARN: BUILD_CONSUMER DEV", client.user_io.out)
+        self.assertNotIn("WARN: BUILD_CONSUMER OTHER", client.user_io.out)
 
     def conan_dev_requires_test(self):
         client = TestClient()
diff --git a/conans/test/libcxx_setting_test.py b/conans/test/libcxx_setting_test.py
--- a/conans/test/libcxx_setting_test.py
+++ b/conans/test/libcxx_setting_test.py
@@ -78,7 +78,7 @@ def test_declared_stdlib_and_passed(self):
             self.assertIn("-stdlib=libstdc++", str(client.user_io.out))
             self.assertIn("Found Define: _GLIBCXX_USE_CXX11_ABI=0", str(client.user_io.out))
 
-            client.run('install -s compiler=clang -s compiler.libcxx=libstdc++11', ignore_error=False)
+            client.run('install -s compiler=clang -s compiler.version=3.3 -s compiler.libcxx=libstdc++11', ignore_error=False)
             client.run('build')
             self.assertIn("-stdlib=libstdc++", str(client.user_io.out))
             self.assertIn("Found Define: _GLIBCXX_USE_CXX11_ABI=1", str(client.user_io.out))
diff --git a/conans/test/options_caching_test.py b/conans/test/options_caching_test.py
--- a/conans/test/options_caching_test.py
+++ b/conans/test/options_caching_test.py
@@ -33,8 +33,9 @@ class ConanLib(ConanFile):
         conaninfo = load(os.path.join(client.current_folder, CONANINFO))
         self.assertIn("zlib:shared=True", conaninfo)
 
+        # Options not cached anymore
         client.run("install --build=missing")
-        self.assertIn("zlib/0.1@lasote/testing:2a623e3082a38f90cd2c3d12081161412de331b0",
+        self.assertIn("zlib/0.1@lasote/testing:5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9",
                       client.user_io.out)
         conaninfo = load(os.path.join(client.current_folder, CONANINFO))
-        self.assertIn("zlib:shared=True", conaninfo)
+        self.assertNotIn("zlib:shared=True", conaninfo)