Repository: conan-io/conan

Issue:
[bug] build_args are null for editable packages in the build order graph
### Describe the bug

In our CI environment, we have a pattern effectively the same as [test_multi_config_decentralized](https://github.com/conan-io/conan/blob/2.15.0/test/integration/lockfile/test_ci.py#L366).

Like done [here](https://github.com/conan-io/conan/blob/6c4a9fc22ba902e78e92fbf25b7e6b11577abad0/test/integration/lockfile/test_ci.py#L350-L351), we're using the `build_args` to run `conan install` for each package.

The same tooling can be used locally, allowing developers to use the identical (container) build environment.

In trying to allow for editable packages, we found that even when explicitly passing `--build=some-editable-package/0.1` the `build_args` would be set to `null` for that package.

This seems to be caused by the check in [_InstallConfiguration._build_args()](https://github.com/conan-io/conan/blob/2.15.0/conans/client/graph/install_graph.py)
```python
    def _build_args(self):
        if self.binary != BINARY_BUILD:
            return None
```

Based on [other](https://github.com/conan-io/conan/blob/6c4a9fc22ba902e78e92fbf25b7e6b11577abad0/conans/client/graph/install_graph.py#L126) [checks](https://github.com/conan-io/conan/blob/6c4a9fc22ba902e78e92fbf25b7e6b11577abad0/conans/client/graph/install_graph.py#L136) in the same file, I think `_build_args` should be:
```diff
diff --git a/conans/client/graph/install_graph.py b/conans/client/graph/install_graph.py
index 4a0fdaf9e..3900a4997 100644
--- a/conans/client/graph/install_graph.py
+++ b/conans/client/graph/install_graph.py
@@ -290,7 +290,7 @@ class _InstallConfiguration:
                     self.depends.append(dep.dst.pref)
 
     def _build_args(self):
-        if self.binary != BINARY_BUILD:
+        if not self.binary in (BINARY_BUILD, BINARY_EDITABLE_BUILD):
             return None
         cmd = f"--requires={self.ref}" if self.context == "host" else f"--tool-requires={self.ref}"
         compatible = "compatible:" if self.info and self.info.get("compatibility_delta") else ""

```

Having tried this change locally, it works as I would expect it to.

### How to reproduce it

```bash
$ conan new cmake_exe
$ conan editable add --name mypkg --version 0.1 .
$ conan graph build-order \
  --format=json \
  --build=missing \
  --order-by=recipe \
  --reduce \
  --requires=mypkg/0.1 \
  --build=mypkg/0.1
{
    "order_by": "recipe",
    "reduced": true,
    "order": [
        [
            {
                "ref": "mypkg/0.1",
                "depends": [],
                "packages": [
                    [
                        {
                            "package_id": "91d1ff771880a35cd1b81b2b1ca3e8df8077c05c",
                            "prev": null,
                            "context": "host",
                            "binary": "EditableBuild",
                            "options": [],
                            "filenames": [],
                            "depends": [],
                            "overrides": {},
                            "build_args": null,
                            "info": {
                                "settings": {
                                    "os": "Linux",
                                    "arch": "x86_64",
                                    "compiler": "gcc",
                                    "compiler.cppstd": "20",
                                    "compiler.libcxx": "libstdc++11",
                                    "compiler.version": "13",
                                    "build_type": "Release"
                                }
                            }
                        }
                    ]
                ]
            }
        ]
    ],
    "profiles": {
        "self": {
            "args": ""
        }
    }
}
```


Discussion:
Hi @Chasbob 

Thanks for your report and your detailed investigation.

I agree, it seems that adding ``BINARY_EDITABLE_BUILD`` would be more correct.
Let me try to propose a fix.
Working on a PR.

In any case, please note that this is a bit of unexpected use case:

- The build-args will be something like ``--requires=dep/0.1 --build=dep/0.1`` instead of null
- But running a ``conan install {build_args}`` in place, is just building that thing there in user space
- So the whole ``conan graph build-order`` + iteration, might be just a ``conan install --build=editable``, will be way easier

There might be something that I am missing, but it could be that there are simpler ways to achieve what you are trying to do.

Also, if you haven't checked it yet, I'd recommend to check the new ``Workspace`` feature in https://docs.conan.io/2/incubating.html. It is still "incubating", but if you are working with editables and doing some higher level automation over them, this could be a strong case for the ``Workspace``. For example, one of the features we are considering is to add a ``conan workspace create`` command that does an orchestrated creation of packages in the Conan cache (not in the workspace) for the given workspace editables.
If this Workspace feature seems interesting, I'd recommend to give it a try, play with it, and report feedback (questions, bugs, feature-requests) in new tickets. Thanks! 
Proposed PR https://github.com/conan-io/conan/pull/18097
Thanks for looking at this so quickly!

To be honest, the context I provided for our use case really muddies the water. 

The specific reason for supporting editable packages in our own tooling is so that developers can produce 'ci compatible' binaries on an ad-hoc basis. Which this solves, as we're doing something similar to the idea of the [Docker Runner](https://docs.conan.io/2/reference/runners/docker.html).



Patch:
diff --git a/conans/client/graph/install_graph.py b/conans/client/graph/install_graph.py
index 4a0fdaf9e21..b68dec9f2cc 100644
--- a/conans/client/graph/install_graph.py
+++ b/conans/client/graph/install_graph.py
@@ -66,7 +66,7 @@ def add(self, node):
         self.nodes.append(node)
 
     def _build_args(self):
-        if self.binary != BINARY_BUILD:
+        if self.binary not in (BINARY_BUILD, BINARY_EDITABLE_BUILD):
             return None
         cmd = f"--requires={self.ref}" if self.context == "host" else f"--tool-requires={self.ref}"
         compatible = "compatible:" if self.info and self.info.get("compatibility_delta") else ""
@@ -290,7 +290,7 @@ def add(self, node):
                     self.depends.append(dep.dst.pref)
 
     def _build_args(self):
-        if self.binary != BINARY_BUILD:
+        if self.binary not in (BINARY_BUILD, BINARY_EDITABLE_BUILD):
             return None
         cmd = f"--requires={self.ref}" if self.context == "host" else f"--tool-requires={self.ref}"
         compatible = "compatible:" if self.info and self.info.get("compatibility_delta") else ""


Test patch:
diff --git a/test/integration/command/info/test_info_build_order.py b/test/integration/command/info/test_info_build_order.py
index a9605cea580..4a39b80e6f9 100644
--- a/test/integration/command/info/test_info_build_order.py
+++ b/test/integration/command/info/test_info_build_order.py
@@ -804,9 +804,8 @@ def test_multi_configuration_profile_args():
 
 def test_build_order_space_in_options():
     tc = TestClient(light=True)
-    tc.save({"dep/conanfile.py": GenConanfile("dep", "1.0")
-                .with_option("flags", ["ANY", None])
-                .with_option("extras", ["ANY", None]),
+    tc.save({"dep/conanfile.py": GenConanfile("dep", "1.0").with_option("flags", ["ANY", None])
+                                                           .with_option("extras", ["ANY", None]),
              "conanfile.txt": textwrap.dedent("""
              [requires]
              dep/1.0
@@ -879,3 +878,25 @@ def validate(self):
                                 "bar/1.0": ["5e4ffcc1ff33697a4ee96f66f0d2228ec458f25c", "Build"]})
         c.assert_listed_binary({"foo/1.0": ["4e2ae338231ae18d0d43b9e119404d2b2c416758", "Build"]},
                                build=True)
+
+
+def test_info_build_order_editable():
+    c = TestClient()
+    c.save({"dep/conanfile.py": GenConanfile("dep", "0.1"),
+            "pkg/conanfile.py": GenConanfile("pkg", "0.1").with_requires("dep/0.1"),
+            "consumer/conanfile.txt": "[requires]\npkg/0.1"})
+    c.run("editable add dep")
+    c.run("export pkg")
+    
+    c.run("graph build-order consumer --build=missing --build=editable -f=json --order-by=recipe")
+    bo_json = json.loads(c.stdout)
+    pkg = bo_json["order"][0][0]["packages"][0][0]
+    assert pkg["binary"] == "EditableBuild"
+    assert pkg["build_args"] == "--requires=dep/0.1 --build=dep/0.1"
+
+    c.run("graph build-order consumer --build=missing --build=editable -f=json "
+          "--order-by=configuration")
+    bo_json = json.loads(c.stdout)
+    pkg = bo_json["order"][0][0]
+    assert pkg["binary"] == "EditableBuild"
+    assert pkg["build_args"] == "--requires=dep/0.1 --build=dep/0.1"