Regras de repositório

Informar um problema Acessar fonte

Nesta página, abordamos como criar regras de repositório e fornecemos exemplos para mais detalhes.

Um repositório externo é uma regra que pode ser usada apenas no arquivo WORKSPACE e permite operações não herméticas na fase de carregamento do Bazel. Cada regra de repositório externo cria o próprio espaço de trabalho, com os próprios arquivos BUILD e artefatos. Eles podem ser usados para depender de bibliotecas de terceiros (como bibliotecas empacotadas Maven), mas também para gerar arquivos BUILD específicos para o host em que o Bazel está sendo executado.

Criação de regras de repositório

Em um arquivo .bzl, use a função repository_rule para criar uma nova regra de repositório e armazene-a em uma variável global.

É possível usar uma regra de repositório personalizada da mesma forma que uma regra de repositório nativo. Ela tem um atributo name obrigatório, e todos os destinos presentes nos arquivos de build podem ser chamados de @<name>//package:target, em que <name> é o valor do atributo name.

A regra é carregada quando você a cria explicitamente ou se é uma dependência do build. Nesse caso, o Bazel executará a função implementation. Essa função descreve como criar o repositório, o conteúdo e os arquivos BUILD.

Atributos

Os atributos são argumentos de regra transmitidos como um dict para o argumento da regra attrs. Os atributos e os tipos deles são definidos e listados quando você define uma regra de repositório. Um exemplo de definição de atributos url e sha256 como strings:

local_repository = repository_rule(
    implementation=_impl,
    local=True,
    attrs={
        "url": attr.string(mandatory=True)
        "sha256": attr.string(mandatory=True)
    }
)

Para acessar um atributo na função de implementação, use repository_ctx.attr.<attribute_name>:

def _impl(repository_ctx):
    url = repository_ctx.attr.url
    checksum = repository_ctx.attr.sha256

Todos os repository_rules têm atributos definidos implicitamente (assim como as regras de build). Os dois atributos implícitos são name (assim como para as regras de criação) e repo_mapping. O nome de uma regra de repositório pode ser acessado com repository_ctx.name. O significado de repo_mapping é o mesmo das regras de repositório nativo local_repository e new_local_repository.

Se o nome de um atributo começar com _, ele será particular e não poderá ser definido pelos usuários.

Função de implementação

Cada regra de repositório requer uma função implementation. Ela contém a lógica real da regra e é executada estritamente na fase de carregamento.

A função tem exatamente um parâmetro de entrada, repository_ctx. A função retorna None para indicar que a regra é reproduzível de acordo com os parâmetros especificados, ou um dict com um conjunto de parâmetros para essa regra que a transformaria em uma regra reproduzível que gera o mesmo repositório. Por exemplo, para uma regra de rastreamento de um repositório git, isso significaria retornar um identificador de confirmação específico em vez de uma ramificação flutuante que foi originalmente especificada.

O parâmetro de entrada repository_ctx pode ser usado para acessar valores de atributos e funções não herméticas (encontrar um binário, executar um binário, criar um arquivo no repositório ou fazer o download de um arquivo da Internet). Consulte a biblioteca para mais contexto. Exemplo:

def _impl(repository_ctx):
  repository_ctx.symlink(repository_ctx.attr.path, "")

local_repository = repository_rule(
    implementation=_impl,
    ...)

Quando a função de implementação é executada?

A função de implementação de um repositório é executada quando o Bazel precisa de um destino desse repositório. Por exemplo, quando outro destino (em outro repositório) depende dele ou se ele é mencionado na linha de comando. Espera-se que a função de implementação crie o repositório no sistema de arquivos. Isso é chamado de "busca" do repositório.

Ao contrário dos destinos normais, os repositórios não são necessariamente buscados novamente quando algo muda que faria com que o repositório fosse diferente. Isso ocorre porque há coisas em que o Bazel não consegue detectar mudanças ou que causa muita sobrecarga em cada build (por exemplo, itens buscados na rede). Portanto, os repositórios só serão buscados novamente se uma das seguintes coisas mudar:

  • Os parâmetros passados para a declaração do repositório no arquivo WORKSPACE.
  • O código Starlark, que consiste na implementação do repositório.
  • O valor de qualquer variável de ambiente transmitido para o método getenv() de repository_ctx ou declarado com o atributo environ da repository_rule. Os valores dessas variáveis de ambiente podem ser conectados na linha de comando com a sinalização --repo_env.
  • O conteúdo de qualquer arquivo transmitido para read(), execute() e métodos semelhantes de repository_ctx, que é referenciado por um rótulo (por exemplo, //mypkg:label.txt, mas não mypkg/label.txt).
  • Quando bazel sync é executado.

Há dois parâmetros de repository_rule que controlam quando os repositórios são buscados novamente:

  • Se a flag configure for definida, o repositório só será buscado novamente em bazel sync quando o parâmetro --configure for transmitido a ele. Se o atributo não for definido, esse comando não vai gerar uma nova busca.
  • Se a sinalização local for definida, além dos casos acima, o repositório também será buscado novamente quando o servidor do Bazel for reiniciado ou quando qualquer arquivo que afete a declaração do repositório seja alterado (por exemplo, o arquivo WORKSPACE ou um arquivo carregado), independentemente de as alterações resultarem em uma alteração na declaração do repositório ou do código dele.

    Repositórios não locais não são buscados novamente nesses casos. Isso ocorre porque presume-se que esses repositórios se comuniquem com a rede ou sejam caros.

Como reiniciar a função de implementação

A função de implementação pode ser reiniciada enquanto um repositório está sendo buscado caso uma dependência solicitada esteja ausente. Nesse caso, a execução da função de implementação será interrompida, a dependência ausente será resolvida e a função será executada novamente depois que a dependência for resolvida. Para evitar reinicializações desnecessárias (que são caras, porque o acesso à rede pode precisar ser repetido), os argumentos de rótulos são pré-buscados, desde que todos os argumentos possam ser resolvidos para um arquivo atual. Resolver um caminho de uma string ou rótulo criado apenas durante a execução da função ainda pode causar uma reinicialização.

Como forçar uma nova busca de repositórios externos

Às vezes, um repositório externo pode ficar desatualizado sem nenhuma alteração na definição ou nas dependências dele. Por exemplo, um repositório que busca origens pode seguir uma ramificação específica de um repositório de terceiros, e novas confirmações estão disponíveis nessa ramificação. Nesse caso, é possível pedir ao Bazel para buscar novamente todos os repositórios externos incondicionalmente chamando bazel sync.

Além disso, algumas regras inspecionam a máquina local e podem ficar desatualizadas se for feito upgrade dela. Aqui, é possível pedir ao Bazel para buscar novamente apenas os repositórios externos em que a definição repository_rule tem o atributo configure definido. Use bazel sync --configure.

Exemplos

  • Conjunto de ferramentas configurado automaticamente para C++: ele usa uma regra de repositório para criar automaticamente os arquivos de configuração C++ para o Bazel procurando o compilador C++ local, o ambiente e as sinalizações compatíveis com o compilador C++.

  • Os repositórios Go usam vários repository_rule para definir a lista de dependências necessárias para usar as regras do Go.

  • rules_jvm_external cria um repositório externo chamado @maven por padrão que gera destinos de build para cada artefato Maven na árvore de dependências transitiva.