Empacotando com Git

pbuilder software stack

Esta página descreve como criar pacotes debian usando o sistema de controle de versão git. Para obter informações gerais sobre o sistema de controle de versão, consulte git. Para obter informações gerais sobre a criação de pacotes, consulte Packaging.

A imagem em anexo mostra o modelo de empacotamento conforme descrito por esta página. Você pode preferir maneiras diferentes.

{i} A suíte de empacotamento git mais comum é "git-buildpackage". O comando mais comum nessa suíte é gbp buildpackage.

Configure o git-buildpackage

git-buildpackage é o conjunto mais popular de ferramentas para criar pacotes Debian, mas sua configuração padrão deve ser modificada antes do uso. Edite seu arquivo ~/.gbp.conf para conter pelo menos o seguinte:

[DEFAULT]

# Manage a "pristine-tar" branch:
pristine-tar = True
pristine-tar-commit = True

# Use Debian-style branch names:
upstream-branch=upstream/latest
debian-branch=debian/latest

# Build packages with pbuilder:
pbuilder = True
# Or use sbuild:
#builder = sbuild

# Sign tags (optional):
#sign-tags = True
#keyid = <fingerprint>

pristine-tar e pristine-tar-commit

Se você precisa importar um projeto de um tarball upstream, um dia você pode ser solicitado(a) a provar que um commit vincula-se a um tarball com uma checksum específica. Essas opções acompanham, por exemplo, a ordem em que os arquivos apareceram no tarball (veja pristine-tar, --git-pristine-tar e --git-pristine-tar-commit).

pbuilder e builder

Os pacotes devem ser construídos em um ambiente chroot limpo para que sua configuração local não contamine o pacote. pbuilder=True usa a pilha pbuilder, e é uma boa escolha padrão. Ou builder=sbuild usa sbuild, o que proporciona mais flexibilidade para casos de uso complexos. Sua pilha precisará ser configurada antes de ser usada - consulte a página relevante para obter detalhes.

sign-tags e keyid

Se você quiser assinar com PGP suas tags git, defina sign-tags=True e defina keyid da fingerprint da chave marcada [SC] na saída de gpg --list-secret-key. Isso anexará uma assinatura PGP quando você executar gbp buildpackage --git-tag, provando que você foi a única pessoa que criou essa tag.

/etc/git-buildpackage/gbp.conf lista muitas outras opções úteis - pode ser uma boa voltar e revisá-lo uma vez que esteja confortável com o seu fluxo de trabalho. Para detalhes, consulte as páginas de manual para cada comando.

{i} git-buildpackage tem vários arquivos de configuração. ~/.gbp.conf é usado para as configurações que se aplicam a todos os seus projetos. Para uma configuração específica de fork ou de projeto, use debian/gbp.conf ou .git/gbp.conf do seu projeto.

Etapa da importação

A etapa de importação envolve a criação de um repositório git com base no que for fornecido pelo upstream e, opcionalmente, a descrição de como obter as atualizações. Isso geralmente significa procurar/baixar tarballs de um servidor FTP, clonar/atualizar as alterações de um forge ou ramificar/combinar commits em seu próprio repositório.

Importar a partir de tarballs

A maneira tradicional de obter o código upstream é importar seu último lançamento em tarball:

git init --initial-branch="$(gbp config DEFAULT.debian-branch)" some-project.git
cd some-project.git
gbp import-orig https://some-project.example.com/releases/some-project_1.0.tar.gz

Isso baixará (pull) o tarball para os branches upstream e debian que você especificou em seu ~/.gbp.conf; crie uma nova tag upstream/1.0 e atualize o ramo pristine-tar (se você definir essa opção).

Você também deve criar um arquivo debian/watch para dizer ao git-buildpackage como baixar novos tarballs. Para mais detalhes, consulte debian/watch.

git import-orig descarta qualquer diretório de nível superior debian/ do seu tarball. No caso improvável de que isso seja um problema, consulte ManageUpstreamDifferences.

Depois de criar seus arquivos debian/watch e debian/changelog, você pode obter novas versões do tarball com gbp import-orig --uscan. Ou, se você não pode criar um arquivo debian/watch, terá que baixar um novo tarball e executar gbp import-orig <tarball> toda vez.

{i} você pode adicionar um alias do git para o seu comando de importação. Por exemplo git config --local alias.get '!gbp import-orig --uscan' faz git get funcionar neste repositório

Importar a partir de um repositório git upstream

Se o upstream não fornece tarballs, mas coloca o código-fonte em uma forge git com tags de lançamentos que têm um padrão útil (como vMAJOR.MINOR.PATCH ou release-MAJOR.MINOR), adapte o código seguinte de acordo com o que precisa:

