1 điểm bởi GN⁺ 5 giờ trước | 1 bình luận | Chia sẻ qua WhatsApp
  • Nix Flakes gộp phụ thuộc dự án, khóa phiên bản, lược đồ đầu ra và môi trường phát triển xoay quanh flake.nixflake.lock, còn Guix cung cấp cùng loại tính năng thông qua tổ hợp các công cụ trực giao như channels, manifests, guix describe, guix shell, operating-system
  • Flakes cố định phụ thuộc bằng inputs theo từng dự án và flake.lock được tạo tự động, còn Guix xây dựng môi trường có thể tái lập bằng guix describe theo từng người dùng, channels.scm ghi commit trong dự án, và guix time-machine
  • Tính thuần khiết được Flakes cưỡng chế bằng restricted evaluation, còn trong Guix thì đạt được theo thiết kế thông qua cấu trúc mô-đun Scheme, đầu vào tường minh và các container build cách ly
  • Cấu trúc đầu ra: Flakes cung cấp attrset chuẩn như packages, devShells, nixosConfigurations, trong khi Guix dùng các bản ghi Scheme và tệp minh bạch như <package>, manifest, operating-system, service để từng lệnh tiêu thụ trực tiếp
  • Tiêu chí lựa chọn: nếu bạn thích một điểm vào duy nhất và lược đồ chuẩn thì Flakes phù hợp hơn, còn nếu thích cách kết hợp các công cụ nhỏ và độc lập thì Guix sẽ hợp hơn

So sánh cốt lõi

  • Không có một tính năng Guix đơn lẻ nào tương ứng trực tiếp với Nix flake; trong khi Nix Flakes giải quyết nhiều vấn đề bằng một tính năng lớn, Guix đáp ứng bằng sự kết hợp của các công cụ nhỏ hơn và trực giao hơn
  • Guix tái sử dụng Nix daemon và chia sẻ các thành phần C++ phụ trách build isolation và store management
  • Guix triển khai lại phần lớn những gì nằm phía trên Nix daemon, như ngôn ngữ, định nghĩa gói và hệ thống service, bằng Guile Scheme
  • Guix và Nix chia sẻ định dạng derivation là ATerm và cùng chung nguồn gốc daemon, nhưng cấu trúc phía trên daemon được Guix tổ chức theo cách riêng của mình
  • Guix có những khả năng mà Flakes cung cấp, nhưng thể hiện chúng dưới hình thức khác

Cấu trúc cơ bản của Nix Flake

  • Nix flake là một source tree có tệp flake.nix ở thư mục gốc, thường ở dạng Git repository
  • Sự hiện diện của flake.nix biến source tree thành một flake, và tệp này có cấu trúc như description, inputs, outputs
  • description là chuỗi để con người đọc được, mô tả nội dung mà flake cung cấp
  • inputs khai báo dependencies như các flake khác, Git repo, tarball; Nix sẽ fetch, evaluate chúng rồi truyền vào hàm outputs
  • outputs là một hàm nhận các input đã được resolve và input đặc biệt self, rồi trả về một attrset có cấu trúc chứa packages, dev shells, NixOS configurations, overlays, v.v.
  • Cấu trúc ví dụ và các mục tiêu thực thi

    • nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; trong inputs ví dụ có nghĩa là lấy branch nixos-unstable từ kho NixOS/nixpkgs trên GitHub
    • Flake ví dụ dùng supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" ];nixpkgs.lib.genAttrs để tạo outputs cho nhiều CPU architecture khác nhau
    • Flakes yêu cầu ở mức packages.<system>; trong ví dụ, package default dưới packages được định nghĩa bằng pkgs.buildGoModule
    • src = ./.; nghĩa là dùng toàn bộ Git repository làm source
    • devShells là định nghĩa development shell mà nix develop sẽ tham chiếu; trong ví dụ dùng pkgs.mkShellbuildInputs = with pkgs; [ go gopls gotools ];
  • flake.lock và đánh giá thuần khiết

    • Khi chạy lệnh Nix với một flake, Nix sẽ tạo tệp JSON flake.lock để cố định mọi input và transitive input vào đúng revision
    • flake.lock là lock file cho phép build reproducibility xuyên suốt giữa các máy và theo thời gian
    • Flakes cưỡng chế pure evaluation, nên $NIX_PATH, builtins.currentSystem và environment variables không thể được đưa vào một cách ngầm định; mọi thứ đều phải tường minh
    • Những gì Flakes thực hiện có thể được tóm gọn là: khai báo dependencies, ghim dependencies, cưỡng chế tính thuần khiết, cung cấp lược đồ đầu ra chuẩn, chia sẻ có thể tái lập và định nghĩa môi trường phát triển

