ไฟล์ Bazel Lock

รายงานปัญหา ดูแหล่งที่มา รุ่น Nightly · 8.0 7.4 7.3 · 7.2 · 7.1 · 7.0 · 6.5

ฟีเจอร์ไฟล์ล็อกใน Bazel ช่วยให้บันทึกเวอร์ชันหรือข้อกำหนดเฉพาะของไลบรารีหรือแพ็กเกจซอฟต์แวร์ที่จําเป็นสําหรับโปรเจ็กต์ได้ โดยจัดเก็บผลลัพธ์ของการแก้ไขโมดูลและการประเมินส่วนขยาย ไฟล์ล็อกจะส่งเสริมการสร้างที่ซ้ำได้ ซึ่งช่วยให้มั่นใจได้ว่าสภาพแวดล้อมการพัฒนาจะสอดคล้องกัน นอกจากนี้ ยังช่วยเพิ่มประสิทธิภาพการสร้างโดยอนุญาตให้ Bazel ข้ามส่วนของกระบวนการแก้ไขที่ไม่ได้รับผลกระทบจากการเปลี่ยนแปลงในข้อกำหนดของโปรเจ็กต์ นอกจากนี้ ไฟล์ล็อกยังช่วยเพิ่มความเสถียรด้วยการป้องกันการอัปเดตที่ไม่คาดคิดหรือการเปลี่ยนแปลงที่ทำให้เกิดข้อบกพร่องในไลบรารีภายนอก ซึ่งจะช่วยลดความเสี่ยงที่จะเกิดข้อบกพร่อง

การสร้างไฟล์ล็อก

ระบบจะสร้างไฟล์ล็อกภายใต้รูทของพื้นที่ทำงานโดยใช้ชื่อ MODULE.bazel.lock ไฟล์นี้สร้างขึ้นหรืออัปเดตระหว่างกระบวนการบิลด์ โดยเฉพาะอย่างยิ่งหลังจากการแก้ไขข้อผิดพลาดของข้อบังคับและการประเมินส่วนขยาย ที่สำคัญคือ จะรวมเฉพาะข้อมูลที่ต้องพึ่งพาซึ่งรวมอยู่ในการเรียกใช้ปัจจุบันของบิลด์เท่านั้น

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

การใช้งานไฟล์ล็อก

คุณควบคุมไฟล์ล็อกได้ด้วย Flag --lockfile_mode เพื่อปรับแต่งลักษณะการทํางานของ Bazel เมื่อสถานะโปรเจ็กต์แตกต่างจากไฟล์ล็อก โหมดที่ใช้ได้มีดังนี้

  • update (ค่าเริ่มต้น): ใช้ข้อมูลที่มีอยู่ในไฟล์ล็อกเพื่อข้ามการดาวน์โหลดไฟล์รีจิสทรีที่รู้จัก และหลีกเลี่ยงการประเมินส่วนขยายอีกครั้งซึ่งผลลัพธ์ยังคงเป็นปัจจุบัน หากข้อมูลขาดหายไป ระบบจะเพิ่มข้อมูลดังกล่าวลงในไฟล์ล็อก ในโหมดนี้ Bazel ยังหลีกเลี่ยงการรีเฟรชข้อมูลที่มีการเปลี่ยนแปลงได้ เช่น เวอร์ชันที่ยกเลิกไปแล้ว สำหรับข้อมูลที่ต้องพึ่งพาซึ่งไม่มีการเปลี่ยนแปลง
  • refresh: เหมือนกับ update แต่ระบบจะรีเฟรชข้อมูลที่เปลี่ยนแปลงได้ทุกครั้งเมื่อเปลี่ยนไปใช้โหมดนี้ และทุกๆ ชั่วโมงโดยประมาณขณะอยู่ในโหมดนี้
  • error: เหมือนกับ update แต่หากข้อมูลขาดหายไปหรือไม่เป็นปัจจุบัน Bazel จะดำเนินการไม่สำเร็จและแสดงข้อผิดพลาด โหมดนี้จะไม่เปลี่ยนแปลงไฟล์ล็อกหรือส่งคำขอเครือข่ายระหว่างการแก้ไข ส่วนขยายโมดูลที่ทําเครื่องหมายเป็น reproducible อาจยังคงส่งคําขอเครือข่ายอยู่ แต่คาดว่าจะให้ผลลัพธ์แบบเดิมเสมอ
  • off: ระบบไม่ได้ตรวจสอบหรืออัปเดตไฟล์ล็อก

