ไฟล์ Bazel Lock

รายงานปัญหา ดูแหล่งที่มา Nightly · 8.4 · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

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

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

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

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

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

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

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

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

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

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

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

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

    เนื่องจากการอัปเดตที่ไม่เข้ากันหรือยังไม่ได้ทดสอบ

ไฟล์ล็อกที่ซ่อนอยู่

นอกจากนี้ Bazel ยังดูแลไฟล์ล็อกอีกไฟล์ที่ "$(bazel info output_base)"/MODULE.bazel.lock รูปแบบและเนื้อหาของ ไฟล์ล็อกนี้ไม่ได้ระบุไว้อย่างชัดเจน โดยจะใช้เพื่อการเพิ่มประสิทธิภาพ เท่านั้น แม้ว่าจะลบพร้อมกับฐานเอาต์พุตผ่าน bazel clean --expunge ได้ แต่การดำเนินการดังกล่าวถือเป็นข้อบกพร่องใน 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 โดยการทำเช่นนี้จะช่วยให้มั่นใจได้ว่า เมื่อได้รับข้อมูลอินพุตเดียวกัน ระบบจะสร้างที่เก็บข้อมูลเดียวกันเสมอ

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

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

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

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

  • ใช้ bazelisk เพื่อเรียกใช้ Bazel และรวมไฟล์ .bazelversion ในการควบคุมเวอร์ชันที่ระบุเวอร์ชัน Bazel ที่สอดคล้องกับไฟล์ล็อก เนื่องจาก Bazel เองก็เป็นทรัพยากร Dependency ของบิลด์ของคุณ ไฟล์ล็อกจึงเจาะจงสำหรับ 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 เพื่ออัปเดตไฟล์ล็อก