# Clone the upstream repository and `cd` into it:
git clone https://forge.example.com/some-project.git
cd project.git

# Use DEP-14 branch names, but don't bother with an upstream branch:
git branch -m debian/latest

# Describe what upstream tags look like (see below for details):
mkdir -p debian
cat >> debian/gbp.conf <<EOF
[DEFAULT]
upstream-tag=v%(version)s

# No tarballs to track (upstream uses git):
pristine-tar = False
pristine-tar-commit = False
EOF
git add debian/gbp.conf

Por padrão, git-buildpackage assume que as tags upstream têm o formato upstream/%(version)s. Configure upstream-tag em debian/gbp.conf se o upstream usa um formato diferente. Para detalhes, consulte o manual.

Desativar pristine-tar e pristine-tar-commit evita criar um branch extra redundante e torna a configuração do projeto mais clara para qualquer pessoa que revise seu trabalho.

Se o upstream não criar tags de lançamento úteis, considere pedir que sejam criadas. Se não estiverem dispostos(as) a criar tags, mas a fornecer tarballs de lançamentos, você terá que importar a partir de tarballs - Git e Debian têm excelentes alternativas para git pull, mas não podem replicar a informação em um tarball de lançamento.

Se o upstream contiver um diretório /debian de nível superior, você precisará excluí-lo do branch upstream. Para detalhes, consulte ManageUpstreamDifferences.

Para obter novas versões de um repositório git upstream, basta fazer um git pull normal do branch upstream/latest.

Importar a partir tanto do tarballs quanto do git

Se o upstream fornecer tarballs e um repositório git, você pode importar de ambos e compará-los:

# Import the tarball first:
git init --initial-branch="$(gbp config DEFAULT.debian-branch)" some-project.git
cd some-project.git
gbp import-orig https://some-project.example.com/releases/some-project_1.0.tar.gz

# Then import the git repo:
git remote add origin https://forge.example.com/some-project.git
git fetch

# Compare the tarball and the repo (remember to use the right tags):
git diff upstream/1.0 v1.0

Se git diff mostrar que uma fonte ou outra está definitivamente correta, exclua some-project.git e comece de novo com o conjunto apropriado de instruções. Ou, se você precisar rastrear ambos, configure o debian/watch e o debian/changelog, e pegue as novas versões com algo como gbp import-orig --uscan && git fetch.

Se não há upstream

Alguns projetos não têm um upstream. Por exemplo, projetos específicos do Debian geralmente têm um único repositório com código upstream em um branch e o empacotamento Debian em outro branch.

Se possível, defina o nome do branch de desenvolvimento principal como upstream/latest:

# Set branch name when creating the repo:
git init --initial-branch="$(gbp config DEFAULT.upstream-branch)" project.git
# Or rename the branch when you start to Debianise:
git branch -m master "$(gbp config DEFAULT.upstream-branch)"

O resto desta página assume que seu projeto está pronto para empacotar, então você pode parar aqui e voltar quando terminar sua primeira versão.

Depois de terminar sua primeira versão, confira o novo branch para mudanças específicas do Debian:

git checkout -b "$(gbp config DEFAULT.debian-branch)" \
        --track "$(gbp config DEFAULT.upstream-branch)"

Projetos sem um repositório upstream geralmente podem escolher seu próprio padrão de tags e ignorar os tarballs upstream. Considere fazer:

mkdir -p debian
cat >> debian/gbp.conf <<EOF
[DEFAULT]
upstream-tag=v%(version)s

# No tarballs to track (no upstream repo):
pristine-tar = False
pristine-tar-commit = False
EOF
git add debian/gbp.conf

Como debian/latest rastreia upstream/latest, você pode obter as alterações upstream com git pull assim como faria com um repositório remoto.

{i} Pacotes específicos do Debian que nunca terão um repositório upstream podem usar o sistema de patch native em vez do modelo padrão quilt - ver Projects/DebSrc3.0.

Etapa do patch

A etapa patch (correções, alterações) envolve a criação de arquivos no seu diretório debian/ e, opcionalmente, a alteração de outros diretórios conforme exigidos pelo Debian. Por exemplo, o Debian requer que os programas tenham uma página man, que você deve criar se estiver faltando no upstream.

{i} Esta seção é um guia neutra com relação às formas de alterar um projeto. Prefira guias específicos a linguagens onde estiver disponível.

Crie o diretório debian/

Os metadados do Debian são armazenados em debian/, que geralmente é inicializado com debmake ou dh-make. Infelizmente, eles só funcionam com tarballs:

