Como escrever regras no Windows

Informar um problema Acessar a origem

Esta página se concentra em escrever regras compatíveis com o Windows, problemas comuns de programação de regras portáteis e algumas soluções.

Caminhos

Problemas:

  • Limite de tamanho: o tamanho máximo do caminho é de 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 a função cd em um diretório com mais de 259 caracteres.

  • Diferenciação de maiúsculas e minúsculas: os caminhos do Windows não diferenciam maiúsculas de minúsculas, e os caminhos Unix fazem isso.

    Esteja ciente disso ao criar linhas de comando para ações.

  • Separadores de caminho: são barras invertidas (\`), not forward slash (/`).

    O Bazel armazena caminhos no estilo Unix com separadores /. Embora alguns programas do Windows suportem caminhos no estilo Unix, outros não. Alguns comandos integrados em cmd.exe são compatíveis com eles, outros não.

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

  • Caminhos absolutos: não comece com barra (/).

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

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

Soluções:

  • Mantenha os caminhos curtos.

    Evite nomes de diretório longos, estruturas de diretório profundamente aninhadas, nomes de arquivos longos, nomes de espaço de trabalho longos nomes de destino longos.

    Tudo isso pode se tornar componentes do caminho dos arquivos de entrada das ações e pode esgotar o limite de tamanho do caminho.

  • Use uma raiz de saída curta.

    Use a sinalização --output_user_root=<path> para especificar um caminho curto para saídas do Bazel. Uma boa ideia é ter um drive (ou drive 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.

    As junções são, vagamente[1], links simbólicos de diretório. 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 um destino longo, as ferramentas com limite de caminho curto poderão acessar os arquivos no diretório com junção.

    Nos arquivos .bat ou no cmd.exe, é possível criar junções como esta:

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

    [1]: a rigor, as junções não são links simbólicos, mas, para ações de build, podem ser consideradas 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, crie os caminhos no estilo Windows. Exemplos

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

Variáveis de ambiente

Problemas:

  • Diferenciação de 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 usa 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.

    Isso funciona no Windows, macOS e Linux.

  • Minimize os 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 em um dicionário e transmita-as para a ação. Exemplos

    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).

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

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

    O Bash é generalizado em sistemas do tipo Unix, mas muitas vezes não está disponível no Windows. O próprio Bazel depende cada vez mais do Bash (MSYS2). Portanto, no futuro, é menos provável que os usuários tenham o MSYS2 instalado com o Bazel. 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). Os sistemas do tipo Unix usam LF (\n).

    Esteja ciente disso ao comparar arquivos de texto. Preste atenção nas suas configurações do Git, especialmente com finais de linha ao fazer o check-out ou confirmar. Consulte a configuração core.autocrlf do Git.

Soluções:

  • Use uma regra sem propósito de Bash.

    native.genrule() é um wrapper para comandos Bash e costuma ser usado para resolver problemas simples, como copiar um arquivo ou gravar um arquivo de texto. Não dependa do Bash (e reinvente a roda): confira se a bazel-skylib tem uma regra específica para suas necessidades. Nenhum deles depende de Bash quando criado/testado no Windows.

    Exemplos de regras de build:

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

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

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

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

    Exemplos de regras de teste:

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

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

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

    Em vez de scripts .sh, você pode resolver tarefas triviais com scripts .bat.

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

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

    Arquivos .bat vazios não podem ser executados. Se você precisar de um script vazio, escreva um espaço nele.

  • Use o Bash de acordo com os princípios.

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

    Em macros Starlark, una scripts e comandos Bash em um native.sh_binary() ou native.genrule(). Ele verificará se o Bash está disponível e executará o script ou comando por ele.

    Nas regras de repositório do Starlark, tente evitar o Bash completamente. Atualmente, o Bazel não oferece como executar comandos do Bash de maneira baseada nas regras de repositório.

Como excluir arquivos

Problemas:

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

    Não é possível excluir arquivos abertos (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.

  • O diretório de trabalho de um processo em execução não pode ser excluído.

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

Soluções:

  • No código, tente fechar os arquivos.

    Em Java, use try-with-resources. Em Python, use with open(...) as f:. Em princípio, tente fechar as alças o mais rápido possível.