ไฟล์ Bazel Lock

รายงานปัญหา ดูแหล่งที่มา

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

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

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

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

การใช้งาน Lockfile

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

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

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

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

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

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

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

เนื้อหาของ Lockfile

ไฟล์ล็อกมีข้อมูลที่จำเป็นทั้งหมดเพื่อพิจารณาว่าสถานะของโปรเจ็กต์มีการเปลี่ยนแปลงหรือไม่ รวมถึงผลลัพธ์ของการสร้างโปรเจ็กต์ในสถานะปัจจุบันด้วย ไฟล์ล็อกประกอบด้วย 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 ใช้แฮชจากไฟล์ล็อกเพื่อค้นหาไฟล์รีจิสทรีในแคชของที่เก็บก่อนที่จะดาวน์โหลดไฟล์ ซึ่งช่วยให้แก้ปัญหาครั้งต่อๆ ไปได้เร็วขึ้น

เวอร์ชัน Yanked ที่เลือก

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

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

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

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

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

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

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

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

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

หากต้องการเพิ่มประโยชน์ของฟีเจอร์ล็อกไฟล์ ให้พิจารณาแนวทางปฏิบัติแนะนำต่อไปนี้

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

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

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

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