用dh-virtualenv为Debian / Raspbian打包Python项目

这篇文章旨在向不经常使用Python的开发者解释一些东西,否则他们可能会对一些概念感到挣扎。

我强烈建议将以下文章的讲座作为这里讨论的概念的介绍。

pypi.org

pypi.org 是一个Python编程语言的官方软件库。它包括我们想在我们的项目中使用的库,这些库在默认情况下不随Python运送。

问题所在

我们的目标是将一个用Python编写的应用程序(以Python3为目标)打包成Raspbian的.deb包(从各方面考虑,它实际上等同于Debian)。

我们的应用程序对几个Python库有依赖性。

例如,我们想用 要求 库。请求库本身依赖于其他库,例如chardet、urllib3等。

手动管理这些依赖关系和手动发送所需的库代码本身就是不现实的。

琵琶

Python有它自己的软件包/依赖性管理系统,叫做 琵琶

pip允许你安装python库和应用程序,以便你自己的代码可以使用这些库。

这里有两个问题。

  • 我们希望将包裹作为一个 蝶变软件包终端用户可以轻松安装。我们可以有把握地假设,在相当多的目标系统上,适当的python库不会被用户安装。
  • 如果我们尝试安装这些库 代表用户的全系统,我们可能会破坏与其他一些软件包的兼容性(例如,由于库的版本之间的API变化)。

因此,我们需要一个解决方案。

虚拟环境

virtualenv将允许我们为Python创建虚拟环境。

在这些虚拟环境中,我们有。

  • 我们自己的Python解释器
  • 所需标准库的副本
  • 我们自己的管道
  • 我们自己的 "全系统 "图书馆

实用部分。试用virtualenv

安装virtualenv(作为dh-virtualenv的一部分,我们过一会儿会讲到),方法是:。

sudo apt install dh-virtualenv

由于request已经在我的测试盒上全系统安装,我们将使用一个不同的软件包作为例子。 润达 将允许你生成一个随机字符串。

检查是否 润达 是在全系统范围内安装的。

pip3 show randstr

这应该不会返回什么。表明这个软件包没有在系统中安装。

形象

现在我们将创建一个虚拟环境。虚拟环境文件夹不一定要在你的代码文件夹里,但它可以。你应该在GIT中忽略它。

假设我们有一个目录/home/pi/tutorial

换到这个目录,并创建一个新的环境文件夹env。

cd /home/pi/tutorial

其中Python3

virtualenv -p /usr/bin/python3 env

注意:如果你想要Python 3,你应该指定Python解释器,否则将使用Python 2。我正在使用Python 3。(运行virtualenv,解释器为/usr/bin/python2)

其中python3会告诉你python3二进制文件的位置,相应地调整virtualenv的路径。

形象

激活环境。

source env/bin/activate

(这个命令路径假定你停留在教程目录中)。还请注意,这不是一个可执行的脚本 - 你必须使用 来源 来在你的bash终端使用它。

注意,(env)是如何在你的命令提示符前预留的。

形象

这意味着环境是活动的。现在你可以再次运行pip3,但这一次pip3将在虚拟环境中执行它的工作。

pip3 show randstr

pip3显示请求

应该仍然没有结果。第二行也将什么也不显示--显示(如果请求在全系统安装)我们确实在一个虚拟环境中。

现在安装randstr。

pip3安装randstr

并再次检查,如果它已经安装。

pip3 show randstr

形象

这次它显示randstr已经安装。它已经被安装在env/lib/python3.5/Site-packages中。

形象

当环境仍然被激活时,让我们写一个小的Python示例程序。

nano sample.py

粘贴以下代码,使用我们刚刚安装的新库生成一个随机字符串。

从randstr导入randstr
print("hello world")
print(randstr())

并保存。

使用python3运行代码。

python3 sample.py

当环境仍然处于活动状态时,这将会起作用。

形象

现在是时候退出环境了,看看代码是否还能运行。

停用

你的提示将恢复正常。还有

python3 sample.py

将抛出一个错误信息,说你的系统中没有'randstr'模块。这正是我们想要的行为。

形象

你可以看看env文件夹,看看它是如何运送所有运行Python代码所需的东西的,包括库、python可执行文件、pip等等。

用dh-virtualenv打包Debian virtualenv

好了,现在基本的东西都出来了,我们要做的是在我们的代码旁边打包一个virtualenv,这样我们的应用程序就能可靠地运行,并且不干扰用户计算机上的其他应用程序。

这是在 dh-virtualenv dh-virtualenv是对Debian构建脚本的一个补充,它允许你对虚拟环境进行打包。

我们需要为我们的新包创建一个基本的包结构。这就是 煮食者 会有帮助。

煮食者

cookiecutter根据模板为你创建新的项目,从而减少了你在开发上花费的开销和时间,并使你对所需的许多文件有了概念。

