Repository: conan-io/conan

Issue:
Non used override requirements brings error in CMake
To help us debug your issue please explain:

- [ x] I've read the [CONTRIBUTING guide](https://github.com/conan-io/conan/blob/develop/.github/CONTRIBUTING.md).
- [ x] I've specified the Conan version, operating system version and any tool that can be relevant.
- [ x] I've explained the steps to reproduce the error or the motivation/use case of the question/suggestion.

I use conan 17.2 on a Windows 10 computer.

Our Jenkins / Gerrit server delivers a list of changed libraries, which are in review phase.
So e.g. I got `LibA` and `Lib B`. Both are changed.
`LibC` depends on `LibA`.
`LibD` depends on `LibA` and `LibB`.
I generate an "override.txt", where "LibA" and "LibB" from the review channel are inside.

Now I can build `LibD` without a problem, because it uses both libraries (`LibA` & `LibB`).

The `test_package` of `LibC` will not build because the generated `conanbuildinfo.cmake` has the following dependency:

```
conan_package_library_targets("${CONAN_LIBS_LIBC}" "${CONAN_LIB_DIRS_LIBC}"
                                  CONAN_PACKAGE_TARGETS_LIBC "CONAN_PKG::LibA CONAN_PKG::LibB" "" LibC)
```
Where there is no definition inside the cmake file, so that he can't find target:

```
CMake Error at CMakeLists.txt:12 (add_executable):
  Target "LibC-test" links to target
  "CONAN_PKG::LibB" but the target was not found.  Perhaps
  a find_package() call is missing for an IMPORTED target, or an ALIAS target
  is missing?
```

Should this behave in this way, when there is an unused "override requirement"?
Is there a good way to detect the not used "override requirements" before (e.g. `conan info`)?



Discussion:
Hi @climblinne 

Could you please clarify how you are using that ``override.txt`` file? What packages use it? How? Are you explicitly using the ``override`` qualifier in the recipe? Please let me know a bit more to understand what you are trying to achieve. Thanks.
@memsharded : Here my excerpt from my base class for libraries:

```python
def requirements(self):
        try:
            with open("./overrides.txt") as file:  
                overrides = file.read()
        except FileNotFoundError:
            print("Unable to find 'overrides.txt' in {}".format(os.getcwd()))
            overrides = None            
        if overrides:
            target = overrides.split(":")
            if len(target[0]) > 0:
                overrides = target[0].split(",")
            else:
                overrides = []
               
            for override in overrides:
                ref = ConanFileReference.loads(override)
                if ref.name == self.name:
                    print("Override ignored because own package:     " + str(override) + " in " + self.name)
                elif ref.name in self.requires:
                    print("Override removed the following reference: " + str(self.requires[ref.name]))
                    print("           Replaced it by this reference: " + str(override))
                    del(self.requires[ref.name])
                    #TODO: Check if version is correct ref.version
                    self.requires(override, override=False)
                else:
                    print("Override added:                           " + str(override) + " in " + self.name)
                    self.requires(override, override=True)
```

Sample `overrides.txt`:
```
LibA/1.0.0-dev.7+HEAD.g32faf5a@review/17384.7,LibB/1.0.0-dev.10+HEAD.g2e52ca5@review/17550.1
```

Our gerrit server informs us about change of some libraries. Now Jenkins starts building these libraries (in correct order uses "dependencies"). They are named with `<library>/<version>@review/123.4`.
After theses it starts all projects, that are dependent on one of these projects in parallel. It uses the `override.txt` filled with the changed libraries. It either substitute the requirement or write an overwrite requirement.

I hope this helps a little bit. 


Resolving patch:
diff --git a/conans/client/installer.py b/conans/client/installer.py
--- a/conans/client/installer.py
+++ b/conans/client/installer.py
@@ -472,7 +472,8 @@ def _call_package_info(self, conanfile, package_folder, ref):
         conanfile.user_info = UserInfo()
 
         # Get deps_cpp_info from upstream nodes
-        public_deps = [name for name, req in conanfile.requires.items() if not req.private]
+        public_deps = [name for name, req in conanfile.requires.items() if not req.private
+                       and not req.override]
         conanfile.cpp_info.public_deps = public_deps
         # Once the node is build, execute package info, so it has access to the
         # package folder and artifacts


Test patch:
diff --git a/conans/test/functional/graph/require_override_test.py b/conans/test/functional/graph/require_override_test.py
--- a/conans/test/functional/graph/require_override_test.py
+++ b/conans/test/functional/graph/require_override_test.py
@@ -1,28 +1,7 @@
+import textwrap
 import unittest
 
-from conans.test.utils.tools import TestClient
-
-base_conanfile = """
-from conans import ConanFile
-
-class ChatConan(ConanFile):
-    name = "%s"
-    version = "%s"
-    build_policy = "missing"
-    requires = %s
-"""
-
-base_conanfile_method = """
-from conans import ConanFile
-
-class ChatConan(ConanFile):
-    name = "%s"
-    version = "%s"
-    build_policy = "missing"
-    
-    def requirements(self):
-        %s
-"""
+from conans.test.utils.tools import TestClient, GenConanfile
 
 
 class RequireOverrideTest(unittest.TestCase):
