Skip to content

Latest commit

 

History

History
220 lines (178 loc) · 7.24 KB

core20-plugins.org

File metadata and controls

220 lines (178 loc) · 7.24 KB

Plugins for core20

Scope

Starting with base: core20, plugins shall be explicitly versioned. This shall ensure that plugins can evolve independently and that no breakages occur when other bases are used.

This document defines the core20 plugin interfaces and the high level changes required in Snapcraft, such as those in the PluginHandler and plugin loading logic. Each plugin will have its own specification relevant to the plugin.

Plugin Layout

Existing plugins using core or core18 as a base shall continue using their original logic for loading, that is When the base in snapcraft is set different one than the previously mentioned bases, then snapcraft will use the following path to search for plugins: snapcraft.plugins.<base> and search for <plugin-name>.py.

In-tree plugins shall be centrally mapped to the plugin class implementation. The plugin help shall be implemented as the doctring for the plugin module.

Custom Plugins

Custom plugins shall be declared on snapcraft.yaml with a prefix of x- and the plugin name. On the file system they shall be found on snap/plugins/x_<plugin.name.py>. The class name must be PluginImpl for the plugin to be easily found.

Core20 Base Plugin

A new plugin shall be implemented, PluginV2 (inheriting from abc.ABC)) as a base for all plugins used that target base core20.

A specific map shall exist to select these plugins when the build-base is set to core20.

The v2 base plugin and the in-tree plugins implementing it must reside in the snapcraft.plugins.v2 package, the base plugin shall be implemented with a class name of PluginV2 in a module with and import path of snapcraft.plugins.v2._plugin, for convenience, snapcraft.plugins.v2.__init__.py will import PluginV2 such that a plugin author could simply import snapcraft.plugins.v2.PluginV2. This plugin defines the following:

import abc
from typing import Any, Dict, List, Set


class PluginV2(abc.ABC):
    @classmethod
    @abc.abstractmethod
    def get_schema(cls) -> Dict[str, Any]:
        """Return a jsonschema compatible dictionary for the plugin properties."""

    def __init__(self, part_name: str, part_properties: Dict[str, str]) -> None:
        """
        :param str name: part names
        :param dict properties: part defined properties.
        """

    @abc.abstractmethod
    def get_build_snaps(self) -> Set[str]:
        """
        Return a set of required packages to install in the build environment.
        """

    @abc.abstractmethod
    def get_build_packages(self) -> Set[str]:
        """
        Return a set of required packages to install in the build environment.
        """

    @abc.abstractmethod
    def get_build_environment(self) -> Dict[str, str]:
        """
        Return a dictionary with the environment to use in the build step.

        For consistency, the keys should be defined as SNAPCRAFT_<PLUGIN>_<KEY>.

        This method is called by the PluginHandler during the "build" step.
        """

    @abc.abstractmethod
    def get_build_commands(self) -> List[str]:
        """
        Return a list of commands to run during the build step.

        This method is called by the PluginHandler during the "build" step.
        These commands are run in a single shell instance. This means
        that commands run before do affect the commands that follow.

        snapcraftctl can be used in the script to call out to snapcraft
        specific functionality.
        """

A common difference from previous implementations is that only build needs to be implemented. This leaves source handling through the pull step a pure Snapcraft core concern.

This new plugin design does not encourage importing any of the Snapcraft internals for a plugin to actually work, this means that most, if not **all** plugins, aside from the need of importing the base plugin will lack an import snapcraft or from snapcraft import statement for the plugin to be functional.

The responsibility of running through the build step is done by PluginHandler.build, to do so, during .build what will happen to construct the build script at a high level is:

  • A single environment dictionary is created.
  • Snapcraft’s internal get_build_environment method is called to update the environment dictionary.
  • The plugin’s get_build_environment method is called to updated the environment dictionary.
  • The Part’s build-environment key is retrieved and used to update the dictionary.

This is a powerful mechanism to give the Snapcraft Snap author the necessary control to override any undesired behavior or tune specific ones as well.

Example

As an example, this would be a simplified implementation of the samurai plugin (a fake ninja based build tool that uses make syntax):

"""
Plugin help
"""

from typing import Any, Dict, List

import snapcraft

class SamuraiPlugin(snapcraft.plugins.v2.PluginV2):
    def get_schema(cls) -> Dict[str, Any]:
        return dict()

    def get_build_environment(self) -> Dict[str, str]:
        environment = super().get_environment()
        environment.update(
            {
                "SNAPCRAFT_SAMURAI_ARGS": "--seppuku",
            }
        )
        return environment

    def get_build_commands(self) -> List[str]:
        commands = super().get_build_commands()
        commands.extend(
            [
                "samurai -j $SNAPCRAFT_SAMURAI_ARGS $SNAPCRAFT_PARALLEL_BUILD_COUNT",
                "samurai install DESTDIR=$SNAPCRAFT_PART_INSTALL",
            ]
        )

        return commands

CLI

Wherever relevant, the Snapcraft commands shall default to the base declared in snapcraft.yaml, otherwise to the latest supported base.

In all cases, Snapcraft shall inform the base that is being used to present information.

A mechanism must exist to be able to invoke Snapcraft commands for a plugin that would apply to different base than the one from the current project or default.

The --base option is the preferred way to specify output targeting a specific base.

Help

$ snapcraft help --base=core python
Displaying help for the 'python' plugin for 'core20'
<plugin-help>

Listing plugins

$ snapcraft list-plugins --base=core
Displaying plugins available for core
<plugin-list>

Expanding snapcraft.yaml

This is a new command, meant to expose the plugins behavior in an easy way to the snapcraft.yaml author. Given the plugin described in Example, with the following snapcraft.yaml

name: project
base: core20
summary: use of the samurai plugin
description: an example meant to expand the samurai plugin

parts:
  samurai-part:
    source: .
    plugin: samurai

It can be expanded (or explained), by running:

$ snapcraft expand
name: project
base: core20
summary: use of the samurai plugin
description: an example meant to expand the samurai plugin

parts:
  samurai-part:
    source: .
    plugin: samurai
    build-environment:
      SNAPCRAFT_SAMURAI_ARGS: "--seppuku"
    override-build: |
     samurai -j $SNAPCRAFT_PARALLEL_BUILD_COUNT
     samurai $SNAPCRAFT_SAMURAI_INSTALL_TARGET DESTDIR=$SNAPCRAFT_PART_INSTALL