https://cookiecutter.readthedocs.io/en/latest/

sudo apt install cookiecutter

注意:软件包 python3-cookiecutter 将为 Python 3 提供一个 Python 模块。我们想要的是应用程序本身,如上所示,它与 cookiecutter 包一起安装。这可能会拉到Python 2,但是--哦,好吧。

cookiecutter对你的终端用户来说是不必要的,它只是用来为你的软件包创建几个文件。

创建一个示例项目目录,我们将在其中应用模板(我仍在教程目录中)。

mkdir sampleproject

cd sampleproject

使用dh-virtualenv的特殊模具,我们可以设置许多必要的文件。

https://github.com/Springerle/dh-virtualenv-mold

煮食者 https://github.com/Springerle/dh-virtualenv-mold.git

这将问你几个问题。

形象

注意,这个文件夹应该命名为debian,即使是为Raspbian打包时也是如此--因此要保持命名为debian。

这将安装以下文件。

形象

现在你需要按照dh-virtualenv-mold下的指示,运行以下命令。

sudo apt-get install build-essential debhelper devscripts equivs
sudo mk-build-deps --install debian/control
为了以后构建软件包,你将从你的项目的顶层目录运行以下命令。
dpkg-buildpackage -uc -us -b
不过现在,这个命令会失败,因为缺少setup.py。我们将在稍后得到setup.py和requirements.txt。
/usr/bin/python3: 不能打开文件'setup.py'。[Errno 2] 没有这样的文件或目录

有关单个文件的信息

更新日志

这个文件将包含你的软件包的发布和版本信息。你可以用一个特殊的工具来更新它。 dch.

这个文件不是你的应用程序的变更记录,而只是你的应用程序的包装的变更记录。

兼容性

这个文件包括一个特殊的神奇数字 "9"。(为了兼容性问题,保持原样就可以了)

控制

这是在 Debian 层面上设置软件包设置和依赖关系的主要文件。如果你的应用程序依赖于,例如,正在安装的omxplayer,它将需要在这里作为一个依赖项。

资料来源:Sampleproject
Section: contrib/python
优先级:额外
维护者。Maximilian Batz
Build-Depends: debhelper (>= 9), python, python-dev, dh-virtualenv (>= 0.10), tar
标准-版本:3.9.5
主页。
https://picockpit.com


软件包: sampleproject
结构:任何
预先依赖: dpkg (>= 1.16.1), python2.7 | python3, ${misc:预先依赖}.
需要依赖。${python:依赖}, ${misc:依赖}.
描述。一个演示virtualenv的例子包,Debian用dh-virtualenv打包
     .
     这是将 "sampleproject "作为一个自成一体的项目分发出去。
     Python virtualenv被包装成一个Debian软件包("omnibus "软件包。
     所有乘客都在船上)。打包后的virtualenv与以下内容保持同步
     宿主的解释器自动。
     .
     见
https://github.com/spotify/dh-virtualenv 了解更多细节。

你还将想要编辑长篇描述。

cookiecutter.json

包括你的初始设置。不需要包装。

版权

你的版权文件,包括你的许可证(如MIT)。它预先填上了你的名字、年份、电子邮件和 "保留部分权利"。

规则

这是一个Makefile文件,用来实际构建你的软件包。它是由cookiecutter模板预先填充的。

示例项目.链接

这个文件允许你在安装过程中创建链接。文件名将包括你的项目名称而不是 项目样本.

参考文献。 https://stackoverflow.com/questions/9965717/debian-rules-file-make-a-symlink

样本项目.postinst

这个文件允许你在安装后运行额外的设置步骤(例如,将你的Python脚本作为一个服务激活)。文件名将包括你的项目名称而不是 项目样本.

样本项目.触发器

据我所知,这是为了让dh-virtualenv在系统(你的开发盒)更新时,在虚拟环境中安装一个更新的Python解释器,以便发货。文件名将包括你的项目名称而不是 项目样本.

这可能是也可能不是,我没有测试过。

setup.py

如上所述,我们需要一个 setup.py 文件。这是Python下应用程序打包的标准方式(它们在发货时有一个setup.py,它被用来执行与打包有关的各种任务)。

在这个页面上可以看到一个简单的setup.py。

https://github.com/benjaminirving/python-debian-packaging-example/blob/master/setup.py

在这个文件中,并非所有的条目都是必要的。例如,你可以不写分类器。我有以下的setup.py。

形象

注意:这里的版本号和其他信息是针对你的 Python 软件包的 (它将在用你的 virtualenv 构建 Debian 软件包的过程中创建)。

你的代码的结构

你的代码现在将住在sampleproject主目录的一个子目录中。

形象

在这种情况下,子目录的名称与主目录相同。

注意 __init__.py

sample.py是我们上面使用的那个,但经过了一些修改,看起来像这样。

形象