# Specify your project name and version:
PROJECT_ID=<project> # e.g. "myproject"
PROJECT_VERSION=<version> # e.g. "1.0"

# Remember to run this in your debian branch:
git checkout debian/latest

# Create a release tarball and associated directory:
mkdir -p tmp debian
git archive HEAD --prefix="${PROJECT_ID}-${PROJECT_VERSION}"/ \
    -o tmp/"${PROJECT_ID}_${PROJECT_VERSION}".orig.tar.gz
cd tmp
tar zxf "${PROJECT_ID}_${PROJECT_VERSION}".orig.tar.gz

# Run debmake and move debian/ into your repo:
cd "${PROJECT_ID}-${PROJECT_VERSION}"
debmake # or dh_make
mv -n debian/* ../../debian/
git add ../../debian/

# Tidy up:
cd ../..
rm -rf tmp/"${PROJECT_ID}-${PROJECT_VERSION}"
rm -rf tmp/"${PROJECT_ID}_${PROJECT_VERSION}".orig.tar.gz
rmdir tmp

# Commit auto-generated files before making manual changes (optional):
git commit debian/ -m 'Create initial debian/ directory with debmake'

Isso criará todos os arquivos que você provavelmente precisará, além de exemplos .ex para arquivos que você pode precisar criar.

Leia todos os arquivos no diretório debian/. A Política Debian explica qual deles você precisa e como devem se parecer. Os testes durante a fase de construção (ex. lintian) dirão qualquer coisa que você esqueceu. debmake e dh-make têm opiniões diferentes sobre quais padrões são melhores - adapte suas sugestões favoritas de cada um deles.

{i} dh-make (com um traço) é o nome de um pacote, dh_make (com uma sublinha) é o nome do programa principal nesse pacote. Veja dh_make(1) para obter informações sobre as perguntas que faz.

Gerencie o debian/changelog

Este arquivo atua tanto como um histórico do projeto legível por humanos(as), quanto como um arquivo de configuração legível por máquina para, por exemplo, o número da versão e a distribuição de destino. Ele será instalado em /usr/share/doc/<your-package>/changelog.Debian.gz.

Você precisa decidir uma política sobre o que incluir no seu changelog. Esta seção discute algumas questões de política para ajudar a decidir e algumas ferramentas para ajudar a automatizar seu fluxo de trabalho.

Veja também DebianChangelog.

Questões comuns de políticas

Como serão seus números de versão?

A maioria dos projetos usa o versionamento semântico, mas alguns usam o versionamento de calendário, ou não têm números de versão. Você precisará de uma maneira de extrair os números de versão do projeto upstream e talvez precise reformatar os números para o Debian.

Você quer incluir as alterações upstream no changelog?
Alguns projetos fazem um grande esforço para dizer aos(às) usuários(as) o que mudou em cada versão, outros apenas mantêm suas páginas de manual atualizadas e esperam que os(as) usuários(as) as releiam de vez em quando. É bom Debianizar as alterações upstream se elas estão disponíveis; mas não vale a pena tentar escrever novas informações que não foram gravadas upstream.
Você deseja gerar seu changelog a partir do histórico de git commit?

Se o seu projeto upstream tiver um arquivo CHANGES perfeitamente mantido, você pode preferir escrever seu próprio script para convertê-lo no formato Debian. Caso contrário, adapte seu fluxo de trabalho para que você possa gerar um changelog a partir de git commits.

Se o seu changelog for baseado no histórico de commits, quais commits você deve incluir?

Por exemplo, seu upstream pode usar branches de tópico (topic branchs), portanto, apenas seus commits de merge pertencem ao changelog. Ou se não tiverem informações úteis sobre as alterações, convém excluir os commits upstream completamente.

Ferramentas úteis

A orientação sobre debianizar os números de versão está disponível em deb-version, mas também esteja ciente de que os repositórios Debian exigem que cada .deb tenha um nome de arquivo exclusivo. Diferentes arquiteturas recebem diferentes nomes de arquivos automaticamente, mas diferentes distribuições precisam de números exclusivos números de revisão Debian. Por exemplo, você gostar usar números ímpares para a versão estável (stable) e números pares para a versão teste (testing), ou você pode usar números de revisão ilustrados como -ubuntu1 ou -forky2.

Se você quiser escrever um changelog manualmente, use dch para criar e editar as entradas. O formato changelog é bastante preciso e às vezes pouco intuitivo, o dch ajudará a encontrar erros. dch --edit usa sensible-editor, para que você possa usar select-editor para configurar seu editor preferido.

Se quiser escrever um script que gere um changelog, leia a especificação changelog. Talvez seja bom usar o dch para editar o arquivo, ou apenas para verificar se você chegou ao formato certo.

Se você quiser gerar o debian/changelog a partir do seu git changelog, use gbp-dch. Você consegue excluir commits upstream executando gbp dch debian/, ou você precise usar --git-log para especificar os parâmetros do git log. Se escolher por este último caso, considere salvá-lo em seu debian/gbp.conf:

[dch]
# Only include merge commits:
git-log = --merges
# Exclude merge commits:
git-log = --no-merges
# Exclude upstream commits:
git-log = --first-parent

gbp dch --new-version adiciona uma nova entrada ao changelog, a menos que a entrada atual tenha distributions definida como UNRELEASED, caso em que mesclará as alterações na entrada atual. Por exemplo, você pode querer fazer vários commits de snapshot durante o desenvolvimento e, em seguida, mesclá-los juntos no changelog público.

Gerenciando o debian/copyright

Este é um arquivo legível por máquina que especifica os direitos legais dos(as) usuários(as) de usar o pacote e os arquivos nele. O debmake deverá fornecer uma versão inicial, mas há muitas ferramentas de revisão de copyright. Você pode usar a que preferir, mas a ferramenta licensecheck é um bom padrão, e o modo interativo da ferramenta cme pode ajudá-lo(a) a aprender como o arquivo funciona.

Escrever o copyright pode ser muito demorado, mas o Debian não hospedará um pacote a menos que se saiba que é legal fazê-lo. Se você tiver um bom relacionamento com o upstream, considere pedir que leiam a seção de licenciamento do guia upstream.

Gerenciando arquivos fora do debian/

Alterações no seu branch debian, mas fora do seu diretório debian/, precisam de manuseio especial. Por exemplo, você pode precisar corrigir o sistema de construção para instalar arquivos nos locais certos, e o Debian se recusará a hospedar até mesmo um tarball upstream que viole a Definição Debian de Software Livre. Para detalhes, consulte ManageUpstreamDifferences.

Etapa da construção

A etapa de construção envolve a geração e o teste dos arquivos do pacote, incluindo um ou mais arquivos .deb.

Para fazer um teste-build do seu pacote, verifique se o seu debian/changelog tem o número de versão correto e faça:

gbp buildpackage --git-dist=<dist> --git-arch=<arch>
# Or if you configured pbuilder=True and want to use pbuilder instead of cowbuilder:
BUILDER=pbuilder gbp buildpackage --git-dist=<dist> --git-arch=<arch>

Se a sua construção for bem-sucedida, deve produzir uma coleção de arquivos ../<project>_<version>*.

Verificadores de pacote procuram por problemas que não causem falhas de construção. É particularmente importante executar lintian, piuparts e autopkgtest, já que o Debian geralmente rejeita pacotes que falham nesses testes.

lintian procura por problemas comuns e violações da política Debian. Por exemplo, textos prontos (boilerplates) que não foram modificados desde que você executou o debmake. Você pode executá-lo com a maioria dos testes ativados usando lintian --info --display-info --pedantic /path/to/your/package.changes, ou escolher suas opções preferidas na página de manual do lintian.

piuparts cria um chroot mínimo e, em seguida, tenta instalar e desinstalar seu pacote nele. O piuparts precisa de arquivos no estilo .tgz do pbuilder - ele não pode usar os diretórios .cow do cowbuilder. É geralmente executado com sudo piuparts --log-level info --basetgz /path/to/your/base-environment.tgz /path/to/your/package.deb, e suas opções são explicadas na página de manual do piuparts.

autopkgtest executa quaisquer testes de integração que você adicionou a debian/tests. Isto geralmente não é necessário para pacotes simples - saiba mais em autopkgtest.

{i} se você não configurou pbuilder=True, o lintian será executado sem argumentos durante a construção. Você pode executá-lo novamente com seus argumentos preferidos caso necessário.

Script de construção

Você pode escrever um script para automatizar seu processo de construção. Aqui está um exemplo que mostra várias opções:

#!/bin/sh

# Exit if any programs fail:
set -e

# Can be /var/cache/pbuilder/result for some workflows:
RESULT_DIRECTORY=..

# Get some information from the changelog
SOURCE="$(dpkg-parsechangelog --show-field=Source)"
VERSION="$(dpkg-parsechangelog --show-field=Version)"

# Read "--git-dist=foo" and "--git-arch=bar" from the command-line:
DIST=sid
ARCH="$(dpkg --print-architecture)"
for ARG
do
    case "$ARG" in
        "--git-dist="*)
            DIST="${ARG#--git-dist=}"
            ;;
        "--git-arch="*)
            ARCH="${ARG#--git-arch=}"
            ;;
        "--git-export-dir="*)
            RESULT_DIRECTORY="${ARG#--git-export-dir=}"
            mkdir -p "$RESULT_DIRECTORY"
            ;;
        -h|--h|--he|--hel|--help)
            cat <<EOF
Usage: $0 [--git-dist=<distribution>] [--git-arch=<architecture>]"

Build a Debian package.
See https://wiki.debian.org/PackagingWithGit#Build_script
EOF
            exit 1
            ;;
    esac
done

if grep -q '^Architecture: all' debian/control
then PKG_ARCH=all
else PKG_ARCH="$ARCH"
fi

CHANGES_FILE="$RESULT_DIRECTORY/${SOURCE}_${VERSION}_${ARCH}.changes"
DEB_FILE="$RESULT_DIRECTORY/${SOURCE}_${VERSION}_${PKG_ARCH}.deb"
LOG_FILE="$RESULT_DIRECTORY/${SOURCE}_${VERSION}_${ARCH}.log"

# Calculate the pbuilder base tarball/path:
BASE=/var/cache/pbuilder/base
if [ -n "$DIST" -a "$DIST" != sid ]
then BASE="$BASE-$DIST"
fi
if [ -n "$ARCH" -a "$ARCH" != "$(dpkg --print-architecture)" ]
then BASE="$BASE-$ARCH"
fi

# Run pbuilder with arguments from the command-line:
echo -n "[$(date)] Running gbp buildpackage" >&2
set -o pipefail
BUILDER=pbuilder gbp buildpackage "$@" \
    | tee "$LOG_FILE" \
    | while read LINE ; do echo -n . >&2 ; done
set +o pipefail
echo " OK" >&2
echo >&2

echo "[$(date)] Running piuparts..." >&2
sudo piuparts --log-level info --basetgz "$BASE.tgz" "$DEB_FILE"
echo "[$(date)] piuparts: OK" >&2
echo >&2

echo "[$(date)] Running autopkgtest..." >&2
set +e
sudo autopkgtest --no-built-binaries --apt-upgrade "$CHANGES_FILE" \
    -- unshare --release "$DIST" --arch "$ARCH"
RESULT="$?"
set -e
case "$RESULT" in
    0) echo "autopkgtest: OK" >&2 ;;
    8) echo "autopkgtest: no tests in this package, or all non-superficial tests were skipped" >&2 ;;
    *) exit "$RESULT" >&2
esac
echo >&2

echo "[$(date)] Running lintian..." >&2
lintian --info --display-info --pedantic "$CHANGES_FILE"
echo "[$(date)] lintian: OK" >&2
echo >&2

echo "[$(date)] Success!" >&2

{i} se preferir executar gbp buildpackage diretamente, você pode chamar seu script a partir da opção buildpackage.postbuild em um arquivo gbp.conf.

Etapa da publicação

A etapa de publicação envolve colocar seus arquivos construídos em um repositório que você controla ou solicitar que outra pessoa (por exemplo, o projeto Debian) o coloque em um repositório que controlado por essa pessoa.

Se você quiser publicar seu pacote para o próprio Debian, registre-se em uma conta do Salsa e verifique a a seção de registro de usuário(a) do FAQ. Enquanto espera, reporte um bug Intent To Package (ITP, intenção de empacotar) e adicione uma entrada ao seu debian/changelog que termina com Closes: #<número-do-bug-itp>.

Altere UNRELEASED no debian/changelog para as distribuições nais quais seu pacote deve estar. O repositório Debian somente permite uma distribuição, então você talvez precise publicar várias vezes, atualizando o número da versão a cada vez. Outros repositórios podem aceitar uma única versão com uma lista de distribuições separada por espaços.

Faça o commit da sua alteração e, em seguida, construa e crie a tag da versão:

gbp buildpackage --git-tag

Isso criará uma tag baseada na opção de configuração debian-tag. Por padrão, assemelha-se a debian/X.Y-Z.

Se você quiser publicar seu pacote para o próprio Debian, faça o push para salsa.debian.org e siga o processo de amadrinhamento/apadrinhamento.

Finalmente, por precaução, adicione um commit de snapshot temporário:

gbp dch --snapshot
git commit -m 'WIP: next version' debian/changelog

Se tudo correr bem, você pode desfazer este commit antes do seu próximo merge, fazendo git commit --reset HEAD^. Mas se você acidentalmente fizer o push das alterações para o Salsa, os testes falharão sem causar futuros problemas em vez de liberar essas alterações indesejadas em um repositório público.

Veja também