Cách tiếp cận tương ứng của Guix

  • Guix đã có sẵn lời giải cho phần lớn các tính năng của Flakes từ trước khi Flakes được đưa vào Nix 2.4 ngày 1 tháng 11 năm 2021
  • Cơ chế channels của Guix được giới thiệu vào khoảng năm 2018~2019
  • Cách tiếp cận của Guix mang tính orthogonal, không dùng một abstraction đơn khối duy nhất mà cho phép sử dụng từng công cụ một cách độc lập
  • Channels và khai báo phụ thuộc

    • Trong Flake, dependencies được khai báo trực tiếp trong flake.nix; trong ví dụ có dùng nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";home-manager.url = "github:nix-community/home-manager";
    • inputs.nixpkgs.follows = "nixpkgs"; của Flake input khiến home-manager không lấy nixpkgs input riêng của nó mà dùng nixpkgs của flake hiện tại, nhờ đó tránh tình huống phát sinh hai bản sao nixpkgs khác nhau
    • channels của Guix là các Git repository chứa Guile modules; thường chứa package definitions, nhưng cũng có thể bao gồm services, cấu hình hệ thống và mã Scheme tùy ý
    • Guix channels được khai báo trong ~/.config/guix/channels.scm, và file Scheme này trả về một danh sách các channel records
    • guix pull sẽ fetch và compile tất cả channels, rồi làm cho các modules đó có thể dùng được trong mọi lệnh guix
    • Channels có thể dùng file .guix-channel ở root của repository để khai báo dependencies với các channels khác
    • Channel dependency của Guix channels nhìn chung tương tự inputs của flake, và khi chạy guix pull thì các transitive channel dependencies cũng được fetch cùng
  • Phụ thuộc theo dự án và phụ thuộc theo người dùng

    • Flakes theo cách per-project, mỗi repository có flake.nix và inputs riêng; còn channels theo kiểu toàn hệ thống hoặc per-user, trong đó channels.scm áp dụng cho mọi lần gọi guix
    • Flakes tự nhiên hỗ trợ các dự án khác nhau có các bộ dependency khác nhau; trong Guix, để đạt hiệu ứng tương tự người ta thường dùng guix time-machine hoặc các profile tách biệt
    • Flakes dùng cú pháp giống URL như github:NixOS/nixpkgs, git+https://...; còn channels dùng các Git URL thuần
    • Cú pháp Flake ergonomic hơn cho các tham chiếu nhanh, còn channels thì đơn giản và explicit hơn
    • Flakes hỗ trợ các repository không có flake.nix như non-flake inputs bằng flake = false;
    • Trong Guix, channel là một Git repository chứa các file Scheme nên không cần cơ chế opt-in đặc biệt; bất kỳ repository nào có Guile modules đều có thể trở thành channel

Khóa phiên bản, tái lập và quay ngược thời gian

  • flake.lock

    • flake.lock là một JSON graph, trong đó mọi input đều được pinning bằng commit hash chính xác và Nix sẽ kiểm tra narHash, tức hash của toàn bộ source tree đã fetch
    • flake.lock được commit vào repository, vì vậy những người clone sẽ nhận được cùng một phiên bản dependency
    • original trong flake.lock là đích đã yêu cầu, còn locked là đích thực tế nhận được
    • Hệ thống hai lớp của flake.lock cho phép selective update như nix flake lock --update-input nixpkgs, tức chỉ cập nhật một input cụ thể và giữ nguyên phần còn lại
  • guix describeguix time-machine

    • Guix ghi lại chính xác commit của mọi channel khi chạy guix pull, và guix describe sẽ hiển thị thông tin này
    • Kết quả guix describe gồm số generation, ngày tháng, dấu current, tên channel, URL repository, branch và commit
    • Các channel commit đã được ghi nhận của Guix tương ứng với lock file, nhưng tồn tại dưới dạng Guile profile ở ~/.config/guix/current chứ không phải là file trong thư mục dự án
    • Để chia sẻ môi trường có thể tái lập, trong Guix có thể dùng guix time-machine
    • guix time-machine --commit=8a1ab328 -- shell -m manifest.scm sẽ pin chính Guix vào một revision cụ thể rồi chạy guix shell bằng package definitions của revision đó
    • guix time-machine sẽ download và compile revision đó nếu cần, rồi tạo một môi trường cô lập mà trong đó package definitions đúng với trạng thái của commit đó
    • Cũng có một mẫu dùng trong Guix là check in channels.scm với các commit đã pin vào repository dự án
    • guix time-machine -C channels.scm -- shell -m manifest.scm sẽ dùng channels.scm đi kèm repository để tái tạo chính xác môi trường
  • Khác biệt giữa hai cách tiếp cận

    • flake.lock là automatic theo từng dự án, còn guix describe là automatic theo từng người dùng
    • channels.scm chứa các commit đã pin cung cấp cơ chế pinning theo dự án trong Guix, nhưng là cách làm thủ công
    • Guix đang cải thiện ergonomics của pinning theo dự án, nhưng workflow hiện tại vẫn cần thiết lập explicit hơn
    • flake.lock là một JSON graph machine-readable, còn đối tượng tương ứng trong Guix là file Scheme liệt kê các channels cùng commit hash
    • Cả hai cách đều đạt mục tiêu pinning dependency, nhưng flake lock có cấu trúc hơn vì là full dependency graph với các mục originallocked cho mọi transitive input
    • guix time-machine là tính năng không có direct flake equivalent; nó không chỉ pin các phiên bản dependency mà còn có thể chuyển sang một trạng thái lịch sử hoàn toàn khác của package collection

