Nix Flakes และฟีเจอร์ของ Guix ที่สอดคล้องกัน
(coopi.neocities.org)- Nix Flakes รวบรวมการพึ่งพาของโปรเจกต์ การล็อก สคีมาของเอาต์พุต และสภาพแวดล้อมสำหรับพัฒนาไว้โดยมี
flake.nixและflake.lockเป็นศูนย์กลาง ส่วน Guix มอบความสามารถประเภทเดียวกันผ่านการผสานเครื่องมือที่แยกเป็นอิสระต่อกัน เช่น channels, manifests,guix describe,guix shell,operating-system - Flakes ตรึงการพึ่งพาด้วย
inputsระดับโปรเจกต์และflake.lockที่สร้างอัตโนมัติ ขณะที่ Guix สร้างสภาพแวดล้อมที่ทำซ้ำได้ด้วยguix describeระดับผู้ใช้,channels.scmที่ระบุ commit ไว้ในโปรเจกต์ และguix time-machine - ความบริสุทธิ์ ถูกบังคับใช้ใน Flakes ผ่าน restricted evaluation ส่วนใน Guix นั้นบรรลุได้ตั้งแต่ระดับการออกแบบผ่านโครงสร้างโมดูล Scheme, อินพุตที่ระบุอย่างชัดเจน และคอนเทนเนอร์ build แบบแยกขาด
- โครงสร้างเอาต์พุต ของ Flakes มอบ attrset มาตรฐานอย่าง
packages,devShells,nixosConfigurationsขณะที่ Guix ใช้เรคคอร์ดและไฟล์ Scheme ที่โปร่งใส เช่น<package>, manifest,operating-system, service ซึ่งแต่ละคำสั่งจะนำไปใช้โดยตรง - เกณฑ์ในการเลือก คือถ้าชอบจุดเข้าใช้งานเดียวและสคีมามาตรฐาน Flakes จะเหมาะกว่า แต่ถ้าชอบแนวทางที่ผสานเครื่องมือเล็ก ๆ ซึ่งเป็นอิสระต่อกัน Guix จะเหมาะกว่า
การเปรียบเทียบหลัก
- ไม่มีฟีเจอร์เดียวใน Guix ที่เทียบเท่า Nix flake โดยตรง ขณะที่ Nix Flakes แก้หลายปัญหาด้วยฟีเจอร์ขนาดใหญ่เพียงตัวเดียว Guix จะตอบโจทย์ด้วยการผสานเครื่องมือที่เล็กกว่าและแยกเป็นอิสระต่อกันมากกว่า
- Guix นำ Nix daemon กลับมาใช้ใหม่ และใช้คอมโพเนนต์ C++ ร่วมกันสำหรับการแยก build และการจัดการ store
- Guix เขียนส่วนใหญ่ขึ้นมาใหม่ด้วย Guile Scheme ไม่ว่าจะเป็นภาษา นิยามแพ็กเกจ หรือระบบ service ที่อยู่เหนือ Nix daemon
- Guix และ Nix ใช้ derivation format อย่าง ATerm และสืบทอดสายของ daemon ร่วมกัน แต่โครงสร้างที่อยู่เหนือ daemon นั้น Guix จัดวางในแบบของตัวเอง
- Guix มี capabilities ที่ Flakes มอบให้ แต่ให้มาในรูปแบบที่แตกต่างกัน
โครงสร้างพื้นฐานของ Nix Flake
- Nix flake คือ source tree ที่มีไฟล์
flake.nixอยู่ที่ root และโดยทั่วไปมักอยู่ในรูป Git repository - การมีอยู่ของ
flake.nixทำให้ source tree นั้นกลายเป็น flake และไฟล์นี้มีโครงสร้างอย่างdescription,inputs,outputs descriptionคือสตริงที่มนุษย์อ่านได้ ซึ่งใช้บอกว่า flake นั้นมอบอะไรให้inputsใช้ประกาศ dependencies เช่น flakes อื่น ๆ, Git repos, tarballs โดย Nix จะ fetch และ evaluate สิ่งเหล่านี้ก่อนส่งต่อให้ฟังก์ชันoutputsoutputsคือฟังก์ชันที่รับอินพุตที่ resolve แล้วและอินพุตพิเศษselfจากนั้นคืนค่า structured attrset ที่บรรจุ packages, dev shells, NixOS configurations, overlays และอื่น ๆ-
โครงสร้างตัวอย่างและเป้าหมายการทำงาน
- ตัวอย่าง
inputsที่มีnixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";หมายถึงการดึง branchnixos-unstableจาก repositoryNixOS/nixpkgsบน GitHub - flake ตัวอย่างใช้
supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" ];และnixpkgs.lib.genAttrsเพื่อสร้าง outputs แยกตาม CPU architecture หลายแบบ - Flakes กำหนดให้มีระดับ
packages.<system>และในตัวอย่างได้กำหนด packagedefaultใต้packagesด้วยpkgs.buildGoModule src = ./.;หมายถึงใช้ Git repository ทั้งหมดเป็น sourcedevShellsคือคำนิยาม development shell ที่nix developจะอ้างอิง โดยในตัวอย่างใช้pkgs.mkShellและbuildInputs = with pkgs; [ go gopls gotools ];
- ตัวอย่าง
-
flake.lockและการประเมินแบบบริสุทธิ์- เมื่อรันคำสั่ง Nix กับ flake, Nix จะสร้างไฟล์ JSON ชื่อ
flake.lockที่ตรึงทุก input และ transitive input ไว้กับ revision ที่แน่นอน flake.lockคือ lock file ที่ทำให้ build reproducibility เกิดขึ้นได้ข้ามทั้งเครื่องและเวลา- Flakes บังคับใช้ pure evaluation โดยไม่ให้
$NIX_PATH,builtins.currentSystem, environment variables หลุดเข้ามาแบบโดยนัย และทุกอย่างต้องระบุอย่าง explicit - ฟังก์ชันที่ Flakes ทำมีได้แก่ การประกาศ dependencies, การ pin dependencies, การบังคับใช้ความบริสุทธิ์, การมอบ standard output schema, การแชร์แบบ reproducible และการนิยาม development environments
- เมื่อรันคำสั่ง Nix กับ flake, Nix จะสร้างไฟล์ JSON ชื่อ
แนวทางที่ Guix ใช้รับมือ
- Guix มีแนวทางแก้ปัญหาสำหรับฟีเจอร์จำนวนมากของ Flakes อยู่แล้วตั้งแต่ก่อนที่ Flakes จะถูกนำเข้ามาใน Nix 2.4 เมื่อวันที่ 1 พฤศจิกายน 2021
- กลไก channels ของ Guix ถูกนำมาใช้ราวปี 2018~2019
- แนวทางของ Guix มีลักษณะ orthogonal และสามารถใช้เครื่องมือแต่ละตัวแยกจากกันได้โดยไม่เลือกใช้ abstraction แบบ monolithic เพียงชุดเดียว
-
Channels และการประกาศ dependencies
- ใน Flake จะประกาศ dependencies โดยตรงภายใน
flake.nixและในตัวอย่างใช้nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";กับhome-manager.url = "github:nix-community/home-manager"; inputs.nixpkgs.follows = "nixpkgs";ของ Flake input ทำให้home-managerใช้nixpkgsของ flake ปัจจุบันแทนที่จะดึงnixpkgsinput ของตัวเองมา จึงหลีกเลี่ยงสถานการณ์ที่เกิดสำเนา nixpkgs คนละชุดขึ้นมาสองชุด- channels ของ Guix คือ Git repository ที่มี Guile modules อยู่ภายใน โดยปกติจะเก็บ package definitions แต่ก็สามารถรวม services, system configurations และ Scheme code แบบใดก็ได้ด้วย
- Guix channels จะประกาศใน
~/.config/guix/channels.scmและไฟล์ Scheme นี้จะคืนค่าเป็น list ของ channel records guix pullจะ fetch และ compile channels ทั้งหมด จากนั้นทำให้ modules เหล่านั้นพร้อมใช้งานในทุกguixcommand- Channels สามารถประกาศ dependencies กับ channels อื่นได้ผ่านไฟล์
.guix-channelที่อยู่ที่ repository root - Channel dependency ของ Guix channels มีความคล้ายกับ
inputsของ flake โดยประมาณ และเมื่อรันguix pullก็จะมีการ fetch transitive channel dependencies มาด้วย
- ใน Flake จะประกาศ dependencies โดยตรงภายใน
-
Dependencies รายโปรเจ็กต์และรายผู้ใช้
- Flakes ใช้แนวทางแบบ per-project โดยแต่ละ repository มี
flake.nixและ inputs ของตัวเอง ขณะที่ channels ใช้แนวทาง system-wide หรือ per-user ซึ่งchannels.scmจะมีผลกับทุกguixinvocations - Flakes รองรับให้โปรเจ็กต์ต่าง ๆ มีชุด dependency ที่ต่างกันได้อย่างเป็นธรรมชาติ ส่วนใน Guix หากต้องการผลลัพธ์แบบเดียวกัน มักจะใช้
guix time-machineหรือ separate profiles - Flakes ใช้ไวยากรณ์คล้าย URL เช่น
github:NixOS/nixpkgs,git+https://...ขณะที่ channels ใช้ Git URL แบบปกติ - ไวยากรณ์ของ Flake ใช้อ้างอิงแบบรวดเร็วได้สะดวกกว่า และ channels นั้นเรียบง่ายกว่าและ explicit กว่า
- Flakes รองรับ repositories ที่ไม่มี
flake.nixเป็น non-flake inputs ด้วยflake = false; - ใน Guix นั้น channel คือ Git repository ที่มี Scheme files อยู่ข้างใน จึงไม่ต้องมีการ opt-in แบบพิเศษ และ repository ใดก็ตามที่มี Guile modules ก็สามารถเป็น channel ได้
- Flakes ใช้แนวทางแบบ per-project โดยแต่ละ repository มี
การตรึงเวอร์ชัน, ความสามารถในการทำซ้ำ, และการย้อนเวลา
-
flake.lockflake.lockเป็น JSON graph โดยทุก input จะถูก pinning ด้วย commit hash ที่แน่นอน และ Nix จะตรวจสอบnarHashซึ่งเป็น hash ของ source tree ทั้งชุดที่ fetch มาflake.lockจะถูก commit เข้า repository ดังนั้นคนที่ clone ไปจะได้รับ dependency versions ชุดเดียวกันoriginalในflake.lockคือเป้าหมายที่ร้องขอ ส่วนlockedคือสิ่งที่ได้มาจริง- ระบบ two-layer ของ
flake.lockทำให้สามารถอัปเดตเฉพาะ input บางตัวและคงตัวอื่นไว้ได้ เช่นnix flake lock --update-input nixpkgs
-
guix describeและguix time-machine- Guix จะบันทึก commits ที่แน่นอนของทุก channels เมื่อรัน
guix pullและguix describeจะแสดงข้อมูลนี้ - เอาต์พุตของ
guix describeมีหมายเลข generation, วันที่, สถานะ current, ชื่อ channel, repository URL, branch และ commit - Recorded channel commits ของ Guix ทำหน้าที่เทียบได้กับ lock file แต่ไม่ได้อยู่เป็นไฟล์ใน project directory แต่อยู่ในรูป Guile profile ที่
~/.config/guix/current - หากต้องการแชร์ environment ที่ทำซ้ำได้ ใน Guix สามารถใช้
guix time-machineได้ guix time-machine --commit=8a1ab328 -- shell -m manifest.scmจะตรึงตัว Guix เองไว้ที่ revision ที่กำหนดก่อน แล้วจึงรันguix shellโดยใช้ package definitions ของ revision นั้นguix time-machineจะ download และ compile revision นั้นหากจำเป็น และสร้าง isolated environment ที่ package definitions อยู่ในสถานะของ commit นั้นอย่างแม่นยำ- ใน Guix ยังมีแพตเทิร์นที่ check in
channels.scmซึ่งมี pinned commits ไว้ใน project repository ด้วย guix time-machine -C channels.scm -- shell -m manifest.scmจะใช้channels.scmที่อยู่ใน repository เพื่อสร้าง environment เดิมกลับมาอย่างแม่นยำ
- Guix จะบันทึก commits ที่แน่นอนของทุก channels เมื่อรัน
-
ความแตกต่างของสองแนวทาง
flake.lockเป็นแบบ per-project และ automatic ส่วนguix describeเป็นแบบ per-user และ automaticchannels.scmที่มี pinned commits ให้ per-project pinning ใน Guix ได้ แต่เป็นวิธีแบบ manual- Guix กำลังปรับปรุง ergonomics ของ per-project pinning แต่ workflow ปัจจุบันยังต้องการการตั้งค่าที่ explicit มากกว่า
flake.lockเป็น machine-readable JSON graph ส่วนสิ่งที่เทียบเคียงกันใน Guix คือ Scheme file ที่แสดงรายการ channels พร้อม commit hashes- ทั้งสองแนวทางบรรลุเป้าหมายเรื่อง dependency pinning ได้เหมือนกัน แต่ flake lock มีโครงสร้างมากกว่าเพราะเป็น full dependency graph ที่มี
originalและlockedentries สำหรับทุก transitive input guix time-machineเป็นฟังก์ชันที่ไม่มีสิ่งเทียบตรงตัวใน flake โดยสามารถย้ายไม่ใช่แค่ไปยัง dependency versions ที่ตรึงไว้ แต่ไปยัง historical state ของ package collection ที่แตกต่างออกไปโดยสมบูรณ์ได้
โมเดลความบริสุทธิ์
- Flakes ทำงานภายใต้บริบทการประเมินผลแบบจำกัด โดยห้ามใช้หรือจะถูกมองข้ามสำหรับ
builtins.currentSystem,builtins.getEnv,$NIX_PATH - ใน Flakes ทุกอย่างต้องมาจากอินพุตที่ประกาศไว้ ทำให้เกิดการพึ่งพา implicit state โดยไม่ตั้งใจได้ยาก
- trade-off ของการประเมินผลแบบบริสุทธิ์ใน Flakes คือจำเป็นต้องมีพารามิเตอร์
systemแบบชัดเจนกระจายอยู่หลายจุดเพื่อใช้ตรวจจับระบบ และไม่สามารถอ่าน environment variables ได้ - เมื่อต้องการ impure escape hatch ใน Flakes ต้องส่ง
--impureอย่างชัดเจน - Guix ไม่ต้องมีโหมดการประเมินผลแบบบริสุทธิ์แยกต่างหาก เพราะตามธรรมเนียมแล้วการประเมินผลนั้นบริสุทธิ์อยู่แล้ว
- Guile modules จะไม่เข้าถึง environment variables เว้นแต่จะมีการส่งต่อให้อย่างชัดเจน
- Guix ไม่มีสิ่งที่เทียบเท่ากับ
$NIX_PATHและจะ resolve packages ผ่านระบบโมดูลแทนที่จะเป็น search path - Guix ไม่มีแนวคิดที่เทียบเท่ากับ
builtins.currentSystemโดยระบบจะถูกระบุอย่างชัดเจนผ่าน metadata ของแพ็กเกจและแฟลก--system - การ build ของ Guix ก็มีความบริสุทธิ์เช่นกัน โดย builds จะรันอยู่ในคอนเทนเนอร์ที่แยกออกจากกันและมองเห็นเฉพาะอินพุตที่ประกาศไว้อย่างชัดเจนเท่านั้น
- ใน Guix builds จะไม่มี
/usr/bin,/etc, หรือการเข้าถึงเครือข่าย และข้อยกเว้นเรื่องการเข้าถึงเครือข่ายจำกัดอยู่ที่ fixed-output derivations เท่านั้น - วิธีการทำ build sandboxing ของ Nix และ Guix ใช้แนวทางแบบเดียวกันโดยพื้นฐาน
- Guix บรรลุความบริสุทธิ์ในระดับสถาปัตยกรรมผ่านโครงสร้าง Scheme modules ขณะที่ Flakes บังคับใช้ความบริสุทธิ์ด้วยการวาง restricted evaluation mode ทับบนระบบที่เดิมไม่บริสุทธิ์
สคีมาของเอาต์พุตและโมเดลข้อมูล
-
Flake output schema
- Flakes กำหนด standard schema สำหรับ outputs โดย
packages.<system>.<name>ใช้กับnix build,devShells.<system>.<name>ใช้กับnix develop, และapps.<system>.<name>ใช้กับnix run - ใน Flake output schema ยังมี
nixosConfigurations.<name>,overlays.<name>,nixosModules.<name>,formatter.<system>,templates.<name>,checks.<system>.<name>ด้วย - การทำให้ Flake output schema เป็นมาตรฐานช่วยให้
nix build .,nix run,nix flake showอ้างอิงตำแหน่งที่สอดคล้องกัน จึงเพิ่ม discoverability - ข้อเสียของ Flake output schema คือมีความ rigid และหากต้องการเพิ่ม output types ตามอำเภอใจ จำเป็นต้องแก้ไขตัว Nix เอง แม้ว่าจะมีกลไก extension ขนาดเล็กอยู่ก็ตาม
- เนื่องจากพารามิเตอร์
<system>ของ Flake จึงต้องจัดการ multi-platform support แบบ explicit และมักใช้ helper functions หรือ libraries อย่างforAllSystems,flake-utils,flake-parts
- Flakes กำหนด standard schema สำหรับ outputs โดย
-
first-class data types ของ Guix
- Guix ไม่มี output schema เดียวแบบ Flakes แต่มี first-class data types ที่หลายคำสั่งสามารถนำไปใช้ได้
- ใน Guix packages ถูกนิยามเป็น records แบบ
<package>และใช้โดยguix install,guix build - ใน Guix manifests ถูกนิยามเป็นไฟล์ Scheme และใช้โดย
guix shell -m,guix package - ใน Guix system configs ถูกนิยามเป็น
operating-systemและใช้โดยguix system reconfigure - ใน Guix home configs ถูกนิยามเป็น
home-environmentและใช้โดยguix home reconfigure - ใน Guix services ถูกนิยามเป็น records แบบ
<service>และใช้ผ่านฟิลด์servicesของoperating-system - ใน Guix channels คือ Git repos และใช้โดย
guix pull - ใน Guix package variants คือ Scheme procedures และใช้โดย
--with-input,--transform
-
ไฟล์และนิยามแพ็กเกจ
- โปรเจกต์ Guix สามารถจัดให้มีได้ทั้ง channel ที่มี package definitions,
manifest.scmสำหรับการพัฒนา,system.scmสำหรับการ deploy, รวมถึง declaration ของoperating-systemหรือhome-environmentที่นำมาประกอบกัน - ใน Guix ไฟล์เหล่านี้ไม่ต้องการ special entry point file และเป็นเพียงไฟล์ Scheme ที่นิยามค่าแบบ Scheme เท่านั้น
- ใน Guix หากระบุไฟล์ให้กับ
guixsubcommand ที่เกี่ยวข้อง คำสั่งจะจัดการให้เอง โดยไม่ต้องมี ceremony หรือ schema validation แยกต่างหาก - ตัวอย่าง
manifest.scmประกาศ development environment โดยส่งรายการชื่อแพ็กเกจ"guile","guile-git","guile-json"ไปยังspecifications->manifest - ตัวอย่าง
mylib.scmนิยาม record แบบ<package>ซึ่งเป็นสิ่งที่เทียบได้กับ Nix derivation ของ Guix และสามารถ query ฟิลด์ต่าง ๆ ของแพ็กเกจแบบเป็นโปรแกรมได้ - ตัวอย่าง package definition มี
(name "mylib"),(version "0.1.0"),(source (local-file ".")),(build-system gnu-build-system),(inputs (list guile guile-git)),(home-page "https://example.com"),(license gpl3+) local-fileของ Guix จะนำไฟล์จาก current directory มาใช้ในเวลา build และคล้ายกับsrc = ./.;ของ Nixgnu-build-systemของ Guix ใช้รูปแบบ./configure && make && make installและใน Guix ยังมี build systems อื่น ๆ เช่นcmake-build-system,python-build-system- Guix กำหนด dependencies ทุกตัวแบบ explicit ต่างจากใน Nix ที่
stdenvจะจัดหาgccและcoreutilsให้แบบ implicit
- โปรเจกต์ Guix สามารถจัดให้มีได้ทั้ง channel ที่มี package definitions,
สภาพแวดล้อมการพัฒนา
- ในตัวอย่าง
devShellsของ Flakes ใช้devShells.x86_64-linux.default = pkgs.mkShell { buildInputs = with pkgs; [ go gopls gotools ]; shellHook = '' echo "Welcome to the devShell!" ''; }; mkShellจะสร้าง derivation ที่สร้าง shell environment ระหว่างการ build โดยbuildInputsจะถูกเพิ่มเข้าไปในPATHภายใน shell และshellHookจะรัน bash ตามต้องการเมื่อเข้าสู่ shell- สามารถเข้าสู่ Flake dev shell ได้ด้วย
nix developหรือnix develop .#my-shellสำหรับ shell ที่ตั้งชื่อไว้ - สภาพแวดล้อมการพัฒนาใน Guix สามารถกำหนดได้ใน
manifest.scmโดยส่ง list ของ package specification strings ให้กับspecifications->manifest - ตัวอย่าง Guix manifest ประกาศ
"go","gopls","go-tools" - สามารถเข้าสู่ shell ที่อิงจาก Guix manifest ได้ด้วย
guix shell -m manifest.scm - ใน ad-hoc environment ของ Guix สามารถส่งแค่ชื่อแพ็กเกจผ่าน command line ได้โดยไม่ต้องมีไฟล์ เช่น
guix shell go gopls go-tools guix shellรองรับ--containerสำหรับการแยกแบบเต็มรูปแบบ,--emulate-fhsสำหรับรันโปรแกรมที่คาดหวัง standard Linux filesystem layout และ--nestingสำหรับรัน Guix ภายใน Guix container- Guix manifests เป็นไฟล์ Scheme แบบ standalone ที่ไม่ได้ฝังอยู่ในโครงสร้าง
flake.nixที่ใหญ่กว่า guix shellทำงานได้แม้ไม่มีไฟล์ แต่nix developต้องมี flake หรือshell.nixของ legacy interface- Flakes มี named dev shells เช่น
devShells.x86_64-linux.test,devShells.x86_64-linux.default - แทนที่จะมี named dev shells, Guix manifests ใช้วิธีวางไฟล์แยกขนานกัน เช่น
manifest.scm,test-manifest.scm - ทั้ง Nix Flakes และ Guix รองรับการพัฒนาแบบ containerized
การกำหนดค่าระบบ
-
NixOS และ Flakes
- ในตัวอย่าง
nixosConfigurationsของ Flakes,nixpkgs.lib.nixosSystemจะรับ list ของ NixOS modules แล้วสร้าง full system derivation ที่รวม kernel, services, config files เป็นต้น - คำสั่งตัวอย่างสำหรับ deploy NixOS แบบ Flake คือ
nixos-rebuild switch --flake .#myhost - ตัวอย่าง
nixosConfigurations.myhostมีsystem = "x86_64-linux";และmodules = [ ./configuration.nix home-manager.nixosModules.home-manager ]; - NixOS modules ใช้ module system ที่มี
options,config,mkIf,mkDefault,mkForceพร้อมการ merge ตามลำดับความสำคัญ - ระบบโมดูลของ NixOS จะแก้ลำดับความสำคัญให้แม้หลายโมดูลจะตั้งค่า option เดียวกัน ทำให้หลีกเลี่ยงความขัดแย้งได้ง่ายแม้มีโมดูลหลายสิบตัวร่วมกันกำหนดค่าเดียวกัน
- ในตัวอย่าง
-
Guix
operating-systemoperating-systemของ Guix ไม่ใช่ function แต่เป็น Scheme record และแต่ละ field เป็น named typed value ที่ Guix จะทำการ validate- คำสั่งตัวอย่างสำหรับ deploy ระบบด้วย Guix คือ
guix system reconfigure config.scm - ตัวอย่าง
operating-systemrecord มี(host-name "myhost"),(timezone "Etc/UTC"), bootloader configuration, file systems และ services - ตัวอย่าง bootloader configuration ของ Guix ใช้
grub-efi-bootloaderและ target"/boot/efi"โดย Guix รองรับ GRUB, U-Boot เป็นต้น - Guix file systems ถูกประกาศเป็น list และ
%base-file-systemsให้ค่า default สำหรับ/dev,/proc,/sysเป็นต้น - Guix services สร้างเป็น directed acyclic graph(DAG) และแต่ละ service สามารถ extend services อื่นได้
%base-servicesมี services ที่จำเป็น เช่น Shepherd init system, syslog, networking เป็นต้น- การกำหนดค่าระบบของ Guix ไม่ต้องมี special output type แค่ระบุไฟล์ที่คืนค่า
operating-systemrecord ให้กับguix systemก็เพียงพอ - การประกอบ services ของ Guix ทำให้เขียน service ใหม่ที่เชื่อมเข้ากับระบบเดิมได้ง่ายในแบบที่ยืดหยุ่น
ความสามารถในการสำรวจและรีจิสทรี
- Flakes มี standard entry point คือ
flake.nixที่ใช้ประกาศ project dependencies, outputs และ schema ที่ค้นพบได้ในไฟล์เดียว - โปรเจ็กต์ Guix อาจใช้ไฟล์ตามธรรมเนียม เช่น
manifest.scm,channels.scm,guix.scm,package.scm - มีความพยายามจะทำให้
guix.scmเป็นไฟล์โปรเจ็กต์มาตรฐานที่guix shellตรวจพบได้อัตโนมัติ แต่ยังไม่เป็นที่ยอมรับมั่นคงเท่าflake.nix - Flakes มี global registry flake-registry ที่แมปชื่อสั้นกับ URL โดยตัวอย่างคือ
nix run nixpkgs#hello,nix build github:NixOS/nixpkgs#firefox - เพื่อความสะดวกแบบใกล้เคียงกัน Guix ใช้ package specifications เช่น
guix shell hello,guix install firefox - Guix ไม่มีสิ่งที่เทียบเท่า registry สำหรับชี้ไปยัง Git repository ใดก็ได้ด้วยชื่อสั้น และจะใช้ URL โดยตรง
- Nix registry เคยเป็นแหล่งความสับสน เพราะไม่ชัดเจนเสมอไปว่า
nixpkgsเป็น registry entry, local path หรือเป้าหมายอย่างอื่น nix flake showเป็นคำสั่งที่แสดงทุกสิ่งที่ flake มีให้ในมุมมองแบบ tree- Guix มี
guix searchสำหรับแพ็กเกจและguix system searchสำหรับ services แต่ไม่มีคำสั่งเทียบเท่าที่แสดงทุกสิ่งที่โปรเจ็กต์หรือ repository ใด ๆ มีให้ และต้องเปิดดูไฟล์ Scheme เอง - Flakes เด่นด้าน discoverability เพราะ
nix flake showแสดงสิ่งที่ project มีให้อย่างสม่ำเสมอในมุมมองเดียว - โปรเจ็กต์ Guix มีลักษณะ ad-hoc มากกว่า โดยต้องรู้ว่าจะดูไฟล์ไหน และไม่มี standard single-entry-point file
- Guix มีความยืดหยุ่นสูงเพราะทุกอย่างเป็น Scheme จึงสามารถนิยามและประกอบสิ่งต่าง ๆ ได้ตามต้องการโดยไม่ต้องมี schema
โมเดลแพ็กเกจและการเขียนกราฟใหม่
- ใน Nix แพ็กเกจคือฟังก์ชันที่คืนค่า derivation ผ่านการเรียก
stdenv.mkDerivation { ... }และผลลัพธ์คือ attribute set แบบทึบแสง - ใน Guix แพ็กเกจคือเรคอร์ด
<package>ซึ่งเป็นโครงสร้างข้อมูลแบบโปร่งใสที่มีฟิลด์มีชื่อ จึงสามารถตรวจสอบ แปลง และประกอบได้ด้วยโพรซีเยอร์ Scheme มาตรฐาน - เนื่องจากคำจำกัดความแพ็กเกจของ Guix เป็น transparent records ไม่ใช่ opaque functions จึงสามารถทำ inspect และ transform แบบเป็นโปรแกรมได้โดยไม่ต้องมีเครื่องมือพิเศษ
- ใน Guix แพ็กเกจเป็นข้อมูล จึงทำ graph rewrites ได้ง่าย
- ใน Guix สามารถใช้
package-input-rewritingเพื่อไล่ตรวจทั้งกราฟการพึ่งพาและแสดงการแทนที่perlด้วยperl-minimalได้ - คีย์เวิร์ด
inheritของ Guix ใช้นิยามแพ็กเกจใหม่โดยสืบทอดทุกฟิลด์ของcoreutilsแล้วเขียนทับเฉพาะฟิลด์ที่ระบุ - Nix มี overlays สำหรับจุดประสงค์คล้ายกัน แต่เนื่องจากอินเทอร์เฟซแบบฟังก์ชันทึบแสง จึงตรวจสอบและแปลงได้ยากกว่า ทำให้ใช้งานได้ด้อยกว่า
การอัปเดตความปลอดภัย การบูตสแตรป และการยืนยันตัวตน
- grafting ของ Guix ช่วยให้นำการอัปเดตความปลอดภัยไปใช้กับต้นไม้การพึ่งพาได้โดยไม่ต้องคอมไพล์แพ็กเกจที่พึ่งพาทั้งหมดใหม่
- เมื่อไลบรารีระดับล่างอย่าง glibc มีช่องโหว่ Guix สามารถเขียนพาธในสตอร์ใหม่เพื่อแทนที่ด้วยเวอร์ชันที่แก้ไขแล้วได้
- Nix จะคอมไพล์ทุกอย่างใหม่ในกรณีอัปเดตความปลอดภัย และในต้นไม้การพึ่งพาขนาดใหญ่ เวลาคอมไพล์อาจต่างกันเป็นหลายชั่วโมง
- Guix ให้ความสำคัญอย่างมากกับ การบูตสแตรปจากซอร์ส และสามารถสร้างทั้งระบบจากฐานความเชื่อถือขนาดเล็กได้
- เชนการบูตสแตรปของ Guix เริ่มจาก hex assembler ขนาดราว 500 ไบต์ ต่อด้วยคอมไพเลอร์ C
mesที่เขียนด้วย Scheme,tccและ GNU toolchain เต็มรูปแบบ - โปรเจ็กต์ bootstrappable builds ครอบคลุมรายละเอียดทั้งหมดของการบูตสแตรปจากซอร์สเต็มรูปแบบ
- Nix พึ่งพา binary seeds มากกว่า Guix
- หากไม่สามารถตรวจสอบเชนการบูตสแตรปได้ ก็ไม่อาจยืนยันได้อย่างสมบูรณ์ว่าระบบถูกสร้างจากซอร์สที่ตั้งใจจริงหรือไม่ ดังนั้นการบูตสแตรปจากซอร์สเต็มรูปแบบจึงสำคัญต่อความเชื่อถือและความสามารถในการตรวจสอบ
- Guix channels รองรับ การยืนยันตัวตนด้วยคริปโตกราฟี เป็นค่าเริ่มต้น
- Guix channel จะระบุ “introduction” ที่ประกอบด้วยคอมมิตเฉพาะและลายเซ็น Ed25519 ของมัน และ Guix จะตรวจสอบเชนลายเซ็นทั้งหมดตั้งแต่ introduction นั้นจนถึงคอมมิตปัจจุบัน
- Flakes ใช้ HTTPS และโครงสร้างพื้นฐานของ GitHub เป็นโมเดลความเชื่อถือ ซึ่งเป็นโมเดลความปลอดภัยที่ต่างจากการยืนยันตัวตน channel ด้วย Ed25519 ของ Guix
ความสอดคล้องหลักในตารางสรุป
- การประกาศการพึ่งพา: Flakes ใช้
inputsในflake.nixส่วน Guix ใช้channels.scmและ.guix-channel - การตรึงเวอร์ชันการพึ่งพา: Flakes ใช้
flake.lockแบบอัตโนมัติรายโปรเจ็กต์ ส่วน Guix ใช้guix describeแบบอัตโนมัติรายผู้ใช้ และchannels.scmที่ระบุคอมมิตเองแบบรายโปรเจ็กต์ - การประเมินแบบบริสุทธิ์ถูกบังคับใช้ในโหมด flake และใน Guix เป็นคุณสมบัติที่มีอยู่โดยการออกแบบ
- สคีมาของเอาต์พุต: Flakes ใช้ attrset แบบมีโครงสร้างของ
outputsส่วน Guix ใช้ Scheme records แบบ ad-hoc - สภาพแวดล้อมพัฒนา: Flakes ใช้
devShellsและnix developส่วน Guix ใช้manifest.scmและguix shell - การกำหนดค่าระบบ: Flakes ใช้
nixosConfigurationsและระบบโมดูล ส่วน Guix ใช้operating-systemและ service DAG - การทำซ้ำได้ด้วยคำสั่งเดียว: Flakes ใช้
nix build github:foo/barส่วน Guix ใช้รูปแบบguix time-machine -C channels.scm -- build - การตรึงเวอร์ชันรายโปรเจ็กต์: Flakes จัดการให้อัตโนมัติด้วย
flake.lockส่วน Guix จัดการด้วยตนเองผ่านchannels.scmที่มีคอมมิต - ความสามารถในการสำรวจ: Flakes ใช้
nix flake showส่วน Guix พึ่งการตรวจสอบโมดูล Scheme - โมเดลแพ็กเกจ: Flakes/Nix เป็นฟังก์ชันทึบแสง ส่วน Guix เป็นเรคอร์ดแบบโปร่งใส
- init system: Nix ใช้ systemd ส่วน Guix ใช้ GNU Shepherd
- การอัปเดตความปลอดภัย: Nix คอมไพล์ใหม่ทั้งหมด ส่วน Guix ใช้ grafting ที่รวดเร็ว
- ความเชื่อถือในการบูตสแตรป: Nix อิงกับ binary seeds ส่วน Guix อิงกับการบูตสแตรปจากซอร์สเต็มรูปแบบ
- การอัปเดตแบบยืนยันตัวตนแล้ว: Flakes อิงความเชื่อถือจาก HTTPS/GitHub ส่วน Guix ใช้การยืนยันตัวตน channel ด้วย Ed25519
- การรองรับ FHS: Nix มี
buildFHSUserEnvส่วน Guix มี--emulate-fhs - การรองรับนอก Linux: Nix มี nix-darwin สำหรับ macOS ส่วน Guix มีการจัดระเบียบรอบ GNU Hurd
- การเป็นซอฟต์แวร์เสรีล้วนหรือไม่: Nix ไม่ได้จำกัดเฉพาะซอฟต์แวร์เสรีและปรับแต่งได้ ส่วน Guix ปฏิบัติตาม FSDG
บทสรุป
- Flakes และ Guix แก้ปัญหาประเภทเดียวกันคือความสามารถในการทำซ้ำ การจัดการการพึ่งพา และการประกาศระบบ แต่ใช้ปรัชญาสถาปัตยกรรมที่ต่างกัน
- Flakes ใกล้เคียงกับการเป็นฟีเจอร์เดียวที่รวมหนึ่งไฟล์ หนึ่งสคีมา หนึ่งไฟล์ล็อก และหนึ่งชุดธรรมเนียมปฏิบัติ
- Guix คือการผสมผสานของเครื่องมือที่ตั้งฉากต่อกัน เช่น channels สำหรับการแจกจ่าย, manifests สำหรับสภาพแวดล้อม,
operating-systemสำหรับการกำหนดค่า,guix time-machineสำหรับการทำซ้ำได้ และ Scheme records สำหรับโครงสร้างอื่น ๆ - หากชอบวิธีมาตรฐานแบบเดียว ไฟล์จุดเริ่มต้นเพียงไฟล์เดียว สคีมาเอาต์พุตแบบเดียว และรูปแบบไฟล์ล็อกแบบเดียว Flakes จะเหมาะโดยธรรมชาติ
- หากชอบแนวทางที่นำเครื่องมือเล็ก ๆ และเป็นอิสระมาประกอบกัน เพื่อให้แต่ละเครื่องมือทำสิ่งเดียวได้ดีตามปรัชญา Unix กับการจัดการแพ็กเกจ Guix จะเหมาะกว่า
- ทั้งสองระบบนิเวศพัฒนาขึ้นโดยมีแนวคิดร่วมกันว่า การจัดการแพ็กเกจควรเป็นแบบฟังก์ชัน แบบประกาศ และทำซ้ำได้ โดยผลักดันแนวคิดเดียวกันผ่านการนำไปใช้ที่ต่างกัน
1 ความคิดเห็น
ความคิดเห็นจาก Lobste.rs
เว็บนี้อ่านบนมือถือแล้วอึดอัดมาก: ตัวอักษรเล็กไปหน่อย และคอยรบกวนทุกครั้งที่เลื่อน
หลังจากเทียบส่วนแรกแล้วก็อ่านต่อไม่ไหว เพราะมัน เด้งกลับขึ้นไปที่สารบัญ ตลอด
ถึงจะอ่านบทความแล้ว ฉันก็ยังไม่ค่อยเข้าใจว่าจะระบุและตรึง dependencies ของโปรเจกต์อย่างไร ดูเหมือนว่าถ้าจะ deploy และแชร์ ก็ต้องไปหา commit hash ของแต่ละ transitive dependency มาใส่ใน
channels.scmเองด้วยมือtime-machineดูเหมือนจะใช้ได้เฉพาะกับชุดแพ็กเกจ Guix ไม่ได้ใช้กับ dependency นอก treeในฝั่ง Nix ก็สามารถรันโค้ดของ nixpkgs ณ commit เก่าได้ค่อนข้างง่าย เช่น
nix run github:nixos/nixpkgs/<commit hash>#<package>จุดที่ Guix แปลกคือมันไม่ได้แยก เวอร์ชันของชุดแพ็กเกจ ออกจาก เวอร์ชันของตัวจัดการแพ็กเกจ ถ้าจะรันแพ็กเกจเก่า ก็ต้องรัน Guix รุ่นเก่าด้วย ซึ่งฉันไม่ค่อยเข้าใจว่าทำไมเราต้องการแบบนั้น
ในบทความบอกว่า flakes ต้องไปหา commit มากำหนดเอง แต่ถัดมากลับยกตัวอย่างคำสั่ง Guix ที่ก็ต้องระบุ commit เหมือนกัน ใน Nix flake เองก็ override เวอร์ชันของ nixpkgs ได้ด้วย
--override-inputแต่ก็ค่อนข้างรก และนั่นก็เป็นหนึ่งในจุดที่ unflake พยายามแก้ปกติจะพัฒนาใน environment ของ
guix shellก่อน แล้วพอถึงขั้นจะแชร์ค่อยใช้guix describe -f channels > channels.scmเพื่อบันทึก commit hash ทั้งหมดลงในchannels.scmจากเอกสาร declaring channel dependencies ดูเหมือนจะระบุ commit ของ dependency ได้ แต่ไม่เห็นมีตัวเลือกตรวจสอบว่า dependency นั้นถ้าไปพึ่ง dependency อื่นต่อ จะถูกตรึงไว้ที่ commit เฉพาะหรือไม่
รูปแบบ
--commit=ของtime-machineใช้กับ Guix channel แต่ใช้-Cเพื่อโหลด channel เพิ่มเติมจากไฟล์ได้ข้อดีคือถึงจะมี การเปลี่ยนแปลงที่ทำให้เข้ากันไม่ได้ ระหว่างตัวจัดการแพ็กเกจกับ record ของแพ็กเกจ ก็ยังรักษาประวัติและความทำซ้ำได้
แต่ต้อง checkout nixpkgs ทุก commit เลย ทำให้ต้นทุนการสร้างครั้งแรกสูงมาก พอสร้างเสร็จแล้วต้นทุนการดูแลดัชนีน่าจะต่ำ
ฉันแจ้ง coopi เรื่องปัญหาของเว็บกับกระทู้นี้ไปแล้ว หวังว่าจะมีการแก้เร็ว ๆ นี้
ในฐานะคนที่เอนเอียงมาทาง Guix เต็มตัว ฉันก็เห็นด้วยกับที่ coopi พูดว่า Guix น่าจะมี ไฟล์/ไดเรกทอรีมาตรฐาน แบบ
flake.nixเดียวหรือไดเรกทอรีnixเดียวที่รวมทุกอย่างไว้ได้เหมือน Nix เพียงแต่การ import Scheme module ต้องระบุ path ให้ถูก เลยอาจทำไม่ได้สำหรับโพสต์ใน Lobsters นี้ เนื้อหาที่ผู้เขียนพูดถึงก็ดูเหมือนใช้แท็กแค่
nixกับlispก็พอแล้วlinuxออก นั่นคือเคอร์เนลเดียวที่ทั้งคู่มีร่วมกันนี่นา :P แต่unixอาจไม่เข้าก็ได้อย่างที่ว่าเช่นประมาณนี้: และก็น่าจะมีคำสั่ง
guix channelที่ช่วยสร้างและจัดการ channel ใหม่ด้วยสงสัยว่าใน Guix มีฟีเจอร์แบบ
.inputs.nixpkgs.followsของ Nix flake ไหม คือเอาไว้ override ค่าที่ตรึงไว้ของ transitive dependencyอีกอย่าง คำอธิบาย Guix ของผู้เขียนหลายส่วนทำให้นึกถึง Nix ก่อนยุค flakes: ไม่มีจุดเข้าใช้งานมาตรฐาน ใช้ channels และอะไรทำนองนั้น เพียงแต่ใน Guix มี type system กับภาษาโปรแกรมจริง ๆ เลยทำให้ pattern แบบเดียวกันเจ็บปวดน้อยกว่า รู้สึกเหมือนประวัติศาสตร์ทางเลือกที่ Nix คงเป็นถ้ามันดีกว่านี้หรือใช้ภาษาอื่น
ปัญหาด้านการใช้งานที่คนอื่นชี้ไว้ทำให้ฉันยังลังเลที่จะแนะนำ ฉันใช้ NoScript ที่ปิด JavaScript เป็นค่าเริ่มต้น เลยไม่ทันสังเกต
ถึงอย่างนั้น บทความนี้ก็มาถูกจังหวะพอดี เพราะที่บริษัทกำลังไปทางใช้ Nix เยอะขึ้น และเราก็กำลังเจอเรื่อง flakes อยู่บ้าง คำอธิบายในบทความนี้ชัดกว่าสิ่งที่ฉันเคยอ่านมาก
คำตอบจาก Coopi: เช้านี้มีการเปลี่ยนแปลงบางอย่าง แต่ติดงานเลยยังไม่ได้ทดสอบ และปรากฏว่ามี ปัญหาใน JavaScript จริง
เว็บนี้ใช้บน iOS มือถือไม่ได้ หน้าเหมือนจะโหลดจากด้านล่างแล้วเลื่อนกลับขึ้นไปด้านบนทันที และถ้าฉันเลื่อนลงเกินหนึ่งหน้าจอ จะมีบางอย่างถูก trigger แล้วดันกลับขึ้นไปอีก
โหมดอ่านยังใช้ได้ แต่ highlighting กับรายละเอียดการจัดสไตล์เดิมที่จริง ๆ ก็ทำไว้ค่อนข้างดีจะหายไป
จะบอกว่าสิ่งที่ flakes ทำสามารถทำได้ด้วยเครื่องมือหลายตัวของ Guix ก็พูดได้อยู่ แต่ก็ควรพูดด้วยว่าใน Nix เองก็มีเครื่องมือเล็ก ๆ ที่แยกหน้าที่ชัดเจนไว้แก้ปัญหาเดียวกันนี้มานานแล้วและยังมีอยู่จนถึงตอนนี้
สิ่งที่ flakes มอบให้คือ จุดเข้าใช้งานโปรเจกต์แบบมาตรฐาน และ ecosystem ที่เกิดขึ้นได้จากสิ่งนั้น เช่น registry ซึ่งในบทความเองก็ยอมรับว่า Guix ยังไม่มีส่วนนี้
ผู้ใช้ Guix อาจตัดสินใจว่าไม่จำเป็นต้องมีจุดเข้าใช้งานมาตรฐาน และผู้ใช้ Nix จำนวนมากก็เคยมองแบบนั้น
แต่การบอกว่าชุดเครื่องมือที่แยกหน้าที่กันทำสิ่งเดียวกับ flakes ได้ ฟังดูคล้ายกับการบอกว่า FreeBSD มี jail ก็เลยไม่ต้องรองรับ OCI ก็ได้ ซึ่งมองข้ามประเด็นที่ว่ามาตรฐานเป็นสิ่งที่ทำให้ ecosystem เกิดขึ้นได้
ฉันสนใจ Guix มากและก็เคย contribute ไปนิดหน่อย เลยอยากเทียบดูว่าการ build ด้วย
guix time-machineพร้อมchannels.scmทำไมถึงช้ากว่าการเปลี่ยน flake pin แล้ว evaluate Nix มากนัก ถ้าช้ากว่าแค่ประมาณ 3 เท่า เช่นจาก 5–10 วินาทีเป็น 15–30 วินาที ฉันยังรับได้ แต่จากที่เคยลอง มันห่างจากระดับนั้นมาก