Como escrever regras no Windows

Nesta página, você verá como escrever regras compatíveis com o Windows, problemas comuns na gravação de regras de portabilidade e algumas soluções.

Caminhos

Problemas:

  • Limite de tamanho: o caminho pode ter até 259 caracteres.

    Embora o Windows também ofereça suporte a caminhos mais longos (até 32.767 caracteres), muitos programas são criados com o limite mínimo.

    Esteja ciente disso sobre os programas que você executa nas ações.

  • Diretório de trabalho: também é limitado a 259 caracteres.

    Os processos não podem usar cd em um diretório com mais de 259 caracteres.

  • Diferenciação entre maiúsculas e minúsculas: os caminhos do Windows são indiferentes a maiúsculas e os caminhos Unix.

    Lembre-se disso ao criar linhas de comando para ações.

  • Separadores de caminho: são uma barra invertida (\`), not forward slash (/`).

    O Bazel armazena caminhos no estilo Unix com separadores /. Alguns programas do Windows oferecem suporte a caminhos no estilo Unix, outros não. Alguns comandos integrados no cmd.exe oferecem suporte a eles, outros não.

    É melhor usar sempre \` separators on Windows: replace/with ao criar linhas de comando e variáveis de ambiente para ações.

  • Caminhos absolutos: não começam com uma barra (/).

    Os caminhos absolutos no Windows começam com uma letra de unidade, como C:\foo\bar.txt. Não há uma única raiz de sistema de arquivos.

    Lembre-se disso caso sua regra verifique se um caminho é absoluto. Caminhos absolutos devem ser evitados, já que geralmente não são portáteis.

Soluções:

  • Mantenha os caminhos curtos.

    Evite nomes longos de diretórios, estruturas de diretórios profundamente aninhadas, nomes de arquivos longos, nomes longos de espaços de trabalho e nomes de destino longos.

    Todos eles podem se tornar componentes de caminho dos arquivos de entrada das ações e podem esgotar o limite de tamanho do caminho.

  • Use uma raiz de saída curta.

    Use a flag --output_user_root=<path> para especificar um caminho curto para as saídas do Bazel. Uma boa ideia é ter uma unidade (ou unidade virtual) apenas para saídas do Bazel (como o arquivo D:\`), and adding this line to your.bazelrc`:

    build --output_user_root=D:/
    

    ou

    build --output_user_root=C:/_bzl
    
  • Use cruzamentos.

    Em geral, as junções são[1] links simbólicos de diretório. As junções são fáceis de criar e podem apontar para diretórios (no mesmo computador) com caminhos longos. Se uma ação de build criar uma junção com um caminho curto, mas com destino longo, as ferramentas com limite de caminho curto poderão acessar os arquivos no diretório da junção.

    Em arquivos .bat ou em cmd.exe, você pode criar junções como:

    mklink /J c:\path\to\junction c:\path\to\very\long\target\path
    

    [1]: estritamente falando, as junções não são links simbólicos, mas, para as ações de criação, elas podem ser consideradas junções como links simbólicos de diretório.

  • Substitua / por `` em caminhos em actions / envvars.

    Ao criar a linha de comando ou as variáveis de ambiente para uma ação, torne os caminhos semelhantes ao Windows. Exemplo:

    def as_path(p, is_windows):
        if is_windows:
            return p.replace("/", "\\")
        else:
            return p
    

Variáveis de ambiente

Problemas:

  • Diferenciação entre letras maiúsculas e minúsculas: os nomes das variáveis de ambiente do Windows não diferenciam maiúsculas de minúsculas.

    Por exemplo, em Java, System.getenv("SystemRoot") e System.getenv("SYSTEMROOT") produzem o mesmo resultado. Isso também se aplica a outros idiomas.

  • Hermeticidade: as ações precisam usar o menor número possível de variáveis de ambiente personalizadas.

    As variáveis de ambiente fazem parte da chave de cache da ação. Se uma ação usar variáveis de ambiente que mudam com frequência ou são personalizadas para os usuários, isso torna a regra menos armazenável em cache.

Soluções:

  • Use apenas nomes de variáveis de ambiente em maiúsculas.

    Esse recurso funciona no Windows, macOS e Linux.

  • Minimize ambientes de ação.

    Ao usar ctx.actions.run, defina o ambiente como ctx.configuration.default_shell_env. Se a ação precisar de mais variáveis de ambiente, coloque todas elas em um dicionário e transmita-o para a ação. Exemplo:

    load("@bazel_skylib//lib:dicts.bzl", "dicts")
    
    def _make_env(ctx, output_file, is_windows):
        out_path = output_file.path
        if is_windows:
            out_path = out_path.replace("/", "\\")
        return dicts.add(ctx.configuration.default_shell_env, {"MY_OUTPUT": out_path})
    