ประโยชน์ของไฟล์ล็อก

ไฟล์ล็อกมีประโยชน์หลายอย่างและนำไปใช้ได้หลายวิธี ดังนี้

  • บิลด์ที่ทำซ้ำได้ การบันทึกเวอร์ชันหรือทรัพยากร Dependency ที่เจาะจงของไลบรารีซอฟต์แวร์จะทำให้ไฟล์ล็อกช่วยให้มั่นใจได้ว่าบิลด์จะสร้างซ้ำได้ในทุกสภาพแวดล้อมและเมื่อเวลาผ่านไป นักพัฒนาแอปสามารถวางใจผลลัพธ์ที่สอดคล้องกันและคาดการณ์ได้เมื่อสร้างโปรเจ็กต์

  • การแก้ปัญหาที่รวดเร็วยิ่งขึ้น ไฟล์ล็อกช่วยให้ Bazel หลีกเลี่ยงการดาวน์โหลดไฟล์รีจิสทรีที่ใช้ไปแล้วในบิลด์ก่อนหน้า วิธีนี้ช่วยเพิ่มประสิทธิภาพการสร้างได้อย่างมาก โดยเฉพาะในสถานการณ์ที่การแก้ปัญหาอาจใช้เวลานาน

  • ความเสถียรและการลดความเสี่ยง ไฟล์ล็อกจะช่วยรักษาเสถียรภาพโดยป้องกันไม่ให้มีการอัปเดตที่ไม่คาดคิดหรือการเปลี่ยนแปลงที่ทำให้เกิดข้อขัดข้องในไลบรารีภายนอก การล็อกการพึ่งพาไว้กับเวอร์ชันที่เจาะจงจะช่วยลดความเสี่ยงที่จะเกิดข้อบกพร่องเนื่องจากการอัปเดตที่เข้ากันไม่ได้หรือไม่ผ่านการทดสอบ

เนื้อหาไฟล์ล็อก

ไฟล์ล็อกมีข้อมูลที่จำเป็นทั้งหมดเพื่อระบุว่าสถานะโปรเจ็กต์มีการเปลี่ยนแปลงหรือไม่ รวมถึงผลลัพธ์ของการสร้างโปรเจ็กต์ในสถานะปัจจุบันด้วย ไฟล์ล็อกประกอบด้วย 2 ส่วนหลัก ได้แก่

  1. แฮชของไฟล์ระยะไกลทั้งหมดที่เป็นอินพุตในการแก้ไขข้อผิดพลาดของโมดูล
  2. สําหรับส่วนขยายโมดูลแต่ละรายการ ไฟล์ล็อกจะมีอินพุตที่ส่งผลต่อส่วนขยายนั้น ซึ่งแสดงด้วย bzlTransitiveDigest, usagesDigest และช่องอื่นๆ ตลอดจนเอาต์พุตของการเรียกใช้ส่วนขยายนั้น ซึ่งเรียกว่า generatedRepoSpecs

ต่อไปนี้คือตัวอย่างที่แสดงโครงสร้างของไฟล์ล็อก พร้อมคำอธิบายของแต่ละส่วน

