.. _how_to_add_a_source_handler: How to add a custom source type to an application ================================================= An application may need additional source types not included in craft-parts by default. In this case, you can create and register a new non-default source handler. .. warning:: New source handlers may be added in minor releases of craft-parts. If a custom source handler shares a ``source_type`` value with a new source handler, registering a custom source handler will override the existing source handler. Some source types are considered mandatory and cannot be overridden or unregistered. In a major release, the set of mandatory source types may change. At that point, an application-defined source type may not override the mandatory source type. Write a new source handler -------------------------- The first step in adding a new source handler is to write one. The components of a source handler are its source model (a `Pydantic `_ model that defines the ``source-*`` keys that may be used in a part) and the handler, a class that defines how the source type behaves during the ``PULL`` step. The Pydantic model is a child class of :py:class:`~craft_parts.sources.base.BaseSourceModel`. The only mandatory field is :py:attr:`~craft_parts.sources.base.BaseSourceModel.source_type`. .. literalinclude:: source-handler/rsync_source.py :language: python :pyobject: RsyncDirectorySourceModel The :py:attr:`~craft_parts.sources.base.BaseSourceModel.pattern` attribute allows Craft Parts to infer the source based on a regular expression. The first source handler with a matching regular expression will be used, with built-in source types matching before externally registered source types. Once this is defined, a :py:class:`~craft_parts.sources.base.SourceHandler` is needed to define the ``PULL`` behaviour of the source type. .. literalinclude:: source-handler/rsync_source.py :language: python :pyobject: RsyncSource .. note:: Craft Parts does not install any required tools for custom source handlers. The handler in this example will fail on a machine that does not have `rsync `_ installed before the part is pulled. Register the source handler --------------------------- Once created, a source must be registered to be used. This must occur before entering the :py:class:`~craft_parts.executor.executor.ExecutionContext` with the :py:class:`~craft_parts.lifecycle_manager.LifecycleManager`'s :py:meth:`~craft_parts.lifecycle_manager.LifecycleManager.action_executor` method. .. literalinclude:: source-handler/rsync_source.py :language: python :start-after: # docs[register-source:start] :end-before: # docs[register-source:end] Run the lifecycle ----------------- With those steps completed, the new source handler is ready to use. A ``parts.yaml`` file such as the following will use the example rsync source type: .. literalinclude:: source-handler/rsync_parts.yaml :language: yaml After loading the parts into a YAML structure, all that's left is to run it: .. literalinclude:: source-handler/rsync_source.py :language: python :start-after: # docs[run-lifecycle:start] :end-before: # docs[run-lifecycle:end]