用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
这将问你几个问题。
注意,这个文件夹应该命名为debian,即使是为Raspbian打包时也是如此--因此要保持命名为debian。
这将安装以下文件。
现在你需要按照dh-virtualenv-mold下的指示,运行以下命令。
sudo apt-get install build-essential debhelper devscripts equivssudo 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的空间。这可能可以通过一些参数来减少,但这一工作要留给读者。
祝你包装愉快