{
  "lockFileVersion": 10,
  "registryFileHashes": {
    "https://bcr.bazel.build/bazel_registry.json": "8a28e4af...5d5b3497",
    "https://bcr.bazel.build/modules/foo/1.0/MODULE.bazel": "7cd0312e...5c96ace2",
    "https://bcr.bazel.build/modules/foo/2.0/MODULE.bazel": "70390338... 9fc57589",
    "https://bcr.bazel.build/modules/foo/2.0/source.json": "7e3a9adf...170d94ad",
    "https://registry.mycorp.com/modules/foo/1.0/MODULE.bazel": "not found",
    ...
  },
  "selectedYankedVersions": {
    "foo@2.0": "Yanked for demo purposes"
  },
  "moduleExtensions": {
    "//:extension.bzl%lockfile_ext": {
      "general": {
        "bzlTransitiveDigest": "oWDzxG/aLnyY6Ubrfy....+Jp6maQvEPxn0pBM=",
        "usagesDigest": "aLmqbvowmHkkBPve05yyDNGN7oh7QE9kBADr3QIZTZs=",
        ...,
        "generatedRepoSpecs": {
          "hello": {
            "bzlFile": "@@//:extension.bzl",
            ...
          }
        }
      }
    },
    "//:extension.bzl%lockfile_ext2": {
      "os:macos": {
        "bzlTransitiveDigest": "oWDzxG/aLnyY6Ubrfy....+Jp6maQvEPxn0pBM=",
        "usagesDigest": "aLmqbvowmHkkBPve05y....yDNGN7oh7r3QIZTZs=",
        ...,
        "generatedRepoSpecs": {
          "hello": {
            "bzlFile": "@@//:extension.bzl",
            ...
          }
        }
      },
      "os:linux": {
        "bzlTransitiveDigest": "eWDzxG/aLsyY3Ubrto....+Jp4maQvEPxn0pLK=",
        "usagesDigest": "aLmqbvowmHkkBPve05y....yDNGN7oh7r3QIZTZs=",
        ...,
        "generatedRepoSpecs": {
          "hello": {
            "bzlFile": "@@//:extension.bzl",
            ...
          }
        }
      }
    }
  }
}

แฮชไฟล์รีจิสทรี

ส่วน registryFileHashes มีแฮชของไฟล์ทั้งหมดจากรีจิสทรีระยะไกลที่เข้าถึงระหว่างการแก้ไขข้อขัดข้องของโมดูล เนื่องจากอัลกอริทึมการแก้ปัญหาเป็นแบบกำหนดได้ทั้งหมดเมื่อได้รับอินพุตเดียวกันและอินพุตระยะไกลทั้งหมดได้รับการแฮช การดำเนินการนี้จึงช่วยให้ได้ผลลัพธ์การแก้ปัญหาที่ซ้ำกันได้โดยสมบูรณ์ ขณะเดียวกันก็หลีกเลี่ยงการซ้ำกันของข้อมูลระยะไกลในไฟล์ล็อกมากเกินไป โปรดทราบว่าการดำเนินการนี้ยังกำหนดให้บันทึกด้วยเมื่อรีจิสทรีหนึ่งๆ ไม่มีโมดูลหนึ่งๆ แต่รีจิสทรีที่มีลําดับความสําคัญต่ำกว่ามี (ดูรายการ "ไม่พบ" ในตัวอย่าง) ข้อมูลที่มีการเปลี่ยนแปลงได้อยู่แล้วนี้สามารถอัปเดตได้ผ่าน bazel mod deps --lockfile_mode=refresh

Bazel ใช้แฮชจากไฟล์ล็อกเพื่อค้นหาไฟล์รีจิสทรีในแคชที่เก็บก่อนที่จะดาวน์โหลด ซึ่งจะช่วยเร่งการแก้ไขในภายหลัง

เวอร์ชันที่ดึงออกซึ่งเลือกไว้

ส่วน selectedYankedVersions มีโมดูลเวอร์ชันที่ดึงออกซึ่งเลือกตามความละเอียดของโมดูล เนื่องจากการดำเนินการนี้มักจะทำให้เกิดข้อผิดพลาดเมื่อพยายามสร้าง ส่วนนี้จึงจะไม่ว่างเปล่าก็ต่อเมื่อมีการอนุญาตเวอร์ชันที่ดึงออกอย่างชัดเจนผ่าน --allow_yanked_versions หรือ BZLMOD_ALLOW_YANKED_VERSIONS

จำเป็นต้องใช้ช่องนี้เนื่องจากข้อมูลเวอร์ชันที่ดึงออกจะเปลี่ยนแปลงได้อยู่แล้วโดยเนื้อแท้เมื่อเทียบกับไฟล์โมดูล จึงไม่สามารถอ้างอิงด้วยแฮช ข้อมูลนี้อัปเดตได้ผ่าน bazel mod deps --lockfile_mode=refresh

