diff --git a/.github/workflows/auto-update.yml b/.github/workflows/auto-update.yml index af5d93c..ffc45b5 100644 --- a/.github/workflows/auto-update.yml +++ b/.github/workflows/auto-update.yml @@ -58,10 +58,15 @@ jobs: sudo systemctl restart nix-daemon - name: Build nix packages + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | export TMPDIR=/nix/tmpdir nix flake update + chmod +x zfs-cachyos/update.py + zfs-cachyos/update.py + - env: API_TOKEN_GITHUB: ${{ secrets.AUTOMERGE_TOKEN }} run: | diff --git a/.gitignore b/.gitignore index b5c1327..54d788e 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,181 @@ trace.txt* update-git-commits.txt *.cmp *.fetchlog + +# Created by https://www.toptal.com/developers/gitignore/api/python +# Edit at https://www.toptal.com/developers/gitignore?templates=python + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### Python Patch ### +# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration +poetry.toml + +# ruff +.ruff_cache/ + +# LSP config files +pyrightconfig.json + +# End of https://www.toptal.com/developers/gitignore/api/python + diff --git a/README.md b/README.md index 63076f8..dbf4b44 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Nix packages for CachyOS Kernel -This repo contains Linux kernels with both [CachyOS patches](https://github.com/CachyOS/kernel-patches) and [CachyOS tunings](https://github.com/CachyOS/linux-cachyos). +This repo contains Linux kernels with both [CachyOS patches](https://github.com/CachyOS/kernel-patches) and [CachyOS tunings](https://github.com/CachyOS/linux-cachyos), as well as [CachyOS-patched ZFS module](https://github.com/CachyOS/zfs). ## Which kernel versions are provided? @@ -29,7 +29,7 @@ For each linux kernel entry under `packages`, we have a corresponding `linuxPack - `linux-cachyos-latest` -> `inputs.nix-cachyos-kernel.legacyPackages.x86_64-linux.linuxPackages-cachyos-latest` - `linux-cachyos-lts-lto` -> `inputs.nix-cachyos-kernel.legacyPackages.x86_64-linux.linuxPackages-cachyos-lts-lto` -## How to use +## How to use kernels Add this repo to the inputs section of your `flake.nix`: @@ -64,3 +64,59 @@ Then specify `pkgs.cachyosKernels.linuxPackages-cachyos-latest` (or other varian }; } ``` + +## How to use ZFS modules + +> Note: CachyOS-patched ZFS module may fail to compile from time to time. Most compilation failures are caused by incompatibilities between kernel and ZFS. Please check [ZFS upstream issues](https://github.com/openzfs/zfs/issues) for any compatibility reports, and try switching between `zfs_2_3`, `zfs_unstable` and `zfs_cachyos`. + +To use ZFS module with `linuxPackages-cachyos-*` provided by this flake, point `boot.zfs.package` to `config.boot.kernelPackages.zfs_cachyos`. + +```nix +{ + nixosConfigurations.example = inputs.nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + ( + { pkgs, ... }: + { + nixpkgs.overlays = [ self.overlay ]; + boot.kernelPackages = pkgs.cachyosKernels.linuxPackages-cachyos-latest; + + # ZFS config + boot.supportedFilesystems.zfs = true; + boot.zfs.package = config.boot.kernelPackages.zfs_cachyos; + + # ... your other configs + } + ) + ]; + }; +} +``` + +If you want to construct your own `linuxPackages` attrset with `linuxKernel.packagesFor (path to your kernel)`, you can directly reference the `zfs-cachyos` attribute in this flake's `packages` / `legayPackages` output, or the `cachyosKernels` overlay: + +```nix +{ + nixosConfigurations.example = inputs.nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + ( + { pkgs, ... }: + { + nixpkgs.overlays = [ self.overlay ]; + boot.kernelPackages = pkgs.cachyosKernels.linuxPackages-cachyos-latest; + + # ZFS config + boot.supportedFilesystems.zfs = true; + boot.zfs.package = pkgs.cachyosKernels.zfs-cachyos.override { + kernel = config.boot.kernelPackages.kernel; + }; + + # ... your other configs + } + ) + ]; + }; +} +``` diff --git a/flake.nix b/flake.nix index 1798496..1469af4 100644 --- a/flake.nix +++ b/flake.nix @@ -23,14 +23,24 @@ let loadPackages = pkgs: - lib.removeAttrs - (pkgs.callPackage ./kernel-cachyos { + let + kernels = + lib.removeAttrs + (pkgs.callPackage ./kernel-cachyos { + inherit inputs; + }) + [ + "override" + "overrideDerivation" + ]; + in + kernels + // { + zfs-cachyos = pkgs.callPackage ./zfs-cachyos { inherit inputs; - }) - [ - "override" - "overrideDerivation" - ]; + kernel = kernels.linux-cachyos-latest; + }; + }; in rec { systems = [ @@ -57,17 +67,23 @@ cachyosKernels = loadPackages prev; }; + # Example configurations for testing CachyOS kernel nixosConfigurations = lib.genAttrs systems ( system: inputs.nixpkgs.lib.nixosSystem { inherit system; modules = [ ( - { pkgs, ... }: + { pkgs, config, ... }: { nixpkgs.overlays = [ self.overlay ]; boot.kernelPackages = pkgs.cachyosKernels.linuxPackages-cachyos-latest; + # ZFS test + boot.supportedFilesystems.zfs = true; + boot.zfs.package = config.boot.kernelPackages.zfs_cachyos; + networking.hostId = "12345678"; + # Minimal config to make test configuration build boot.loader.grub.devices = [ "/dev/vda" ]; fileSystems."/" = { diff --git a/kernel-cachyos/mkCachyKernel.nix b/kernel-cachyos/mkCachyKernel.nix index 4462be3..fadaac4 100644 --- a/kernel-cachyos/mkCachyKernel.nix +++ b/kernel-cachyos/mkCachyKernel.nix @@ -77,10 +77,21 @@ let description = "Linux CachyOS Kernel" + lib.optionalString lto " with Clang+ThinLTO"; }; }; + + zfsPackage = callPackage ../zfs-cachyos { + inherit inputs; + kernel = kernelPackage; + }; in [ (lib.nameValuePair "linux-cachyos-${pnameSuffix}" kernelPackage) (lib.nameValuePair "linuxPackages-cachyos-${pnameSuffix}" ( - kernelModuleLLVMOverride (linuxKernel.packagesFor kernelPackage) + kernelModuleLLVMOverride ( + (linuxKernel.packagesFor kernelPackage).extend ( + final: prev: { + zfs_cachyos = zfsPackage; + } + ) + ) )) ] diff --git a/zfs-cachyos/default.nix b/zfs-cachyos/default.nix new file mode 100644 index 0000000..593ca42 --- /dev/null +++ b/zfs-cachyos/default.nix @@ -0,0 +1,35 @@ +{ + inputs, + callPackage, + kernel ? null, + lib, + fetchFromGitHub, +}: +let + versionJson = lib.importJSON ./version.json; + zfsGeneric = callPackage "${inputs.nixpkgs.outPath}/pkgs/os-specific/linux/zfs/generic.nix" { + inherit kernel; + }; +in +# https://github.com/chaotic-cx/nyx/blob/aacb796ccd42be1555196c20013b9b674b71df75/pkgs/linux-cachyos/packages-for.nix#L99 +(zfsGeneric { + kernelModuleAttribute = "zfs_cachyos"; + kernelMinSupportedMajorMinor = "1.0"; + kernelMaxSupportedMajorMinor = "99.99"; + enableUnsupportedExperimentalKernel = true; + version = builtins.elemAt (lib.splitString "-" versionJson.zfs_branch) 1; + tests = { }; + maintainers = with lib.maintainers; [ + pedrohlc + ]; + hash = ""; + extraPatches = [ ]; +}).overrideAttrs + (prevAttrs: { + src = fetchFromGitHub { + owner = "cachyos"; + repo = "zfs"; + inherit (versionJson) rev hash; + }; + postPatch = builtins.replaceStrings [ "grep --quiet '^Linux-M" ] [ "# " ] prevAttrs.postPatch; + }) diff --git a/zfs-cachyos/update.py b/zfs-cachyos/update.py new file mode 100755 index 0000000..a30b273 --- /dev/null +++ b/zfs-cachyos/update.py @@ -0,0 +1,112 @@ +#!/usr/bin/env nix-shell +#!nix-shell -i python3 -p python3 -p python3Packages.requests -p nix-prefetch-git + +import json +import os +import re +import subprocess +import sys +from pathlib import Path +from typing import Dict, Any, Optional + +import requests + + +def get_latest_zfs_cachyos_branch() -> Optional[str]: + api_url = "https://api.github.com/repos/CachyOS/zfs/branches" + all_branches = [] + page = 1 + per_page = 100 # Maximum allowed + + # Setup headers for GitHub API authentication if token is available + headers = {} + github_token = os.environ.get("GITHUB_TOKEN") + if github_token: + headers["Authorization"] = f"token {github_token}" + + while True: + params = {"per_page": per_page, "page": page} + response = requests.get(api_url, params=params, headers=headers, timeout=30) + response.raise_for_status() + + branches = response.json() + if not branches: + break + + all_branches.extend(branches) + page += 1 + + # If we got less than per_page results, we're on the last page + if len(branches) < per_page: + break + + cachyos_branches = [] + + branch_pattern = re.compile(r"^zfs-\d+\.\d+\.\d+-cachyos$") + + for branch in all_branches: + branch_name = branch.get("name", "") + if branch_pattern.match(branch_name): + cachyos_branches.append(branch_name) + + if not cachyos_branches: + print("No branch found matching zfs-x.y.z-cachyos or x.y.z-cachyos pattern") + return None + + cachyos_branches.sort(reverse=True) + latest_branch = cachyos_branches[0] + print(f"Found latest branch: {latest_branch}") + return latest_branch + + +def run_nix_prefetch_git(branch: str) -> Optional[Dict[str, Any]]: + cmd = ["nix-prefetch-git", "https://github.com/CachyOS/zfs.git", "--branch-name", branch] + + print(f"Running command: {' '.join(cmd)}") + result = subprocess.run(cmd, capture_output=True, text=True, timeout=300) + + if result.returncode != 0: + print(f"nix-prefetch-git command failed with return code: {result.returncode}") + print(f"Error output: {result.stderr}") + return None + + output = result.stdout.strip() + if not output: + print("nix-prefetch-git output is empty") + return None + + parsed_output = json.loads(output) + return parsed_output + + +def save_version_info(branch: str, prefetch_data: Dict[str, Any], output_file: Path): + with open(output_file, "w", encoding="utf-8") as f: + json.dump({"zfs_branch": branch, **prefetch_data}, f, indent=2) + + print(f"Version info saved to: {output_file}") + + +def main() -> int: + print("Starting ZFS CachyOS version update...") + + latest_branch = get_latest_zfs_cachyos_branch() + if not latest_branch: + print("Failed to get latest branch, exiting") + return 1 + + prefetch_data = run_nix_prefetch_git(latest_branch) + if not prefetch_data: + print("nix-prefetch-git execution failed, exiting") + return 1 + + script_dir = Path(__file__).parent + output_file = script_dir / "version.json" + + save_version_info(latest_branch, prefetch_data, output_file) + + print("ZFS CachyOS version info update completed!") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/zfs-cachyos/version.json b/zfs-cachyos/version.json new file mode 100644 index 0000000..b393a24 --- /dev/null +++ b/zfs-cachyos/version.json @@ -0,0 +1,15 @@ +{ + "zfs_branch": "zfs-2.3.6-cachyos", + "url": "https://github.com/CachyOS/zfs.git", + "rev": "4ddaf45ba468c6953a4fcdbfe79795f74fa6e489", + "date": "2025-03-13T10:35:31-04:00", + "path": "/nix/store/clbq55q8pca9im5jsr28g472x0l0y50w-zfs", + "sha256": "07gh7x7lwq013ni4jb6vxavhf348g8zl3db65sz408lsp2bpx0v5", + "hash": "sha256-ZYN+l7iaIkC+Lma1QT96iAwHt+rbLEmiHQFgTk8/8B0=", + "fetchLFS": false, + "fetchSubmodules": false, + "deepClone": false, + "fetchTags": false, + "leaveDotGit": false, + "rootDir": "" +} \ No newline at end of file