ฉันจะใช้ไฟล์จาก HTTP เป็นสิ่งที่จำเป็นต้องมีใน GNU ได้อย่างไร


10

ฉันต้องการใช้ไฟล์จากเวิลด์ไวด์เว็บเป็นข้อกำหนดเบื้องต้นใน makefiles ของฉัน:

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

ฉันแค่ต้องการ "ส่งผ่าน" หากไฟล์รีโมตใหม่กว่าไฟล์โลคัลเช่นเดียวกับที่ทำให้ใช้งานได้ตามปกติ

ฉันไม่ต้องการเก็บตัวอย่าง example.gz ที่เก็บไว้ชั่วคราว- ไฟล์มีขนาดใหญ่และฉันไม่ต้องการข้อมูลดิบ ฉันต้องการหลีกเลี่ยงการดาวน์โหลดไฟล์ทั้งหมด เป้าหมายคือการประมวลผลสองสามขนานพร้อมกันโดยใช้-jแฟล็ก make

วิธีที่สะอาดในการแก้ปัญหานี้คืออะไร? ฉันสามารถนึกถึงวิธีไปสองสามวิธี:

  • เก็บไฟล์ดัมมี่ที่ว่างเปล่าออกไปอัพเดตทุกครั้งที่เป้าหมายถูกสร้างขึ้นใหม่
  • ปลั๊กอินบางตัวที่ใช้ระบบปลั๊กอินใหม่ของ 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 ดังนั้นการเยื้องเป็นแท็บไม่ใช่การเว้นวรรคแน่นอนมันเป็นสิ่งสำคัญเช่นกันที่ไม่มีช่องว่างหลังจาก\บนบรรทัดการต่อเนื่อง - หรือกำจัด backslash-escapes และทำให้ยาวหนึ่งครั้ง เกือบจะไม่สามารถอ่านบรรทัด)

นี้ GNU makeสูตรตรวจสอบก่อนว่าไฟล์ที่เรียกว่าexample.gzมีอยู่ (เพราะเรากำลังจะใช้มันกับ-zในcurl) และสร้างมันด้วยtouchถ้ามันไม่ได้ การสัมผัสสร้างด้วยเวลาประทับ 00:00 น. (12.00 น. ของวันปัจจุบัน)

จากนั้นก็จะใช้curl's -z( --time-cond) ตัวเลือกในการดาวน์โหลดเฉพาะexample.gzถ้ามันได้รับการแก้ไขตั้งแต่ครั้งสุดท้ายที่ถูกดาวน์โหลด -zสามารถได้รับการแสดงออกวันที่จริงหรือชื่อไฟล์ หากได้รับชื่อไฟล์มันจะใช้เวลาแก้ไขของไฟล์เป็นเงื่อนไขเวลา

หลังจากนั้นหากlocal.datไม่ได้อยู่มันจะสร้างมันด้วยtouchการใช้การประทับเวลารับประกันว่าจะเก่าexample.gzกว่า สิ่งนี้จำเป็นเนื่องจากlocal.datจะต้องมีอยู่สำหรับคำสั่งถัดไปเพื่อใช้statในการรับการประทับเวลา mtime

จากนั้นหากexample.gzมีการประทับเวลาใหม่กว่าlocal.datมันท่อexample.gzเข้าและการเปลี่ยนเส้นทางออกไปtransmogrifylocal.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)
บ๊อบ

ใช่. แต่ถ้าไม่มีอย่างนั้นก็ไม่มีทางทำสิ่งที่ OP ต้องการ (นอกเสียจากว่าเขายินดีที่จะดาวน์โหลดไฟล์ขนาดใหญ่ไปยังไฟล์ temp ทุกครั้งที่เขาเรียกmakeใช้ใช้cmpหรืออย่างใดอย่างหนึ่งเพื่อเปรียบเทียบไฟล์เก่าและใหม่และmv newfile oldfileถ้ามันต่างกัน) . BTW ส่วนหัวควบคุมแคชจะไม่บอกคุณว่าไฟล์นั้นใหม่กว่าเวลาที่กำหนด พวกเขาบอกคุณว่าผู้ดูแลเซิร์ฟเวอร์ต้องการให้คุณแคชไฟล์ที่กำหนดไว้นานแค่ไหนและมักจะถูกใช้โดยนักการตลาดด้านการตลาดเพื่อเป็นวิธีปฏิบัติที่ป้องกันการแคชเพื่อ "ปรับปรุง" สถิติเว็บของพวกเขา
cas

ETag เป็นอีกวิธีในการทำเช่นเดียวกับไฟล์ checksum แยกต่างหาก ทุกอย่างขึ้นอยู่กับการตั้งค่าเซิร์ฟเวอร์ ตัวอย่างเช่นหนึ่งอาจดึงcdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA1SUMSและตรวจสอบว่ามีการเปลี่ยนแปลงก่อนที่จะเรียก ISO เต็ม ETag ทำสิ่งเดียวกันโดยใช้ส่วนหัวแทนที่จะเป็นไฟล์แยกต่างหาก (และเช่นIf-Modified-Sinceนั้นต้องอาศัยเซิร์ฟเวอร์ HTTP ที่ใช้งาน) Cache-Controlจะเป็นตัวเลือกสุดท้ายแทนการดาวน์โหลดไฟล์หากไม่มีวิธีอื่นรองรับ - เป็นวิธีที่แม่นยำที่สุดในการทำนายอนาคต
บ๊อบ

เนื้อหาETag/ If-None-Matchเช็คซัมอื่น ๆ มีความน่าเชื่อถือมากกว่าIf-Modified-Sinceเช่นกัน ไม่ว่าในกรณีใดความคิดเห็นเหล่านี้จะพยายามจัดทำข้อสันนิษฐานของคำตอบ (นั่นคือ-zสมมติว่ารองรับเซิร์ฟเวอร์) - วิธีการพื้นฐานควรง่ายต่อการปรับให้เข้ากับอัลกอริทึมการตรวจสอบการเปลี่ยนแปลงอื่น ๆ
บ๊อบ

1
อย่าลังเลที่จะเขียนคำตอบการใช้โซลูชันบนพื้นฐานของ ETag ถ้าเป็นเรื่องที่ดีฉันจะโหวตมัน จากนั้นบางคนจะเข้ามาและชี้ให้เห็นว่าไม่ใช่ทุกเว็บเซิร์ฟเวอร์ที่มีส่วนหัว Etag :)
cas

1

อีกทางเลือกหนึ่งคือการใช้ระบบสร้างที่ใช้การตรวจสอบการพึ่งพาเพื่อตรวจสอบว่าจะก่อให้เกิดการสร้างใหม่ ฉันใช้เคล็ดลับ "touch" กับ Gnu Make a lot แต่มันง่ายกว่ามากเมื่อคุณสามารถระบุการพึ่งพาแบบไดนามิกและเมื่อไฟล์ที่ไม่เปลี่ยนแปลงไม่ได้สร้างทริกเกอร์ใหม่ นี่คือตัวอย่างการใช้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เป็น manpage ของ curl แนะนำให้ใช้-I: "(-X) เพียงเปลี่ยนคำจริงที่ใช้ในคำขอ HTTP แต่จะไม่เปลี่ยนวิธีการทำงานของ curl ดังนั้นตัวอย่างเช่นหากคุณต้องการทำการร้องขอ HEAD ที่เหมาะสมโดยใช้ -X HEAD จะไม่พอคุณต้องใช้ตัวเลือก -I, -
LightStruk
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.