ส่วนขยายของโมดูล

ส่วน moduleExtensions คือแผนที่ที่มีเฉพาะส่วนขยายที่ใช้ในการเรียกใช้ปัจจุบันหรือเรียกใช้ก่อนหน้านี้ โดยไม่รวมส่วนขยายที่ไม่ได้ใช้งานแล้ว กล่าวคือ หากไม่มีการใช้ส่วนขยายในกราฟความเกี่ยวข้องอีกต่อไป ระบบจะนำส่วนขยายนั้นออกจากmoduleExtensionsแผนภูมิ

หากส่วนขยายไม่ขึ้นอยู่กับระบบปฏิบัติการหรือประเภทสถาปัตยกรรม ส่วนนี้จะมีรายการ "ทั่วไป" รายการเดียว หรือจะรวมหลายรายการโดยตั้งชื่อตามระบบปฏิบัติการ สถาปัตยกรรม หรือทั้ง 2 อย่างก็ได้ โดยแต่ละรายการจะสอดคล้องกับผลการประเมินส่วนขยายในรายละเอียดเหล่านั้น

รายการแต่ละรายการในการแมปส่วนขยายจะสอดคล้องกับส่วนขยายที่ใช้และจะระบุด้วยไฟล์และชื่อที่รวมอยู่ ค่าที่สอดคล้องกันของรายการแต่ละรายการจะมีข้อมูลที่เกี่ยวข้องซึ่งเชื่อมโยงกับชิ้นงานนั้นๆ ดังนี้

  1. bzlTransitiveDigest คือข้อมูลสรุปของการใช้งานส่วนขยายและไฟล์ .bzl ที่โหลดโดยส่วนขยาย
  2. usagesDigest คือข้อมูลสรุปการใช้งานของส่วนขยายในกราฟความเกี่ยวข้อง ซึ่งรวมแท็กทั้งหมด
  3. ฟิลด์อื่นๆ ที่ไม่ได้ระบุซึ่งติดตามอินพุตอื่นๆ ไปยังส่วนขยาย เช่น เนื้อหาของไฟล์หรือไดเรกทอรีที่อ่าน หรือตัวแปรสภาพแวดล้อมที่ใช้
  4. generatedRepoSpecs จะเข้ารหัสที่เก็บข้อมูลที่ส่วนขยายสร้างขึ้นด้วยอินพุตปัจจุบัน
  5. ช่อง moduleExtensionMetadata (ไม่บังคับ) มีข้อมูลเมตาที่ส่วนขยายระบุ เช่น โมดูลรูทควรนําเข้าที่เก็บข้อมูลบางรายการที่สร้างขึ้นผ่าน use_repo หรือไม่ ข้อมูลนี้ขับเคลื่อนคำสั่ง bazel mod tidy

ส่วนขยายโมดูลสามารถเลือกไม่รวมอยู่ในไฟล์ล็อกได้โดยการตั้งค่าข้อมูลเมตาที่แสดงผลด้วย reproducible = True ซึ่งหมายความว่าเราจะสร้างที่เก็บข้อมูลเดียวกันทุกครั้งที่ได้รับอินพุตเดียวกัน

แนวทางปฏิบัติแนะนำ

