Repository: conan-io/conan

Issue:
Conan crashes with there is a duplicate private package
I've run into a scenario where I have two packages where A depends on B, and both have C as a private dependency (C is a unit-testing framework). In this case, when running `conan install` on A, it crashes with the following stack-trace:

```
HEADER ONLY
Requirements
    Boost/1.60.0@lasote/stable
    catch/1.3.0@bjoern/testing
    catch/1.3.0@bjoern/testing
    filesystem/1.0.0@bjoern/testing
    io/1.0.0@bjoern/testing
    zlib/1.2.8@lasote/stable
Traceback (most recent call last):
  File "/Users/bjoern/.pipsi/bin/conan", line 11, in <module>
    sys.exit(run())
  File "/Users/bjoern/.pipsi/virtualenvs/conan/lib/python2.7/site-packages/conans/conan.py", line 6, in run
    main(sys.argv[1:])
  File "/Users/bjoern/.pipsi/virtualenvs/conan/lib/python2.7/site-packages/conans/client/command.py", line 432, in main
    error = command.run(args)
  File "/Users/bjoern/.pipsi/virtualenvs/conan/lib/python2.7/site-packages/conans/client/command.py", line 367, in run
    method(args[0][1:])
  File "/Users/bjoern/.pipsi/virtualenvs/conan/lib/python2.7/site-packages/conans/client/command.py", line 186, in install
    build_mode=args.build)
  File "/Users/bjoern/.pipsi/virtualenvs/conan/lib/python2.7/site-packages/conans/client/manager.py", line 122, in install
    installer.install(deps_graph, build_mode)
  File "/Users/bjoern/.pipsi/virtualenvs/conan/lib/python2.7/site-packages/conans/client/installer.py", line 70, in install
    skip_private_nodes = self._compute_private_nodes(deps_graph, build_mode)
  File "/Users/bjoern/.pipsi/virtualenvs/conan/lib/python2.7/site-packages/conans/client/installer.py", line 110, in _compute_private_nodes
    package_folder = self._paths.package(package_reference)
  File "/Users/bjoern/.pipsi/virtualenvs/conan/lib/python2.7/site-packages/conans/paths.py", line 92, in package
    return normpath(join(self.conan(package_reference.conan), PACKAGES_FOLDER,
  File "/Users/bjoern/.pipsi/virtualenvs/conan/lib/python2.7/site-packages/conans/paths.py", line 45, in conan
    assert isinstance(conan_reference, ConanFileReference)
AssertionError
```

Now if I remove the `"private"` for package C from A, everything runs fine. Is this intended behaviour, or a bug?
Btw, I've tried using this as a way to specify dependencies that are used only for development (e.g. for running the unit-tests), but should not be propagated to users of the project. Is this the recommended way to achieve this, or would suggest something else? I could for instance also use an option like `--with-tests`.



Discussion:
It seems it is a bug, not intended behaviour, I will check it asap.

Conditional dependencies can be defined, and you could use options to enable/disable them. Check: http://docs.conan.io/en/latest/reference/conanfile.html#requirements

However, this is possibly not very idiomatic, and scopes (dev, production), or a higher level could be defined, lets open a specific issue for it


Resolving patch:
diff --git a/conans/client/installer.py b/conans/client/installer.py
--- a/conans/client/installer.py
+++ b/conans/client/installer.py
@@ -107,6 +107,8 @@ def _compute_private_nodes(self, deps_graph, build_mode):
         for private_node, private_requirers in private_closure:
             for private_requirer in private_requirers:
                 conan_ref, conan_file = private_requirer
+                if conan_ref is None:
+                    continue
                 package_id = conan_file.info.package_id()
                 package_reference = PackageReference(conan_ref, package_id)
                 package_folder = self._paths.package(package_reference)


Test patch:
diff --git a/conans/test/integration/private_deps_test.py b/conans/test/integration/private_deps_test.py
--- a/conans/test/integration/private_deps_test.py
+++ b/conans/test/integration/private_deps_test.py
@@ -1,13 +1,11 @@
 import unittest
 from conans.test.tools import TestClient, TestServer
 from conans.model.ref import ConanFileReference
-import platform
 import os
 from conans.test.utils.cpp_test_files import cpp_hello_conan_files
-from conans.paths import CONANFILE, BUILD_INFO, CONANINFO, BUILD_INFO_CMAKE
+from conans.paths import CONANINFO, BUILD_INFO_CMAKE
 from conans.util.files import load
 from conans.model.info import ConanInfo
-from conans.model.build_info import DepsCppInfo
 from nose.plugins.attrib import attr
 
 
@@ -43,12 +41,6 @@ def reuse_test(self):
                                                         "Hello2/0.1@lasote/stable"])
 
         # WE need to copy the DLLs and dylib
-        local_install = """    def imports(self):
-        self.copy("*.dll", "", "bin")
-        self.copy("*.dylib", "", "lib")
-"""
-        copy_dlls_conanfile = files3[CONANFILE] + local_install
-        files3[CONANFILE] = copy_dlls_conanfile
         client.save(files3)
 
         client.run('install --build missing')
@@ -83,8 +75,6 @@ def reuse_test(self):
                                                           "Hello2/0.1@lasote/stable"])
 
         # WE need to copy the DLLs
-        copy_dlls_conanfile = files2[CONANFILE] + local_install
-        files2[CONANFILE] = copy_dlls_conanfile
         client2.save(files2)
 
         client2.run("install . --build missing")
@@ -105,8 +95,6 @@ def reuse_test(self):
         files3 = cpp_hello_conan_files("Hello3", "0.2", ["Hello1/0.1@lasote/stable",
                                                           "Hello2/0.1@lasote/stable"], language=1)
 
-        copy_dlls_conanfile = files3[CONANFILE] + local_install
-        files3[CONANFILE] = copy_dlls_conanfile
         client2.save(files3)
         client2.run('install -o language=1 --build missing')
         client2.run('build')
@@ -119,3 +107,23 @@ def reuse_test(self):
         self.assertEqual(['Hola Hello3', 'Hola Hello1',
                           'Hola Hello0', 'Hola Hello2', 'Hola #'],
                          str(client2.user_io.out).splitlines()[-5:])
+
+        # Issue 79, fixing private deps from current project
+        files3 = cpp_hello_conan_files("Hello3", "0.2", ["Hello1/0.1@lasote/stable",
+                                                         "Hello2/0.1@lasote/stable",
+                                                         ("Hello0/0.1@lasote/stable", "private"),
+                                                         ("Hello00/0.2@lasote/stable", "private")],
+                                       language=1)
+
+        client2.save(files3, clean_first=True)
+        client2.run('install -o language=1 --build missing')
+        client2.run('build')
+        self.assertNotIn("libhello0.a", client2.user_io.out)
+        self.assertNotIn("libhello00.a", client2.user_io.out)
+        self.assertNotIn("libhello1.a", client2.user_io.out)
+        self.assertNotIn("libhello2.a", client2.user_io.out)
+        self.assertNotIn("libhello3.a", client2.user_io.out)
+        client2.runner(command, client2.current_folder)
+        self.assertEqual(['Hola Hello3', 'Hola Hello1',
+                          'Hola Hello0', 'Hola Hello2', 'Hola #', 'Hola Hello0', 'Hola #'],
+                         str(client2.user_io.out).splitlines()[-7:])