为snapcraft创建一个简单的定制的plugin

来源:互联网 发布:光纤星型网络结构 编辑:程序博客网 时间:2024/05/24 03:20

我们知道snapcraft的plugin框架是可以扩展的.我们可以为我们的snapcraft根据新的需求定义一个新的custom plugin来build我们的项目.在今天的这篇文章中,我们将介绍如何为我们的snapcraft创建一个新的plugin.关于snapcraft的plugin的更多的知识,请参阅我们的文档.更多关于snapcraft的知识,可以参阅我们的网站snapcraft.io.我们也可以在地址找到许多的plugin的例程供我们参考.


1)创建一个最基本的custom plugin



目前,我们能够在网上找到的最相近的文档在:

http://snapcraft.io/docs/build-snaps/plugins

按照要求,我们创建一个最基本的custom plugin的模版.我们可以通过如下的方法把我们的代码下载下来:

$ git clone https://github.com/liu-xiao-guo/plugin_template

我们的项目的文件架构:

liuxg@liuxg:~/release/plugin_template$ tree -L 3.├── parts│   └── plugins│       └── myplugin.py└── snapcraft.yaml

在上面的文件架构中,我们可以看出来,我们在我们的项目的根目录下创建了一个叫做parts的目录.在它的下面,我们也创建了一个叫做plugins的子目录.里面我们创建了一个最基本的文件myplugin.py.它的内容如下:

myplugin.py


# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-import loggingimport osimport globfrom pprint import pprintimport snapcraftlogger = logging.getLogger(__name__)def _dump(name, obj):    for attr in dir(obj):        # logger.warning("obj.%s = %s", attr, getattr(obj, attr))        func = getattr(obj, attr, None)        if func:            logger.warning("%s.%s = %s",name, attr, func)                logger.warning("===================================")class MyPlugin(snapcraft.BasePlugin):    @classmethod    def schema(cls):        schema = super().schema()        schema['properties']['myprop'] = {            'type': 'string',            'default': ''        }        # Inform Snapcraft of the properties associated with building. If these        # change in the YAML Snapcraft will consider the build step dirty.        schema['build-properties'].append('myprop')        return schema                            def __init__(self, name, options, project):        super().__init__(name, options, project)        logger.warning("__init__ begins name: %s", name)        logger.warning("options.source: %s", options.source)        logger.warning("options.myprop: %s", options.myprop)         logger.warning("self.builddir: %s", self.builddir)        logger.warning("self.installdir: %s", self.installdir)        # logger.warning("self.project.parallel_build_count: %d", self.project.parallel_build_count)        # logger.warning("self.project.arch_triplet: %s", self.project.arch_triplet)        # logger.warning("self.project.stage_dir: %s", self.project.stage_dir)               logger.warning("Going to add the needed build packages...")        # self.build_packages.append('golang-go')        # _dump("options", options)        # _dump("project", project)                logger.warning("build-packages:")        for pkg in options.build_packages:            logger.warning("build package: %s", pkg)    def build(self):        # setup build directory        super().build()        logger.warning("build begins ... ")                   def pull(self):        super().pull()        logger.warning("pull begins ... ")                           def clean_pull(self):        super().clean_pull()               logger.warning("clean pull begins ... ")      

在这里,我们可以看出来一个最基本的最简单的一个plugin的模版.我们的MyPlugin继承于snapcraft.BasePlugin.其实里面没有做任何实质性的东西.这里值得指出的是,我们使用了logger.warning(...)来帮我们输出调试信息.在真正的release时,我们需要删除这些输出.我们知道,在snapcraft build一个项目时,它经历如下的过程:




一个plugin在上面的5个过程中,它有经历pullbuild.我们也可以参考在snapcraft项目中的许多plugin的实例来如何实现上面的method.
在上面的代码中:

        schema['properties']['myprop'] = {            'type': 'string',            'default': ''        }

