Come posso usare i file da HTTP come prerequisiti in GNU?


10

Voglio usare i file dal World Wide Web come prerequisiti nei miei makefile:

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

Voglio "transmogrificare" solo se il file remoto è più recente del file locale, proprio come make normalmente funziona.

Io non voglio mantenere una copia cache della example.gz - i file sono grandi, e non ho bisogno di dati grezzi. Preferibilmente vorrei evitare di scaricare il file. L'obiettivo è quello di elaborare alcuni di questi in parallelo usando il -jflag make.

Qual è un modo pulito per risolvere questo? Posso pensare ad alcuni modi per andare:

  • Tenere un file fittizio vuoto nascosto, aggiornato ogni volta che viene ricreata la destinazione
  • Alcuni plugin che usano il nuovo sistema di plugin di GNU make (di cui non so nulla)
  • Un metodo indipendente che monta i server HTTP nel filesystem locale

Prima di approfondire, vorrei qualche consiglio, preferibilmente esempi specifici!

Risposte:


15

Prova qualcosa del genere nel tuo 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: questo è un Makefile, quindi i rientri sono tabulazioni, non spazi. Naturalmente. È anche importante che non ci siano spazi dopo le \righe di continuazione - in alternativa sbarazzarsi delle backslash-escape e renderlo lungo, linea quasi illeggibile)

Questa makericetta GNU controlla prima che example.gzesista un file chiamato (perché lo useremo con -zin curl), e lo crea con touchse non lo fa. Il tocco lo crea con un timestamp di 00:00 (12:00 del giorno corrente).

Quindi utilizza curll' opzione -z( --time-cond) per scaricare solo example.gzse è stato modificato dall'ultima volta in cui è stato scaricato. -zpuò essere data un'espressione data effettiva o un nome file. Se viene assegnato un nome file, utilizzerà l'ora di modifica del file come condizione temporale.

Dopodiché, se local.datnon esiste, lo crea con touch, usando un timestamp garantito per essere più vecchio di quello di example.gz. Ciò è necessario perché local.datdeve esistere il comando successivo da utilizzare statper ottenere il timestamp mtime.

Poi, se example.gzha un timestamp più recente rispetto local.dat, è tubi example.gzin transmogrifye reindirizza l'output local.dat.

Infine, fa le cose di contabilità e pulizia:

  • si tronca example.gz(perché è sufficiente mantenere un timestamp e non l'intero file)
  • touches in example.gzmodo che abbia lo stesso timestamp dilocal.dat

Il target .PHONY garantisce che il local.dattarget sia sempre eseguito, anche se il file con quel nome esiste già.

Grazie a @Toby Speight per aver sottolineato nei commenti che la mia versione originale non avrebbe funzionato, e perché.

In alternativa, se si desidera reindirizzare il file direttamente transmogrifysenza scaricarlo prima nel filesystem:

.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: questo è per lo più non testato, quindi potrebbero essere necessarie alcune piccole modifiche per ottenere la sintassi esattamente corretta. La cosa importante qui è il metodo, non una soluzione cargo-cult copia-incolla.

Sto usando le varianti di questo metodo (ad esempio touch-ing un file timestamp) con makeper decenni. Funziona e di solito mi consente di evitare di dover scrivere il mio codice di risoluzione della dipendenza in sh (anche se ho dovuto fare qualcosa di simile con stat --printf %Yqui).

Tutti sanno che makeè un ottimo strumento per la compilazione di software ... IMO è anche uno strumento molto sottovalutato per le attività di amministrazione e scripting del sistema.


1
Il -zflag, ovviamente, presuppone che il server remoto utilizzi le If-Modified-Sinceintestazioni. Questo potrebbe non essere necessariamente il caso. A seconda della configurazione del server, potresti invece dover fare qualcosa con ETag, o controllando le Cache-Controlintestazioni, o controllando un file di checksum separato (ad esempio se il server fornisce a sha1sum).
Bob,

si lo fa. ma senza quello, non c'è assolutamente modo di fare ciò che l'OP vuole (a meno che non sia disposto a scaricare l'enorme file in un file temporaneo ogni volta che viene eseguito make, utilizzare cmpo altro per confrontare file vecchi e nuovi e mv newfile oldfilese sono diversi) . A proposito, le intestazioni di controllo della cache non ti dicono se il file è più recente di un determinato momento. ti dicono per quanto tempo gli amministratori del server vogliono che tu memorizzi nella cache un determinato file - e sono spesso usati dai droidi di marketing come pratica di busting della cache per "migliorare" le loro statistiche web.
Caso

ETag è un altro modo di farlo, così come un file checksum separato. Tutto dipende da come è configurato il server. Ad esempio, si potrebbe recuperare cdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA1SUMS e verificare se è cambiato prima di decidere di recuperare l'intero ISO. ETag fa la stessa cosa, usando un'intestazione anziché un file separato (e, come If-Modified-Since, si affida al server HTTP che lo implementa). Cache-Controlsarebbe un'opzione di ultima istanza a corto di scaricare il file se non sono supportati altri metodi - è certamente il meno preciso in quanto tenta di prevedere il futuro.
Bob,

Probabilmente, ETag/ If-None-Matche altri checksum sono anche più affidabili di If-Modified-Since. In ogni caso, questi commenti provano solo a delineare i presupposti della risposta (vale a dire che -zpresuppone il supporto del server) - il metodo di base dovrebbe essere abbastanza facile da adattare ad altri algoritmi di controllo delle modifiche.
Bob,

1
sentiti libero di scrivere una risposta implementando una soluzione basata su ETag. Se va bene, lo voterò. e poi qualcuno verrà e indicherà che non tutti i server Web forniscono un'intestazione Etag :).
Caso

1

Un'altra alternativa è quella di utilizzare un sistema di build che utilizza checksum di dipendenza per determinare se attivare le ricostruzioni. Ho usato molto il trucco "touch" con Gnu Make, ma è molto più semplice quando è possibile specificare dipendenze dinamiche e quando i file che non cambiano non attivano le ricostruzioni. Ecco un esempio usando 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

Invece di -X HEAD, la manpage di curl consiglia di usare -I: "(-X) cambia solo la parola effettiva usata nella richiesta HTTP, non altera il comportamento del ricciolo. Quindi, per esempio, se vuoi fare una richiesta HEAD corretta, usando -X HEAD non sarà sufficiente. Devi usare l'opzione -I, - head. "
LightStruk
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.