Ações

Problemas:

  • Saídas executáveis: todo arquivo executável precisa ter uma extensão executável.

    As extensões mais comuns são .exe (arquivos binários) e .bat (scripts em lote).

    Saiba que os scripts de shell (.sh) NÃO são executáveis no Windows. Não é possível especificá-los como executable do ctx.actions.run. Os arquivos também não podem ter a permissão +x. Portanto, não é possível executar arquivos arbitrários como no Linux.

  • Comandos Bash: por questão de portabilidade, evite executar comandos Bash diretamente nas ações.

    O Bash é muito usado em sistemas do tipo Unix, mas geralmente não está disponível no Windows. O Bazel está cada vez mais dependendo do Bash (MSYS2). Portanto, no futuro, é menos provável que os usuários futuros tenham o MSYS2 instalado com ele. Para facilitar o uso de regras no Windows, evite executar comandos Bash em ações.

  • Terminações de linha: o Windows usa CRLF (\r\n), e sistemas Unix usam LF (\n).

    Esteja ciente disso ao comparar arquivos de texto. Esteja atento às configurações do Git, especialmente aos finais de linha ao fazer check-out ou fazer commit. Consulte a configuração core.autocrlf do Git.

Soluções:

  • Use uma regra específica sem Bash.

    O native.genrule() é um wrapper para comandos Bash, geralmente usado para resolver problemas simples, como copiar um arquivo ou gravar um arquivo de texto. Você pode evitar confiar no Bash (e reinventar a roda): confira se o bazel-skylib tem uma regra específica para suas necessidades. Nenhuma delas depende do Bash quando criado/testado no Windows.

    Exemplos de regras de criação:

    • copy_file() (fonte, documentação): copia um arquivo em outro lugar, tornando-o executável opcionalmente.

    • write_file() (origem, documentação): grava um arquivo de texto com as terminações de linha desejadas (auto, unix ou windows), opcionalmente tornando-o executável (se for um script).

    • run_binary() (origem, documentação): executa um binário (ou regra *_binary) com entradas fornecidas e saídas esperadas como uma ação de build. Esse é um wrapper de regra de build para ctx.actions.run.

    • native_binary() (origem, documentação): encapsula um binário nativo em uma regra *_binary, que você pode usar bazel run ou usar no atributo tool do run_binary() ou no atributo tools do native.genrule()

    Exemplos de regra de teste:

    • diff_test() (origem, documentação): teste que compara o conteúdo de dois arquivos.

    • native_test() (origem, documentação): encapsula um binário nativo em uma regra *_test, que você pode bazel test

  • No Windows, use scripts .bat para coisas triviais.

    Em vez de scripts .sh, é possível resolver tarefas triviais com scripts .bat.

    Por exemplo, se você precisar de um script que não faça nada, imprima uma mensagem ou saia com um código de erro corrigido, um arquivo .bat simples será suficiente. Se a regra retornar um provedor DefaultInfo(), o campo executable poderá se referir a esse arquivo .bat no Windows.

    Como as extensões de arquivo não são importantes no macOS e no Linux, você sempre pode usar .bat como extensão, mesmo para scripts de shell.

    Não é possível executar arquivos .bat vazios. Se precisar de um script vazio, escreva um espaço nele.

  • Use o Bash com base em princípios.

    Nas regras de criação e teste do Starlark, use ctx.actions.run_shell para executar scripts e comandos de Bash como ações.

    Nas macros do Starlark, una scripts e comandos Bash em um native.sh_binary() ou native.genrule(). O Bazel verifica se o Bash está disponível e executa o script ou comando pelo Bash.

    Nas regras de repositório do Starlark, tente evitar o Bash completamente. Atualmente, o Bazel não oferece uma maneira de executar comandos Bash de forma baseada em princípios nas regras de repositório.

Como excluir arquivos

Problemas:

  • Não é possível excluir arquivos enquanto eles estão abertos.

    Arquivos abertos não podem ser excluídos (por padrão), as tentativas resultam em erros de "Acesso negado". Se não for possível excluir um arquivo, talvez um processo em execução ainda o mantenha aberto.

  • Não é possível excluir o diretório de trabalho de um processo em execução.

    Os processos têm um identificador aberto para o diretório de trabalho, e o diretório não pode ser excluído até que o processo seja encerrado.

Soluções:

  • No seu código, tente fechar os arquivos prontamente.

    Em Java, use try-with-resources. Em Python, use with open(...) as f:. Em princípio, tente fechar os identificadores assim que possível.