Mô hình tính thuần

  • Flakes chạy trong ngữ cảnh đánh giá bị hạn chế, việc dùng builtins.currentSystem, builtins.getEnv, $NIX_PATH bị cấm hoặc bị bỏ qua
  • Trong Flakes, mọi thứ đều phải đến từ các đầu vào đã khai báo, giúp khó phát sinh phụ thuộc ngoài ý muốn vào trạng thái ngầm định
  • Đánh đổi của pure evaluation trong Flakes là cần các tham số system tường minh ở nhiều nơi để nhận diện hệ thống, đồng thời không thể đọc biến môi trường
  • Khi cần một lối thoát impure trong Flakes, phải truyền tường minh --impure
  • Guix không cần một chế độ pure evaluation riêng, vì theo quy ước việc đánh giá vốn đã là thuần
  • Các module Guile không truy cập biến môi trường trừ khi chúng được truyền vào một cách tường minh
  • Guix không có thứ gì tương đương với $NIX_PATH, và phân giải gói thông qua hệ thống module thay vì search path
  • Guix không có khái niệm tương đương builtins.currentSystem, và các hệ thống được chỉ định tường minh bằng metadata của gói và cờ --system
  • Việc build trong Guix cũng là thuần, các bản build chạy trong các container cô lập chỉ nhìn thấy những đầu vào được khai báo tường minh
  • Trong các bản build của Guix không có /usr/bin, /etc, hay quyền truy cập mạng; ngoại lệ về truy cập mạng chỉ giới hạn ở fixed-output derivations
  • Cách sandbox build của Nix và Guix về bản chất dùng cùng một hướng tiếp cận
  • Guix đạt được tính thuần ở cấp độ kiến trúc thông qua cấu trúc module Scheme, còn Flakes áp đặt tính thuần bằng cách chồng một chế độ đánh giá bị hạn chế lên trên một hệ thống vốn dĩ không thuần

