¿Cómo puedo usar archivos de HTTP como requisitos previos en GNU make?

10

Quiero usar archivos de la World Wide Web como requisitos previos en mis archivos MAKE:

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

Solo quiero "transfigurar" si el archivo remoto es más nuevo que el archivo local, al igual que make normalmente opera.

Yo no quiero mantener una copia en caché de example.gz - los archivos son grandes, y no necesito los datos en bruto. Preferiblemente, me gustaría evitar descargar el archivo. El objetivo es procesar algunos de estos en paralelo usando la -jbandera make.

¿Cuál es una forma limpia de resolver esto? Se me ocurren algunos caminos a seguir:

  • Mantenga un archivo ficticio vacío guardado, actualizado cada vez que se recrea el objetivo
  • Algunos complementos que usan el nuevo sistema de complementos de GNU make (del que no sé nada)
  • Una forma independiente de hacer montajes de servidores HTTP en el sistema de archivos local

Antes de seguir investigando, me gustaría un consejo, ¡preferiblemente ejemplos específicos!

tubo
fuente

Respuestas:

15

Pruebe algo como esto en su 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 es un Makefile, por lo que las sangrías son pestañas, no espacios. Por supuesto. También es importante que no haya espacios después \de las líneas de continuación; alternativamente, elimine los escapes de barra invertida y hágalo uno largo, línea casi ilegible)

Esta makereceta de GNU primero verifica que example.gzexista un archivo llamado (porque lo vamos a usar con -zin curl), y lo crea con touchsi no es así. El toque lo crea con una marca de tiempo de 00:00 (12am del día actual).

Luego usa curlla opción 's -z( --time-cond) para descargar solo example.gzsi se ha modificado desde la última vez que se descargó. -zse le puede dar una expresión de fecha real o un nombre de archivo. Si se le da un nombre de archivo, utilizará la hora de modificación del archivo como condición de tiempo.

Después de eso, si local.datno existe, lo crea con touchuna marca de tiempo que es más antigua que la de example.gz. Esto es necesario porque local.dattiene que existir para que el siguiente comando lo use statpara obtener su marca de tiempo mtime.

Entonces, si example.gztiene una marca de tiempo más reciente que local.dat, tuberías de TI example.gzen transmogrifyy redirige la salida a local.dat.

Finalmente, hace las tareas de contabilidad y limpieza:

  • se trunca example.gz(porque solo necesita mantener una marca de tiempo, y no todo el archivo)
  • touches example.gzpara que tenga la misma marca de tiempo quelocal.dat

El objetivo .PHONY asegura que el local.datobjetivo siempre se ejecute, incluso si el archivo con ese nombre ya existe.

Gracias a @Toby Speight por señalar en los comentarios que mi versión original no funcionaría y por qué.

Alternativamente, si desea canalizar el archivo directamente transmogrifysin descargarlo primero en el sistema de archivos:

.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: esto no se ha probado en su mayoría, por lo que puede requerir algunos cambios menores para obtener la sintaxis correcta Lo importante aquí es el método, no una solución de culto de carga de copiar y pegar.

He estado usando variaciones de este método (es decir, touchmarcando un archivo de marca de tiempo) makedurante décadas. Funciona, y generalmente me permite evitar tener que escribir mi propio código de resolución de dependencia en sh (aunque he tenido que hacer algo similar stat --printf %Yaquí).

Todo el mundo sabe que makees una gran herramienta para compilar software ... En mi opinión, también es una herramienta muy subestimada para las tareas de administración de scripts y administración del sistema.

cas
fuente
1
La -zbandera, por supuesto, supone que el servidor remoto usa If-Modified-Sinceencabezados. Esto podría no ser necesariamente el caso. Dependiendo de la configuración del servidor, es posible que deba hacer algo con ETag, o al verificar los Cache-Controlencabezados, o al verificar un archivo de suma de verificación por separado (por ejemplo, si el servidor proporciona un sha1sum).
Bob
Sí lo hace. pero sin eso, no hay forma de hacer lo que quiere el OP (a menos que esté dispuesto a descargar el archivo enorme en un archivo temporal cada vez que lo ejecuta make, usar cmpo algo para comparar archivos viejos y nuevos, y mv newfile oldfilesi son diferentes) . Por cierto, los encabezados de control de caché no le dicen si el archivo es más nuevo que un momento dado. te dicen por cuánto tiempo los administradores del servidor quieren que guardes en caché un archivo determinado, y los droides de marketing a menudo los usan como una práctica para eliminar caché para "mejorar" sus estadísticas web.
cas
ETag es otra forma de hacerlo, ya que es un archivo de suma de verificación separado. Todo depende de cómo esté configurado el servidor. Por ejemplo, uno podría obtener cdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA1SUMS y verificar si ha cambiado antes de decidir obtener el ISO completo. ETag hace lo mismo, usando un encabezado en lugar de un archivo separado (y, como If-Modified-Since, depende del servidor HTTP que lo implementa). Cache-Controlsería una opción de último recurso antes de descargar el archivo si no se admiten otros métodos; ciertamente es el menos preciso ya que trata de predecir el futuro.
Bob
Podría decirse que ETag/ If-None-Matchy otras sumas de verificación son más confiables que If-Modified-Sincetambién. En cualquier caso, estos comentarios solo intentan exponer los supuestos de la respuesta (es decir, que -zasume el soporte del servidor): el método básico debería ser bastante fácil de adaptar a otros algoritmos de verificación de cambios.
Bob
1
no dude en escribir una respuesta implementando una solución basada en ETag. Si es bueno, lo votaré. y luego alguien vendrá y señalará que no todos los servidores web proporcionan un encabezado Etag :).
cas
1

Otra alternativa es usar un sistema de compilación que use sumas de verificación de dependencia para determinar si se activarán las reconstrucciones. He usado el truco "táctil" con Gnu Make mucho, pero es mucho más simple cuando puedes especificar dependencias dinámicas y cuando los archivos que no cambian no desencadenan reconstrucciones. Aquí hay un ejemplo 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
usuario5484700
fuente
En lugar de -X HEAD, la página de manual de curl recomienda usar -I: "(-X) solo cambia la palabra real utilizada en la solicitud HTTP, no altera el comportamiento de curl. Entonces, por ejemplo, si desea hacer una solicitud HEAD adecuada, use -X HEAD no será suficiente. Necesitas usar la opción -I, - head ".
LightStruk