Jak mogę używać plików z HTTP jako wymagań wstępnych w GNU?


10

Chcę używać plików z sieci WWW jako warunków wstępnych w moich plikach makefiles:

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

Chcę „transmogryfikować” tylko wtedy, gdy plik zdalny jest nowszy niż plik lokalny, tak jak normalnie działa make .

Ja nie chce się zachować w pamięci podręcznej kopię example.gz - pliki są duże, a ja nie potrzebuję surowych danych. Najlepiej wolałbym w ogóle unikać pobierania pliku. Celem jest przetworzenie kilku z nich równolegle przy użyciu -jflagi make.

Jaki jest czysty sposób na rozwiązanie tego problemu? Mogę wymyślić kilka sposobów:

  • Trzymaj pusty plik fikcyjny przechowywany w pamięci, aktualizowany za każdym razem, gdy cel jest odtwarzany
  • Niektóre wtyczki korzystające z nowego systemu wtyczek GNU make (o których nic nie wiem)
  • Make-agnostyczny sposób, który montuje serwery HTTP w lokalnym systemie plików

Przed dalszym kopaniem chciałbym uzyskać porady, najlepiej konkretne przykłady!

Odpowiedzi:


15

Wypróbuj coś takiego w swoim 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

(uwaga: jest to plik Makefile, więc wcięcia są tabulatorami, a nie spacjami. oczywiście. Ważne jest również to, że po \liniach kontynuacji nie ma spacji - alternatywnie pozbyć się odwrotnych ukośników i uczynić go jednym długim, prawie nieczytelna linia)

Ten makeprzepis GNU najpierw sprawdza, czy plik o nazwie example.gzistnieje (ponieważ będziemy go używać z -zin curl), i tworzy go, touchjeśli nie ma. Dotyk tworzy go ze znacznikiem czasu 00:00 (12 rano bieżącego dnia).

Następnie używa opcji curls -z( --time-cond), aby pobrać tylko, example.gzjeśli został zmodyfikowany od czasu ostatniego pobrania. -zmoże otrzymać rzeczywiste wyrażenie daty lub nazwę pliku. Jeśli podano nazwę pliku, wykorzysta czas modyfikacji pliku jako warunek czasowy.

Następnie, jeśli local.datnie istnieje, tworzy go za touchpomocą znacznika czasu, który ma być starszy niż example.gz. Jest to konieczne, ponieważ local.datmusi istnieć, aby następne polecenie statmogło uzyskać znacznik czasu mtime.

Następnie, jeśli example.gzjest nowsza niż datownik local.dat, to rury example.gzna język transmogrifyi przekierowuje dane wyjściowe local.dat.

Wreszcie zajmuje się księgowością i porządkami:

  • obcina się example.gz(ponieważ wystarczy zachować znacznik czasu, a nie cały plik)
  • touches, example.gzaby miał ten sam znacznik czasu colocal.dat

Cel .PHONY zapewnia, że local.datcel jest zawsze wykonywany, nawet jeśli plik o tej nazwie już istnieje.

Dzięki @Toby Speight za wskazanie w komentarzach, że moja oryginalna wersja nie działa i dlaczego.

Alternatywnie, jeśli chcesz bezpośrednio potokować plik transmogrifybez pobierania go najpierw do systemu plików:

.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

UWAGA: jest to w większości niesprawdzone, więc może wymagać drobnych zmian, aby uzyskać prawidłową składnię. Ważną rzeczą jest tutaj metoda, a nie rozwiązanie kultu ładunku.

Od dziesięcioleci używam odmian tej metody (tj. touch-Plikowanie pliku znacznika czasu) make. Działa i zwykle pozwala mi uniknąć pisania własnego kodu rozwiązywania zależności w sh (chociaż musiałem tutaj zrobić coś podobnego stat --printf %Y).

Wszyscy wiedzą, że makejest doskonałym narzędziem do kompilowania oprogramowania ... IMO jest również bardzo niedocenianym narzędziem do administrowania systemem i zadań skryptowych.


1
-zFlaga, oczywiście, zakłada, że zdalny serwer używa If-Modified-Sincenagłówków. To niekoniecznie musi tak być. W zależności od konfiguracji serwera może być konieczne zrobienie czegoś ETag, sprawdzenie Cache-Controlnagłówków lub sprawdzenie oddzielnego pliku sumy kontrolnej (np. Jeśli serwer udostępnia a sha1sum).
Bob

tak. ale bez tego nie ma możliwości robienia tego, czego chce OP (chyba, że ​​jest skłonny pobrać ogromny plik do pliku tymczasowego za każdym razem, gdy uruchamia się make, użyć cmplub coś do porównania starych i nowych plików, a mv newfile oldfilejeśli są różne) . BTW, nagłówki kontroli pamięci podręcznej nie mówią, czy plik jest nowszy niż określony czas. informują o tym, jak długo administratorzy serwera chcą buforować dany plik - i są często używane przez droidy marketingowe jako praktyka pomijania pamięci podręcznej w celu „poprawy” ich statystyk internetowych.
cas

ETag jest innym sposobem na zrobienie tego, podobnie jak oddzielny plik sumy kontrolnej. Wszystko zależy od konfiguracji serwera. Na przykład można pobrać cdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA1SUMS i sprawdzić, czy zmieniło się przed podjęciem decyzji o pobraniu pełnego ISO. ETag robi to samo, używając nagłówka zamiast osobnego pliku (i, podobnie jak If-Modified-Since, polega na implementacji go przez serwer HTTP). Cache-Controlbyłoby ostatnią opcją bez pobierania pliku, jeśli nie są obsługiwane żadne inne metody - jest to z pewnością najmniej dokładne, ponieważ próbuje przewidzieć przyszłość.
Bob

Prawdopodobnie ETag/ If-None-Matchi inne sumy kontrolne są również bardziej niezawodne If-Modified-Since. W każdym razie w tych komentarzach po prostu próbuje się określić założenia odpowiedzi (a mianowicie, że -zzakłada obsługę serwera) - podstawowa metoda powinna być dość łatwa do dostosowania do innych algorytmów sprawdzania zmian.
Bob

1
napisz odpowiedź implementującą rozwiązanie oparte na ETag. Jeśli coś będzie dobrego, będę go głosować. a potem ktoś przyjdzie i zwróci uwagę, że nie wszystkie serwery WWW zapewniają nagłówek Etag :).
cas

1

Inną alternatywą jest użycie systemu kompilacji, który używa sum kontrolnych zależności w celu ustalenia, czy wyzwalać przebudowy. Użyłem sztuczki „dotykowej” w Gnu Make dużo, ale jest o wiele prostsze, kiedy można określić zależności dynamiczne i gdy pliki, które się nie zmieniają, nie powodują przebudowy. Oto przykład użycia 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

Zamiast strony -X HEADcurl zaleca się użycie -I: „(-X) zmienia tylko rzeczywiste słowo użyte w żądaniu HTTP, nie zmienia to sposobu, w jaki zachowuje się curl. Na przykład jeśli chcesz wykonać prawidłowe żądanie HEAD, używając -X HEAD nie wystarczy. Musisz użyć opcji -I, - head. ”
LightStruk
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.