Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature request] Explain why a match was not found (conan why) #4089

Closed
2 tasks done
sztomi opened this issue Dec 7, 2018 · 17 comments · Fixed by #14694
Closed
2 tasks done

[feature request] Explain why a match was not found (conan why) #4089

sztomi opened this issue Dec 7, 2018 · 17 comments · Fixed by #14694

Comments

@sztomi
Copy link
Contributor

sztomi commented Dec 7, 2018

I have a relatively frequent use-case which could be automated in conan (maybe as a conan why command). First, let me show an example how I do this manually and then I'll propose conan why.

The example and manual solution

  • Trying to install a package for a certain profile
  • There is no matching package in the cache or remotes
  • I need to figure out which setting or option is wrong and what's the best match

I'm served with a message that looks like this:

PlexMediaServer/1.15.0@plex/stable: WARN: Can't find a 'PlexMediaServer/1.15.0@plex/stable' package for the specified options and settings:
- Settings: arch=x86_64, build_type=Release, compiler=clang, compiler.libcxx=libc++, compiler.version=5.0, os=Macos
- Options: devel=False, sanitize=none, variation=nano, boost:shared=False, bzip2:fPIC=True, bzip2:shared=False, cppnetlib:shared=False, curl:shared=False, fmt:shared=False, freei
mage:shared=False, libidn:shared=False, libxml2:shared=False, minizip:shared=False, opencv:shared=False, plex-openssl:shared=False, soci:shared=False, sqlite:shared=False, taglib
:shared=False, zlib:shared=False
- Package ID: b9cf955f067ee02ab9107d531142201be6422019

Now, in this case I know I have exactly one package in my cache, so I proceed to list its settings and options:

$ conan info PlexMediaServer/1.15.0@plex/stable

[I] ➜ ./conan-bin search PlexMediaServer/1.15.0@plex/stable
Existing packages for recipe PlexMediaServer/1.15.0@plex/stable:

    Package_ID: f5f11a16f57dea41ac9cbfd09c094673f35b4e4f
        [options]
            devel: True
            sanitize: none
            variation: nano
        [settings]
            arch: x86_64
            build_type: Release
            compiler: clang
            compiler.libcxx: libc++
            compiler.version: 5.0
            os: Macos
        [requires]
            boost/1.59.0-37@plex/stable:f3008bb2d07dac7305d36831eff30641d375e5c3
            bzip2/1.0.6-10@plex/stable:0c446de161870e43ba015ddcae0051201b8523e8
            ca-bundle/2018-10-17-1@plex/stable:5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9
            cmakecache/1-15@plex/stable:5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9
            cmaketoolchain/1-14@plex/stable:5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9
            cotire/1.8.0-391bf6b-10@plex/stable:5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9
            cppnetlib/0.10.1-35@plex/stable:78ff5bd100860b10449c8f9203c37913498e118f
            curl/7.56.1-44@plex/stable:82e67269b6c125788ab8cdb27ae6f546537f47be
            fmt/4.1.0-135ab5c-9@plex/stable:27de2ffeada2aa97bda8c9d4a57fea3c49ff6655
            freeimage/3.17.0-13@plex/stable:27de2ffeada2aa97bda8c9d4a57fea3c49ff6655
            libidn/2.0.5-14@plex/stable:2ecea8b4c00f534446d65d264899e590afe91c27
            libxml2/2.9.8-7@plex/stable:f3881625999479f891a7fcd01279b92e7993f60d
            minizip/1.2.8-12@plex/stable:f3881625999479f891a7fcd01279b92e7993f60d
            opencv/2.4.13-07711e4-16@plex/stable:64a735b0d0e2664d702117e3988fb9e3c6b21525
            plex-openssl/1.0.2p-17@plex/stable:f3881625999479f891a7fcd01279b92e7993f60d
            rapidjson/1.1.0-9@plex/stable:27de2ffeada2aa97bda8c9d4a57fea3c49ff6655
            soci/3.0.0-9a9baa1-10@plex/stable:6f085b771649cc265b6b0f42cc878ab40e474a91
            sqlite/3.23.1-13@plex/stable:2ecea8b4c00f534446d65d264899e590afe91c27
            taglib/1.11.1-35@plex/stable:8bedfc069c29e5a10c786ab5501478c56fdc37e9
            universalchardet/1.0.0-9e41626-9@plex/stable:27de2ffeada2aa97bda8c9d4a57fea3c49ff6655
            zlib/1.2.8-12@plex/stable:2ecea8b4c00f534446d65d264899e590afe91c27
        Outdated from recipe: False