ลองทำตามแนวทางปฏิบัติแนะนำต่อไปนี้เพื่อรับประโยชน์สูงสุดจากฟีเจอร์ไฟล์ล็อก

  • อัปเดตไฟล์ล็อกเป็นประจำเพื่อให้สอดคล้องกับการเปลี่ยนแปลงในข้อกำหนดหรือการกำหนดค่าของโปรเจ็กต์ วิธีนี้ช่วยให้มั่นใจได้ว่าบิลด์ต่อๆ ไปจะอิงตามชุดทรัพยากร Dependencies ที่ทันสมัยและถูกต้องที่สุด หากต้องการล็อกส่วนขยายทั้งหมดพร้อมกัน ให้เรียกใช้ bazel mod deps --lockfile_mode=update

  • รวมไฟล์ล็อกไว้ในการควบคุมเวอร์ชันเพื่ออำนวยความสะดวกในการทำงานร่วมกันและตรวจสอบว่าสมาชิกทุกคนในทีมมีสิทธิ์เข้าถึงไฟล์ล็อกเดียวกัน ซึ่งจะช่วยส่งเสริมสภาพแวดล้อมการพัฒนาที่สอดคล้องกันทั่วทั้งโปรเจ็กต์

  • ใช้ bazelisk เพื่อเรียกใช้ Bazel และรวมไฟล์ .bazelversion ในการควบคุมเวอร์ชันที่ระบุเวอร์ชัน Bazel ที่สอดคล้องกับไฟล์ล็อก เนื่องจาก Bazel เองเป็นข้อกำหนดของบิลด์ของคุณ ไฟล์ล็อกจึงใช้กับ Bazel เวอร์ชันหนึ่งๆ โดยเฉพาะ และจะเปลี่ยนแปลงแม้ในรุ่น Bazel ที่เข้ากันได้แบบย้อนหลัง การใช้ bazelisk ช่วยให้มั่นใจว่านักพัฒนาซอฟต์แวร์ทุกคนใช้ Bazel เวอร์ชันที่ตรงกับไฟล์ล็อก

การทำตามแนวทางปฏิบัติแนะนำเหล่านี้จะช่วยให้คุณใช้ฟีเจอร์ไฟล์ล็อกใน Bazel ได้อย่างมีประสิทธิภาพ ซึ่งจะนำไปสู่เวิร์กโฟลว์การพัฒนาซอฟต์แวร์ที่มีประสิทธิภาพ เชื่อถือได้ และทำงานร่วมกันได้มากขึ้น

ความขัดแย้งในการผสาน

รูปแบบไฟล์ล็อกออกแบบมาเพื่อลดความขัดแย้งในการผสาน แต่ความขัดแย้งดังกล่าวอาจยังคงเกิดขึ้นได้

การแก้ปัญหาอัตโนมัติ

Bazel มีโปรแกรมควบคุมการผสาน git ที่กำหนดเองเพื่อช่วยแก้ไขความขัดแย้งเหล่านี้โดยอัตโนมัติ

ตั้งค่าไดรเวอร์โดยเพิ่มบรรทัดนี้ลงในไฟล์ .gitattributes ที่รูทของที่เก็บ Git

# A custom merge driver for the Bazel lockfile.
# https://bazel.build/external/lockfile#automatic-resolution
MODULE.bazel.lock merge=bazel-lockfile-merge

จากนั้นนักพัฒนาแอปแต่ละรายที่ต้องการใช้ไดรเวอร์จะต้องลงทะเบียนไดรเวอร์ดังกล่าวเพียงครั้งเดียวโดยทำตามขั้นตอนต่อไปนี้

  1. ติดตั้ง jq (1.5 ขึ้นไป)
  2. เรียกใช้คำสั่งต่อไปนี้
jq_script=$(curl https://raw.githubusercontent.com/bazelbuild/bazel/master/scripts/bazel-lockfile-merge.jq)
printf '%s\n' "${jq_script}" | less # to optionally inspect the jq script
git config --global merge.bazel-lockfile-merge.name   "Merge driver for the Bazel lockfile (MODULE.bazel.lock)"
git config --global merge.bazel-lockfile-merge.driver "jq -s '${jq_script}' -- %O %A %B > %A.jq_tmp && mv %A.jq_tmp %A"

การแก้ไขด้วยตนเอง

ข้อขัดแย้งในการผสานที่ง่ายในช่อง registryFileHashes และ selectedYankedVersions สามารถแก้ไขได้อย่างปลอดภัยโดยเก็บรายการทั้งหมดจากทั้ง 2 ด้านของข้อขัดแย้งไว้

คุณไม่ควรแก้ไขข้อขัดแย้งในการผสานประเภทอื่นๆ ด้วยตนเอง ให้ดำเนินการต่อไปนี้แทน

  1. กู้คืนสถานะก่อนหน้าของไฟล์ล็อกผ่าน git reset MODULE.bazel.lock && git checkout MODULE.bazel.lock
  2. แก้ไขความขัดแย้งในไฟล์ MODULE.bazel
  3. เรียกใช้ bazel mod deps เพื่ออัปเดตไฟล์ล็อก