我们也定义了一个我们自己的被叫做myprop的property.为了展示我们对这个定制的snapcraft的plugin的调用,我们设计了如下的snapcraft.yaml文件:

snapcraft.yaml

name: plugin # you probably want to 'snapcraft register <name>'version: '0.1' # just for humans, typically '1.2+git' or '1.3.2'summary: This is a sample plugin for snapcraft # 79 char long summarydescription: |  This is a plugin examplegrade: stable # must be 'stable' to release into candidate/stable channelsconfinement: strict # use 'strict' once you have the right plugs and slotsparts:  my-part:    # This is a custom plugin defined in "parts" dir    plugin: myplugin    # This is the property defined in the plugin. It is a file name    # to be used for the congfigure hook    myprop: configure    source: .    

在这里,我们运用了myplugin,同时我们也使用了在我们plugin中所定义的myprop属性为configure.source通常是一个plugin必不可少的一个属性.在我们的例程中,我们定义它为".",也即当前的目录.

至此,我们最基本的一个plugin的框架已经搭好了,那么我们来对我们的项目进行build.在项目的根目录中打入:

$ snapcraft



从上面我们可以看出来它已经成功利用我们自己设计的plugin来build我们的项目,并且我们可以看出来"pull begins ..."及"build begins ..."字样.这些都是在我们的上面的myplugin.py中的logger.warning(...)所输出的.同时,我们也打印出来一些我们可能需要的Object属性,比如self.builddir等.我们也可以看出我们的options.myprop的值为"configure".同样,我们也可以来clean我们的项目:

$ snapcraft clean



从上面可以看出来,在myplugin.py中所定义的"clean_pull(self)"也被调用.我们可以通过这个method来删除我们在pull中下载的任何东西.

到目前为止,我们的最基本的template plugin没有做任何实质性的东西,它只是展示了继承于snapcraft.BasePlugin类里最基本的method(比如build(self))的调用.在下面的章节中,我们将展示如何利用这些方法来做我们需要做的事.


2)创建一个简单的运用snapcraft plugin的应用



在这一章节中,我们来展示如何使用我们上面的plugin来做一些有意义的事.在今天的例程中,我们想把在我们项目最终的snap包中打入如下的configure文件:

liuxg@liuxg:~/snappy/desktop/plugin/prime$ tree -L 3.├── bin│   └── config├── command-config.wrapper└── meta    ├── hooks    │   └── configure    └── snap.yaml

一旦我们在meta/hooks目录下生产这个configure(可执行文件)文件,其内容如下:

configure


#!/bin/shif ! username=$(snapctl get username); then    echo "Username is required"    exit 1fiif ! password=$(snapctl get password); then    echo "Password is required"    exit 1fi# Handle username and password, perhaps write to a credential file of some sort.echo "user=$username" > $SNAP_DATA/credentialsecho "password=$password" >> $SNAP_DATA/credentialschmod 600 $SNAP_DATA/credentials

一旦在我们的snap安装中有上面的configure文件,那么我们可以在我们的Ubuntu Core系统中,使用如下的命令:

$ sudo snap set plugin username=foo password=bar

来生产在$SNAP_DATA目录下的credentials文件.其内容如下:



由于一些原因,目前只能在Ubuntu Core的系统中进行测试(比如树莓派,dragon board, KVM等上进行测试).在Ubuntu Desktop的桌面环境中还是有一点问题.
基于这样的思路,我们重新改写我们的myplugin.py文件:

myplugin.py


# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-import loggingimport osimport globfrom pprint import pprintimport snapcraftlogger = logging.getLogger(__name__)def _dump(name, obj):    for attr in dir(obj):        # logger.warning("obj.%s = %s", attr, getattr(obj, attr))        func = getattr(obj, attr, None)        if func:            logger.warning("%s.%s = %s",name, attr, func)                logger.warning("===================================")class MyPlugin(snapcraft.BasePlugin):    @classmethod    def schema(cls):        schema = super().schema()        schema['properties']['myprop'] = {            'type': 'string',            'default': ''        }        # Inform Snapcraft of the properties associated with building. If these        # change in the YAML Snapcraft will consider the build step dirty.        schema['build-properties'].append('myprop')        return schema            def _copy(self, path_copyto):        path = os.path.join(path_copyto, "meta/hooks/")        logger.warning("path: %s", path);        os.makedirs(os.path.dirname(path), exist_ok=True)        source = self.builddir + "/" + self.options.myprop        logger.warning("source: %s", source)        destination = path + self.options.myprop        logger.warning("destination: %s", destination)        snapcraft.common.link_or_copy(source, destination, False)                    def __init__(self, name, options, project):        super().__init__(name, options, project)        logger.warning("__init__ begins name: %s", name)        logger.warning("options.source: %s", options.source)        logger.warning("options.myprop: %s", options.myprop)         logger.warning("self.builddir: %s", self.builddir)        logger.warning("self.installdir: %s", self.installdir)        # logger.warning("self.project.parallel_build_count: %d", self.project.parallel_build_count)        # logger.warning("self.project.arch_triplet: %s", self.project.arch_triplet)        # logger.warning("self.project.stage_dir: %s", self.project.stage_dir)               logger.warning("Going to add the needed build packages...")        # self.build_packages.append('golang-go')        #_dump("options", options)        #_dump("project", project)                logger.warning("build-packages:")        for pkg in options.build_packages:            logger.warning("build package: %s", pkg)    def build(self):        # setup build directory        super().build()        logger.warning("build begins ... ")                # copy congfigure file to parts/<part>/build/meta/hooks        self._copy(self.builddir)                # copy configure file to parts/<part>/install/meta/hooks        self._copy(self.installdir)           def pull(self):        super().pull()        logger.warning("pull begins ... ")                           def clean_pull(self):        super().clean_pull()               logger.warning("clean pull begins ... ")

在这里,我们把我们的configure文件考入到我们相应part的build及install目录里.这样我们的任务就完成了.我们主要修改的部分在"build(self)".同样地,我们也对我们的snapcraft.yaml做了如下的修改:

snapcraft.yaml


name: plugin # you probably want to 'snapcraft register <name>'version: '0.1' # just for humans, typically '1.2+git' or '1.3.2'summary: This is a sample plugin for snapcraft # 79 char long summarydescription: |  This is a plugin examplegrade: stable # must be 'stable' to release into candidate/stable channelsconfinement: strict # use 'strict' once you have the right plugs and slotsapps:  config:   command: bin/configparts:  my-part:    # This is a custom plugin defined in "parts" dir    plugin: myplugin    # This is the property defined in the plugin. It is a file name    # to be used for the congfigure hook    myprop: configure    source: .      config:    plugin: dump    source: ./bin    organize:      "*": bin/

在这里,我们加入了一个叫做config的app.它可以被用来展示我们的设置的结果:

config


#!/bin/bashecho "Reading config file at: $SNAP_DATA"config_file="$SNAP_DATA/credentials"if [ -f "$config_file" ]thencat $config_fileelseecho "$config_file not found."echo "Please run the following commmand to generate the file:"echo "sudo snap set plugin username=foo password=bar"fi

重新build我们的项目:



从上面可以看出来我们中间输出的一些调试的信息.当然我们可以做任何我们需要做的事情,比如根据build-packages的定义来分别安装对应的debian包等.

我们也可以来测试我们的应用:


事实上我们也可以直接使用由我们的snapcraft所提供的dump plugin来完成这个.有兴趣的开发者可以参阅我的文章"如何为我们的Ubuntu Core应用进行设置".我们从这个例子中展示如何创建一个我们自己的snapcraft的custom plugin.
所有的源码在:https://github.com/liu-xiao-guo/plugin

更多关于如何设计自己的custom plugin:
 - Snappy Ubuntu Core Clinic (youtube)
    -   Snappy Ubuntu Core Clinic (youku)


0 0
原创粉丝点击