此外,我在主(顶层)sampleproject目录下建立了一个虚拟环境,用于测试,同时开发。

virtualenv -p /usr/bin/python3 sp_env

称为sp_env,表示样本项目环境

进入环境。

source sp_env/bin/activate

将randstr库安装到这个环境中。

pip3安装randstr

而现在我们可以运行代码了。

python3 sampleproject/sample.py

形象

好的。退出环境 (!重要!),并尝试再次构建该软件包。

停用

dpkg-buildpackage -us -uc

默认情况下(因为有了cookie cutter),你的包将被创建在/opt/venvs/中进行安装。

在/home/pi/tutorial/sampleproject/debian/sampleproject/opt/venvs/sampleproject/bin/python3中新增python可执行文件

这可以在 debian/rules 文件。

现在,软件包已经建立,并存放在sampleproject顶层目录之外(tutorial目录内)。

形象

你可以用dpkg安装.deb文件。

sudo dpkg -i sampleproject_0.2.1+nmu1_armhf.deb

请看安装结果与

tree /opt/venvs

安装了127个目录和945个文件。

现在你可以尝试用以下方法来执行样本项目

/opt/venvs/sampleproject/bin/sampleproject

要求/依赖性

应用程序不会像(也许)预期的那样运行,而是抛出一个关于randstr不存在的错误。这是什么原因?

形象

原因是dh-virtualenv不知道我们有一个要求,即在构建过程中捆绑软件包randstr。这是难题的最后一块。

这些要求需要添加到 setup.py作为一种让pip知道在正在创建的虚拟环境中需要安装哪些额外的软件包的方式。

在setup.py中添加以下内容。

install_requires=[

        'randstr

]

然后整个文件将看起来像这样。

形象

在我的测试中,放置在顶层的requirements.txt做到了 不是 影响 dh-virtualenv 和实际包含在 Debian 包中的 Python 包的行为。如果你还想要,这里有办法。

pip为你提供了一种方法,可以在虚拟环境中放出你用于开发的确切的依赖关系。进入虚拟环境。

source sp_env/bin/activate

并创建requirements.txt文件。

pip3 freeze > requirements.txt

现在你可以看一下那个文件了。

cat requirements.txt

形象

尽管这个文件似乎没有被dh-virtualenv使用(也许它需要放在一个不同的子目录中),但它对你来说是一个很好的参考,可以看到你应该把哪些软件包作为依赖项放入setup.py的install_requires部分。

注意,文件sampleproject.links为我们提供了一种方便的方式,将其链接到/usr/bin文件夹中,因此我将在下次构建时删除注释符号。

形象

解决了这个问题,现在是时候清除sampleproject,并再次构建它,然后安装它。不要忘了先停用!

停用

sudo apt purge sampleproject

dpkg-buildpackage -us -uc

cd ...

sudo dpkg -i sampleproject_0.2.1+nmu1_armhf.deb

这一次,这个包应该可以用sampleproject访问。

哪一个样本项目

项目样本

形象

参考文献。 https://packaging.python.org/discussions/install-requires-vs-requirements/

额外提示:改变安装位置

/opt/venvs并不是一个可以放置软件包的Debian "地方"。

规格在这里。

http://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html

https://unix.stackexchange.com/questions/10127/why-did-my-package-get-installed-to-opt

  • /usr/local是 不是 用于包裹
  • /opt不是用来存放Debian软件包的(它是用来存放用户安装的第三方软件的)。

http://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch04s06.html

应用程序可以使用一个在 /usr/lib.如果一个应用程序使用一个子目录,所有应用程序专门使用的架构相关数据必须放在该子目录中。

https://wiki.debian.org/HowToPackageForDebian

https://www.debian.org/doc/debian-policy/ch-opersys.html#file-system-hierarchy

"FHS要求独立于架构的特定应用静态文件位于 /usr/share 被放宽到一个建议。特别是: 的一个子目录 /usr/lib 可以被一个包使用 (或一个包的集合),以容纳与架构无关的和与架构有关的混合文件。 然而,当一个目录完全由与架构无关的文件组成时,它应该位于 /usr/share."

对我来说,最好的位置似乎是/usr/share

我们需要编辑两个文件。

在debian/rules中DH_VIRTUALENV_INSTALL_ROOT必须改成/usr/share,像这样。

形象

和debian/sampleproject.links必须被修改。

形象

另外,我们将在更新日志中加入一个新条目。

dch -i

形象

简单地编辑文本,以反映一个新的版本号,和一个更新日志的条目。

然后,该项目可以再次建立。

dpkg-buildpackage -us -uc

安装后,你可以验证是否确实使用了新的位置。

形象

由于虚拟环境和与之配套的一切,该软件包将在你的目标系统上占用大约16MB的空间。这可能可以通过一些参数来减少,但这一工作要留给读者。

祝你包装愉快