Empacotando projetos Python para Debian / Raspbian com dh-virtualenv
Este artigo visa explicar algumas coisas aos desenvolvedores que não usam muito Python, e podem ter dificuldades com alguns dos conceitos de outra forma.
Recomendo vivamente a palestra do artigo seguinte como uma introdução aos conceitos aqui discutidos:
pypi.org
pypi.org é um repositório oficial de software para a linguagem de programação Python. Ele inclui bibliotecas que queremos usar em nossos projetos, que não são distribuídas por padrão com o Python.
O problema
Nosso objetivo é empacotar uma aplicação escrita em Python (tendo como alvo o Python3) como um pacote .deb para o Raspbian (que é, tudo considerado, realmente equivalente ao Debian).
A nossa aplicação tem dependências em várias bibliotecas Python.
Por exemplo, gostaríamos de usar o solicitações biblioteca. A própria biblioteca de pedidos depende de outras bibliotecas, por exemplo, chardet, urllib3, etc.
A gestão manual destas dependências e o envio manual do código de biblioteca necessário é intrinsecamente impraticável.
pip
Python tem o seu próprio sistema de gestão de pacotes / dependências, chamado pip
pip permite-lhe instalar bibliotecas e aplicações python, para que o seu próprio código possa utilizar estas bibliotecas.
Aqui há dois problemas:
- queremos enviar o pacote como um pacote Debianpara que os utilizadores finais possam instalar facilmente. Podemos assumir com segurança que num número significativo de sistemas alvo as bibliotecas python apropriadas não terão sido instaladas pelo utilizador.
- se tentarmos instalar estas bibliotecas em todo o sistema em nome do utilizadorpodemos quebrar a compatibilidade com alguns outros pacotes (por exemplo, devido a alterações de API entre as versões das bibliotecas).
Portanto, precisamos de uma solução.
virtualenv
virtualenv vai permitir-nos criar ambientes virtuais para Python.
Nesses ambientes virtuais que temos:
- o nosso próprio intérprete Python
- cópias das bibliotecas padrão necessárias
- nosso próprio canal
- a nossa própria biblioteca "de todo o sistema
Parte prática: Experimentar o virtualenv
Instalar virtualenv (como parte do dh-virtualenv, o que vamos fazer dentro de pouco tempo) fazendo:
sudo apt install dh-virtualenv
Como os pedidos já estão instalados em todo o sistema na minha caixa de teste, vamos usar um pacote diferente como exemplo. randstr permitirá que você gere uma cadeia aleatória.
Verifique se randstr está instalado em todo o sistema:
pip3 mostrar randstr
Isto não deve devolver nada. Indicando que este pacote não está instalado em todo o sistema:
Agora vamos criar um ambiente virtual. A pasta de ambiente virtual NÃO tem que viver dentro da sua pasta de código, mas pode. Você deve ignorá-la no GIT.
digamos que temos um diretório /home/pi/tutorial
Mude para este diretório, e crie uma nova pasta ambiente env:
cd /home/pi/tutorial
que python3
virtualenv -p /usr/bin/python3 env
Nota: você deve especificar o intérprete Python se você quiser Python 3, caso contrário Python 2 será usado. Eu estou usando Python 3. (Executando virtualenv com intérprete /usr/bin/python2)
que python3 lhe dirá onde reside o binário python3, ajuste o caminho para o virtualenv em conformidade.
activar o ambiente:
fonte env/bin/activar
(Este caminho de comando assume que você permaneceu no diretório do tutorial). Note também, que este não é um script executável - você tem que usar o fonte para o usar com o seu terminal de bash.
Repare, como (env) é preparado antes do seu prompt de comando:
Isto significa que o ambiente está ativo. Agora você pode executar pip3 novamente, mas desta vez pip3 vai executar o seu trabalho no ambiente virtual:
pip3 mostrar randstr
pip3 mostrar pedidos
ainda não deve render nada. A segunda linha também não mostrará nada - mostrando que (se os pedidos forem instalados em todo o sistema) estamos de fato em um ambiente virtual.
Agora instale o randstr:
pip3 instalar randstr
e verificar novamente, se está instalado:
pip3 mostrar randstr
Desta vez mostra que o randstr está instalado. Ele foi instalado em env/lib/python3.5/site-packages:
Enquanto o ambiente ainda está ativado, vamos escrever uma pequena aplicação de amostra Python:
nano amostra.py
cole o seguinte código, gerando uma string aleatória usando a nova biblioteca que acabamos de instalar:
de randstr importação randstr
print("olá mundo")
print(randstr())
e salvar.
Execute o código usando o python3:
python3 amostra.py
enquanto o ambiente ainda estiver activo, isto vai funcionar:
Agora é hora de sair do ambiente, para ver se o código ainda vai funcionar:
desativar
O seu pedido voltará ao normal. E
python3 amostra.py
irá lançar uma mensagem de erro, sobre nenhum módulo 'randstr' existente no seu sistema. Este é exactamente o comportamento que nós queremos!
Você pode dar uma olhada na pasta env, vendo como ela envia todas as coisas necessárias para executar seu código Python, incluindo bibliotecas, o executável python, pip, e muito mais.
Empacotamento Debian virtualenv com dh-virtualenv
OK, agora com o básico fora do caminho, o que queremos é empacotar um virtualenv junto com o nosso código, para que a nossa aplicação seja executada de forma confiável e sem perturbar outras aplicações nos computadores dos nossos usuários.
Aqui é onde dh-virtualenv entra na imagem. dh-virtualenv é uma adição aos scripts de construção Debian, que lhe permite empacotar ambientes virtuais.
Precisamos de criar uma estrutura básica para o nosso novo pacote. Aqui é onde cookiecutter vai ajudar.
cookiecutter
O cookiecutter cria novos projetos para você a partir de modelos, reduzindo assim as despesas gerais e o tempo que você gasta com o desenvolvimento e a organização dos muitos arquivos que são necessários.
https://cookiecutter.readthedocs.io/en/latest/
sudo apt instalar o cookiecutter
Nota: o pacote python3-cookiecutter irá fornecer um módulo Python para o Python 3. O que queremos é a aplicação em si, que é instalada com o pacote cookiecutter, como visto acima. Isto pode puxar no Python 2, mas - oh bem.
O cookiecutter não é necessário para seus usuários finais, ele é usado apenas para criar vários arquivos para seu pacote.
criar um exemplo de diretório de projetos, no qual aplicaremos o modelo (eu ainda estou no diretório tutorial):
projeto de amostra mkdir
cd sampleproject
Usando um molde especial para dh-virtualenv podemos montar muitos dos arquivos necessários:
https://github.com/Springerle/dh-virtualenv-mold
cookiecutter https://github.com/Springerle/dh-virtualenv-mold.git
Isto vai fazer-lhe várias perguntas.
Note que a pasta deve ser nomeada debian, mesmo quando embalada para Raspbian - portanto mantenha o nome como debian.
Isto irá instalar os seguintes ficheiros:
Agora você precisa executar os seguintes comandos, de acordo com as instruções sob o molde dh-virtualenv:
sudo apt-get install build-essential debhelper devscripts equivssudo mk-build-deps --install debian/control
Para construir o pacote mais tarde, você executará o comando follwoing a partir do diretório de nível superior do seu projeto:
dpkg-buildpackage -uc -us -b
Neste momento, porém, o comando falhará porque o setup.py está faltando. Vamos chegar a setup.py e requirements.txt dentro de pouco tempo:
/usr/bin/python3: não consegue abrir o ficheiro 'setup.py': [Errno 2] Não há tal arquivo ou diretório
Informações sobre os arquivos individuais
changelog
Este arquivo conterá o seu lançamento e informações da versão para o pacote. Você pode atualizá-lo usando uma ferramenta especial, dch.
Este arquivo não é um changelog para a sua aplicação, mas apenas um changelog para a embalagem da sua aplicação.
compatriota
Este arquivo inclui um número mágico especial "9". (para questões de compatibilidade, não há problema em deixá-lo como está)
controle
Este é o arquivo principal para definir as configurações dos pacotes, e as dependências em um nível Debian. Se a sua aplicação depende, por exemplo, do omxplayer a ser instalado, ela precisará entrar aqui como uma dependência:
Fonte: projecto de amostra
Secção: contrib/python
Prioridade: extra
Mantenedor: Maximilian Batz
Build-Depends: debhelper (>= 9), python, python-dev, dh-virtualenv (>= 0.10), tar
Padrão-Versão: 3.9.5
Página inicial: https://picockpit.com
Pacote: projecto de amostra
Arquitetura: qualquer
Pré-Depende: dpkg (>= 1.16.1), python2.7 | python3, ${misc:Pré-Depende}
Depende: ${python:Depends}, ${misc:Depends}
Descrição: Um pacote de exemplo para demonstrar o empacotamento Debian virtualenv com o dh-virtualenv
.
Esta é uma distribuição de "projecto de amostra" como um projecto auto-contido
Python virtualenv embrulhado em um pacote Debian (pacote "omnibus"),
todos os passageiros a bordo). O virtualenv empacotado é mantido em sincronia com
o intérprete do anfitrião automaticamente.
.
Ver https://github.com/spotify/dh-virtualenv para mais detalhes.
Você também vai querer editar a longa Descrição.
cookiecutter.json
Inclui as suas configurações iniciais. Não é necessário para embalagem.
direitos autorais
Seu arquivo de direitos autorais, com sua licença (por exemplo, MIT). É pré-preenchido com o seu nome, ano, e-Mail e "alguns direitos reservados".
regras
Isto é um Makefile, para realmente construir o seu pacote. Ele é pré-preenchido pelo modelo do coolkiecutter.
exemploprojeto.links
Este arquivo permite que você crie links durante a instalação . O nome do arquivo incluirá o nome do seu projeto ao invés de projecto de amostra.
Ref: https://stackoverflow.com/questions/9965717/debian-rules-file-make-a-symlink
exemplo de projeto.postinst
Este arquivo permite que você execute passos adicionais de configuração após a instalação (por exemplo, ativando seu script python como um serviço). O nome do arquivo incluirá o nome do seu projeto ao invés de projecto de amostra.
gatilhos.de.amostra
Tanto quanto sei, isto é para a dh-virtualenv instalar um novo intérprete python no ambiente virtual para enviar, se o sistema (sua caixa de desenvolvimento) for atualizado. O nome do arquivo incluirá o nome do seu projeto ao invés de projecto de amostra.
Este pode ou não ser o caso, eu não o testei.
setup.py
Como mencionado acima, nós precisamos de um setup.py arquivo. Esta é a forma padrão de empacotamento das aplicações em Python (elas são enviadas com um arquivo setup.py, que é executado para várias tarefas relacionadas ao empacotamento).
Um simples setup.py pode ser visto nesta página:
https://github.com/benjaminirving/python-debian-packaging-example/blob/master/setup.py
Nem todas as entradas nestes arquivos são necessárias. Por exemplo, você pode deixar de fora os classificadores. Eu tenho o seguinte setup.py:
Nota: o número da versão e outras informações aqui dentro são para o seu pacote Python (que será criado durante a construção de um pacote Debian com o seu virtualenv).
Estrutura para o seu código
O seu código irá agora viver num subdirectório do directório principal do projecto de amostra:
Neste caso, o subdiretório tem o mesmo nome do diretório principal.
Note o __init__.py
A sample.py é a que usamos acima, mas um pouco retrabalhada para ficar assim:
Além disso, configurei um ambiente virtual para testes enquanto desenvolvia dentro do diretório principal (nível superior) do projeto de amostra:
virtualenv -p /usr/bin/python3 sp_env
chamado sp_env para ambiente de projeto modelo
A entrar no ambiente:
fonte sp_env/bin/activate
Instale a biblioteca randstr neste ambiente:
pip3 instalar randstr
e agora podemos executar o código:
python3 amostraprojeto/amostra.py
ESTÁ BEM. Sair do ambiente (! importante!)e tentar construir o pacote novamente:
desativar
dpkg-buildpackage -us -uc
Por padrão (por causa do cortador de cookies), seu pacote será criado para instalação em /opt/venvs/:
Novo python executável em /home/pi/tutorial/sampleproject/debian/sampleproject/opt/venvs/sampleproject/bin/python3
Isto pode ser alterado no debian/regras arquivo.
Agora o pacote foi construído, e depositado fora do diretório de topo do projeto de exemplo (dentro do diretório tutorial):
Você pode instalar o arquivo .deb usando o dpkg:
sudo dpkg -i sampleproject_0.2.1+nmu1_armhf.deb
Veja os resultados da instalação com
árvore /opt/venvs
127 diretórios e 945 arquivos foram instalados.
Agora você pode tentar executar o projeto de amostra usando
/opt/venvs/sampleproject/bin/sampleproject
requisitos / dependências
A aplicação não será executada como (talvez) esperado, mas atira um erro sobre o randstr não estar presente. O que dá?
A razão é que a dh-virtualenv não sabe sobre os requisitos que temos, para empacotar o pacote randstr durante o processo de construção. Esta é a peça final do puzzle.
Os requisitos precisam de ser acrescentados ao setup.pycomo uma forma de informar ao pip quais pacotes adicionais precisam ser instalados no ambiente virtual que está sendo criado.
adicione o seguinte ao setup.py:
install_requires=[
'randstr'
]
O arquivo inteiro então vai ficar assim:
Nos meus testes os requisitos.txt colocados ao nível superior fizeram não influenciam o comportamento do dh-virtualenv e dos pacotes Python realmente incluídos no pacote Debian. Se você ainda o quer, veja como:
pip oferece-lhe uma forma de colocar para fora as dependências exatas que você usou para se desenvolver no ambiente virtual. Entre no ambiente virtual:
fonte sp_env/bin/activate
E crie o arquivo requirements.txt:
pip3 freeze > requirements.txt
Agora você pode dar uma olhada nesse arquivo:
cat requirements.txt
Mesmo que este arquivo pareça não ser utilizado pelo dh-virtualenv (talvez ele precise ir em um subdiretório diferente), ele é uma boa referência para você mesmo, para ver quais pacotes você deve colocar como dependências na parte install_requires do setup.py.
Note que o arquivo sampleproject.links nos ofereceu uma maneira conveniente de vincular isso na pasta /usr/bin, portanto removerei o sinal de comentário para a próxima compilação:
Com isso fora do caminho, é hora de purgar o projeto de amostra, e construí-lo novamente, e depois instalá-lo. Não se esqueça de desativar primeiro!
desativar
sudo apt purge sampleproject
dpkg-buildpackage -us -uc
cd ...
sudo dpkg -i sampleproject_0.2.1+nmu1_armhf.deb
Desta vez, o pacote deve estar acessível utilizando o projecto de amostra:
que projecto de amostra
projecto de amostra
Ref: https://packaging.python.org/discussions/install-requires-vs-requirements/
Dica de bónus: mudar o local de instalação
O /opt/venvs não é um "lugar" muito Debian para se colocar um pacote.
As especificações estão aqui:
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 é não para embalagens
- /opt não é para pacotes Debian propriamente ditos (é para software de terceiros instalado pelo usuário)
http://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch04s06.html
Os aplicativos podem usar um único subdiretório em /usr/lib
. Se uma aplicação utiliza um subdiretório, todos os dados dependentes de arquitetura utilizados exclusivamente pela aplicação devem ser colocados dentro desse subdiretório.
https://wiki.debian.org/HowToPackageForDebian
https://www.debian.org/doc/debian-policy/ch-opersys.html#file-system-hierarchy
"O requisito FHS de que os arquivos estáticos independentes da arquitetura de aplicação específica estejam localizados em /usr/acção
é relaxado a uma sugestão. Em particular, um subdiretório de /usr/lib
pode ser usado por um pacote (ou uma coleção de pacotes) para manter uma mistura de arquivos independentes e dependentes da arquitetura. Entretanto, quando um diretório é inteiramente composto de arquivos independentes de arquitetura, ele deve estar localizado em /usr/acção
.”
A melhor localização para mim parece ser /usr/share
Precisamos de editar dois ficheiros:
em debian/rules DH_VIRTUALENV_INSTALL_ROOT deve ser alterado para /usr/share, desta forma:
e debian/sampleproject.links devem ser alterados:
Além disso, vamos fazer uma nova entrada no changelog:
dch -i
basta editar o texto, para refletir um novo número de versão, e uma entrada para o changelog.
Então o projeto pode ser construído novamente:
dpkg-buildpackage -us -uc
Após a instalação, você pode verificar se de fato o novo local é utilizado:
O pacote irá ocupar cerca de 16 MB no seu sistema alvo, graças ao ambiente virtual e a tudo o que é enviado com ele. Isso provavelmente poderia ser reduzido por alguns parâmetros, mas esse exercício é deixado para o leitor.
Divirta-se com a embalagem!