It's not easy to spot the wrong setting or option there, especially that the error message above listed the full_options, but search only lists the package options. I don't know where the mismatch is at this moment.

So I do the following: I dump the sorted options from the conaninfo.txt from the package I'd expect to be a match, and I dump the options from the error output (breaking up the lines & removing commas manually and sorting both files). So now I have files with contents like this (showing only one for brevity):

boost:shared=False
bzip2:fPIC=True
bzip2:shared=False
cppnetlib:shared=False
curl:shared=False
devel=True
fmt:shared=False
freeimage:shared=False
libidn:shared=False
libxml2:shared=False
minizip:shared=False
opencv:shared=False
plex-openssl:shared=False
sanitize=none
soci:shared=False
sqlite:shared=False
taglib:shared=False
variation=nano
zlib:shared=False

Then I diff them:

➜ diff ../../pms/opts1.txt ../../pms/opts2.txt
6c6
< devel=False
---
> devel=True

And there I have my answer.

Needless to say, I was lucky I had only one package. It's much harder to figure out when there are multiple packages. In that case, I usually search with -q to reduce the number of hits, but in many cases it's still a lot of legwork to spot what's wrong. I don't always do this diffing process, many times I just scroll up and down and try keep each option and setting in my head.

Proposed solution: conan why

When an install command fails with the error above, I'd like to be able to ask conan what went wrong and what's the closest match. Matches should be ranked by the number of options and settings that matched between the consuming installation context ("wanted") and the package that's being considered for installation. Maybe a percentage value could be used to unify the matching metric. A perfect match is 1.0. My propsed workflow would be (# denoting my comments):

$ conan install xxxx 
# get the error from above

$ conan why
Failed matches while resolving PlexMediaServer/1.15.0@plex/stable:
  * Considered f5f11a16f57dea41ac9cbfd09c094673f35b4e4f (match: 0.92):
    - Mismatching settings: None
    - Mismatching options:
      - `devel`
        Wanted:  devel=False
        Package: devel=True
  # Listing any further package IDs after this

# Listing any further missing packages the same way after this

Ideally, one should be able to limit the number of listed packages, because I'd imagine usually only the first few best matches will be interesting.

I think all the information is present at runtime when conan install is executed.
What are your thoughts?


To help us debug your issue please explain:

  • I've read the CONTRIBUTING guide.
  • [n/a] I've specified the Conan version, operating system version and any tool that can be relevant.
  • I've explained the steps to reproduce the error or the motivation/use case of the question/suggestion.
@uilianries
Copy link
Member

Excellent idea, I've had the same problem many times. But why not extend conan install/create with your idea, instead to create a new command?

@sztomi
Copy link
Contributor Author

sztomi commented Dec 7, 2018

Good idea, and probably easier to implement (no need to record state).

@ghost
Copy link

ghost commented Dec 8, 2018

Hey, nice idea. I think extending "install" ( --verbose maybe?) would be better. Then you have everything in one step, and you don't have to optionally call "why". If "install" fails, the process must be aborted anyway.

@memsharded
Copy link
Member

Lets say you have a dependency graph of 50 packages. You fire one conan install --why with one configuration which you don't have binaries for. That requires a full search for each one, then looking for the best matches. That could go up to a minute, for one remote, then scale linearly with every remote you have.

I understand the interest of the idea, not saying it wouldn't be useful, but I see it with a low priority and a non trivial complexity.

@memsharded
Copy link
Member

Assigned to @lasote for further feedback about this possible feature.

@sztomi
Copy link
Contributor Author

sztomi commented Dec 9, 2018

That could go up to a minute

