conan-io / conan

Conan - The open-source C and C++ package manager
https://conan.io
MIT License
8.25k stars 980 forks source link

Support name/version deduction from `conanfile.py` for conan upload command #4498

Closed solvingj closed 4 years ago

solvingj commented 5 years ago

This topic has been discussed many times. I raise it as an issue again because it has come up as a pain point yet again. I also provide an alternative suggestion at the end of this issue.

History The argument against this feature has historically been that conan upload (and download) are fundamentally different from conan create and conan install commands. create and install operate upon recipes while upload operates on the upon "the cache". This is absolutely correct in principle.

In practice, it's overwhelmingly common for both interactive workflows and automated/CI workflows to do the following two commands in succession: conan create -> conan upload. This has an subtle and unfortunate awkwardness which has been worked around many times by many different people. Thus, this issue suggests adding some mechanism to provide the functionality described, in order to optimize one extremely common, yet still awkward situation.

Where the desired goal of the conan upload command is to upload the single binary of the package which was just created from the conanfile.py in the current directory. In automated/CI workflows, it's common to use Docker, and/or start the build out with a clean cache. In these cases, only the single binary for the target package exists in the cache.

Potential Implementation Add some path parameter such as: conan upload ... --path /path/to/conanfile

Deduce name and version with something like conan inspect or an internal function.

Automatically construct the following string to be used as pattern_or_reference, equivalent to: conan upload ... name/version*

Again, this should make sense in the majority of cases because automated builds often start out with clean cache, so this will often contain exactly 1 binary. A slightly more "robust" implementation might support placeholder/variable substitution syntax whenever --path is specified, enabling something like:

conan upload ... {name}/{version}@myuser/mychannel

None of this seems particular hard, and I can't immediately see any negative implications. It seems like the most significant concerns would be "is this case and implementation general enough?" and "how hard is this to support long-term?". Those would certainly be legitimate.

Specific Case The somewhat tedious and awkward situation right now is for automated scripts. The problem is that the conan create can be done without specifying the name and version in the command, while conan upload cannot. In the past, the solution has actually been for the automation scripts to parse the name and version from conanfile.py to be used in the conan upload command later. bincrafters_package_tools and conan_package_tools do this. Others just hardcoding the package name and/or version into their scripts as seen with BlinkApp here:

https://blog.conan.io/2018/04/25/Continuous-integration-for-C-C++embedded-devices-with-jenkins-docker-and-conan.html

conan inspect The new conan inspect -a command provides a significant improvement for automating this process for most cases. However, it requires that the machine running the script has python and conan installed.

Still an Issue Our current case involves Jenkins agents which have neither python nor conan installed, only Docker. Our new Jenkins shared library compiles a list of conan commands to be run in docker, and then runs them inside the container. As it stands today, we will have no choice but to add hard-coded the name and version variables into each (250+) Jenkinsfiles just so that we can formulate the conan upload command. It seems unnecessary.

Alternative Suggestion Since the conan command-line API is actually evolving nicely, and emerging as a crucial API for automation and integration with other tools, this problem could be approached by implementing a new conan command with a more general use:

conan makeref <path_to_conanfile> <user>/<channel>

which would output:

mypackage/version@user/channel

And thus, enable something like the following (although I'm not sure if this would require other changes to make it work):

conan makeref . myuser/mychannel | conan upload ...

I would be open to this approach as well.

memsharded commented 5 years ago

Regarding the first proposal, I don't think it is a good approach, to have a conan upload command that will be running a create first, just to get the package reference of the package being created. Just a confusing UI. I think it is much better decoupled as it is now, and it covers

conan inspect The new conan inspect -a command provides a significant improvement for automating this process for most cases. However, it requires that the machine running the script has python and conan installed.

This doesn't make much sense to me. Of course you need to have Conan installed, but you do anyway, for the create, upload, and any other possible conan functionality you might be requesting. I fail to see why this wouldn't be a good solution. The proposed conan makeref would require have Conan installed as well.

There is another way use machine readable structured output from commands, basically the json output:

$ conan create . user/testing --json=output.json

That json output is not trivial to parse, you need to get the recipe with "exported": true,. This might be considered as an improvement, to add something there in the json output that will make this simpler.

However, in this case, I think it makes more sense to use the conan inspect command, that was specifically added for this use case in mind. We could discuss if it makes sense to provide some option that would simplify its output and give name/version directly in output, would be ok for me, will propose it, thanks for all the suggestions!

solvingj commented 5 years ago

To clarify the first proposal, the intention was not to have conan upload running conan create. The user would run conan upload separately, but conan upload could deduce the values of the two variables using conan inspect.

To clarify our current situation, in which the machine constructing the conan ... commands does not have Conan installed... Jenkins agent doesn't have python or Conan installed, only docker. The Jenkinsfile/shared library are responsible only for compiling a list of commands to be run inside docker. The docker container has Python/Conan installed, but not the Jenkins agent. Does that make more sense?

Similarly, it's also easy to imagine any scripts which do remote invocation via SSH or powershell.