Lược đồ đầu ra và mô hình dữ liệu

  • Lược đồ đầu ra của Flake

    • Flakes định nghĩa một lược đồ chuẩn cho outputs, trong đó packages.<system>.<name> được dùng bởi nix build, devShells.<system>.<name> bởi nix develop, và apps.<system>.<name> bởi nix run
    • Lược đồ đầu ra của Flake cũng có nixosConfigurations.<name>, overlays.<name>, nixosModules.<name>, formatter.<system>, templates.<name>, checks.<system>.<name>
    • Việc chuẩn hóa lược đồ đầu ra của Flake giúp nix build ., nix run, nix flake show tham chiếu tới các vị trí nhất quán, qua đó tăng khả năng khám phá
    • Nhược điểm của lược đồ đầu ra Flake là nó cứng nhắc; muốn thêm các kiểu đầu ra tùy ý thì cần sửa chính Nix, dù vẫn có một cơ chế mở rộng nhỏ
    • Do tham số <system> của Flake, hỗ trợ đa nền tảng phải được xử lý tường minh, và thường dùng các hàm hoặc thư viện hỗ trợ như forAllSystems, flake-utils, flake-parts
  • Các kiểu dữ liệu hạng nhất trong Guix

    • Guix không có một lược đồ đầu ra đơn nhất như Flakes, mà có các kiểu dữ liệu hạng nhất để nhiều lệnh có thể sử dụng
    • Trong Guix, packages được định nghĩa bằng các record <package> và được guix install, guix build sử dụng
    • Trong Guix, manifests được định nghĩa bằng các tệp Scheme và được guix shell -m, guix package sử dụng
    • Trong Guix, cấu hình hệ thống được định nghĩa bằng operating-system và được guix system reconfigure sử dụng
    • Trong Guix, cấu hình home được định nghĩa bằng home-environment và được guix home reconfigure sử dụng
    • Trong Guix, services được định nghĩa bằng các record <service> và được trường services của operating-system sử dụng
    • Trong Guix, channels là các repo Git và được guix pull sử dụng
    • Trong Guix, các biến thể gói là các procedure Scheme và được --with-input, --transform sử dụng
  • Tệp và định nghĩa gói

    • Một dự án Guix có thể cung cấp kết hợp giữa channel chứa các định nghĩa gói, manifest.scm cho phát triển, system.scm cho triển khai, cùng các khai báo operating-system hoặc home-environment
    • Trong Guix, các tệp này không yêu cầu tệp entry point đặc biệt nào, mà đơn giản chỉ là các tệp Scheme định nghĩa các giá trị Scheme
    • Trong Guix, chỉ cần chỉ định tệp cho subcommand guix liên quan là lệnh sẽ xử lý, không cần ceremony riêng hay kiểm tra lược đồ
    • Ví dụ manifest.scm khai báo môi trường phát triển bằng cách truyền danh sách tên gói "guile", "guile-git", "guile-json" cho specifications->manifest
    • Ví dụ mylib.scm định nghĩa một record <package>, tương đương với Nix derivation trong Guix, và có thể truy vấn các trường của gói theo cách lập trình
    • Ví dụ định nghĩa gói có các trường (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 của Guix lấy các tệp trong thư mục hiện tại tại thời điểm build, tương tự src = ./.; trong Nix
    • gnu-build-system của Guix dùng cách ./configure && make && make install, và Guix cũng có các build system khác như cmake-build-system, python-build-system
    • Guix đặt mọi dependency ở dạng tường minh, khác với Nix nơi stdenv ngầm cung cấp gcccoreutils

Môi trường phát triển

  • Trong ví dụ devShells của Flakes, sử dụng devShells.x86_64-linux.default = pkgs.mkShell { buildInputs = with pkgs; [ go gopls gotools ]; shellHook = '' echo "Welcome to the devShell!" ''; };
  • mkShell tạo ra một derivation tạo môi trường shell khi được build; buildInputs sẽ được thêm vào PATH bên trong shell, còn shellHook chạy bash tùy ý khi vào shell
  • Có thể vào Flake dev shell bằng nix develop hoặc nix develop .#my-shell cho shell có tên
  • Môi trường phát triển của Guix có thể được định nghĩa trong manifest.scm bằng cách truyền danh sách chuỗi package specification cho specifications->manifest
  • Ví dụ Guix manifest khai báo "go", "gopls", "go-tools"
  • Có thể vào shell dựa trên Guix manifest bằng guix shell -m manifest.scm
  • Guix cũng cho phép môi trường ad-hoc mà không cần file, chỉ bằng cách truyền tên package trên dòng lệnh như guix shell go gopls go-tools
  • guix shell hỗ trợ --container để cô lập hoàn toàn, --emulate-fhs để chạy chương trình kỳ vọng bố cục filesystem Linux tiêu chuẩn, và --nesting để chạy Guix bên trong container Guix
  • Guix manifests là các file Scheme độc lập, không được nhúng trong cấu trúc flake.nix lớn hơn
  • guix shell có thể hoạt động cả khi không có file, nhưng nix develop cần flake hoặc shell.nix của giao diện legacy
  • Flakes cung cấp các named dev shell như devShells.x86_64-linux.test, devShells.x86_64-linux.default
  • Thay vì named dev shell, Guix manifests thường dùng các file riêng đặt song song như manifest.scm, test-manifest.scm
  • Cả Nix Flakes và Guix đều hỗ trợ phát triển trong môi trường container hóa

Cấu hình hệ thống

  • NixOS và Flakes

    • Trong ví dụ nixosConfigurations của Flakes, nixpkgs.lib.nixosSystem nhận danh sách module NixOS để tạo ra một full system derivation bao gồm kernel, services, config files, v.v.
    • Lệnh ví dụ để triển khai NixOS dựa trên Flake là nixos-rebuild switch --flake .#myhost
    • Ví dụ nixosConfigurations.myhost bao gồm system = "x86_64-linux";modules = [ ./configuration.nix home-manager.nixosModules.home-manager ];
    • NixOS modules là một hệ thống module dùng cơ chế gộp theo mức ưu tiên thông qua options, config, mkIf, mkDefault, mkForce
    • Hệ thống module của NixOS giải quyết mức ưu tiên ngay cả khi nhiều module cùng thiết lập một option, nên dễ tránh xung đột dù hàng chục module cùng đóng góp vào một cấu hình
  • Guix operating-system

    • operating-system của Guix là một Scheme record chứ không phải function; mỗi field là một giá trị có tên và kiểu, được Guix kiểm tra hợp lệ
    • Lệnh ví dụ để triển khai hệ thống Guix là guix system reconfigure config.scm
    • Ví dụ record operating-system bao gồm (host-name "myhost"), (timezone "Etc/UTC"), cấu hình bootloader, file systems và services
    • Ví dụ cấu hình bootloader của Guix dùng grub-efi-bootloader với target "/boot/efi"; Guix hỗ trợ GRUB, U-Boot, v.v.
    • File systems của Guix được khai báo dưới dạng danh sách, còn %base-file-systems cung cấp mặc định cho /dev, /proc, /sys, v.v.
    • Services của Guix tạo thành directed acyclic graph (DAG), và mỗi service có thể mở rộng các service khác
    • %base-services cung cấp các service thiết yếu như Shepherd init system, syslog, networking, v.v.
    • Cấu hình hệ thống Guix không cần special output type; chỉ cần chỉ định cho guix system một file trả về record operating-system
    • Cách kết hợp service của Guix giúp dễ viết service mới để nối vào hệ thống hiện có theo những cách linh hoạt

Khả năng khám phá và registry

  • Flakes có flake.nix, một điểm vào tiêu chuẩn để khai báo dependency của dự án, output và schema có thể khám phá được trong một file
  • Dự án Guix có thể dùng các file theo quy ước như manifest.scm, channels.scm, guix.scm, package.scm
  • Có nỗ lực chuẩn hóa guix.scm thành file dự án mà guix shell tự động nhận diện, nhưng nó chưa được thiết lập vững chắc như flake.nix
  • Flakes có registry toàn cục flake-registry để ánh xạ tên ngắn sang URL; ví dụ gồm nix run nixpkgs#hello, nix build github:NixOS/nixpkgs#firefox
  • Guix dùng package specification để có sự tiện lợi tương tự, ví dụ guix shell hello, guix install firefox
  • Guix không có đối tượng tương đương registry để trỏ một kho Git bất kỳ bằng tên ngắn, mà dùng trực tiếp URL
  • Nix registry từng là nguồn gây nhầm lẫn vì không phải lúc nào cũng rõ nixpkgs là một mục registry, một đường dẫn cục bộ hay một mục tiêu khác
  • nix flake show là lệnh hiển thị mọi mục mà một flake cung cấp dưới dạng tree view
  • Guix có guix search cho package và guix system search cho service, nhưng không có lệnh tương ứng để hiển thị mọi mục mà một dự án hay repository cụ thể cung cấp; phải tự xem các file Scheme
  • Flakes có khả năng khám phá mạnh vì nix flake show cho một cái nhìn nhất quán về những gì project cung cấp
  • Các dự án Guix mang tính ad-hoc hơn; bạn cần biết phải xem file nào và không có file điểm vào duy nhất được chuẩn hóa
  • Guix có tính linh hoạt mạnh vì mọi thứ đều là Scheme, nên có thể định nghĩa và kết hợp bất cứ thứ gì mà không cần schema

Mô hình gói và viết lại đồ thị

  • Trong Nix, gói là một hàm trả về derivation thông qua lời gọi stdenv.mkDerivation { ... }, và kết quả đó là một tập thuộc tính mờ
  • Trong Guix, gói là một bản ghi <package>, tức một cấu trúc dữ liệu minh bạch với các trường được đặt tên, nên có thể được kiểm tra, biến đổi và kết hợp bằng các thủ tục Scheme tiêu chuẩn
  • Các định nghĩa gói của Guix là các bản ghi minh bạch chứ không phải các hàm mờ, nên có thể thực hiện inspect và transform bằng chương trình mà không cần công cụ đặc biệt
  • Trong Guix, vì packages là dữ liệu nên có thể dễ dàng thực hiện graph rewrites
  • Trong Guix, package-input-rewriting có thể biểu diễn việc duyệt toàn bộ đồ thị phụ thuộc để thay perl bằng perl-minimal
  • Từ khóa inherit của Guix định nghĩa lại một gói bằng cách kế thừa mọi trường của coreutils và chỉ ghi đè các trường được chỉ định
  • Nix có overlays với mục đích tương tự, nhưng do giao diện hàm mờ nên việc kiểm tra và biến đổi khó hơn, khiến tính tiện dụng kém hơn

Cập nhật bảo mật, bootstrap, xác thực

  • grafting của Guix cho phép áp dụng các bản cập nhật bảo mật vào cây phụ thuộc mà không cần build lại mọi gói phụ thuộc
  • Khi các thư viện cấp thấp như glibc có lỗ hổng, Guix có thể viết lại các đường dẫn trong kho lưu trữ để thay bằng phiên bản đã vá
  • Nix build lại mọi thứ trong tình huống cập nhật bảo mật, và với các cây phụ thuộc lớn thì thời gian build có thể chênh nhau tới hàng giờ
  • Guix tập trung mạnh vào bootstrap dựa trên mã nguồn, cho phép build toàn bộ hệ thống từ một nền tảng tin cậy rất nhỏ
  • Chuỗi bootstrap của Guix bắt đầu từ một hex assembler khoảng 500 byte, rồi tới trình biên dịch C mes viết bằng Scheme, tcc, và toàn bộ GNU toolchain
  • Dự án bootstrappable builds bao quát các chi tiết đầy đủ về bootstrap toàn bộ từ mã nguồn
  • Nix phụ thuộc vào nhiều binary seed hơn Guix
  • Nếu không thể kiểm toán chuỗi bootstrap thì không thể xác minh hoàn toàn rằng hệ thống thực sự được build từ đúng mã nguồn dự định, vì vậy bootstrap toàn bộ từ mã nguồn rất quan trọng đối với độ tin cậy và khả năng kiểm chứng
  • Guix channels hỗ trợ xác thực bằng mật mã theo mặc định
  • Một Guix channel chỉ định một “introduction” gồm một commit cụ thể và chữ ký Ed25519 của nó, và Guix xác minh toàn bộ chuỗi chữ ký từ introduction đó đến commit hiện tại
  • Flakes dùng HTTPS và hạ tầng GitHub làm mô hình tin cậy, đây là mô hình bảo mật khác với channel authentication bằng Ed25519 của Guix

Các đối ứng chính trong bảng tóm tắt

  • Khai báo phụ thuộc: Flakes dùng inputs trong flake.nix, còn Guix dùng channels.scm.guix-channel
  • Cố định phụ thuộc: Flakes dùng flake.lock tự động theo từng dự án, còn Guix dùng guix describe tự động theo từng người dùng và channels.scm chỉ định commit thủ công theo từng dự án
  • Đánh giá thuần được ép buộc trong flake mode, còn trong Guix đây là đặc tính vốn có theo thiết kế
  • Lược đồ đầu ra: Flakes dùng attrset có cấu trúc trong outputs, còn Guix dùng các Scheme record ad-hoc
  • Môi trường phát triển: Flakes dùng devShellsnix develop, còn Guix dùng manifest.scmguix shell
  • Cấu hình hệ thống: Flakes dùng nixosConfigurations và hệ thống module, còn Guix dùng operating-system và DAG dịch vụ
  • Tính tái lập bằng một lệnh: Flakes có nix build github:foo/bar, còn Guix có dạng guix time-machine -C channels.scm -- build
  • Cố định theo từng dự án: Flakes xử lý tự động bằng flake.lock, còn Guix xử lý thủ công bằng channels.scm có chứa commit
  • Khả năng khám phá: Flakes dùng nix flake show, còn Guix dựa vào việc kiểm tra module Scheme
  • Mô hình gói: Flakes/Nix là hàm mờ, còn Guix là record minh bạch
  • Hệ thống init: Nix dùng systemd, còn Guix dùng GNU Shepherd
  • Cập nhật bảo mật: Nix build lại toàn bộ, còn Guix dùng grafting nhanh
  • Độ tin cậy bootstrap: Nix dựa vào binary seed, còn Guix dựa trên bootstrap toàn bộ từ mã nguồn
  • Cập nhật có xác thực: Flakes dùng mô hình tin cậy HTTPS/GitHub, còn Guix dùng channel authentication bằng Ed25519
  • Hỗ trợ FHS: Nix cung cấp buildFHSUserEnv, còn Guix cung cấp --emulate-fhs
  • Hỗ trợ ngoài Linux: Nix có nix-darwin cho macOS, còn Guix được tổ chức quanh GNU Hurd
  • Việc chỉ dùng phần mềm tự do: Nix không bắt buộc và có thể cấu hình, còn Guix tuân thủ FSDG

Kết luận

  • Flakes và Guix giải quyết cùng một loại vấn đề về tính tái lập, quản lý phụ thuộc và khai báo hệ thống, nhưng với các triết lý kiến trúc khác nhau
  • Flakes gần như là một tính năng đơn lẻ với một tệp, một lược đồ, một tệp khóa và một tập quy ước
  • Guix là sự kết hợp của các công cụ trực giao như channels cho phân phối, manifests cho môi trường, operating-system cho cấu hình, guix time-machine cho tính tái lập, và các Scheme record cho những cấu trúc khác
  • Nếu bạn thích một cách chuẩn duy nhất, một tệp điểm vào duy nhất, một lược đồ đầu ra duy nhất và một định dạng khóa duy nhất, thì Flakes là lựa chọn tự nhiên
  • Nếu bạn thích cách kết hợp các công cụ nhỏ, độc lập để mỗi công cụ làm tốt một việc theo triết lý Unix áp dụng vào quản lý gói, thì Guix sẽ phù hợp hơn
  • Hai hệ sinh thái này phát triển xoay quanh ý tưởng rằng quản lý gói nên mang tính hàm, khai báo và có thể tái lập, và đang thúc đẩy cùng một ý tưởng đó bằng các cách triển khai khác nhau

1 bình luận

 
Ý kiến trên Lobste.rs
  • Trang này đọc trên di động quá khó chịu: chữ hơi nhỏ, và cứ cuộn là lại bị quấy rầy
    Sau phần so sánh đầu tiên thì tôi không đọc nổi nữa, vì nó cứ bật ngược lên mục lục

    • Hoàn toàn không đọc được. Nó nhảy lên nhảy xuống như yo-yo. Đây là một trong những bài gần đây tôi rất muốn đọc, nên thật thất vọng vì đây là trải nghiệm đọc bực bội nhất từ trước đến nay
    • Trên desktop cũng xảy ra y hệt. Thật vô lý, trông như cố tình phá hỏng khả năng truy cập vậy
  • Đọc xong bài mà tôi vẫn chưa hiểu rõ phải chỉ định và cố định dependency của dự án như thế nào. Nếu muốn phát hành và chia sẻ thì có vẻ phải tự tìm rồi điền commit hash của từng dependency bắc cầu vào channels.scm
    time-machine có vẻ chỉ hoạt động với tập gói Guix, chứ không áp dụng cho dependency ngoài cây
    Bạn cũng có thể chạy mã ở một thời điểm cũ của nixpkgs khá dễ, kiểu nix run github:nixos/nixpkgs/<commit hash>#<package>
    Điểm lạ của Guix là nó không tách phiên bản bộ sưu tập gói với phiên bản trình quản lý gói. Muốn chạy gói cũ thì cũng sẽ chạy luôn cả bản phát hành Guix cũ, mà tôi không hiểu vì sao lại muốn thế
    Bài viết nói flakes phải tự tìm commit để chỉ định thủ công, rồi ngay sau đó lại đưa ví dụ một lệnh Guix cũng phải chỉ định commit. Trong Nix flake cũng có thể ghi đè phiên bản nixpkgs bằng --override-input, nhưng khá bẩn, nên đó cũng là một trong những điểm unflake đang cố cải thiện

    • Tôi ít kinh nghiệm dùng Guix hơn tác giả, nhưng cũng đã đọc tài liệu kha khá nên xin trả lời vài ý
      Thông thường bạn phát triển trong một môi trường guix shell riêng, rồi đến lúc cần chia sẻ thì dùng guix describe -f channels > channels.scm để ghi toàn bộ commit hash vào channels.scm
      Xem tài liệu declaring channel dependencies thì có thể chỉ định commit của dependency, nhưng có vẻ không có tùy chọn nào để xác minh rằng khi dependency đó lại có dependency tiếp thì phía bên kia cũng đã được cố định vào commit cụ thể
      Ký hiệu --commit= của time-machine áp dụng cho kênh Guix, nhưng cũng có thể nạp thêm kênh từ tệp bằng -C
      Điều này có lợi ở chỗ dù có thay đổi phá vỡ tương thích trong trình quản lý gói và bản ghi gói, bạn vẫn không mất lịch sử và tính tái lập
    • Có thể làm được bằng cách tạo chỉ mục ngược cho nixpkgs: từ commit X đến Y của nixpkgs có chứa phiên bản A của một gói cụ thể
      Tuy vậy, vì phải checkout nixpkgs ở từng commit nên chi phí xây dựng ban đầu sẽ rất lớn. Sau khi làm xong thì chi phí duy trì chỉ mục có lẽ sẽ thấp
  • Tôi đã báo cho coopi về vấn đề của trang và cả thread này, hy vọng sớm được sửa
    Từ góc nhìn nghiêng hẳn về Guix, tôi cũng thấy như coopi nói, sẽ rất hay nếu Guix có một tệp/thư mục chuẩn giống Nix, kiểu một flake.nix hoặc một thư mục nix, để chứa mọi thứ. Nhưng có thể điều đó là bất khả thi vì muốn import mô-đun Scheme thì phải chỉ đúng đường dẫn
    Bài Lobsters này đã chứa những gì tác giả muốn nói, nên có vẻ chỉ cần các thẻ nixlisp là đủ

    • Tôi không bị thuyết phục bởi ý kiến bỏ linux. Đó là kernel duy nhất mà hai bên cùng có mà :P còn unix thì đúng là có thể không hợp như bạn nói
    • Cũng sẽ rất hay nếu có kiểu dữ liệu kênh có cấu trúc để giúp tự động suy ra một kênh cung cấp những gì, giống như flakes
      Ví dụ kiểu thế này:
      (channel  
        (operating-systems  
          (list my-vm))  
        (services  
          (list my-system-service)))  
      
      Và cũng nên có lệnh guix channel để hỗ trợ tạo và quản lý kênh mới
  • Tôi tò mò không biết Guix có tính năng ghi đè giá trị cố định của dependency bắc cầu như .inputs.nixpkgs.follows trong Nix flake hay không
    Ngoài ra, phần lớn mô tả của tác giả về Guix khiến tôi liên tưởng đến Nix thời trước flakes: không có điểm vào tiêu chuẩn, cấu trúc dùng kênh, v.v. Dù vậy, trong Guix có hệ thống định dạng và một ngôn ngữ thực sự, nên cùng một kiểu mẫu có lẽ bớt đau đầu hơn. Cảm giác như một dòng lịch sử thay thế đã có thể xuất hiện nếu Nix tốt hơn hoặc dùng ngôn ngữ khác

    • Tính năng đó dùng để làm gì?
  • Tôi ngại giới thiệu bài này vì các vấn đề về khả năng sử dụng mà bình luận khác đã chỉ ra. Tôi dùng NoScript với mặc định tắt JavaScript nên không nhận ra
    Dù vậy, bài này đến đúng lúc. Công ty tôi đang đi theo hướng dùng Nix rất nhiều và chúng tôi hơi vật lộn với flakes, mà phần giải thích trong bài này rõ ràng hơn hẳn những gì tôi từng đọc trước đó

    • Coopi nói rằng họ đã cố tuân theo nâng cấp tiến bộ để vẫn đọc được dù không có JavaScript hay CSS; phía JavaScript thì đã làm hỏng, nhưng ít nhất triết lý đó vẫn có hiệu lực. Giờ chắc JavaScript cũng đã được sửa rồi
  • Đây là phản hồi của Coopi: sáng nay có thay đổi nhưng vì công việc nên chưa kịp kiểm thử, và hóa ra là JavaScript có vấn đề

  • Trang này không dùng được trên iOS mobile. Có vẻ trang được tải ở phía dưới rồi ngay lập tức cuộn lên trên, và nếu tôi cuộn xuống quá một màn hình thì có gì đó bị kích hoạt và lại kéo ngược lên trên
    Chế độ đọc vẫn hoạt động, nhưng phần tô sáng và các chi tiết kiểu dáng vốn khá ổn thì biến mất

  • Nói rằng những gì flakes làm cũng có thể làm bằng nhiều công cụ khác nhau của Guix là hợp lý, nhưng cũng nên chỉ ra rằng Nix từ lâu đã có và đến giờ vẫn có những công cụ nhỏ, trực giao để giải quyết cùng các vấn đề đó
    Điều flakes mang lại là điểm vào dự án tiêu chuẩn và hệ sinh thái mà điều đó cho phép, ví dụ như registry. Bài viết cũng nói Guix không có phần này
    Người dùng Guix có thể cho rằng không cần điểm vào tiêu chuẩn, và nhiều người dùng Nix từ trước đến nay cũng nghĩ vậy
    Nhưng nói rằng có thể làm được flakes bằng một bộ công cụ trực giao thì nghe hơi giống lập luận rằng FreeBSD không cần hỗ trợ OCI vì jail là đủ cho mọi nhu cầu. Nó bỏ qua chuyện chính sự chuẩn hóa mới tạo điều kiện cho hệ sinh thái hình thành
    Tôi rất quan tâm đến Guix và cũng đã đóng góp đôi chút, nên muốn so sánh vì sao việc build bằng guix time-machine cùng với channels.scm lại chậm hơn nhiều so với việc đổi giá trị cố định của flake rồi đánh giá Nix. Nếu chỉ chậm khoảng 3 lần, ví dụ từ 5–10 giây thành 15–30 giây, thì tôi vẫn chấp nhận được, nhưng khi tôi thử thì còn cách rất xa mức đó