ไฟล์ Bazel Lock

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

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

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

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

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

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

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

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

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

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

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

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

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

นอกจากนี้ 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 เพื่ออัปเดตไฟล์ล็อก