@@ -30,49 +9,56 @@ class RequireOverrideTest(unittest.TestCase):
     def setUp(self):
         self.client = TestClient()
 
-    def _save(self, name, version, req_method, requires=None):
-        reqs = []
-        if not req_method:
-            requires = requires or []
-            text = "("
-            for req in requires:
-                if isinstance(req, str):
-                    reqs.append('"%s"' % str(req))
-                else:
-                    reqs.append(str(req))
-            text += ', '.join(reqs)
-            text += ")"
-            tmp = base_conanfile % (name, version, text)
-        else:
-            requires = requires or []
-            for req in requires:
-                if isinstance(req, str):
-                    reqs.append('self.requires("%s")' % str(req))
-                else:
-                    reqs.append('self.requires("%s", override="%s")' % (req[0], req[1]))
-            text = '\n        '.join(reqs) if reqs else "pass"
-            tmp = base_conanfile_method % (name, version, text)
-        self.client.save({"conanfile.py": tmp}, clean_first=True)
-
-    def _save_and_export(self, name, version, req_method, requires=None, ):
-        self._save(name, version, req_method, requires)
-        self.client.run("export . user/channel")
+    def _save(self, req_method, requires):
+        conanfile = GenConanfile()
+        for req in requires:
+            req2, override = req if isinstance(req, tuple) else (req, False)
+            if not req_method:
+                conanfile.with_require_plain(req2, override=override)
+            else:
+                conanfile.with_requirement_plain(req2, override=override)
+        self.client.save({"conanfile.py": conanfile}, clean_first=True)
 
     def test_override(self):
+        self.client.save({"conanfile.py": GenConanfile()})
+        self.client.run("export . libA/1.0@user/channel")
+        self.client.run("export . libA/1.0@user/channel")
+
         for req_method in (False, True):
-            self._save_and_export("libA", "1.0", req_method)
-            self._save_and_export("libA", "2.0", req_method)
-            self._save_and_export("libB", "1.0", req_method, ["libA/1.0@user/channel"])
-            self._save_and_export("libC", "1.0", req_method, ["libA/2.0@user/channel"])
-            self._save("project", "1.0", req_method, ["libB/1.0@user/channel",
-                                                      "libC/1.0@user/channel"])
-            self.client.run("create . user/channel", assert_error=True)
+            self._save(req_method, ["libA/1.0@user/channel"])
+            self.client.run("export . libB/1.0@user/channel")
+            self._save(req_method, ["libA/2.0@user/channel"])
+            self.client.run("export . libC/1.0@user/channel")
+            self._save(req_method, ["libB/1.0@user/channel", "libC/1.0@user/channel"])
+            self.client.run("info .", assert_error=True)
             self.assertIn("Requirement libA/2.0@user/channel conflicts with "
                           "already defined libA/1.0@user/channel", self.client.out)
 
-            self._save("project", "1.0", req_method, ["libB/1.0@user/channel",
-                                                      "libC/1.0@user/channel",
-                                                      ("libA/1.0@user/channel", "override")])
-            self.client.run("create . user/channel")
-            self.assertIn("libA/2.0@user/channel overridden by project/1.0@user/channel",
-                          self.client.out)
+            self._save(req_method, ["libB/1.0@user/channel", "libC/1.0@user/channel",
+                                    ("libA/1.0@user/channel", "override")])
+            self.client.run("info .")
+            self.assertIn("libA/2.0@user/channel overridden", self.client.out)
+
+    def test_public_deps(self):
+        client = TestClient()
+        pkg2 = textwrap.dedent(""" 
+            from conans import ConanFile
+            class Pkg(ConanFile):
+                requires = ("pkg/0.1@user/stable", "override"),
+                def package_info(self):
+                    self.output.info("PUBLIC PKG2:%s" % self.cpp_info.public_deps)
+            """)
+        client.save({"conanfile.py": pkg2})
+        client.run("create . pkg2/0.1@user/stable")
+        self.assertIn("pkg2/0.1@user/stable: PUBLIC PKG2:[]", client.out)
+        pkg3 = textwrap.dedent(""" 
+            from conans import ConanFile
+            class Pkg(ConanFile):
+                requires = "pkg2/0.1@user/stable", ("pkg/0.1@user/stable", "override")
+                generators = "cmake"
+            """)
+        client.save({"conanfile.py": pkg3})
+        client.run("install .")
+        self.assertIn("pkg2/0.1@user/stable: PUBLIC PKG2:[]", client.out)
+        conanbuildinfo = client.load("conanbuildinfo.cmake")
+        self.assertIn("set(CONAN_DEPENDENCIES pkg2)", conanbuildinfo)