Understood - but that is much faster than manually digging out the settings and options to figure out what's wrong. I might want to take a stab at this - do labels mean that there would be interest in merging if I made a PR?

@lasote lasote removed their assignment Dec 10, 2018
@lasote
Copy link
Contributor

lasote commented Dec 12, 2018

We would need to define what is a "close/near binary package":

  • Settings? I assume, the "os", "arch", and "compiler" can't change if you are debugging a missing binary package, because probably you weren't expecting a binary for a different operating system.
  • Options only?

Maybe it is enough to show/suggest a "conan search" command with the settings (and the remote) when Conan raises the error because of a missing configuration? It will show a list of available binary packages.

@sztomi
Copy link
Contributor Author

sztomi commented Dec 12, 2018

We would need to define what is a "close/near binary package":

If I remember correctly, conan doesn't do a form of "matching", instead it computes the package ID from settings+options+requires and then just tries to find that. I would use the same elements in a matching algorithm that are used to compute the hash.

Maybe it is enough to show/suggest a "conan search" command with the settings (and the remote) when Conan raises the error because of a missing configuration? It will show a list of available binary packages.

I disagree. While helping the discoverability of search is great for new users, this doesn't really address the recurring pain I outlined in the starting post. It still requires painful manual searching over each configuration exactly the same way I described (and we, seasoned conan users already know how to search so it's not helping us). Search is precisely what I do there as the first step, but it's not enough.

@memsharded
Copy link
Member

I would use the same elements in a matching algorithm that are used to compute the hash.

That is the problem. The setting.os has exactly the same weight as the options.shared in the hash. But when a binary is missing you certainly don't want conan to say, ey, instead of a "os=Windows", there is one "os=Linux" package binary there. That won't help. Same with things as the compiler. So defining a distance that makes sense is not completely straightforward.

@sztomi
Copy link
Contributor Author

sztomi commented Dec 18, 2018

On the contrary, that would absolutely help. You are making the assumption that I'd solve the setting mismatch by using a different value, which obviously doesn't make sense in your example. But more often than not, the solution is not to change the setting I use, it's to get that missing build. Such output would help me realize what's missing. In this example: "oh, right! I never ran the build for Linux. That's what I need to do!"

I think equal weight is actually sufficient and I'd argue that it's not possible to come up with a universal weighing scheme anyway (especially with the flexibility of conan in terms of settings and options).

@memsharded
Copy link
Member

But more often than not, the solution is not to change the setting I use, it's to get that missing build. Such output would help me realize what's missing. In this example: "oh, right! I never ran the build for Linux. That's what I need to do!"

But that is exactly what the output of the missing binary is saying, I am not sure about what you mean:

$ conan install zlib/1.2.11@conan/stable -s os=Windows -s compiler="Visual Studio" -s compiler.version=10
...
...
zlib/1.2.11@conan/stable: WARN: Can't find a 'zlib/1.2.11@conan/stable' package for the specified settings, options and dependencies:
- Settings: arch=x86_64, build_type=Release, compiler=Visual Studio, compiler.runtime=MD, compiler.version=10, os=Windows
- Options: minizip=False, shared=False
- Dependencies:
- Package ID: 85f780d0530411a64b0be4407b381706014b445d

ERROR: Missing prebuilt package for 'zlib/1.2.11@conan/stable'
Try to build it from sources with "--build zlib"
Or read "http://docs.conan.io/en/latest/faq/troubleshooting.html#error-missing-prebuilt-package"

Then, the fact that we never ran a build for VS10 should be evident from the output:

  • Settings: arch=x86_64, build_type=Release, compiler=Visual Studio, compiler.runtime=MD, compiler.version=10, os=Windows

And outputting "close" matches is nothing but noise. From my point of view this is the most common case by far. For other cases, the why I think it would probably be something like a

$ conan search <ref> --find="arch=x86_64, build_type=Release, compiler=Visual Studio, compiler.runtime=MD, compiler.version=10, os=Windows"

(the UI is just an idea, not a proposal).

@sztomi
Copy link
Contributor Author

sztomi commented Dec 19, 2018

