Como posso usar arquivos do HTTP como pré-requisitos no GNU make?

10

Eu quero usar arquivos da World Wide Web como pré-requisitos em meus makefiles:

local.dat: http://example.org/example.gz
    curl -s $< | gzip -d | transmogrify >$@

Eu só quero "transmogrificar" se o arquivo remoto é mais novo que o arquivo local, assim como make normalmente opera.

Eu faço não quero manter uma cópia em cache de example.gz - os arquivos são grandes, e eu não preciso dos dados brutos. De preferência, eu gostaria de evitar o download do arquivo em tudo. O objetivo é processar alguns deles em paralelo usando o sinalizador -j make.

O que é uma maneira limpa de resolver isso? Eu posso pensar em algumas maneiras de ir:

  • Manter um arquivo fictício vazio armazenado, atualizado sempre que o destino for recriado
  • Algum plugin usando o novo sistema de plugins do GNU make ( que eu não sei nada sobre)
  • Uma maneira independente de montar servidores HTTP no sistema de arquivos local

Antes de prosseguir, gostaria de receber alguns conselhos, de preferência exemplos específicos!

    
por pipe 20.02.2018 / 01:54

2 respostas

15

Tente algo assim em seu Makefile:

.PHONY: local.dat

local.dat:
    [ -e example.gz ] || touch -d '00:00' example.gz
    curl -z example.gz -s http://example.org/example.gz -o example.gz
    [ -e $@ ] || touch -d 'yesterday 00:00' $@
    if [     "$(shell stat --printf '%Y' example.gz)" \
         -gt "$(shell stat --printf '%Y' $@)"         ] ; then \
      zcat example.gz | transmogrify >$@ ; \
    fi
    truncate -s 0 example.gz
    touch -r $@ example.gz

(nota: isso é um Makefile, então os recuos são guias, não espaços. claro.  Também é importante que não haja espaços após o \ nas linhas de continuação - alternativamente, elimine as escapes de contrabarra e torne-a uma linha longa, quase ilegível)

Esta receita de make do GNU primeiro verifica se existe um arquivo chamado example.gz (porque vamos usá-lo com -z em curl ) e cria com touch se ele não o faz t. O toque cria um timestamp de 00:00 (12h do dia atual).

Em seguida, ele usa a opção curl -z ( --time-cond ) para fazer o download apenas de example.gz se tiver sido modificado desde a última vez em que foi baixado. -z pode receber uma expressão de data real ou um nome de arquivo. Se for dado um nome de arquivo, ele usará o horário de modificação do arquivo como a condição de tempo.

Depois disso, se local.dat não existir, ele será criado com touch , usando um registro de data e hora garantido como mais antigo do que example.gz . Isso é necessário porque local.dat tem que existir para o próximo comando usar stat para obter seu timestamp mtime.

Em seguida, se example.gz tiver um registro de data e hora mais recente que local.dat , ele canaliza example.gz para transmogrify e redireciona a saída para local.dat .

Finalmente, ele faz a contabilidade & coisas de limpeza:

  • trunca example.gz (porque você só precisa manter um registro de data e hora, e não o arquivo inteiro)
  • touch es example.gz para que tenha o mesmo timestamp que local.dat

O alvo .PHONY garante que o alvo local.dat seja sempre executado, mesmo que o arquivo desse nome já exista.

Obrigado ao @Toby Speight por apontar nos comentários que minha versão original não funcionaria e por quê.

Como alternativa, se você quiser enviar o arquivo diretamente para transmogrify sem baixá-lo primeiro no sistema de arquivos:

.PHONY: local.dat

local.dat:
    [ -e example.gz ] || touch -d '00:00' example.gz
    [ -e $@ ] || touch -d 'yesterday 00:00' $@
    if [     "$(shell stat --printf '%Y' example.gz)" \
         -gt "$(shell stat --printf '%Y' $@)"         ] ; then \
      curl -z example.gz -s http://example.org/example.gz | transmogrify >$@ ; \
    fi
    touch -r $@ example.gz

OBSERVAÇÃO: isso não é testado, portanto, pode exigir algumas pequenas alterações para obter a sintaxe corretamente. O importante aqui é o método, não uma solução de copiar e colar carga-cult.

Eu tenho usado variações desse método (por exemplo, touch -ing um arquivo de timestamp) com make por décadas. Ele funciona, e geralmente me permite evitar ter que escrever meu próprio código de resolução de dependência no sh (embora eu tenha que fazer algo similar com stat --printf %Y aqui).

Todo mundo sabe que make é uma ótima ferramenta para compilar software ... O IMO também é uma ferramenta muito subestimada para tarefas administrativas e de script do sistema.

    
por 20.02.2018 / 02:38
1

Outra alternativa é usar um sistema de compilação que use somas de verificação de dependência para determinar se é necessário acionar recriações. Eu usei o truque do "toque" com o Gnu Make muito, mas é muito mais simples quando você pode especificar dependências dinâmicas e quando arquivos que não mudam não acionam recriações. Aqui está um exemplo usando o GoodMake :

#! /usr/local/goodmake.py /bin/sh -se

#! *.date
    # Get the last-modified date
    curl -s -v -X HEAD http://${1%.date} 2>&1 | grep -i '^< Last-Modified:' >$1

#? local.dat
    site=http://example.org/example.gz
    $0 $site.date
    curl -s $site | gzip -d | transmogrify >$1
    
por 12.11.2018 / 20:42