Copy sources from all your dependencies

Please, first clone the sources to recreate this project. You can find them in the examples2 repository in GitHub:

  1. $ git clone https://github.com/conan-io/examples2.git
  2. $ cd examples2/examples/extensions/deployers/sources

In this example we are going to see how to create and use a custom deployer. This deployer copies all the source files from your dependencies and puts them into a specific output folder

Note

To better understand this example, it is highly recommended to have previously read the Deployers reference.

Locate the deployer

In this case, the deployer is located in the same directory as our example conanfile, but as shown in Deployers reference, Conan will look for the specified deployer in a few extra places in order, namely:

  1. Absolute paths

  2. Relative to cwd

  3. In the [CONAN_HOME]/extensions/deployers folder

  4. Built-in deployers

Run it

For our example, we have a simple recipe that lists both zlib and mcap as requirements. With the help of the tools.build:download_source=True conf, we can force the invocation of its source() method, which will ensure that sources are available even if no build needs to be carried out.

Now, you should be able to use the new deployer in both conan install and conan graph commands for any given recipe:

  1. $ conan graph info . -c tools.build:download_source=True --deployer=sources_deploy

Inspecting the command output we can see that it copied the sources of our direct dependencies zlib and mcap, plus the sources of our transitive dependencies, zstd and lz4 to a dependencies_sources folder. After this is done, extra preprocessing could be done to accomplish more specific needs.

Note that you can pass the --deployer-folder argument to change the base folder output path for the deployer.

Code tour

The source_deploy.py file has the following code:

sources_deploy.py

  1. from conan.tools.files import copy
  2. import os
  3. def deploy(graph, output_folder, **kwargs):
  4. # Note the kwargs argument is mandatory to be robust against future changes.
  5. for name, dep in graph.root.conanfile.dependencies.items():
  6. if dep.folders is None or dep.folders.source_folder is None:
  7. raise ConanException(f"Sources missing for {name} dependency.\n"
  8. "This deployer needs the sources of every dependency present to work, either building from source, "
  9. "or by using the 'tools.build:download_source' conf.")
  10. copy(graph.root.conanfile, "*", dep.folders.source_folder, os.path.join(output_folder, "dependency_sources", str(dep)))

deploy()

The deploy() method is called by Conan, and gets both a dependency graph and an output folder path as arguments. It iterates all the dependencies of our recipe and copies every source file to their respective folders under dependencies_sources using conan.tools.copy.

Note

If you’re using this deployer as an example for your own, remember that tools.build:download_source=True is necessary so that dep.folders.source_folder is defined for the dependencies. Without the conf, said variable will not be defined for those dependencies that do not need to be built from sources nor in those commands that do not require building, such as conan graph.

Note

If your custom deployer needs access to the full dependency graph, including those libraries that might be skipped, use the tools.graph:skip_binaries=False conf. This is useful for collecting, for example, all the licenses in your graph.