[question] how to deploy without dependencies
What is your question?
Currently, I use conan install --requires="my_package" --deployer="my_deployer" to deploy my binary. However, this command pulls all dependencies also, but I only need my package binary. Is there a way to avoid pulling other dependencies?
Have you read the CONTRIBUTING guide?
- [X] I've read the CONTRIBUTING guide
Hi @pwqbot
Thanks for your question.
You have the direct_deploy that only deploys the direct reference, not the dependencies.
But I guess you don't mean that, but the fact that Conan is resolving the dependency graph. It is indeed necessary to compute the dependency graph, because the binary that is pulled when you do conan install --requires="mypkg/version" also depends on the dependencies and transitive dependencies. For example if mypkg is an application, and the dependencies are static libraries, it might be necessary to re-build mypkg from source to get an update binary. Only computing the dependency graph allows to compute updated package_ids and making sure the thing that is being deployed is what is expected.
Conan has the "skip" binaries mechanism, so if things are updated and all is looking good, Conan will mark most of the binaries as "skip" and avoid pulling the dependencies if they are not necessary (like all static libraries will be skipped), making the process efficient.
If all you want is access to the artifacts for a given pkg/version:package_id, then you can do conan download + conan cache path for that specific package-id, and copy the files from the package. If you want to do something more advanced (without modifying the cache, that is not allowed), then you might want to wrap that in a custom command instead of trying a deployer, and your custom command can download the specific package-id and do what you want. But that is a different approach than the deployers that are designed to do operations on a dependency graph, not on one package.
Hi @pwqbot
Thanks for your question.
You have the
direct_deploythat only deploys the direct reference, not the dependencies.But I guess you don't mean that, but the fact that Conan is resolving the dependency graph. It is indeed necessary to compute the dependency graph, because the binary that is pulled when you do
conan install --requires="mypkg/version"also depends on the dependencies and transitive dependencies. For example ifmypkgis an application, and the dependencies are static libraries, it might be necessary to re-buildmypkgfrom source to get an update binary. Only computing the dependency graph allows to compute updatedpackage_idsand making sure the thing that is being deployed is what is expected.Conan has the "skip" binaries mechanism, so if things are updated and all is looking good, Conan will mark most of the binaries as "skip" and avoid pulling the dependencies if they are not necessary (like all static libraries will be skipped), making the process efficient.
If all you want is access to the artifacts for a given
pkg/version:package_id, then you can doconan download + conan cache pathfor that specific package-id, and copy the files from the package. If you want to do something more advanced (without modifying the cache, that is not allowed), then you might want to wrap that in a custom command instead of trying a deployer, and your custom command candownloadthe specific package-id and do what you want. But that is a different approach than thedeployersthat are designed to do operations on a dependency graph, not on one package.
Thanks! I think download + cache path may work. How to query for package id with params like package/version -s build_type=Debug -pr x86_linux_gcc_13_Debug -pr:b x86_linux_gcc_13_Debug?
Thanks! I think download + cache path may work. How to query for package id with params like package/version -s build_type=Debug -pr x86_linux_gcc_13_Debug -pr:b x86_linux_gcc_13_Debug?
With conan graph info ... passing those arguments. Note that this will compute the dependency graph, as commented above the package_id is also a function of the dependencies versions and revisions, so it is necessary to compute the graph, even if the binaries for the dependencies are not downloaded.
Alternatively, the conan list command has the --filter-profile and --filter-settings that can help listing the packages that matches some profiles and settings, but not this is just a filter of the existing binaries that matches those conditions, not an update package_id computation.
Any further feedback here @pwqbot? I think we can close the ticket as solved, but please let us know if there is any further question.
Any further feedback here @pwqbot? I think we can close the ticket as solved, but please let us know if there is any further question.
sure, we have resolved this issue. Here is the extension:
import json
from conan.api.conan_api import (
ConanAPI,
ListAPI,
RemotesAPI,
DownloadAPI,
CacheAPI,
)
import shutil, os
from conan.api.model import ListPattern
from conans.model.package_ref import PkgReference
from conan.api.output import ConanOutput
from conan.cli.command import conan_command
@conan_command(group="Custom commands")
def download_bin(conan_api: ConanAPI, parser, *args):
"""
Download a package from a remote, with calculating dependencies
"""
parser.add_argument("package", help="Package to download", default="")
parser.add_argument(
"-p", "--profile", dest="profile", help="Profile to use", required=True
)
parser.add_argument(
"-r", "--remote", dest="remote", help="Remote to use", required=True
)
parser.add_argument(
"-of",
"--output-folder",
dest="output_folder",
help="Output folder",
required=True,
)
args = parser.parse_args(*args)
package = args.package
list_api = ListAPI(conan_api)
ref_pattern = ListPattern(f"{package}:*")
remote_api = RemotesAPI(conan_api)
download_api = DownloadAPI(conan_api)
cache_api = CacheAPI(conan_api)
# split by "/"
package = package.split(":")[0]
name, version = package.split("/")
output_folder = args.output_folder
profiles = conan_api.profiles.get_profile([args.profile])
for remote in remote_api.list(args.remote):
pkg_list = list_api.select(ref_pattern, profile=profiles, remote=remote)
ConanOutput().info(
f"Downloading package: {pkg_list.serialize()} from {remote}\n"
)
download_api.download_full(pkg_list, remote, None)
for _, package in pkg_list.serialize().items():
for revision, package in package["revisions"].items():
for id, _ in package["packages"].items():
package_ref = PkgReference.loads(
f"{name}/{version}#{revision}:{id}"
)
path = cache_api.package_path(package_ref)
ConanOutput().info(f"Downloaded {name}/{version} to {path}\n")
bin_dir = os.path.join(path, "bin")
if not os.path.exists(output_folder):
os.makedirs(output_folder)
for file in os.listdir(bin_dir):
ConanOutput().info(f"Copying {file} to {output_folder}")
shutil.copy(
os.path.join(bin_dir, file),
os.path.join(output_folder, file),
)
return ""
Great, thanks for the feedback!
Some comments:
- Please don't instantiate yourself sub-apis like
list_api = ListAPI(conan_api). This will not be a supported use case, and using theconan_api.subapi.methodwill be the way. Please check https://docs.conan.io/2/examples/extensions/commands/clean/custom_command_clean_revisions.html#code-tour for an example. - You might leverage the
conan_api.command, something like:
To run other commands. In this case, it seems that you could further simplify your code by calling@conan_command(group="custom commands") def mycommand(conan_api, parser, *args, **kwargs): \""" mycommand help \""" result = conan_api.command.run({argument})conan list ... --filter-profile=myprofileviaconan_api.command.run()to do the job
We need to further document the ConanAPI, sorry we couldn't sufficiently prioritize that yet, but it is in our plans.
I think your custom command is exactly the goal of the custom commands framework, to be able to implement this kind of automation that is a bit too specific to be built-in. It was a great job.
I think this question can be closed as solved, thanks again for the feedback, don't hesitate to create new tickets for any further question.