GNU make에서 HTTP의 파일을 전제 조건으로 사용하려면 어떻게해야합니까?


10

나는 파일을 사용하고자하는 월드 와이드 웹 내 메이크의 전제 조건으로 :

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

make가 정상적으로 작동하는 것처럼 원격 파일이 로컬 파일보다 최신 버전 인 경우에만 "변환"하고 싶습니다 .

나는 할 수 없습니다 의 캐시 된 복사본을 유지하려는 example.gz를 파일이 크고, 나는 원시 데이터를 필요로하지 않습니다 -. 바람직하게는 파일 다운로드를 전혀 피하고 싶습니다. 목표는 -jmake 플래그를 사용하여 이들 중 몇 가지를 병렬로 처리하는 것입니다.

이것을 해결하는 확실한 방법은 무엇입니까? 몇 가지 방법을 생각할 수 있습니다.

  • 빈 더미 파일을 보관하고 대상을 다시 만들 때마다 업데이트하십시오.
  • GNU make의 새로운 플러그인 시스템을 사용하는 일부 플러그인 (아무것도 모른다)
  • 로컬 파일 시스템에 HTTP 서버를 마운트하는 독립적 인 방법

더 파고 들기 전에 몇 가지 조언, 바람직하게는 구체적인 예를 원합니다!

답변:


15

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

(참고 : 이것은 Makefile이므로 들여 쓰기는 공백이 아니라 탭입니다. 물론 \연속 선 뒤에 공백이 없어야합니다. 또는 백 슬래시 이스케이프를 제거하고 길게 만들 수도 있습니다. 거의 읽을 수없는 줄)

이 GNU make레시피는 먼저 example.gz( -z에서 와 함께 사용하기 때문에) 라는 파일이 존재 하는지 확인하고 그렇지 않은 경우 파일을 curl만듭니다 touch. 터치하면 00:00 (오늘 오전 12시)의 타임 스탬프로 터치를 만듭니다.

그런 다음 사용 curl-z( --time-cond만 다운로드) 옵션을 example.gz그것을 다운로드 한 마지막 시간 이후 수정 된 경우. -z실제 날짜 표현 또는 파일 이름을 지정할 수 있습니다. 파일 이름이 제공되면 파일의 수정 시간을 시간 조건으로 사용합니다.

그런 다음 local.dat존재하지 않는 경우 시간 보다 오래된touch 타임 스탬프를 사용하여로 만듭니다 . 이것은 mtime 타임 스탬프를 얻기 위해 다음 명령을 사용 하기 위해 필요하기 때문에 필요 합니다 .example.gzlocal.datstat

그런 다음 example.gz보다 최신 타임 스탬프가있는 경우 local.dat파이프 example.gztransmogrify출력을로 리디렉션합니다 local.dat.

마지막으로 부기 및 정리 작업을 수행합니다.

  • example.gz전체 파일이 아닌 타임 스탬프 만 유지하면되기 때문에 잘립니다.
  • touches example.gz와 동일한 타임 스탬프를 갖도록local.dat

.PHONY 대상은 local.dat해당 이름의 파일이 이미 존재하더라도 대상이 항상 실행 되도록 합니다.

원래 버전이 작동하지 않는다는 의견을 지적한 @Toby Speight와 그 이유에 감사드립니다.

또는 transmogrify먼저 파일 시스템으로 파일을 다운로드하지 않고 파일을 직접 파이프하려는 경우 :

.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

참고 : 이것은 대부분 테스트되지 않았으므로 구문을 정확하게 얻으려면 약간의 변경이 필요할 수 있습니다. 여기서 중요한 것은 복사 붙여 넣기 카고 컬트 솔루션이 아닌 방법입니다.

나는 수십 년 동안 이 방법의 변형 (예 : touch타임 스탬프 파일)을 사용 make해 왔습니다. 그것은 작동하며 일반적으로 sh로 자신의 의존성 해결 코드를 작성하지 않아도됩니다 ( stat --printf %Y여기서는 비슷한 작업을 수행해야했지만 ).

누구나 알고있는 make것은 소프트웨어 컴파일을위한 훌륭한 도구입니다 ... IMO는 또한 시스템 관리 및 스크립팅 작업을위한 매우 과소 평가 된 도구입니다.


1
-z플래그는 물론, 원격 서버가 사용하는 가정 If-Modified-Since헤더를. 반드시 그런 것은 아닙니다. 서버 설정에 따라 대신 ETag, 또는 Cache-Control헤더를 확인하거나 별도의 체크섬 파일을 확인하여 (예 : 서버가를 제공하는 경우 sha1sum) 무언가를 수행해야 할 수도 있습니다 .
Bob

예, 그렇습니다. 그러나 그것 없이는 OP가 원하는 것을 할 수있는 방법이 전혀 없습니다 (거대한 파일을 실행할 때마다 임시 파일로 기꺼이 다운로드 하거나 이전 파일과 새 파일을 비교하기 위해 make사용 cmp하거나 무언가를 원치 않는 한 mv newfile oldfile다른 경우) . BTW, 캐시 제어 헤더는 파일이 주어진 시간보다 최신인지 알려주지 않습니다. 그들은 서버 관리자가 당신이 주어진 파일을 캐시하기를 원하는 시간을 알려줍니다-그리고 종종 웹 통계를 "개선"하기 위해 캐시 버스 팅 연습으로 마케팅 드로이드에 의해 사용됩니다.
cas

ETag 입니다 별도의 체크섬 파일로 그 일을하는 또 다른 방법은. 서버 설정 방법에 따라 다릅니다. 예를 들어, cdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA1SUMS 를 가져 와서 전체 ISO를 가져 오기로 결정하기 전에 변경되었는지 확인할 수 있습니다 . ETag는 별도의 파일 대신 헤더를 사용하여 동일한 작업을 수행합니다 (와 같이 If-Modified-Since이를 구현하는 HTTP 서버에 의존 함). Cache-Control다른 방법이 지원되지 않는 경우 파일을 다운로드하지 않는 마지막 복원 옵션이 될 것입니다. 미래를 예측하려고 시도 할 때 가장 정확하지는 않습니다.
Bob

틀림없이 ETag/ If-None-Match및 다른 체크섬도보다 신뢰할 수 If-Modified-Since있습니다. 어쨌든 이러한 의견은 대답의 가정 (즉, -z서버 지원 을 가정)을 제시하려고 시도 합니다. 기본 방법은 다른 변경 검사 알고리즘에 쉽게 적응할 수 있어야합니다.

1
ETag를 기반으로 솔루션을 구현하는 답변을 자유롭게 작성하십시오. 그것이 좋다면, 나는 그것을 찬성합니다. 그런 다음 누군가가 와서 모든 웹 서버가 Etag 헤더를 제공하는 것은 아니라고 지적합니다 :).
cas

1

또 다른 대안은 종속성 체크섬을 사용하는 빌드 시스템을 사용하여 재구성을 트리거할지 여부를 결정하는 것입니다. Gnu Make와 함께 "터치"트릭을 많이 사용했지만 동적 종속성을 지정할 수 있고 변경되지 않은 파일이 재 구축을 트리거하지 않는 경우 훨씬 간단합니다. 다음은 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

대신에 -X HEAD컬의 맨 페이지가 사용을 권장, -I"(-X)에만 HTTP 요청에 사용 된 실제 단어를 변경, 그것은 방법 컬 동작합니다 변경되지 않습니다 그래서 예를 들어 당신이 -X HEAD를 사용하여 적절한 HEAD 요청을 만들고 싶어. 충분하지 않습니다. -I,-head 옵션을 사용해야합니다. "
LightStruk
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.