Repository: conan-io/conan

Issue:
[bug] Default options from lockfile are not applied in the requirements() method when calling conan create
### Environment Details (include every applicable attribute)
  * Operating System+version: Ubuntu 19.10
  * Conan version: 1.19.2 - 1.21.1
  * Python version: 3.6

### Steps to reproduce

Consider the following tree and files:

```
.
├── ffmpeg
│   ├── conanfile.py
└── variant
    └── conanfile.py
```

variant/conanfile.py:

```py
class Meta(ConanFile):
  name = "nano"
  settings = "os", "arch", "compiler"
  version = "1.0"

  requires = (
    "ffmpeg/1.0",
  )

  default_options = {"ffmpeg:variation": "nano"}
```

ffmpeg/conanfile.py (shortened):

```py
class FfmpegConan(ConanFile):
    name = "ffmpeg"
    version = "1.0"
    settings = "os", "compiler", "build_type", "arch"
    options = {"variation": ["standard", "nano"]}
    default_options = {"variation": "standard"}

    def requirements(self):
        variation = str(self.options.variation)
        print(f"(requirements) variation = {variation}")
```

Script:

```
$ conan export ffmpeg
$ conan export variant
$ conan graph lock --build --lockfile . variant
$ conan graph build-order --build cascade --build outdated .
$ cat conan.lock
$ conan create --build ffmpeg/1.0 --test-folder=None -ne --lockfile . ffmpeg
```

#### What I would expect to happen:

Since in the root package ("variant") the ffmpeg `variation` option is overridden, I would expect it to take effect in the lockfile (it does) and to be applied when `conan create` is called (it isn't). 

The following should be printed:

```
(requirements) variation = nano
```

#### What actually happens

```
(requirements) variation = standard
```

is printed; even though

  * I can see the correct value captured in the lockfile
  * In other methods (if I print it similarly) the correct value is applied) 
  * When other commands are called (`conan graph lock` and `conan graph build-order`) I also see the correct value.

Repro: https://github.com/sztomi/default_options_not_applied





Discussion:

Resolving patch:
diff --git a/conans/client/graph/graph_builder.py b/conans/client/graph/graph_builder.py
--- a/conans/client/graph/graph_builder.py
+++ b/conans/client/graph/graph_builder.py
@@ -83,6 +83,7 @@ def extend_build_requires(self, graph, node, build_requires_refs, check_updates,
             r.build_require = True
 
         if graph_lock:
+            graph_lock.pre_lock_node(node)
             graph_lock.lock_node(node, requires, build_requires=True)
 
         self._resolve_ranges(graph, requires, scope, update, remotes)
@@ -137,6 +138,8 @@ def _get_node_requirements(self, node, graph, down_ref, down_options, down_reqs,
          the downstream requirements and overrides and solving version-ranges
         """
         # basic node configuration: calling configure() and requirements()
+        if graph_lock:
+            graph_lock.pre_lock_node(node)
         new_options = self._config_node(node, down_ref, down_options)
         # Alias that are cached should be replaced here, bc next requires.update() will warn if not
         self._resolve_cached_alias(node.conanfile.requires.values(), graph)
diff --git a/conans/model/graph_lock.py b/conans/model/graph_lock.py
--- a/conans/model/graph_lock.py
+++ b/conans/model/graph_lock.py
@@ -278,10 +278,7 @@ def update_check_graph(self, deps_graph, output):
                     raise ConanException("Mismatch between lock and graph:\nLock:  %s\nGraph: %s"
                                          % (repr(pref), repr(node.pref)))
 
-    def lock_node(self, node, requires, build_requires=False):
-        """ apply options and constraints on requirements of a node, given the information from
-        the lockfile. Requires remove their version ranges.
-        """
+    def pre_lock_node(self, node):
         if node.recipe == RECIPE_VIRTUAL:
             return
         try:
@@ -291,6 +288,16 @@ def lock_node(self, node, requires, build_requires=False):
                 return
             raise ConanException("The node ID %s was not found in the lock" % node.id)
 
+        node.graph_lock_node = locked_node
+        node.conanfile.options.values = locked_node.options
+
+    def lock_node(self, node, requires, build_requires=False):
+        """ apply options and constraints on requirements of a node, given the information from
+        the lockfile. Requires remove their version ranges.
+        """
+        if not node.graph_lock_node:
+            return
+        locked_node = node.graph_lock_node
         if build_requires:
             locked_requires = locked_node.build_requires or []
         else:
@@ -302,8 +309,6 @@ def lock_node(self, node, requires, build_requires=False):
             prefs = {self._nodes[id_].pref.ref.name: (self._nodes[id_].pref.copy_clear_revs(), id_)
                      for id_ in locked_requires}
 
-        node.graph_lock_node = locked_node
-        node.conanfile.options.values = locked_node.options
         for require in requires:
             try:
                 locked_pref, locked_id = prefs[require.ref.name]


Test patch:
diff --git a/conans/test/functional/graph_lock/graph_lock_test.py b/conans/test/functional/graph_lock/graph_lock_test.py
--- a/conans/test/functional/graph_lock/graph_lock_test.py
+++ b/conans/test/functional/graph_lock/graph_lock_test.py
@@ -705,3 +705,38 @@ def test(self):
         client2.run("install . --lockfile", assert_error=True)
         self.assertIn("ERROR: 'zlib' cannot be found in lockfile for this package", client2.out)
         self.assertIn("If it is a new requirement, you need to create a new lockile", client2.out)
+
+
+class LockFileOptionsTest(unittest.TestCase):
+    def test_options(self):
+        client = TestClient()
+        ffmpeg = textwrap.dedent("""
+            from conans import ConanFile
+            class FfmpegConan(ConanFile):
+                options = {"variation": ["standard", "nano"]}
+                default_options = {"variation": "standard"}
+
+                def requirements(self):
+                    variation = str(self.options.variation)
+                    self.output.info("Requirements: Variation %s!!" % variation)
+                    if self.options.variation == "standard":
+                        self.requires("missingdep/1.0")
+            """)
+
+        variant = textwrap.dedent("""
+            from conans import ConanFile
+            class Meta(ConanFile):
+                requires = "ffmpeg/1.0"
+                default_options = {"ffmpeg:variation": "nano"}
+            """)
+
+        client.save({"ffmepg/conanfile.py": ffmpeg,
+                     "variant/conanfile.py": variant})
+        client.run("export ffmepg ffmpeg/1.0@")
+        client.run("export variant nano/1.0@")
+
+        client.run("graph lock nano/1.0@ --build")
+        lockfile = client.load("conan.lock")
+        self.assertIn('"options": "variation=nano"', lockfile)
+        client.run("create ffmepg ffmpeg/1.0@ --build --lockfile")
+        self.assertIn("ffmpeg/1.0: Requirements: Variation nano!!", client.out)