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 for mais novo que o arquivo local, assim como o make normalmente opera.

Eu não quero manter uma cópia em cache 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. O objetivo é processar alguns deles em paralelo usando o -jsinalizador make.

Qual é uma maneira limpa de resolver isso? Eu posso pensar em algumas maneiras de seguir:

  • Mantenha um arquivo fictício vazio escondido, atualizado sempre que o destino for recriado
  • Alguns plug-in usando o GNU make novo sistema plug-in (que eu não sei nada sobre)
  • Uma maneira independente de agendamento que monta servidores HTTP no sistema de arquivos local

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

tubo
fonte

Respostas:

15

Tente algo assim no 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: este é um Makefile, portanto, os recuos são tabulações, não espaços. é claro. Também é importante que não haja espaços após as \linhas de continuação - alternativamente, elimine as escapes da barra invertida e faça uma longa, linha quase ilegível)

Esta makereceita GNU primeiro verifica se example.gzexiste um arquivo chamado (porque vamos usá-lo com -zin curl) e o cria touchse não existir. O toque o cria com um registro de data e hora de 00:00 (00:00 do dia atual).

Em seguida, ele usa curla opção 's -z( --time-cond) para fazer o download apenas example.gzse tiver sido modificado desde a última vez em que foi baixado. -zpode receber uma expressão de data real ou um nome de arquivo. Se receber um nome de arquivo, ele usará a hora da modificação do arquivo como condição de hora.

Depois disso, se local.datnão existir, ele será criado touch, usando um carimbo de data / hora garantido para ser mais antigo que o de example.gz. Isso é necessário porque local.datdeve existir para o próximo comando usar statpara obter o registro de data e hora do mtime.

Então, se example.gztem um timestamp mais recente do que local.dat, ele tubos example.gzem transmogrifye redireciona a saída para local.dat.

Finalmente, ele faz as coisas de contabilidade e limpeza:

  • trunca example.gz(porque você só precisa manter um carimbo de data e hora, e não o arquivo inteiro)
  • touches example.gzpara que ele tenha o mesmo timestamp quelocal.dat

O destino .PHONY garante que o local.datdestino seja sempre executado, mesmo se o arquivo com esse nome já existir.

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

Como alternativa, se você quiser canalizar o arquivo diretamente transmogrifysem fazer o download 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

NOTA: como a maioria não é testada, pode ser necessário fazer pequenas alterações para obter a sintaxe exatamente correta. O importante aqui é o método, não uma solução de culto à carga de copiar e colar.

Eu tenho usado variações desse método (por exemplo, em touchum arquivo de carimbo de data / hora) makehá décadas. Funciona e geralmente me permite evitar escrever meu próprio código de resolução de dependência no sh (embora eu tenha tido que fazer algo semelhante stat --printf %Yaqui).

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

cas
fonte
1
A -zsinalização, é claro, assume que o servidor remoto usa If-Modified-Sincecabeçalhos. Isso pode não ser necessariamente o caso. Dependendo da configuração do servidor, você pode precisar fazer algo com ETag, ou verificando Cache-Controlcabeçalhos ou verificando um arquivo de soma de verificação separado (por exemplo, se o servidor fornecer a sha1sum).
Bob
sim. mas sem isso, não há como fazer o que o OP deseja (a menos que ele esteja disposto a baixar o arquivo enorme para um arquivo temporário toda vez que executar make, use cmpou algo para comparar arquivos antigos e novos e mv newfile oldfilese forem diferentes) . Aliás, os cabeçalhos de controle de cache não informam se o arquivo é mais recente que um determinado momento. eles informam por quanto tempo os administradores do servidor querem que você armazene em cache um determinado arquivo - e são freqüentemente usados ​​por dróides de marketing como uma prática de impedir o cache para "melhorar" suas estatísticas da web.
cas
ETag é outra maneira de fazer isso, assim como um arquivo de soma de verificação separado. Tudo depende de como o servidor está configurado. Por exemplo, é possível buscar cdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA1SUMS e verificar se ele mudou antes de decidir buscar a ISO completa. ETag faz a mesma coisa, usando um cabeçalho em vez de um arquivo separado (e, como If-Modified-Since, depende do servidor HTTP que o implementa). Cache-Controlseria uma opção de último recurso, exceto baixar o arquivo, se nenhum outro método for suportado - certamente é o menos preciso, pois ele tenta prever o futuro.
22418 Bob
Indiscutivelmente, ETag/ If-None-Matche outras somas de verificação são mais confiáveis ​​do que If-Modified-Sincetambém. De qualquer forma, esses comentários apenas tentam expor as suposições da resposta (ou seja, que -zassume o suporte do servidor) - o método básico deve ser bastante fácil de se adaptar a outros algoritmos de verificação de alterações.
22418 Bob
1
sinta-se à vontade para escrever uma resposta implementando uma solução baseada no ETag. Se for bom, eu vou votar. e então alguém aparecerá e indicará que nem todos os servidores da web fornecem um cabeçalho Etag :).
cas
1

Outra alternativa é usar um sistema de construção que use somas de verificação de dependência para determinar se é necessário acionar reconstruções. Eu usei o truque do "toque" com o Gnu Make, mas é muito mais simples quando você pode especificar dependências dinâmicas e quando arquivos que não são alterados não acionam reconstruçõ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
user5484700
fonte
Em vez de -X HEAD, a página de manual do curl recomenda o uso de -I: "(-X) altera apenas a palavra real usada na solicitação HTTP, não altera a maneira como o curl se comporta. Portanto, por exemplo, se você deseja fazer uma solicitação HEAD adequada, use -X HEAD não será suficiente. Você precisa usar a opção -I, - head. "
LightStruk