Maybe the scale of things is different. Or the situation: as a developer you create an artificial situation where you say, "let's create an output for when there is no match for the OS", and then you read the message and it seems very clear. But when you don't know what is mismatching in the first place, it's not clear at all (user's perspective).

I find it not evident in a real world scenario with 25 profiles. That's why I detailed the process in my first post. My experience is that this error message shows a "needle and a haystack" and I have to find the needle in an even bigger haystack. It literally says: "here are all the settings and options I computed, one or more of them is wrong, go figure out which, you are on your own".

I'll give you another example. Here's an imaginary error message:

zlib/1.2.11@conan/stable: WARN: Can't find a 'zlib/1.2.8-11@plex/stable' package for the specified settings, options and dependencies:
- Settings: arch=armv7sf, build_type=Release, compiler=clang, compiler.version=6.0, os: Linux
- Options: shared=False
- Dependencies:
- Package ID: 85f780d0530411a64b0be4407b381706014b445d

And then you search and get:

Existing packages for recipe zlib/1.2.8-11@plex/stable:

    Package_ID: 101ff7db5b8a3368d94d6200b2fc866c85116b6d
        [options]
            shared: False
        [settings]
            arch: x86
            build_type: Release
            compiler: gcc
            compiler.threads: posix
            compiler.version: 6.3
            os: Windows
        Outdated from recipe: False

    Package_ID: 1299b26cefc5e04411a3481abe1c8b63227e2896
        [options]
            shared: False
        [settings]
            arch: x86
            build_type: Release
            compiler: Visual Studio
            compiler.runtime: MD
            compiler.version: 14
            os: Windows
        Outdated from recipe: False

    Package_ID: 2ecea8b4c00f534446d65d264899e590afe91c27
        [options]
            shared: False
        [settings]
            arch: x86_64
            build_type: Release
            compiler: clang-apple-clang
            compiler.libcxx: None
            compiler.sanitizer: None
            compiler.version: 5.0
            os: Macos
        Outdated from recipe: False

    Package_ID: 40286b2554ea1ce6f128ed0a3f399df9a3a6f4ce
        [options]
            shared: False
        [settings]
            arch: x86_64
            build_type: Debug
            compiler: clang-apple-clang
            compiler.libcxx: None
            compiler.sanitizer: None
            compiler.version: 5.0
            os: Macos
        Outdated from recipe: False

    Package_ID: 410a82f39f8e65926453a8a69ed0d1e44b92a962
        [options]
            shared: False
        [settings]
            arch: x86
            build_type: Release
            compiler: clang
            compiler.version: 5.0
            os: Android
            os.android_api_level: 21
            os.android_ndk: r16b
        Outdated from recipe: False

    Package_ID: 46c4712f43e453a1e0dc2cb8601ab88b9fc12e26
        [options]
            shared: False
        [settings]
            arch: armv7
            build_type: Release
            compiler: clang
            compiler.version: 5.0
            os: Android
            os.android_api_level: 21
            os.android_ndk: r16b
        Outdated from recipe: False

    Package_ID: 518365eebb4c428f581c6cd505b61135d1fcc814
        [options]
            shared: False
        [settings]
            arch: armv7hf-sysv
            build_type: Release
            compiler: clang
            compiler.version: 5.0
            os: Linux
        Outdated from recipe: False

    Package_ID: 68f75692adcdc474ced75368cf48ae2aaac3d684
        [options]
            shared: False
        [settings]
            arch: x86_64
            build_type: Release
            compiler: clang-apple-clang
            compiler.libcxx: None
            compiler.sanitizer: None
            compiler.version: 5.0
            os: iOS
        Outdated from recipe: False

    Package_ID: 6ca0d56d07f67b6ca11bd4bc84e9492aa5daa1e4
        [options]
            shared: False
        [settings]
            arch: x86
            build_type: Release
            compiler: clang
            compiler.version: 5.0
            os: Linux
        Outdated from recipe: False

    Package_ID: 6d903db1d8f7fad270eb88b93f16dc9b8d908b7c
        [options]
            shared: False
        [settings]
            arch: armv7sf
            build_type: Release
            compiler: clang
            compiler.version: 5.0
            os: Linux
        Outdated from recipe: False

    Package_ID: 740a21f3db572a2abb5da3bbb6d68d4b66e9eebf
        [options]
            shared: False
        [settings]
            arch: x86_64
            build_type: Debug
            compiler: clang
            compiler.version: 5.0
            os: Linux
        Outdated from recipe: False

    Package_ID: 761f870b337402a883ddbf20dbcfe1bb8e67155a
        [options]
            shared: False
        [settings]
            arch: x86_64
            build_type: Release
            compiler: clang
            compiler.version: 5.0
            os: FreeBSD
        Outdated from recipe: False

    Package_ID: 76cf3e0ccf9cf50d05f96dfc2f780a5b431e6378
        [options]
            shared: False
        [settings]
            arch: x86_64
            build_type: Release
            compiler: gcc
            compiler.threads: posix
            compiler.version: 6.3
            os: Windows
        Outdated from recipe: False

    Package_ID: 805790c8ff023abe3def2a8d664e74241a30df80
        [options]
            shared: False
        [settings]
            arch: x86_64
            build_type: Debug
            compiler: clang-apple-clang
            compiler.libcxx: None
            compiler.sanitizer: None
            compiler.version: 5.0
            os: iOS
        Outdated from recipe: False

    Package_ID: 8094f5147bc9378351237bfd795472578065861f
        [options]
            shared: False
        [settings]
            arch: x86_64
            build_type: Release
            compiler: clang
            compiler.version: 5.0
            os: Linux
        Outdated from recipe: False

    Package_ID: 9908482ff4d38990752d22013dda89c0f27b0e6a
        [options]
            shared: False
        [settings]
            arch: aarch64
            build_type: Debug
            compiler: clang
            compiler.version: 5.0
            os: Android
            os.android_api_level: 21
            os.android_ndk: r16b
        Outdated from recipe: False

    Package_ID: a15fac5e5aed6cd9d037d38e8088580bd28218da
        [options]
            shared: False
        [settings]
            arch: aarch64
            build_type: Release
            compiler: clang
            compiler.version: 5.0
            os: Android
            os.android_api_level: 21
            os.android_ndk: r16b
        Outdated from recipe: False

    Package_ID: a68449d756b1b72296c5af2c87b414ca2b387531
        [options]
            shared: False
        [settings]
            arch: armv7
            build_type: Release
            compiler: clang-apple-clang
            compiler.libcxx: None
            compiler.sanitizer: None
            compiler.version: 5.0
            os: iOS
        Outdated from recipe: False

    Package_ID: a8aed829304fe5cc95659bc2d44fa1628511899a
        [options]
            shared: False
        [settings]
            arch: x86
            build_type: Debug
            compiler: Visual Studio
            compiler.runtime: MDd
            compiler.version: 14
            os: Windows
        Outdated from recipe: False

    Package_ID: ac8837a168e424b117b9441ab76dcbe38c55e526
        [options]
            shared: False
        [settings]
            arch: aarch64
            build_type: Release
            compiler: clang
            compiler.version: 5.0
            os: Linux
        Outdated from recipe: False

    Package_ID: bcd8f0ac05c8a0bc9166655d6991d094dfd58096
        [options]
            shared: False
        [settings]
            arch: armv7hf
            arch.neon: True
            build_type: Release
            compiler: clang
            compiler.version: 5.0
            os: Linux
        Outdated from recipe: False

    Package_ID: dd563d43c7be8718ac8574bbbf0b3e5d0a513596
        [options]
            shared: False
        [settings]
            arch: aarch64
            build_type: Release
            compiler: clang-apple-clang
            compiler.libcxx: None
            compiler.sanitizer: None
            compiler.version: 5.0
            os: iOS
        Outdated from recipe: False

    Package_ID: eaa78d4aeac07e59aa38f527b81dceab7d559a5a
        [options]
            shared: False
        [settings]
            arch: armv7hf
            build_type: Release
            compiler: clang
            compiler.version: 5.0
            os: Linux
        Outdated from recipe: False

(this is real output and I planted one setting mismatch)

You might be tempted to say, "OK, but I'll obviously filter for Linux", but we still have 8 of those. Can you find which setting is wrong in the above list without pulling hair? Now you are scrolling up and down in your terminal to see the error message and compare to various recipes, lose track of where you were etc. Or you try to be smart and do something like I did in the motivating example in the first post.

My point is that this is way too difficult and the error message is not helpful in larger scale projects. But it could be more helpful because all the information is there.

And outputting "close" matches is nothing but noise.

By default, maybe, but on these occasions they would be super useful. That's why I proposed a separate command, but then agreed with the suggestions that a flag would be better. I don't think the default behavior should change.

Another informative aspect would be if it could say: "all settings and options matched in all recipes except: os". The profiles we use are almost never changing, so most often the answer is that the missing profile was not built.

For other cases, the why I think it would probably be something like a

I don't understand this idea. Are you saying that instead of a flag to install you would add a flag to search for the same functionality?

@memsharded
Copy link
Member

You might be tempted to say, "OK, but I'll obviously filter for Linux", but we still have 8 of those. Can you find which setting is wrong in the above list without pulling hair? Now you are scrolling up and down in your terminal to see the error message and compare to various recipes, lose track of where you were etc. Or you try to be smart and do something like I did in the motivating example in the first post.

No, I am not suggesting to filter by linux. I was suggesting that the --find functionality is actually computing the "closest distance" ordered list of close matches.

I don't understand this idea. Are you saying that instead of a flag to install you would add a flag to search for the same functionality?

Yes, I am suggesting doing it in 2 steps. Maybe the command line can be also printed directly in the error output of missing package, so users wanting to know "why" they could copy and paste it.
I am very concerned of the growing complexity of the install, both in UI and the growing list of arguments, but also in internal implementation. I would like to make sure they are kept very decoupled, at least initially.

@sztomi
Copy link
Contributor Author

sztomi commented Dec 19, 2018

I would like to make sure they are kept very decoupled, at least initially.

Given sufficient output I could implement this in a totally separate tool. I think the only piece missing is json output from install which includes the missing packages. I'll still try it with a prototype where the recipe name is manually entered.

@memsharded
Copy link
Member

Given sufficient output I could implement this in a totally separate tool. I think the only piece missing is json output from install which includes the missing packages. I'll still try it with a prototype where the recipe name is manually entered.

Ok, could we agree in the UI then? I think it makes sense in conan search, so in that case the information should be provided as an argument. conan search already has -q QUERY, --query QUERY, with a syntax that allows defining settings and options to search for, maybe it makes sense to reuse that syntax, but I am open to any suggestion.

@sztomi
Copy link
Contributor Author

sztomi commented Dec 19, 2018

I think it makes sense in conan search

Hmm, I might disagree on that. The most common use-case would be to find matches for the current settings and options (i.e. after conan install failed). In that case, it would be a lot of legwork to construct the query string which is a different format from the error message (although your suggestion for a copy-pastable pre-made command in the output would help with that).

For me, search is a bit different semantically and I think that command is also a bit overburdened similarly to install (since currently search acts as a way to search recipes but also to display their settings/options when a complete package reference is passed). This would add a third, different functionality to search. So maybe a separate subcommand is the way to go after all? Playing with some ideas:

Find matching packages for the current settings and options (read from conaninfo.txt):

This would be the most frequent use-case; simplest invocation.

$ conan match zlib/1.2.8-11@plex/stable

Find matching packages for profile

$ conan match -pr someprofile.txt zlib/1.2.8-11@plex/stable

Find matching packages for manually provided settings

$ conan match -s os=Linux -o shared=False zlib/1.2.8-11@plex/stable

etc.

I changed my original suggestion of why because yarn also has a why command but it does something completely different.

@memsharded memsharded added component: ux No changes to core business logic and removed UX labels Jan 2, 2019
@memsharded
Copy link
Member

Good news everyone.

Conan 2.0.15 in #14694 provides the conan graph explain that will do exactly this, explain why missing binaries are missing comparing them with existing one, looking for the "closest" ones.

@memsharded memsharded added this to the 2.0.15 milestone Nov 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants